How I Write Agent Skill From One Real Failure
Write agent skill from one repeated failure: see SKILL.md layout, the description line wey controls when e fires, plus a simple test to confirm say e work.
Write your own agent skill from one real failure
The best way to write your own agent skill na to distill am from one real failure. Find one task wey your coding agent don get wrong twice, write down the correction wey you type both times, then save that correction as a SKILL.md file wey the agent fit load by itself. Everything after that na mechanics: the file layout, and the one line wey decide whether the skill go ever fire.
That order matter. Skill wey you write from imagination dey document problem wey you never get, and e still dey use context for every session. Skill wey you distill from failure wey you watch come with its own test: ask the same thing again, then check whether the agent get am right this time. If the format still new to you, read wetin agent skills be and how agent dey load dem first, then come back write one.
Start with task wey agent get wrong twice
Once fit be chance. Twice don become pattern, and pattern worth keeping for file.
See this failure wey dey repeat for real servers. You ask agent to add reverse proxy block to nginx. E edit /etc/nginx/conf.d/app.conf, then run sudo systemctl restart nginx. The edit get typo, so nginx refuse to start, and site remain down until you fix am:
nginx: [emerg] unknown directive "proxy_pas" in /etc/nginx/conf.d/app.conf:12
Job for nginx.service failed because the control process exited with error code.You correct am for chat. Test the config with sudo nginx -t before you touch the service, then apply am with reload instead of restart. One week later, for another task, the same mistake happen again. That second time na the signal.
Write down 2 things while the failure still dey show: the request wey you type, and the correction wey you give, using the same words. Those 2 lines become the skill. The request tell you wetin the trigger must match. The correction na the complete content.
Anthropic own authoring guidance put this first. Run the agent on representative tasks without skill, record where e fail, then write only the instructions wey fix those failures. The failures na the specification, so if you no fit trace a skill back to one, na usually skill wey nobody need.
For worked example of the same distillation, Ponytail turn one repeated failure, where agent rewrite much more than you ask, into a skill you fit read from beginning to end before you write your own.
Skill get what inside am
Skill na directory wey get one required file inside.
.claude/skills/nginx-config-changes/
├── SKILL.md
├── reference/
│ └── proxy-headers.md
└── scripts/
└── check-and-reload.shSKILL.md dey start with frontmatter block: na small YAML settings be this (na the same configuration format wey Docker Compose files dey use) between --- markers. After that, instructions dey follow for markdown. See the complete skill for the failure wey happen before.
---
name: nginx-config-changes
description: Tests and reloads nginx safely after a config edit. Use when editing files under /etc/nginx, adding a server block or a reverse proxy, or changing a TLS certificate path.
---
## Rules
Run `sudo nginx -t` after every edit under `/etc/nginx`. Do not touch the service until it prints `test is successful`.
Apply the change with `sudo systemctl reload nginx`. Never use `restart`. A reload keeps the running workers serving traffic until the new config parses, so a broken config leaves the site up. A restart stops nginx first, so a broken config takes the site down.
If `nginx -t` fails, fix the file and test again. Never reload a config that failed the test.
For the proxy header defaults this project expects, see [reference/proxy-headers.md](reference/proxy-headers.md).That file no reach twenty lines, and e don complete as skill. These na the parts:
name: e fit reach 64 characters, and na lowercase letters, digits, and hyphens only. E no fit containclaudeoranthropic. For personal or project skill, na only display label this one be. The command wey you type come from the directory name, so this one answer to/nginx-config-changes.description: wetin the skill dey do and when to use am, up to 1,024 characters. Na this line dey do the real work, and the next section no talk about anything else.- The body: na the instructions be this. E go load only when the skill actually fire.
reference/: extra files wey the agent go read when e need dem. Link dem fromSKILL.mdand keep the links one level deep, because file wey another referenced file point to fit only read part of am.scripts/: files wey the agent go execute instead of read. Na only their output dey use context, so 300-line script no costly.
Skill go grow reach full layout when the behaviour wey e dey correct stubborn enough to need one. Unlazy skill use that extra space for Depth Tree, set of gates files, and PLAN.md contract to stop agent from announce say e don finish while whole branches of the work still remain untouched.
Where you put the directory go decide who fit use the skill.
.claude/skills/<name>/SKILL.mdinside the repository: na only this project, and e go follow everybody wey clone the repo.~/.claude/skills/<name>/SKILL.md: every project for your machine, but nobody else own.<plugin>/skills/<name>/SKILL.md: e dey ship inside plugin, and e dey available anywhere wey that plugin enable.
Use mkdir -p .claude/skills/nginx-config-changes create one, then write the file. Claude Code dey watch these directories, so if you edit existing skill, the change go take effect inside the running session. If you create top-level skills directory wey no dey there when the session start, you need restart, because nothing dey watch when the session begin.
Description field na the line wey get the biggest effect for the file
When agent start, e loads name and description of every skill wey dey available enter its context. E no load the bodies. When your request reach, na that one line be the full basis wey e use decide whether this skill relevant, so even perfect body wey hide behind vague description no go ever get read.
Write the description for third person. “Tests and reloads nginx safely” dey work. “I can help you with nginx” no dey work, because dem inject the text into system prompt, where first person go sound like na the model dey talk about itself.
Put two things inside am: wetin the skill dey do, and the condition wey make am apply. Put the important use case first, because Claude Code dey cut listing entry for 1,536 characters. Optional when_to_use field dey available for extra trigger phrases and example requests, and dem append am to the description under that same cap.
Then use the words wey you go actually type. description: Helps with nginx no dey match anything, because nobody dey type “helps with”. The version above mention /etc/nginx, server block, reverse proxy and TLS (transport layer security) certificate path, wey roughly be the vocabulary for any request wey suppose trigger am.
Na this be the test for description. Give that one line to person wey never see the body before, together with the request wey you wan type, then ask dem whether the skill apply. If dem no fit tell, the model no fit tell either.
Make body small, because e go remain for context
When dem invoke skill, e rendered content enter conversation as one message and remain there for the rest of the session. Claude Code no dey read the file again for later turns. Every line wey you write na cost wey you go pay for the whole session, no be for only one answer.
Anthropic recommend make SKILL.md no pass 500 lines, and move extra detail go separate files. Compaction show why this number no be arbitrary. When dem summarise conversation to free context, Claude Code attach again the most recent invocation of every skill, keep only the first 5,000 tokens for each one, and fill combined 25,000 token budget starting from the skill wey dem invoke last. If skill long, dem go cut am for middle. Several long skills fit push each other comot completely.
So write only wetin the model no already know. E know wetin nginx be and wetin reverse proxy dey do. E no know your house rule about reload over restart, and na that rule alone make this file exist.
If the skill tell agent to run bundled script, name the path with ${CLAUDE_SKILL_DIR} so e go resolve anywhere dem install the skill, and pre-approve the same command so the run no go stop for permission prompt.
---
name: nginx-config-changes
description: Tests and reloads nginx safely after a config edit. Use when editing files under /etc/nginx, adding a server block or a reverse proxy, or changing a TLS certificate path.
allowed-tools: Bash(${CLAUDE_SKILL_DIR}/scripts/check-and-reload.sh *)
---The grant cover the turn wey invoke the skill and e clear when you send your next message, so e no go quietly turn permanent permission.
How to prove say the skill dey work
To watch skill load show say agent don find am. E no show say the answer change. Check both things, and check am for fresh session, because the session wey you use write the skill already get everything wey you talk while you dey write am. That leftover context fit hide gaps for the file.
- Start new session with
claudefor the project. - Type the request the way you go type am for normal workday, with your own words, without mentioning the skill.
- Watch whether e invoke. If the skill no fire, fix the description. The body no be the problem yet.
- Invoke am by hand with
/nginx-config-changesas control. If e work correctly by hand but e no work correctly from request, that confirm say na trigger problem, no be instruction problem. - Run the same request with the skill switched off, then compare both answers. For the
/skillsmenu, highlight the skill, pressSpaceto cycle the state gooff, then pressEnterto save. That one writeskillOverridesentry inside.claude/settings.local.json. PressSpaceagain to cycle am back toonwhen you don finish. - Write two or three requests wey suppose no trigger the skill, then check say e stay quiet for dem.
To automate this loop, install the skill-creator plugin from the official marketplace.
/plugin marketplace add anthropics/claude-plugins-official
/plugin install skill-creator@claude-plugins-officialIf the install output talk say Run /reload-plugins to activate., run that command. Then ask Claude to evaluate your skill by name. The plugin dey store test cases for evals/evals.json inside the skill directory, and e dey run each case for separate subagent, so every run start with clean context. E then write comparison between with-skill and without-skill. Na that be the honest number: the improvement for pass rate measured against the tokens and time wey the skill cost.
Skill fit also carry its own proof instead of leaving am for separate eval run. Na this the Old Coder skill dey do when e make the agent return evidence report wey you fit run again by yourself.
Failure mode: skill no dey trigger
You type the request, agent still do the old wrong thing, and no skill line show. Check these ones in order.
- Description talk about wetin the skill dey do but e never talk when to use am, so nothing for your request match am.
- Description avoid the words wey you type. If you talk "nginx", description must talk nginx.
disable-model-invocation: truedey set for frontmatter. This one remove the description completely from model context, so na only you fit invoke the skill with/name.- A
pathsglob for frontmatter limit activation to files wey match am, but the file wey you dey work on no match. - The skill dey inside nested
.claude/skills/directory below where you start. Dem go load only after agent read or edit file inside that subdirectory. Until then, the skill no dey available at all.
Failure mode: skill dey trigger all the time
The opposite problem na when description too broad, so skill dey fire for unrelated work. “Use when working on the server” match almost any request for a server repository. The body go load for tasks wey e no fit help with, and e go remain for context for the rest of the session.
Make description narrow to the condition wey really matter, and name the files or commands wey e cover. Add a paths glob when skill dey apply only to specific files. For anything wey get side effects, like deploy or commit, set disable-model-invocation: true and invoke am yourself with /name, so agent no go decide by itself say na good time to deploy.
Failure mode: the skill belong inside your rules file
Rules file like CLAUDE.md or AGENTS.md dey load for the beginning of every session, and e dey apply to every task. Skill body only dey load when the skill run. Frequency na the whole decision. If na fact wey apply to every task for the repository, like the package manager wey you dey use, put am for rules file. If na procedure wey apply to small part of tasks, like the nginx rule above, put am for skill. E no go cost anything for days when nobody edit nginx.
The real failure na when you put am for both places. The two copies go gradually become different, and when the agent do the wrong thing, you no fit know which copy e follow. Choose one place for each instruction. If rule dey already for exactly one place but agent still skip am, na different problem be that. Check how ignored instruction dey work before you move am into skill and hope say the move go fix am. The boundary between skills, MCP servers and rules files dey help for the harder cases, including when the correct answer na MCP (model context protocol) server wey go give the agent new tool instead of new instruction.
Share am once e don prove say e useful
Skill wey survive one week of real work dey worth committing. Project skills for .claude/skills/ dey get review like code, and dem dey come with the repository. So teammate wey clone am go get your correction without any setup step. To move skill between repositories without copy and paste na separate problem, and how to share agent skills across repos cover am.
One portability note. Claude Code accept plenty frontmatter fields, but the Agent Skills standard allow only six: name, description, license, compatibility, metadata and allowed-tools. If you upload skill to claude.ai, or package am for the Skills API, with any other thing inside the frontmatter, e go fail completely instead of ignoring the field:
Unexpected key(s) in SKILL.md frontmatter: argument-hint. Allowed properties are: allowed-tools, compatibility, description, license, metadata, nameStay inside these six fields, and the same file go load for Claude Code and for anything else wey dey read the standard. Where the file load still decide wetin e fit do, because Cowork runs inside Anthropic sandbox while Claude Code runs for your own machine or VPS, so the nginx skill above make sense to carry go teammate's checkout, but e no get use for sandbox wey no fit reach the server. To write the instructions themselves so dem fit work after moving to another model na separate job, and writing skills that work with any model explain am.
FAQ
SKILL.md file suppose long reach how?
Make e no pass 500 lines, and expect say most useful skills go shorter well well pass dat. The body dey enter conversation when dem invoke the skill, and e remain there for the rest of the session. So every line na recurring cost, no be one-time cost. Move long reference material go separate files inside the skill directory, then link dem from SKILL.md, one level deep, so the agent go read dem only when e need dem. Dem dey execute bundled scripts instead of reading dem, so na only their output dey cost tokens.
Why my skill no dey trigger at all?
Description na the usual cause, because na only that part of the skill dey inside context when the model dey decide. Make sure e talk when to use the skill, no be only wetin e dey do. Make sure too say e contain the words wey you actually dey type for your requests. If the description look correct, check frontmatter for disable-model-invocation: true, wey dey hide the skill completely from the model. Check too for a paths glob wey limit am to files wey you no dey touch. Skill wey dey inside nested .claude/skills/ directory below your starting directory na another cause. E go load only after the agent read or edit file inside that subdirectory.
How I go know whether skill really help?
Compare am with a baseline. Gather some real requests. Run each one for fresh session with the skill available. Then run dem again with the skill switched off from the /skills menu, and read both answers side by side. Fresh session matter because the conversation where you write the skill still get your explanations. That one fit make incomplete file look complete. The skill-creator plugin run this comparison for you and report the pass rate beside the token cost.
I fit use the same SKILL.md with another agent?
Yes, as long as you stay inside the fields wey the Agent Skills standard define: name, description, license, compatibility, metadata and allowed-tools. Claude Code accept plenty more fields, and e support body features too, like shell command injection wey other tools no dey run. If you upload skill with field wey no dey inside the standard, e go fail with clear error wey list the allowed properties. So decide early whether the skill suppose remain for Claude Code or travel.