Advertise a skill by description, load the body on demand
Write a SKILL.md, confirm the system prompt carries its name, description and path but not its body, and force it with /skill:name.
A prompt template waits until you type it. A skill begins when Pi recognises the kind
of task. The whole mechanism turns on one field: the system prompt carries every skill’s
name, description and path, never the body, so the description is the entire routing
surface. This page writes a SKILL.md and shows exactly what the model is told.
Write the skill
A skill is a directory containing SKILL.md:
review-guard/
└── SKILL.md---
name: review-guard
description: Reviews changed code against this repository's conventions and runs its own checks. Use when reviewing a diff, a pull request, or uncommitted changes.
---
# Review guard
1. Run `scripts/run-checks.sh` and read the output before reviewing anything.
2. Read `references/checklist.md` and apply it to the diff.
3. Report findings ordered by severity, each with a file path.Place it in your user or project skills directory and run Pi from a location where it is discoverable. The description states both what the skill does and when it applies; “Reviews code” gives the model nothing to match against “implement this”, while the text above does.
What the model is told
| At startup | After the task matches, or /skill:name |
|---|---|
| name, description and path, in the system prompt | the SKILL.md body |
| not the body | arguments appended as a user request |
That split is why an irrelevant skill costs almost nothing, and why the body loads
whole every time it fires. A body that has outgrown a screen wants a file beside it
(chapter 14), not a longer SKILL.md.
Expected outcome
The backing test creates skills in a user directory and inspects the request the provider receives. It asserts, at Pi 1.0.4:
- the system prompt matches the skill name, its description and
SKILL.md, and does not match a marker placed in the body; - a skill with no
descriptionis absent from the prompt entirely — a silent disappearance, not an error; /skill:review-guard src/auth onlyputs the body and the appended argument in the user message;disable-model-invocation: trueremoves the description from what the model is told but leaves/skill:review-guardworking;- a skill under
skills/group/inner/is discovered recursively; - of two skills named
review, exactly one is advertised.
These are observed assertions from a real session with a scripted provider, not a transcript of a real model deciding to route.
Mechanism and limitations
Documented: the pinned docs/skills.md defines the format and frontmatter fields,
says startup adds each skill’s name, description and path to the system prompt but not
the full instructions, states that arguments after /skill:name are appended, documents
disable-model-invocation, and notes that directories containing SKILL.md are
discovered recursively and that skills without descriptions are not loaded.
Observed: skills.test.ts checks every bullet above against the prompt and messages
a scripted provider received. It never exercises routing itself.
Routing is a convention, not a guarantee: docs/skills.md says a model might fail to
load a relevant skill, which is why /skill:name exists. A skill is still text — it can
say “never force push”, but nothing enforces it. If you reach for /skill:name
routinely, the description needs work or the skill is really a template.
Understand this example
Copy this prompt into your AI tool. No code runs here.
Apply this example
Copy this prompt into your AI tool. No code runs here.