GuideAgent skills
How to write a SKILL.md for Claude Code: structure, examples, pitfalls
Write a SKILL.md for Claude Code that loads at the right time: frontmatter fields, trigger-ready descriptions, scripts, file locations and testing.
To write a SKILL.md for Claude Code, create a folder under .claude/skills/ (or ~/.claude/skills/ for personal use), add a SKILL.md file that starts with YAML frontmatter, and put your instructions in Markdown below it. The description field decides when Claude loads the skill on its own, so it has to say what the skill does and when to use it. Everything else in the frontmatter is optional.
What a Claude Code skill is and how Claude picks one
A skill is a folder of instructions, and optionally scripts and reference files, that Claude loads when a task calls for it. The Claude Code skills documentation (opens in a new tab) suggests making one when you keep pasting the same checklist or procedure into chat, or when a section of CLAUDE.md has grown into a procedure.
Skills load in stages. At the start of a session, Claude Code puts each skill's name and description into a listing in Claude's context. The body of SKILL.md loads only when you or Claude invoke the skill. Anthropic's Agent Skills overview (opens in a new tab) puts the metadata at roughly 100 tokens per skill and recommends keeping the instructions under 5,000 tokens. Bundled files cost nothing until Claude reads them.
Claude decides to load a skill by matching your request against the descriptions in that listing. You can also run any skill yourself by typing / and its name at the start of a message.
Skills replaced custom commands. A file at .claude/commands/deploy.md and a skill at .claude/skills/deploy/SKILL.md both create /deploy, and old command files still work. Skills add a folder for supporting files and frontmatter that controls who can invoke them.
How to write a SKILL.md for Claude Code: layout and frontmatter
A minimal skill is one folder with one file:
.claude/skills/release-notes/
└── SKILL.md
The frontmatter sits between two --- lines, and the opening --- must be the very first line of the file. If it is not, Claude Code reads the whole file, markers included, as plain skill content. If the YAML fails to parse, the skill still loads but with no fields set, so Claude cannot match it by description.
Every field is optional, and description is the one the docs recommend. Field names must match exactly: Claude Code silently ignores a field it does not recognize. These are the fields most skills need:
| Field | What it does | Default |
|---|---|---|
name | Command name in the / menu | The folder name |
description | What the skill does and when to use it. Claude matches requests against it | First non-empty line of the body |
when_to_use | Extra trigger phrases, appended to the description | None |
disable-model-invocation | true stops Claude from loading the skill on its own | false |
user-invocable | false hides the skill from the / menu so only Claude can use it | true |
allowed-tools | Tools Claude may use without asking during the turn that invokes the skill | None |
paths | Glob patterns. Claude auto-loads the skill only when working on matching files | None |
context | fork runs the skill in a separate subagent without your chat history | Inline |
argument-hint | Autocomplete hint, such as [issue-number] | None |
Claude Code also accepts model, effort, agent, hooks, shell, arguments, disallowed-tools, background, metadata, license and compatibility. If the same skill will be uploaded to claude.ai or the Skills API, stick to name, description, license, compatibility, metadata and allowed-tools. Any other field makes packaging or upload fail with an "Unexpected key(s)" error.
The overview page sets stricter rules for those surfaces: name up to 64 characters, lowercase letters, numbers and hyphens only, and without the words "anthropic" or "claude". The description there is capped at 1,024 characters.
A SKILL.md template you can copy
The template below is illustrative. It drafts release notes from recent commits, runs one bundled script and points to a style file:
---
name: release-notes
description: Drafts release notes from recent git commits, grouped into features, fixes and breaking changes. Use when the user asks for release notes, a changelog entry or a summary of what shipped.
argument-hint: "[version]"
allowed-tools: Bash(git log *) Bash(python3 ${CLAUDE_SKILL_DIR}/scripts/group_commits.py *)
---
## Recent commits
!`git log --oneline -30`
## Instructions
1. Run `python3 ${CLAUDE_SKILL_DIR}/scripts/group_commits.py --limit 30`
and use its groups as the outline.
2. Title the notes with version $ARGUMENTS.
3. Follow the tone rules in `reference/style.md`.
4. List breaking changes first, each with the migration step.
5. If there are no commits, say so and stop.
The !`git log --oneline -30` line is dynamic context injection: Claude Code runs the command before Claude sees the skill and replaces the line with its output. $ARGUMENTS becomes whatever follows the command, so /release-notes 2.4.0 fills in the version.
Writing a description that triggers at the right time
The description is the only part of the skill Claude reads before deciding to load it. Anthropic's examples follow one pattern: a sentence on what the skill does, then the situations and words that should trigger it. The pdf skill in Anthropic's repository (opens in a new tab) lists concrete tasks (merging, splitting, filling forms, OCR) and ends with a plain rule that any mention of a .pdf file should trigger it.
Some practical rules from the Claude Code docs:
- Put the main use case first. The combined
descriptionandwhen_to_usetext is cut at 1,536 characters in the listing. - Use the words people actually type. If users say "changelog", the description should too.
- If the skill fires when you do not want it, make the description narrower, or set
disable-model-invocation: true. - When you have many skills, Claude Code drops some descriptions to fit a listing budget of 1% of the context window, starting with the skills you use least.
/doctorestimates the listing's cost, and/skill-doctor(v2.1.252 or later) shows which skills you never use.
Use disable-model-invocation: true for anything with side effects, such as deploying or sending a message. The docs say plainly that you do not want Claude deciding to deploy because the code looks ready. A skill set that way keeps its description out of Claude's context until you call it.
Adding scripts and reference files
Supporting files keep SKILL.md short. The Claude Code docs recommend staying under 500 lines and moving detail into separate files that the main file links to, with a note on what each contains.
release-notes/
├── SKILL.md
├── reference/
│ └── style.md
└── scripts/
└── group_commits.py
Reference files enter context only when Claude reads them. Scripts are executed, and only their output enters context, which suits work that should give the same answer every time, such as parsing or validation.
Refer to bundled files through ${CLAUDE_SKILL_DIR}, which expands to the folder that holds SKILL.md wherever the skill is installed. Claude Code expands it in the body and in Bash rules in allowed-tools. Using the same variable in both places, as the template does, lets the script run without a permission prompt. ${CLAUDE_PROJECT_DIR} does the same for project files and needs v2.1.196 or later.
Injected commands have limits worth knowing. They never stop to ask for permission: outside auto mode, a command your permission rules do not allow aborts the skill, which is why the template pre-approves git log in allowed-tools. Each one runs under the Bash tool's two-minute timeout, and a command that fails aborts the whole invocation, so Claude never sees the skill. Append || true to a command you expect to exit non-zero.
Personal vs project skills
Where the folder lives decides which sessions load it:
| Location | Path | Who gets it |
|---|---|---|
| Personal | ~/.claude/skills/<name>/SKILL.md | You, in every project on this machine |
| Project | .claude/skills/<name>/SKILL.md | Everyone working in the repo, once committed |
| Nested | <subdir>/.claude/skills/<name>/SKILL.md | Sessions working on files in that subdirectory |
| Plugin | <plugin>/skills/<name>/SKILL.md | Wherever the plugin is enabled, as /plugin-name:skill-name |
When two skills share a name, enterprise beats personal and personal beats project. Plugin skills never clash because they carry the plugin prefix. A skill also wins over a command file of the same name in .claude/commands/.
Claude Code watches these folders and picks up new or edited skills during the session without a restart. If you create a top-level skills directory that did not exist at startup, run /reload-skills. Personal skills do not load in cloud or Cowork sessions, which read skills from your claude.ai account and, for cloud sessions, from the repo.
How to test a skill
Start with the two ways the docs suggest. Ask a question that matches the description and see if Claude loads the skill, then run it directly with /release-notes. Asking "What skills are available?" shows whether Claude Code found it at all.
If the skill does not trigger:
- Run
claude --debugto see YAML parse errors. - Run
claude plugin validate .claude/skills(or~/.claude/skills) to find frontmatter that does not parse. This needs v2.1.233 or later. - Check that the description contains the words you used in the request.
Triggering is half the test. The docs recommend running a few realistic prompts in fresh sessions, once with the skill and once with it set to "off" in skillOverrides, and comparing the results. A fresh session matters because context left over from writing the skill hides gaps in the instructions. The skill-creator plugin automates that loop, including description tuning, and installs with /plugin install skill-creator@claude-plugins-official.
If Claude follows a skill at first and drifts later, remember that the file is read once per invocation. Word rules so they apply to the whole task, and put the most important ones near the top, because compaction keeps only the first 5,000 tokens of each invoked skill.
Security: reviewing skills from other people
The Agent Skills overview tells you to use skills only from trusted sources, meaning ones you wrote or got from Anthropic. A skill can direct Claude to run tools and code in ways that do not match its stated purpose. Anthropic's public skills repository (opens in a new tab) labels its own skills as demonstrations and asks you to test them before relying on them.
Three Claude Code behaviors make review important:
- Commands inside
!`...`run on your machine before Claude reads the skill. - A project skill's
allowed-toolsapplies even in a-prun in a folder you have never trusted, so a repo's skill can grant itself tool access. - A skill folder that contains
.claude-plugin/plugin.jsonloads as a plugin and can bring hooks and MCP servers. In a project's.claude/skills/, that needs workspace trust first.
Before you install or commit someone else's skill, check:
- To do: Every file in the folder, including scripts, images and reference files
- To do: Each injected command and what it reads or sends
- To do: The
allowed-toolslist, for broad patterns such asBash(*) - To do: Any URLs the skill fetches, since fetched text can carry instructions and can change after you review it
- To do: Whether the folder contains a
.claude-plugin/plugin.json
Organizations can turn off injected commands for user, project and plugin skills with "disableSkillShellExecution": true in managed settings. Bundled and managed skills are not affected.
Frequently asked questions
What is the difference between a skill and CLAUDE.md?
`CLAUDE.md` content loads into every session. A skill's body loads only when someone invokes it, so long procedures and reference material cost almost nothing until they are needed. Facts that apply to every task belong in `CLAUDE.md`, and multi-step procedures belong in a skill.
Can a skill force Claude to follow a rule every time?
No. A skill is instructions, and Claude can drift from them later in a long session. For a rule that must hold on every edit or command, use a hook, which Claude Code runs each time its event fires. A skill can register hooks through its `hooks` frontmatter field, active from invocation until the session ends.
Do Claude Code skills work in other AI tools?
Claude Code skills follow the Agent Skills open standard published at agentskills.io, which other tools can read. Fields outside the standard, such as `context` or `disable-model-invocation`, and features like injected shell commands are Claude Code extensions. Keep to the six standard frontmatter fields if portability matters.
How do I share a skill with my team?
Commit the folder under `.claude/skills/` in the repository so everyone who works there gets it. For use across many repos, package it in a plugin's `skills/` directory. Administrators can also deploy skills to every user through managed settings.
Sources
- 1.Extend Claude with skills - Claude Code DocsOfficial docsPrimarycode.claude.com
- 2.anthropics/skillsRepositoryPrimarygithub.com
- 3.Agent Skills - Claude Platform DocsOfficial docsPrimaryplatform.claude.com
- 4.pdf skill folderRepositoryPrimarygithub.com
Spotted an error? See our corrections policy.
Enjoyed this? Get the weekly brief.
New guides, Project & Tool of the Week and the AI developments that matter. One email, no spam.
Read next
- Weekly digest
The week on HuiaHub: sandboxed agents, RAG tooling and local models
41 new HuiaHub pages this week: sandboxing coding agents, RAG retrieval, local models on Macs and phones, Claude Haiku 5.5 and six how-to guides.
4 min read
ExplainerAgents & automationAI agents found in US bank accounts: what banks are blocking and why
See which banks are restricting AI agents in bank accounts, how read-only access differs from credential sharing, and which claims remain unverified.
10 min read
GuideCoding & dev toolsPHP critical security update CVE-2026-109618: Versions and patch steps
Check the PHP critical security update CVE-2026-109618, identify affected servers, install fixed PHP versions, and apply temporary settings if needed.
12 min read