·Skills & Commands
What Claude Code skills are, how the SKILL.md convention works, and how to write, package, and share your own skills — with a real example and field-tested best practices.
Claude Code Skills: A Complete Guide to Building Composable Agent Capabilities
Claude Code is an agentic coding tool: you describe what you want, and it edits files, runs commands, and ships. As you use it on a real project, you notice the same instructions come up over and over — how your team writes commit messages, how to scaffold a new component, how to triage a flaky test. Skills are the way to package those repeatable procedures so Claude Code can pull them in on demand. This guide covers what skills are, the SKILL.md convention, how they relate to slash commands, how to build and share one, and the practices that separate a toy skill from one that actually holds up in daily use.
What a skill actually is
A skill is a directory that contains a SKILL.md file. That's the whole required structure. The SKILL.md file has YAML frontmatter describing the skill, followed by a Markdown body with the detailed instructions, scripts, and examples.
The crucial design choice is progressive disclosure. When Claude Code starts a session, it loads only the frontmatter — the skill's name and description, roughly 30 to 100 tokens each. The full body of instructions is only read if and when Claude decides a user's request matches that skill. This is why you can register a large library of skills without bloating the context window on every turn: the cheap metadata is always present, and the expensive body loads lazily.
Think of a skill as a named, on-demand procedure that lives next to your code. Claude can invoke it when relevant, and you never pay for instructions you are not using.
The SKILL.md convention
A minimal skill looks like this:
my-skill/
└── SKILL.md
Inside SKILL.md, the frontmatter carries two required fields and a handful of optional ones:
---
name: commit-message-style
description: Writes Conventional Commits messages that match the team's changelog format. Use when the user wants to commit, or asks for a commit message.
allowed-tools: ["Bash(git log:*)", "Bash(git diff:*)"]
---
# Commit message style
When the user asks for a commit message:
1. Run `git diff --cached` to see what is staged.
2. Run `git log -5 --oneline` to match the recent message tone.
3. ...
The fields:
name(required) — the skill identifier, typically kebab-case. Keep it stable; other configs may reference it.description(required) — a short summary of what the skill does and when to use it. This is the only text Claude sees until it decides to load the skill, so it does double duty as a trigger. Aim for under 1,024 characters and include the situations where it applies ("Use when the user wants to…").allowed-tools(optional) — restricts which tools the skill may invoke, in the same format as elsewhere in Claude Code (for exampleBash(git log:*)). Omit it to inherit the session's default tool set.user-invocable(optional) — set totrueif the skill should also appear as an explicit slash command the user can call directly.
Beyond SKILL.md, a skill directory can hold anything that helps the instructions: reference files, templates, helper scripts, sample output. Keep the body of SKILL.md itself focused — a common guideline is to keep it under roughly 5,000 tokens, and to move long reference material into separate files the skill can read on demand.
Skills vs slash commands
The relationship between skills and slash commands confuses people at first, because they can overlap.
A slash command is an explicit, user-initiated action: you type /something and it runs. Historically these were defined as simple prompt files.
A skill is a capability the model can pull in automatically when a request matches its description. With user-invocable: true, a skill is also exposed as a slash command.
The practical takeaway: if you find yourself writing a slash command that is really "a reusable procedure Claude should know how to do," write it as a skill instead. Skills give you the automatic triggering for free, and the explicit invocation is an opt-in flag rather than the only entry point. Slash commands remain useful for quick, one-off prompts that do not need discovery logic.
Building a real skill
Let's make a skill that is genuinely useful: a consistent code-review checklist tailored to a repository. Create the directory under .claude/skills/ (project-local) or ~/.claude/skills/ (user-global):
.claude/skills/
└── review-checklist/
└── SKILL.md
.claude/skills/review-checklist/SKILL.md:
---
name: review-checklist
description: Runs a consistent code-review checklist against staged or recent changes before opening a PR. Use when the user asks to review code, prepare a PR, or check their own changes.
allowed-tools: ["Bash(git diff:*)", "Bash(git log:*)", "Read", "Grep"]
---
# Review checklist
Apply these checks to the current change set (`git diff` against the base branch):
1. **Tests** — are there new or updated tests for the behavior change? Flag pure additions with no test.
2. **Error paths** — does the new code handle failure cases, or only the happy path?
3. **Naming** — do new identifiers match the conventions in the surrounding module?
4. **Public surface** — does the change add to a public/exported API? If so, is it documented?
5. **Secrets and logs** — any credentials, tokens, or PII introduced into code or log lines?
Report findings as a short, ordered list grouped by file. End with one of: `LGTM`, `Minor fixes`, or `Block`.
To use it, just ask Claude Code in natural language: "Review my staged changes before I push." Because the description says to use it when the user asks to review code, Claude will load the skill and apply the checklist — no slash command required. You can also call it explicitly as /review-checklist if you set user-invocable: true.
Where skills live
Skills are loaded from several places, which lets you mix team-wide and personal capabilities:
- Project skills —
.claude/skills/checked into the repo, shared with everyone on the project. - User skills —
~/.claude/skills/for capabilities you want across all projects (your personal git aliases, your editor habits). - Plugin-provided skills — installed plugins can contribute skills alongside their other features.
This layering matters: put things that are project-specific (a commit style, a deploy procedure, a domain glossary) in the repo so the whole team gets them; put things that are yours (how you like PRs summarized) in your user directory.
Packaging and sharing
To share a skill beyond a single repo, the common path is a plugin. A plugin bundles one or more skills (plus optionally slash commands, hooks, and MCP servers) into a distributable unit that others install by name. Because each skill is just a directory with a SKILL.md, the barrier to extracting a skill into a shareable plugin is low: move the directory into a plugin layout, add a manifest, and publish.
A real, well-known example of this pattern is Superpowers (chartable on ClaudeMap), a community skill pack that packages dozens of vetted procedures — code review, test generation, migration helpers, and more — as composable skills you can drop into your own setup. Studying a pack like that is the fastest way to internalize how to scope a skill well: each one is small, has a sharp description, and delegates cross-cutting concerns to other skills rather than ballooning into a monolith.
When you package your own, the two questions to keep asking are: "Would a stranger understand when to use this from the description alone?" and "Could I split this into two skills that trigger more reliably?" Skills that try to do everything tend to trigger unreliably; skills that do one thing trigger like clockwork.
Best practices
A few patterns we see hold up across mature skill libraries:
- Make the description earn its keep. It is the only thing loaded at startup and the only thing that decides whether the skill fires. Be specific about when to use it, not just what it does.
- Keep the body small and pointer-rich. Put long reference material in adjacent files and have the skill read them on demand, rather than inlining everything.
- Constrain tools deliberately. Use
allowed-toolsto keep a skill from doing more than it should — a review skill that can rewrite files is a review skill waiting to cause an accident. - Prefer many narrow skills over one big one. Triggering is more reliable when each skill owns a single intent.
- Test the trigger, not just the body. After writing a skill, try phrasing the request three different ways and confirm it loads. A skill whose body is perfect but never fires is worthless.
Start by extracting one procedure you repeat daily into .claude/skills/. Once you feel the relief of not typing those instructions again, you will start to see procedures worth packaging everywhere.
This article is based on publicly available information as of July 2026; the relevant APIs may evolve.