Filesystem-based agent skills.
A skill is a subdirectory under a skills directory (e.g. .planck/skills/)
containing a SKILL.md file. The file has YAML frontmatter with name and
description, followed by usage instructions, resource references, and any
other context the agent needs.
Directory layout
.planck/skills/
└── n8n-expert/
├── SKILL.md ← required
├── docs/
│ └── node-types.md ← lazily loaded by the agent via `read`
└── scripts/
└── validate.sh ← runnable via `bash`SKILL.md format
---
name: n8n-expert
description: Expert at building n8n workflows and automation.
---
# N8N Expert
You are an expert at n8n...
## Resources
- `docs/node-types.md` — reference for all n8n node types
- `scripts/validate.sh` — validates a workflow JSON fileOnly name and description are parsed from the frontmatter. The rest of
the file is plain Markdown consumed by the agent when it loads the skill.
Usage
skills = Planck.Agent.Skill.load_all(["~/.planck/skills"])
# Skills are typically threaded through AgentSpec.to_start_opts/2 via
# skill_pool:, which resolves spec.skills names and appends the skill
# section to system_prompt for the relevant agent.
start_opts = Planck.Agent.AgentSpec.to_start_opts(spec, skill_pool: skills)The agent discovers skills from the system prompt index and loads SKILL.md
via the read tool when a skill is relevant. Scripts are run via bash.
No special runtime support is required — skills are just files.
Summary
Functions
Load a single skill from a SKILL.md file path.
Build a list_skills tool that returns all available skill names and descriptions.
Load all skills from a list of directories.
Build a load_skill tool that loads a skill's SKILL.md by name.
Generate a skills section for injection into an agent's system prompt.
Types
@type t() :: %Planck.Agent.Skill{ description: String.t(), name: String.t(), path: Path.t(), skill_file: Path.t() }
A loaded skill.
:name— identifier used in the system prompt index:description— one-line summary shown to the agent:path— absolute path to the skill directory:skill_file— absolute path toSKILL.md
Functions
Load a single skill from a SKILL.md file path.
Returns {:ok, skill} or {:error, reason}.
@spec list_skills_tool([t()]) :: Planck.Agent.Tool.t()
Build a list_skills tool that returns all available skill names and descriptions.
This is an opt-in discovery tool. Add "list_skills" to an agent's TEAM.json
"tools" array when that agent needs to autonomously discover what skills exist.
Workers that receive skill names from the orchestrator do not need this tool.
Load all skills from a list of directories.
Each directory is scanned for subdirectories containing a SKILL.md file.
Directories that do not exist are silently skipped. Invalid SKILL.md files
are skipped with a warning.
Paths are expanded via Path.expand/1 so ~ and relative paths resolve
correctly.
@spec load_skill_tool([t()]) :: Planck.Agent.Tool.t()
Build a load_skill tool that loads a skill's SKILL.md by name.
The tool is a closure over the given skill pool. It is automatically added to
every agent when skills are available — agents do not need to declare it in
their TEAM.json "tools" array.
Generate a skills section for injection into an agent's system prompt.
Produces a compact index of skill names and descriptions, followed by an
instruction to load skills via the load_skill tool. Returns nil when
the list is empty.