Claude Code skills answer a specific pain: you keep pasting the same checklist into chat, or a section of your CLAUDE.md has quietly grown from facts about the project into a multi-step procedure. The official guidance is exactly that β when instructions become a procedure you re-explain, move them into a skill. Unlike CLAUDE.md content, a skill's body loads only when it's used, so a long runbook costs you almost nothing until the moment you need it.
This post covers the SKILL.md format end to end: the frontmatter fields, how triggering actually works, arguments, supporting files, and a template you can copy.
Everything about writing a good skill follows from one design fact:
/skill-name
).So the description is not documentation β it's the trigger. The body is not a summary β it's the procedure. Most broken skills I've seen get these backwards: a vague description ("Helps with releases") that never matches anything, and a body that's a one-liner.
A skill is a directory with a SKILL.md
file. In a project:
.claude/skills/release-notes/SKILL.md
(Personal skills live under ~/.claude/skills/
and follow you across projects.)
---
name: release-notes
description: "Draft release notes from merged PRs. Use when the user"
asks for release notes, a changelog entry, or "what shipped".
---
Collect merged PRs since the last git tag, then write release notes.
1. Run `git describe --tags --abbrev=0` to find the last tag.
2. List merges since then: `git log <tag>..HEAD --merges --oneline`.
3. Group changes into Added / Fixed / Changed.
4. Write entries as user-facing outcomes, not commit messages.
5. Show the draft before writing to CHANGELOG.md.
That's a complete, working skill. Type /release-notes
to run it directly, or just ask "can you draft release notes?" and let the description do its job.
If you've used custom commands before: commands and skills are now the same thing. A file at .claude/commands/deploy.md
and a skill at .claude/skills/deploy/SKILL.md
both create /deploy
and behave the same way. Skills just add optional extras β a directory for supporting files and frontmatter to control invocation.
All fields are optional. Only description
is recommended β without it, Claude has nothing to match against, and the skill is effectively manual-only.
---
name: my-skill
description: What this skill does
disable-model-invocation: true
allowed-tools: Read Grep
---
name
/my-skill
). Defaults to the directory name, so most skills omit it.description
disable-model-invocation: true
/name
. Use it for anything with side effects you want a human to initiate: deploys, commits, publishing, sending messages. This is the difference between a allowed-tools
Read Grep
), so a read-only helper doesn't stop to ask permission mid-run.That last pairing is worth internalizing: knowledge skills β model-invoked; action skills β slash-only. The frontmatter is where you encode that decision, and it's the single biggest safety lever in the format.
Skills take arguments when invoked as commands, with real substitution syntax:
$ARGUMENTS
β everything you passed. (If it doesn't appear in the body, arguments are appended as ARGUMENTS: <value>
instead.)$0
, $1
β positional access, shorthand for $ARGUMENTS[0]
, $ARGUMENTS[1]
.arguments: [issue, branch]
in frontmatter and $issue
/ $branch
expand by position. Self-documenting, so I'd default to this for anything with two or more parameters.So /fix-issue 1423 hotfix/login
with arguments: [issue, branch]
gives you a body that reads like prose: "Fix issue $issue
on branch $branch
."
Official guidance: keep SKILL.md under 500 lines and move detailed reference material into separate files in the skill directory:
my-skill/
βββ SKILL.md (required β overview and navigation)
βββ reference.md (detailed API docs β loaded when needed)
βββ examples.md (usage examples β loaded when needed)
βββ scripts/
βββ helper.py (executed, not loaded)
The important part is the navigation: link each file from SKILL.md with a note about what it contains and when to read it β
## Additional resources
- For complete API details, see [reference.md](reference.md)
- For usage examples, see [examples.md](examples.md)
This is the same two-stage trick again, one level down. SKILL.md stays a lean table of contents; the 2,000-line API reference costs nothing until Claude actually follows the link. Scripts are even cheaper β they get executed, not read into context.
Almost every triggering problem is a description problem:
disable-model-invocation: true
and stop fighting the matcher./skill-name
once. If it works manually but never automatically, it's the description. It's almost always the description.One more option worth knowing: skills can run in their own subagent context (context: fork
), which keeps a noisy multi-step procedure from flooding your main session. Useful for research-style skills that read a lot but should report back a summary.
SKILL.md follows the Agent Skills open standard, and the same format is now read by several coding agents (Claude Code extends it with invocation control, subagent execution, and dynamic context injection). Writing your team runbooks in this format is a reasonably safe bet even if your tool mix changes later.
I maintain Rulestack, a set of focused rule and skill packs for Claude Code, Cursor, and Codex β including a full Claude Code skill-authoring pack.
Daily AI-coding-agent tips on Bluesky: follow @ai-shop.bsky.social.