SkillLoader discovers them automatically from your workspace when workspace_root is set on an agent.
Skill directory structure
SKILL.md is required. Add scripts/ only when your skill needs executable tools.
Step-by-step guide
Create the skill directory
Place your skill in one of the workspace discovery paths.
SkillLoader.discover_workspace_skills() searches these locations relative to workspace_root:.agent/skills/<skill-name>/_agent/skills/<skill-name>/.agents/skills/<skill-name>/_agents/skills/<skill-name>/
release_assistant:Write SKILL.md
SKILL.md has two parts: a YAML frontmatter block with metadata, and a Markdown body with the instructions injected into the agent’s system prompt.SkillMetadata:Unique identifier for the skill. Used to load it by name:
skills=["release_assistant"].Human-readable description of what the skill does.
Semantic version string. Defaults to
1.0.0 if omitted.Author name or team identifier.
List of topic tags for discoverability, e.g.
[release, docs].External dependencies or tools the skill relies on, e.g.
[git]. Informational only — the agent does not enforce these automatically.Add tool functions in scripts/
Create one or more Tool discovery rules:
.py files inside scripts/. SkillLoader imports each file and treats every public function with a docstring as a tool.- Functions whose names begin with
_are skipped. - A docstring is required — functions without one are ignored.
- Type annotations are used to generate the parameter schema. Unannotated parameters default to
string. - The docstring becomes the tool’s
descriptionin the schema passed to the model.
The Skill base class
All loaded skills are instances of logicore.skills.base.Skill. You can also construct a Skill object programmatically without a filesystem directory:
Skill constructor parameters
A
SkillMetadata dataclass instance with name, description, version, author, tags, and requires.Markdown instructions injected into the agent’s system prompt inside
<skills> tags.List of tool schema dicts in OpenAI function-calling format. Each entry has
type: "function" and a nested function object with name, description, and parameters.Dict mapping tool function names to their Python callables, used at runtime when the model invokes a skill tool.
Optional additional text appended directly to the system prompt, separate from the
<skills> block.pathlib.Path to the skill’s root directory. Used by get_scripts_dir() and get_resources_dir() helpers. Set to None for programmatically constructed skills.The SkillLoader class
SkillLoader is a static-method utility class in logicore.skills.loader. It handles all filesystem-based skill operations.
SkillLoader.load(skill_dir)
SkillLoader.load(skill_dir)
Load a single skill from a directory path. Returns a
Skill instance, or None if SKILL.md is missing or parsing fails.SkillLoader.discover(skills_dir)
SkillLoader.discover(skills_dir)
Scan a parent directory and load every subdirectory that contains a
SKILL.md. Returns a list of Skill instances.SkillLoader.discover_workspace_skills(workspace_root)
SkillLoader.discover_workspace_skills(workspace_root)
Search all four convention directories (This is the method called internally when you pass
.agent/skills/, _agent/skills/, .agents/skills/, _agents/skills/) under workspace_root and return all discovered skills.workspace_root to an Agent and load skills by string name.Complete working example
The following is a self-contained example of a customdata_extractor skill with two tools.
Sharing and publishing skills
Skills are plain directories — sharing them is as simple as copying the folder.Within a team
Commit the
.agent/skills/ directory to your repository. Every team member with workspace_root pointing at the repo root will discover the same skills automatically.As a package
Distribute a skill as a Python package that places its skill directory into
logicore/skills/defaults/ on installation, making it available by name without a workspace_root.Skills placed in
logicore/skills/defaults/ are resolved before workspace skills. If a workspace skill and a built-in skill share the same name, the built-in will take precedence.