Claude Code Skills Examples: Write One That Actually Triggers
Claude Code skills examples from a real repo: SKILL.md frontmatter, why the description decides triggering, what loads when, and skills vs CLAUDE.md.
By Matthews WongReviewed on Checked against Claude Code v2.1.296
Key takeaway
A Claude Code skill is a folder with a SKILL.md file: YAML frontmatter whose description tells Claude when to use it, then the instructions. Only the description sits in context until the skill is used, so the description decides whether it triggers, and a long procedure costs almost nothing until it is needed.
You will be able to
- Write a SKILL.md whose description names the words a real request will contain.
- Predict what a skill costs in context before and after it is used.
- Choose between CLAUDE.md, a skill and a manual-only command for a given rule.
Step through the diagram
Press Play, or step with the arrows. Every step is written out below the diagram.
How a skill loads: description first, body on demand
Each skill puts only its description into Claude's context at session start; a matching request, a typed /name or a hook report loads the full body, which then stays in the conversation.
Reviewed on 13 October 2026 · Claude Code v2.1.296
Keys: ← → step · Home / End · K play or pause
A skill is a SKILL.md file: frontmatter whose description says when to use it, then the instructions. Everything Claude reads shares one context window.
At session start, CLAUDE.md loads in full, but each of the four skills adds only its description to a short listing. The bodies stay on disk.
name: drawing-blog-diagrams description: Draw in-article explanatory diagrams for blog posts …You ask for a diagram. Claude compares the request with every description in the listing; this one says “Use when adding a diagram”, so it matches.
Use when adding a diagram, figure, illustration or in-article image to a blog postPredict the next step The description matched. What enters the context now? (The skill's full body · Nothing more: the description is enough · Every skill's body at once)Only now does Claude Code load the full body into the conversation. It stays there for the session and is not re-read, so write standing instructions.
You can also type /drawing-blog-diagrams. Custom commands have been merged into skills: a file in .claude/commands/ and a skill folder both create a slash command.
.claude/commands/deploy.md → /deploy .claude/skills/deploy/SKILL.md → /deployPredict the next step The figure hook reports subject-absent. What happens next? (Nothing: only your requests trigger skills · The diagram skill gets pulled in)This repo's figure hook reports codes such as subject-absent. The diagram skill lists those exact codes in its description, so a hook report pulls in the right skill.
and when the figure-fitness hook reports subject-absent, subject-distant, own-work-preferred, caption-restates-alt, alt-prefix, overused-figure or portrait-figure.
What is a Claude Code skill, and what goes in SKILL.md?
A skill is a folder with a SKILL.md file in it. The file has two parts: YAML frontmatter between --- markers, then Markdown instructions. Project skills live in .claude/skills/ inside the repository and reach everyone who clones it; personal skills live in your home folder and follow you across projects. The folder name, or a name field, becomes the command you can type, such as /drawing-blog-diagrams.
Read more (2)Show less
Every frontmatter field is optional, but description is the one the docs recommend, because Claude uses it to decide when to apply the skill. Other fields decide who may invoke it (disable-model-invocation, user-invocable), which tools are pre-approved for the turn that invokes it (allowed-tools) and which files activate it (paths). Claude Code ignores a field it doesn't recognise without reporting an error, so a misspelt field quietly does nothing.
Custom commands have been merged into skills. A file at .claude/commands/deploy.md and a skill at .claude/skills/deploy/SKILL.md both create /deploy and work the same way, and existing command files keep working. A skill adds a folder for supporting files, control over who invokes it, and the ability for Claude to load it on its own, so the docs suggest skills for new work. This repository never had a .claude/commands/ folder; it went straight to skills.
Why does the description decide whether a skill triggers?
At session start Claude Code puts a listing of skill names and descriptions into context, not the bodies. Claude matches your request against that listing, so if the description doesn't contain the words your request will use, the skill never loads, however good its instructions are. The docs' first check for a skill that won't trigger is whether its description includes the keywords people would naturally say.
Read more (2)Show less
Two limits shape how you write it. The description, plus the optional when_to_use text, is cut at 1,536 characters in the listing, so put the key use case first. And when you have many skills, Claude Code drops descriptions to fit a listing budget of about 1% of the context window, starting with the skills you invoke least.
This repository's four descriptions are written as trigger lists. They name the files, scripts and terms a request will contain: BLOG_FIGURES, scripts/generate-blog-diagram.mjs, merge-blog-staging, JSON-LD. Each runs to roughly 500 to 800 characters, well under the cap, and each body stays well under the 500 lines the docs suggest as a ceiling for SKILL.md.
When should a rule be a skill rather than CLAUDE.md?
CLAUDE.md loads in full at the start of every session and is paid for on every request. A skill costs only its description until it is used, then its body enters the conversation. The docs' split: put "always do X" rules in CLAUDE.md, and put reference material Claude needs only sometimes, or a workflow you trigger by name, in a skill. Their rule of thumb is to keep CLAUDE.md under 200 lines; this repo's file is well past that, and its long blog procedures are the obvious candidates to move into the skills it already has.
Read more (2)Show less
Once a skill loads, it stays. Its content enters the conversation as one message and Claude Code does not re-read the file on later turns, so write standing instructions, such as "run the tests after every edit", rather than one-time steps. After compaction, Claude Code re-attaches each invoked skill but keeps only its first 5,000 tokens, within 25,000 tokens for all skills together, so put the critical rules at the top.
A skill is still guidance that Claude applies with judgement. For a rule that must hold every time, the skills page itself says to move it into a hook, which runs on its event whether or not Claude is following the skill. That is the next lesson.
The real config behind this lesson
Excerpts from the repository that builds and deploys this website, quoted as they are.
---
name: drawing-blog-diagrams
description: Draw in-article explanatory diagrams for blog posts in this site's visual language instead of sourcing them. Use when adding a diagram, figure, illustration or in-article image to a blog post; when a borrowed diagram has foreign-language labels or is unreadable on the dark page; when working with scripts/generate-blog-diagram.mjs, BLOG_FIGURES, lib/blog-figures.ts, BlogFigure, the stack or columns layout, scripts/audit-blog-figures.mjs or scripts/review-blog-figures.mjs; and when the figure-fitness hook reports subject-absent, subject-distant, own-work-preferred, caption-restates-alt, alt-prefix, overused-figure or portrait-figure. Covers the palette, layout primitives, label writing rules, wiring a figure into a post bilingually, the audit gate and the fitness review.
---The whole frontmatter of this repo's diagram skill: just name and description. The description is a trigger list. It opens with the use case, then names the scripts, the registry and the component a request will mention, and it ends with the exact finding codes the figure hook prints, so a hook report and the skill share the same words.
## Purpose
A published post is **six files that must agree**. Editing them by hand works
once and drifts by the third post, and the failure is silent — a missing key
breaks one locale of one page in production, which survives for months.
So nothing is hand-edited: content is staged, one script validates it
completely, and only then is anything written. This skill is that process and
the ways it has gone wrong.
For what to _write_, see **`writing-blog-content`**. For figures, see
**`drawing-blog-diagrams`**.The body opens with why the procedure exists, then hands off: what to write lives in one skill, figures in another. Small skills that point at each other let a task load only the part it needs, instead of one long file loading everything at once.
Mistakes that cost real time
A vague description
"Helps with blog posts" matches everything and nothing. If descriptions are vague or overlap, the docs warn that Claude may load the wrong skill or miss the one that would help. Name the files, commands and phrases a request will actually contain.
Broken YAML that fails quietly
If the frontmatter doesn't parse, or the opening --- isn't the file's first line, your fields don't apply: /name still works, but Claude can't match against your description. Run claude plugin validate .claude/skills, or start with --debug to see the parse error.
Too many skills, descriptions dropped
The listing has a budget. When it overflows, Claude Code keeps every name but drops descriptions, least-used skills first, which removes the very keywords that trigger them. Run /doctor for the listing's cost, and /skills, then t, to sort skills by token count.
What I'd change here: the hook codes have drifted
The diagram skill's description lists seven finding codes, but scripts/review-blog-figures.mjs can now also report missing-translation and audit. A hook report carrying only those two no longer matches the description. A trigger list copied from a script has to be updated whenever the script grows a new code.
| Frontmatter | You can invoke | Claude can invoke | In context before use |
|---|---|---|---|
| (default) | Yes | Yes | The description |
| disable-model-invocation: true | Yes | No | Nothing |
| user-invocable: false | No | Yes | The description |
Do it on your own machine
You need Claude Code and any git repository. Make one skill that loads on its own, watch it trigger, then turn it into a manual-only command.
Create .claude/skills/summarize-changes/SKILL.md. The description says what it does, then lists the words a real request will use.
--- description: Summarizes uncommitted changes and flags anything risky. Use when the user asks what changed, wants a commit message, or asks to review their diff. --- ## Current changes !`git diff HEAD` ## Instructions Summarize the changes above in two or three bullet points, then list any risks you notice.Edit any file, start Claude Code and ask in plain words. The skill should load without you naming it. Then call it directly by typing its name.
claude > What did I change? > /summarize-changesAdd disable-model-invocation: true to the frontmatter, start a new session and ask in plain words again. Claude no longer loads it; only /summarize-changes does.
--- description: Summarizes uncommitted changes and flags anything risky. Use when the user asks what changed, wants a commit message, or asks to review their diff. disable-model-invocation: true ---Open /skills and press t to sort by token count, then run /context and find the Skills row. Compare it before and after the change.
/skills /context
Three questions before you move on
Pick an answer to see why it is right or wrong. Nothing is saved or graded, so guess freely.
Answer in your head, then check
1.Your skill has excellent instructions, but Claude never uses it unless you type its name. What do you check first?Show the answer
Answer:The description. Claude matches requests against the descriptions in the listing, so it must contain the words people actually say. Then check that the frontmatter parses: broken YAML loads the skill with empty metadata, so Claude can't match your description.
2.What part of a default skill is in context before anyone uses it?Show the answer
Answer:Its name and description, plus when_to_use if set, capped at 1,536 characters. The body loads only when you or Claude invoke the skill, and then it stays in the conversation.
3.A deploy procedure must never run just because Claude decided the code looks ready. How do you set that up?Show the answer
Answer:Make it a skill with disable-model-invocation: true. Only typing /deploy runs it, Claude Code blocks Claude's own attempts to invoke it, and its description stays out of context until then.
Related deep dives on this site
Sources
Primary sources checked on the research date. Follow them for the current version.
- Claude Code docs: Extend Claude with skills
- Claude Code docs: skill frontmatter reference
- Claude Code docs: control who invokes a skill
- Claude Code docs: skill content lifecycle
- Claude Code docs: troubleshooting a skill that doesn't trigger
- Claude Code docs: CLAUDE.md vs skills vs hooks
- Claude Code docs: context cost by feature
- Claude Code docs: commands reference (/skills, /context)
- Claude Code docs in Indonesian: skills