If you want to call MagicSkills directly from scripts, tests, agent runtimes, or higher-level frameworks instead of going through the CLI, use the Python API. The content below follows the current __all__ in /root/LLK/MagicSkills/src/magicskills/__init__.py.
from pathlib import Path
from magicskills import (
ALL_SKILLS,
REGISTRY,
Skills,
listskill,
readskill,
execskill,
)Exports
- types:
Skill,Skills - accessors and constants:
REGISTRY,ALL_SKILLS(),DEFAULT_SKILLS_ROOT - single-skill and execution functions:
listskill,readskill,showskill,execskill,addskill,createskill_template,install,uploadskill,deleteskill - skills collection and registry functions:
addskills,listskills,deleteskills,syncskills,loadskills,saveskills - description and dispatch functions:
change_tool_description,changetooldescription,change_cli_description,changeclidescription,skill_tool
Usage advice
- If you already have a
Skillsobject, prefer instance methods such asskills.readskill(),skills.execskill(), andskills.syncskills(). - If you want to directly reuse CLI-equivalent capabilities, top-level functions are more direct.
changetooldescriptionis a compatibility alias ofchange_tool_description; they are equivalent.changeclidescriptionis a compatibility alias ofchange_cli_description; they are equivalent.
Use case
Use this when you need to manually construct a skill metadata object, or serialize skill metadata into another system.
Constructor signature
Skill(
name: str,
description: str,
path: Path,
base_dir: Path,
source: str,
is_global: bool = False,
universal: bool = False,
)Parameters
name: the skill name, usually equal to the skill directory namedescription: a short description of the skill, usually coming from thedescriptionfield inSKILL.mdfrontmatterpath: the skill directory pathbase_dir: the skills root directory that contains the skillsource: source information, such as a local path, Git URL, or repository addressis_global: whether it comes from a global directoryuniversal: whether it comes from the.agent/skillslayout
Available capabilities
- direct access to dataclass fields
- call
to_dict()to get a JSON-friendly dictionary
Examples
from pathlib import Path
from magicskills import Skill
skill = Skill(
name="demo",
description="Demo skill",
path=Path("./skills/demo").resolve(),
base_dir=Path("./skills").resolve(),
source="https://github.com/example/repo.git",
)
print(skill.name)
print(skill.to_dict())Use case
Use this when you want to maintain a group of skills in memory and manage listing, reading, execution, syncing, deletion, and related operations in an object-oriented style.
Constructor signature
Skills(
skill_list: Iterable[Skill] | None = None,
paths: Iterable[Path | str] | None = None,
tool_description: str | None = None,
cli_description: str | None = None,
agent_md_path: Path | str | None = None,
name: str = "all",
)Parameters
skill_list: an explicit list ofSkillobjectspaths: a list of skills root directories, or a list of individual skill directories; skills are discovered automatically during constructiontool_description: the tool description text of this collectioncli_description: an alternate CLI-oriented description text forsyncskills(mode="cli_description")agent_md_path: whichAGENTS.mdfile this collection should sync to by defaultname: the collection name, defaulting to"all"
Notes
- If
skill_listandpathsare both provided, they must resolve to exactly the same skills, otherwise aValueErroris raised. - When only
pathsis provided, directories are scanned automatically forSKILL.md. - When only
skill_listis provided,pathsare inferred automatically. agent_md_pathdefaults toAGENTS.mdin the current working directory.
Common instance methods
get_skill(target): retrieve oneSkillby name or directory pathaddskill(target, source=None)deleteskill(target)listskill()readskill(target)uploadskill(target)showskill(target)execskill(command, shell=True, timeout=None, stream=False)change_tool_description(description)change_cli_description(description)syncskills(output_path=None, mode="none")skill_tool(action, arg="")
These instance methods map one-to-one to the top-level functions described below. If you prefer a functional style, you can use the top-level functions directly.
Examples
from magicskills import Skills
skills = Skills(
paths=["./.claude/skills"],
name="coder",
agent_md_path="./agents/coder/AGENTS.md",
)
print(skills.listskill())
print(skills.readskill("demo"))
result = skills.execskill("echo hello", stream=False)
print(result.returncode, result.stdout)
skills.syncskills()SkillsRegistry is the internal registry type behind REGISTRY. Direct instantiation is disabled. Use the global REGISTRY singleton for named collection management.
Use case
This is the process-level global SkillsRegistry singleton. Most named collection operations can be done directly around it.
Parameters
None. It is a ready-made object and does not need to be instantiated.
Examples
from magicskills import REGISTRY
print([item.name for item in REGISTRY.listskills()])Create and persist a collection through the global registry:
from magicskills import REGISTRY
REGISTRY.addskills(name="coder")
coder = REGISTRY.get_skills("coder")
print(coder.agent_md_path)
REGISTRY.saveskills()
REGISTRY.loadskills()Use case
This is an accessor function that returns the built-in Allskills view from the current registry. Many top-level functions work naturally with the result of ALL_SKILLS() as their first argument.
Parameters
No parameters.
Notes
ALL_SKILLS()always resolves the current value fromREGISTRY.- If you call
loadskills()in the same process, callingALL_SKILLS()again returns the refreshedAllskillsview.
Examples
from magicskills import ALL_SKILLS, listskill, readskill
print(listskill(ALL_SKILLS()))
print(readskill(ALL_SKILLS(), "demo"))Use case
You want the default .claude/skills path for the current working directory, so you can reuse it in your own initialization or installation logic.
Parameters
None. It is a constant whose value is Path.cwd() / ".claude" / "skills".
Examples
from magicskills import DEFAULT_SKILLS_ROOT
print(DEFAULT_SKILLS_ROOT)Use case
You want to format the skill list of a Skills collection into plain text output.
Signature
listskill(skills: Skills) -> strParameters
skills: theSkillscollection to list
Return value
- returns a formatted multi-line string
Examples
from magicskills import ALL_SKILLS, listskill
print(listskill(ALL_SKILLS()))Use case
Read SKILL.md by skill name, or read any text file by file path.
Signature
readskill(skills: Skills, target: str | Path) -> strParameters
skills: the targetSkillscollectiontarget: a skill name, or an explicit file path
Return value
- returns the text content of the file
Examples
Read by skill name:
from magicskills import ALL_SKILLS, readskill
content = readskill(ALL_SKILLS(), "demo")
print(content)Read by path:
from pathlib import Path
from magicskills import ALL_SKILLS, readskill
content = readskill(ALL_SKILLS(), Path("./skills/demo/SKILL.md"))
print(content)Use case
You want more than SKILL.md; you want the metadata and full file contents of the entire skill directory.
Signature
showskill(skills: Skills, target: str | Path) -> strParameters
skills: the targetSkillscollectiontarget: a skill name or a skill directory path
Return value
- returns a formatted full display string
Examples
from magicskills import ALL_SKILLS, showskill
print(showskill(ALL_SKILLS(), "demo"))Use case
Use this when you want to execute commands via the Python API and receive structured execution results.
Signature
execskill(
skills: Skills,
command: str,
shell: bool = True,
timeout: float | None = None,
stream: bool = False,
) -> ExecResultParameters
skills: theSkillscollection required by the current API shapecommand: the command string to executeshell: whether to execute through a shell; defaultTruetimeout: timeout in seconds; omit to disablestream: whether to stream output directly to the current terminal; defaultFalse
Return value
- returns
ExecResultwith fieldscommand,returncode,stdout, andstderr - when
stream=True,stdoutandstderrare empty strings because the output is already written directly to the terminal
Examples
Get a structured result:
from magicskills import ALL_SKILLS, execskill
result = execskill(ALL_SKILLS(), "echo hello", stream=False)
print(result.returncode, result.stdout, result.stderr)Execute in no-shell mode:
from magicskills import ALL_SKILLS, execskill
result = execskill(ALL_SKILLS(), "python -c 'print(123)'", shell=False)
print(result.stdout)Stream execution:
from magicskills import ALL_SKILLS, execskill
execskill(ALL_SKILLS(), "pytest -q", stream=True)With timeout:
from magicskills import ALL_SKILLS, execskill
result = execskill(ALL_SKILLS(), "sleep 1", timeout=2)
print(result.returncode)Use case
You need to generate a minimal usable skill skeleton first, and then fill in SKILL.md, scripts, and reference files.
Signature
createskill_template(name: str, base_dir: Path | str) -> PathParameters
name: the skill name, also used as the directory namebase_dir: the skills root under which the skill should be created
Return value
- returns the
Pathof the new skill directory
Examples
from magicskills import createskill_template
skill_dir = createskill_template("my-skill", "./skills")
print(skill_dir)This API ensures the following exist:
<base_dir>/<name>/references/scripts/assets/- a default
SKILL.md
Use case
You already have an existing skill directory and only want to register it into a Skills collection.
Signature
addskill(
skills: Skills,
target: Path | str,
source: str | Path | None = None,
) -> PathParameters
skills: the targetSkillscollectiontarget: either a skill directory path, or a skill name already discoverable from built-inAllskillssource: optional source information; if omitted, the absolute path of the parent directory is recorded by default
Return value
- returns the registered skill directory
Path
Examples
Register into the built-in Allskills view:
from magicskills import ALL_SKILLS, addskill
path = addskill(ALL_SKILLS(), "./skills/demo")
print(path)Add one existing skill by name into another collection:
from magicskills import ALL_SKILLS, REGISTRY, addskill
reviewer = REGISTRY.get_skills("reviewer")
path = addskill(reviewer, "demo")
print(path)Notes:
- This API registers one existing skill and does not copy files.
- If you register a skill into a non-
Allskillscollection, the same skill is also added to the built-inAllskillsview. - If the target collection belongs to the current
REGISTRY, the registry is saved automatically.
Use case
You want to install skills through the Python API instead of calling the CLI.
Signature
install(
source: str | None = None,
global_: bool = False,
universal: bool = False,
yes: bool = False,
target_root: Path | str | None = None,
) -> list[Path]Parameters
source: a local path, GitHub short form, Git URL, or a skill name in the default repositoryglobal_: whether to use Home as the install base directoryuniversal: whether to switch the install root to.agent/skillsyes: whether to overwrite directly if the target already existstarget_root: custom install directory; cannot be used together withglobal_oruniversal
Return value
- returns the list of directories actually written to disk
Examples
Install one skill from the default repository:
from magicskills import install
paths = install("demo")
print(paths)Batch install from a local directory:
from magicskills import install
paths = install("./skills", target_root="./custom-skills", yes=True)
print(paths)Install using a GitHub short form:
from magicskills import install
paths = install("owner/repo", global_=True)
print(paths)Notes:
- The resolution order is the same as the CLI: local path first, then default repository skill name, then Git repository.
- After installation, skills are registered into the built-in
Allskillsview and persisted into the currentREGISTRY.
Use case
You want to trigger the skill upload, fork, push, and PR workflow directly from Python code.
Signature
uploadskill(
skills: Skills | Path | str,
target: str | Path | None = None,
) -> UploadResultParameters
skills: two valid forms are supported- pass a
Skillsobject: in this case you must also passtarget, which identifies a skill by name or path in that collection - pass a
Pathorstrpath: in this casetargetstaysNone, and the first argument itself is the skill directory target: used when the first argument isSkills, representing a skill name or skill directory path
Return value
- returns
UploadResultwith fieldsskill_name,repo,branch,remote_subpath,committed,pushed,push_remote,push_branch,pr_url, andpr_created
Examples
Upload by name from the built-in Allskills view:
from magicskills import ALL_SKILLS, uploadskill
result = uploadskill(ALL_SKILLS(), "demo")
print(result.pr_url)Upload directly by local path:
from magicskills import uploadskill
result = uploadskill("./skills/demo")
print(result.repo, result.push_branch)Notes
- Before running, the same prerequisites as the CLI must be satisfied:
ghmust be installed and authenticated locally, and the target skill directory must containSKILL.md. - If you pass a
Skillsobject and multiple skills have the same name, pass an explicit directory path instead.
Use case
You want to delete a skill from the Python API; when applied to the built-in Allskills view, it also deletes the directory on disk.
Signature
deleteskill(skills: Skills, target: str) -> strParameters
skills: the targetSkillscollectiontarget: a skill name or a skill directory path
Return value
- returns the resolved path string of the deleted skill
Examples
Remove only from a named collection:
from magicskills import REGISTRY, deleteskill
team = REGISTRY.get_skills("coder")
deleted = deleteskill(team, "./skills/demo")
print(deleted)Delete completely from the built-in Allskills view:
from magicskills import ALL_SKILLS, deleteskill
deleted = deleteskill(ALL_SKILLS(), "demo")
print(deleted)Notes:
- When you pass a non-
Allskillscollection, the skill is only removed from that collection and not deleted from disk. - When you pass the built-in
Allskillsview, the actual skill directory is deleted, and matching path references are removed from other named collections as well.
Use case
You want to create a named Skills collection and register it into the global REGISTRY immediately.
Signature
addskills(
name: str,
skill_list: list[Skill] | str | None = None,
paths: list[str] | None = None,
tool_description: str | None = None,
cli_description: str | None = None,
agent_md_path: str | None = None,
) -> SkillsParameters
name: the collection nameskill_list: may be a list ofSkillobjects, or a single skill name stringpaths: a list of skills root paths or individual skill directory pathstool_description: the tool description text of the collectioncli_description: the CLI description text of the collectionagent_md_path: whichAGENTS.mdthis collection should sync to by default
Return value
- returns the created
Skillsobject and persists it into the registry by default
Examples
Create an empty collection:
from magicskills import addskills
skills = addskills("coder")
print(skills.name, len(skills.skills))Create by paths:
from magicskills import addskills
# Prerequisite: these skills have already entered the built-in Allskills view via install/addskill
skills = addskills(
"coder",
paths=["./.claude/skills"],
tool_description="Unified skill tool for coding tasks",
cli_description="Use magicskills CLI commands only",
agent_md_path="./agents/coder/AGENTS.md",
)
print(skills.agent_md_path)Create from a single skill name:
from magicskills import addskills
# Prerequisite: the built-in Allskills view can already resolve a skill named demo
skills = addskills("reviewer", skill_list="demo")
print([item.name for item in skills.skills])Notes
- If both
pathsandskill_listare omitted, an empty collection is created. pathsand string-formskill_listboth depend on the current built-inAllskillsview being able to resolve the target skill or its parent skills root.
Use case
List all named collections currently managed by the global REGISTRY.
Signature
listskills() -> list[Skills]Parameters
None.
Return value
- returns a list of
Skillsobjects
Examples
from magicskills import listskills
for item in listskills():
print(item.name, len(item.skills))Use case
Delete the registration of a named Skills collection.
Signature
deleteskills(name: str, *more_names: str) -> NoneParameters
name: the first named collection to deletemore_names: optional additional named collections to delete in the same call
Examples
from magicskills import deleteskills
deleteskills("coder")Delete multiple named collections:
from magicskills import deleteskills
deleteskills("coder", "reviewer", "release_skills")Notes
- Only the collection registration is deleted; skill files remain intact.
Allskillscannot be deleted.
Use case
Sync a Skills collection into an AGENTS.md file.
Signature
syncskills(
skills: Skills,
output_path: Path | str | None = None,
mode: str = "none",
) -> PathParameters
skills: theSkillscollection to syncoutput_path: the target file path; if omitted,skills.agent_md_pathis usedmode: one ofnoneorcli_description
How to choose the mode
none: use this for agents that can directly discover and use skills from the skill information list inAGENTS.mdcli_description: use this for agents that cannot directly use skills from the skill information list inAGENTS.mdand instead need CLI guidance throughmagicskills skill-tool
Return value
- returns the final written file path as a
Path
Examples
Sync to the collection's default file:
from magicskills import REGISTRY, syncskills
coder = REGISTRY.get_skills("coder")
path = syncskills(coder)
print(path)Sync to a specified file:
from magicskills import REGISTRY, syncskills
coder = REGISTRY.get_skills("coder")
path = syncskills(coder, "./AGENTS.md")
print(path)Sync using only cli_description:
from magicskills import REGISTRY, syncskills
coder = REGISTRY.get_skills("coder")
path = syncskills(coder, mode="cli_description")
print(path)Use case
Reload the persisted state of the global REGISTRY from disk.
Signature
loadskills(path: str | None = None) -> list[Skills]Parameters
path: optional registry JSON path; if omitted, the currentREGISTRYstore path is used
Return value
- returns the list of loaded
Skills
Examples
from magicskills import loadskills
collections = loadskills("./collections.json")
print([item.name for item in collections])Use case
Write the current global REGISTRY state back to disk.
Signature
saveskills(path: str | None = None) -> strParameters
path: optional output path; if omitted, save to the currentREGISTRYstore path
Return value
- returns the written file path as a string
Examples
from magicskills import saveskills
saved_path = saveskills("./collections.json")
print(saved_path)Use case
Modify the tool_description metadata on a Skills collection.
Signature
change_tool_description(skills: Skills, description: str) -> None
changetooldescription(skills: Skills, description: str) -> NoneParameters
skills: the targetSkillscollectiondescription: the new description text
Examples
from magicskills import REGISTRY, change_tool_description
coder = REGISTRY.get_skills("coder")
change_tool_description(coder, "Unified skill tool for coding and review tasks")Call through the compatibility alias:
from magicskills import REGISTRY, changetooldescription
coder = REGISTRY.get_skills("coder")
changetooldescription(coder, "Unified skill tool")Notes
- If the target collection belongs to the current
REGISTRY, this API automatically persists the modification into the registry. - This metadata is suitable for external frameworks or your own wrapper layer to read.
- It no longer affects
syncskills()output.
Use case
Modify the cli_description metadata on a Skills collection.
Signature
change_cli_description(skills: Skills, description: str) -> None
changeclidescription(skills: Skills, description: str) -> NoneParameters
skills: the targetSkillscollectiondescription: the new description text
Examples
from magicskills import REGISTRY, change_cli_description
coder = REGISTRY.get_skills("coder")
change_cli_description(
coder,
'Whenever you receive a task, you must first run "magicskills skill-tool listskill --name {skills_name}", then use readskill to inspect relevant docs, and finally decide whether to keep reading or run execskill.',
)Call through the compatibility alias:
from magicskills import REGISTRY, changeclidescription
coder = REGISTRY.get_skills("coder")
changeclidescription(coder, 'Whenever you receive a task, you must first run "magicskills skill-tool listskill --name {skills_name}", then use readskill to inspect relevant docs, and finally decide whether to keep reading or run execskill.')Notes
- If the target collection belongs to the current
REGISTRY, this API automatically persists the modification into the registry. - This metadata is suitable for CLI-oriented wrappers or your own runtime layer to read.
- It affects
syncskills()output only when you usemode="cli_description".
Use case
You want to reuse a unified agent/tool-call style entry point in Python, rather than dispatching listskill, readskill, and execskill yourself.
Signature
skill_tool(skills: Skills, action: str, arg: str = "") -> dict[str, object]Parameters
skills: the targetSkillscollectionaction: action name, supporting:listskill,list,list_metadatareadskill,read,read_fileexecskill,exec,run_commandarg: action argument- for
listskill, it may be empty - for
readskill, pass a skill name or file path - for
execskill, pass a plain command string, JSON string, or the legacyname::commandformat
Return value
- returns a dictionary, typically shaped like
{"ok": True, "action": "...", "result": ...} - when the action is unknown or execution fails, returns
{"ok": False, "error": "..."}
Examples
List skills:
from magicskills import ALL_SKILLS, skill_tool
print(skill_tool(ALL_SKILLS(), "listskill"))Read a skill:
from magicskills import ALL_SKILLS, skill_tool
print(skill_tool(ALL_SKILLS(), "readskill", "demo"))Execute a plain command:
from magicskills import ALL_SKILLS, skill_tool
print(skill_tool(ALL_SKILLS(), "execskill", "echo hello"))Execute a JSON-form command:
from magicskills import ALL_SKILLS, skill_tool
print(skill_tool(ALL_SKILLS(), "execskill", '{"command":"echo hello"}'))Execute the legacy command format:
from magicskills import ALL_SKILLS, skill_tool
print(skill_tool(ALL_SKILLS(), "execskill", "demo::echo hello"))