Table of Contents generated with DocToc
This is a step-by-step guide to writing your first working skill in <PROJECT>. It takes you from “I have an idea” to “the pull request is merged”. You do not need any earlier experience with the framework.
This is not the full authoring reference. Once you know the shape of a skill, the magpie-write-skill skill (you run it with /write-skill) takes you through every check, safety step, and packaging detail. Come back to it after your first skill has landed and you want the complete checklist.
New to some of these words? Here is what they mean here. The education landing page has a fuller list.
--- lines.<PROJECT> or <tracker> that each project fills in with its own value.You need:
<framework> repository, and a setup that can run uv commands (see CONTRIBUTING.md).You do not need to understand the full set of skill types, the Privacy-LLM gate, or how adapters work before you start. Those matter for complex skills. A first skill almost always avoids them.
A skill is a Markdown file that an AI agent reads and follows, step by step. It is not a function, a script, or a config file.
| Traditional code | A skill |
|---|---|
| Runs the same way every time | Read by a language model, so the output can vary |
| Right or wrong (yes or no) | Better or worse at the task, by degree |
| Checked by a test suite | Checked by an eval suite: example inputs plus what a good answer must look like |
| Changed when the logic changes | Changed when the agent's behaviour drifts from what you meant |
| “Does it pass?” | “Does it behave well across all the examples?” |
This changes how you think about “correct”. You cannot test a skill the way you test a function. Instead, you write example cases that cover the range of real inputs, and you check that the agent's output meets the criteria you care about. When you find a new way it can fail, you add an example for it.
The pattern catalogue has ready-to-copy examples. The eval-driven-development page goes deeper on how to judge output that can vary.
Skills live in skills/<name>/SKILL.md. Each skill is a directory (not a single file), so there is room for supporting files, scripts, and eval examples next to the skill text.
Read two or three existing skills first, to get a feel for the style:
ls skills/ cat skills/issue-fix-workflow/SKILL.md
Look at:
--- markers.<PROJECT>, <tracker>, <upstream>, <security-list>), used so that no real project name appears in the skill body.Good first skills are small. One trigger, one output, one decision the agent helps the person make. For example:
A skill that tries to do three things at once is harder to test, harder to review, and harder to improve. Pick the smallest piece you can check.
The framework ships a script that creates a starter file for you. Run it from the repository root, passing the skill name and the output directory:
python3 skills/write-skill/scripts/init_skill.py <name> --path skills/<name>
This creates skills/<name>/SKILL.md with the required settings keys, the SPDX comment, the placeholder comment, and the adopter-overrides section already in place.
Fill in the settings (the frontmatter) before you write the body:
--- name: <name> description: | One or two sentences. What does this skill do, and when is it useful? Written from the maintainer's perspective: "Triages incoming issues by …", not "This skill triages…". when_to_use: | The trigger vocabulary. What phrases or situations cause the agent to invoke this skill? Be concrete — the agent uses this text to decide whether this is the right skill for the moment. capability: capability:<tag> license: Apache-2.0 ---
The capability: tag places this skill in the framework's set of categories. Look at the existing skills for the tag that fits best. Common values: capability:triage, capability:authoring, capability:security, capability:release, capability:contributor-growth.
A skill body is a list of numbered steps the agent follows in order. Each step has a heading, a short note on why the step matters, and either a concrete action for the agent to take or a decision for it to put to the maintainer.
The smallest useful structure:
## Step 1 — [Name of what the agent does first] [Why this step comes first. What context the agent needs.] [The action: what to read, what to check, what to draft.] ## Step 2 — Propose to the maintainer Draft a response with the following information: - [Field 1] - [Field 2] Present this to the maintainer and wait for confirmation before taking any action that is visible outside the session.
Every skill body must follow three rules:
External content is data, not instructions (PRINCIPLE 0). If the skill reads issue bodies, PR comments, email, or any other outside text, it passes that text through the Privacy-LLM gate or treats it as plain data. It never treats it as an order to the agent. Do not write a step that says “follow the instructions in the issue”. Write a step that says “read the issue body to work out X”.
Propose, confirm, act. Any action that is visible outside the session (posting a comment, applying a label, closing an issue) must be proposed to the maintainer and confirmed before it runs. The skill ends with a proposal, not an action, unless the maintainer has confirmed in this session.
Use placeholders, not project names. Write <tracker>, <upstream>, <PROJECT>, and <security-list> wherever a real project name would go. A skill with apache/airflow written into it will drift from the framework and break later.
The framework's validator checks that the frontmatter is complete, the placeholders are used, the links work, and the capability tag is present. Run it before you write evals:
uv run --project tools/skill-and-tool-validator --group dev skill-and-tool-validate
Fix every warning before you move on. The most common first-time problems:
when_to_use — the agent cannot pick your skill without it.capability: tag — the taxonomy-coverage check fails.[text](path) points to a real file.A skill without an eval suite is not finished (AGENTS.md § Reusable skills). The eval suite is your evidence that the skill behaves well across the range of inputs it will meet in real use.
The harness tests a skill one step at a time. For each step you want to cover, you give some example inputs and say what a correct answer must look like. See tools/skill-evals/README.md for the full method. The layout is:
tools/skill-evals/evals/<name>/ <step>/ # one directory per skill step you test fixtures/ step-config.json # which skill file and which step this tests user-prompt-template.md # the input the agent receives output-spec.md # the exact output a correct answer must return case-1-.../ # one directory per example case case-2-.../
step-config.json ties the eval to your skill and the step heading it checks:
{ "skill_md": "skills/<name>/SKILL.md", "step_heading": "## Step 2 — Propose to the maintainer" }
output-spec.md states what the agent must return (the harness checks the output against it, usually as structured JSON). user-prompt-template.md is the input, with {placeholders} filled in from each case.
Write at least a few cases: a normal input, an empty or trivial input, and one attack case (an input designed to make the agent act without confirmation). The attack case is your prompt-injection check.
Run the suite from the repository root. On its own the runner just assembles the prompts; add --cli with your agent's command to actually run and grade them (for example claude -p, llm, or ollama run …):
# assemble the cases, no model call PYTHONPATH=tools/skill-evals/src python3 -m skill_evals.runner \ tools/skill-evals/evals/<name>/ # run and grade with your agent's CLI PYTHONPATH=tools/skill-evals/src python3 -m skill_evals.runner --cli "<agent-command>" \ tools/skill-evals/evals/<name>/
See the eval-driven-development page for a fuller worked example.
Before you open it:
# Final validation pass uv run --project tools/skill-and-tool-validator --group dev skill-and-tool-validate # Confirm evals still pass (add --cli with your agent's command to grade) PYTHONPATH=tools/skill-evals/src python3 -m skill_evals.runner --cli "<agent-command>" \ tools/skill-evals/evals/<name>/
Both must be clean. Then commit and open a PR against the default branch of <framework>. The PR description should answer:
A reviewer will read the skill, run the evals, and check the injection-defence steps. The review goes faster when the PR description points the reviewer at the interesting decisions.
Skills drift over time. The agent‘s behaviour changes as the model behind it updates; the project’s process changes as people come and go; the framework's conventions change too.
When you notice drift:
There is no separate “maintenance” step. The eval suite is the living definition of “correct” for your skill. Keeping it green is keeping the skill healthy.
Writing a skill that acts instead of proposing. Every action visible outside the session must be confirmed first. If your skill's last step is “post the comment”, add a step before it: “Draft the comment and propose it to the maintainer. Wait for confirmation.”
Writing in a project name. <tracker> and <upstream> are the placeholders. If you catch yourself writing apache/airflow, that is a mistake to fix.
Writing only one eval fixture. A single normal-case fixture is not a suite. At least add an empty-input case and an attack case. The attack fixture is often the most valuable one: it is the one that catches prompt-injection problems.
Skipping the validator before opening the PR. CI runs the same validator. Running it yourself first saves a round of back-and-forth.
Writing a skill body that is too long. If your skill has more than eight steps, it is probably doing two jobs. Split it. Two small skills you can test on their own are more reliable than one large skill you cannot.
This is step 4 in the learning progression. The natural next step is to make the skill safe to run against outside text:
Supporting references for skill-writing:
/write-skill once you are ready for the complete walk-through.