Claude Code Skills: Build Your Own Custom Commands (2026)
Every developer using Claude Code ends up with the same private ritual: pasting the same instructions into chat, again and again. The commit-message format your team insists on. The four steps of your deploy. The reminder that the API returns errors in that shape, not the obvious one.
Skills exist to end that ritual. A skill is a folder with a SKILL.md file inside — instructions Claude loads on demand, either because you typed /skill-name or because Claude noticed your request matched what the skill is for. It’s the difference between telling a new teammate the deployment steps every single morning and writing them a runbook once.
They’re also the fastest-moving part of Claude Code right now, which is exactly why the answers you get from an AI chatbot about them are often a version behind. Custom slash commands were merged into skills. Nested monorepo skills, live reload, invocation control, and the skill listing budget are all recent behavior. This guide is current as of July 2026 and built from the official skills documentation, the Agent Skills open standard, and skills that actually run in real projects.
Skills often get confused with MCP. If you’re debugging a connection, you want Fix ‘MCP Server Failed to Connect’ in Claude Code. If you’re not sure what MCP even is, start with What is MCP?. This guide is about instructions, not connections — the difference matters, and there’s a decision table below.
Your first skill in three minutes
No theory yet — build one. This skill summarizes your uncommitted changes and flags anything risky, and it demonstrates the two invocation paths plus one genuinely magic feature.
1. Create the directory. Personal skills live in your home folder and work in every project:
mkdir -p ~/.claude/skills/summarize-changes
2. Save this as ~/.claude/skills/summarize-changes/SKILL.md:
---
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 such as missing error handling, hardcoded values,
or tests that need updating. If the diff is empty, say there are no
uncommitted changes.
3. Test it. Open any git project, edit a file, run claude, and either ask naturally — “What did I change?” — or invoke it directly:
/summarize-changes
Both work. The natural question works because Claude matched it against the description; the slash command works because the directory name became the command name.
The magic feature is that !`git diff HEAD` line. Claude Code runs the command before Claude sees anything and pastes the output into the skill content. Claude doesn’t decide to run git diff — it receives your actual diff, already inlined. That’s called dynamic context injection, and it’s the difference between a skill that guesses and a skill that knows.
What a skill actually is
Three facts explain almost everything about how skills behave:
-
A skill is a directory whose entrypoint is
SKILL.md. Frontmatter between---markers says when to use it; the markdown body says what to do. All frontmatter fields are optional — onlydescriptionis recommended, because that’s what Claude matches your requests against. -
Descriptions are always in context; bodies load on invocation. Claude Code keeps a listing of every skill’s name and description in the context window so Claude knows what’s available. The full instructions only load when the skill actually runs. This is why a 400-line runbook as a skill costs you almost nothing until the day you need it — and why the same 400 lines pasted into CLAUDE.md would tax every single session.
-
Custom commands and skills are now the same system. A file at
.claude/commands/deploy.mdand a skill at.claude/skills/deploy/SKILL.mdboth create/deploy. Your old commands keep working; skills add supporting files, invocation control, and automatic loading. If both exist with the same name, the skill wins.
If you’ve read our piece on context engineering, you’ll recognize the pattern: skills are progressive disclosure applied to your own instructions. Cheap index always present, expensive detail loaded just in time.
Where skills live (and which one wins)
| Location | Path | Applies to |
|---|---|---|
| Enterprise | Managed settings (org-deployed) | All users in your organization |
| Personal | ~/.claude/skills/<name>/SKILL.md | All your projects |
| Project | .claude/skills/<name>/SKILL.md | This project only (commit it) |
| Plugin | <plugin>/skills/<name>/SKILL.md | Wherever the plugin is enabled |
When names collide, enterprise overrides personal, and personal overrides project. A skill at any level also overrides a bundled skill of the same name — drop a code-review skill into your project’s .claude/skills/ and it replaces the built-in /code-review. Plugin skills are namespaced (plugin-name:skill-name), so they never collide with anything.
Three behaviors worth knowing before they surprise you:
- Live reload. Claude Code watches skill directories. Add or edit a
SKILL.mdand it takes effect in the current session — no restart. (Creating a brand-new top-level skills directory mid-session is the exception; restart once so it can be watched.) - Monorepo nesting. Skills also load from nested
.claude/skills/directories. A skill inapps/web/.claude/skills/deploy/becomes available when Claude works on files inapps/web/, under the qualified name/apps/web:deployif it clashes with a root-leveldeploy. Each package can carry its own procedures. - Parent discovery. Start Claude in a subdirectory and it still picks up
.claude/skills/from every parent directory up to the repo root.
The frontmatter fields you’ll actually use
The full reference has more than a dozen fields. These eight cover real-world usage:
| Field | What it does |
|---|---|
description | How Claude decides when to load the skill. Put the key use case and trigger phrases first. |
disable-model-invocation | true = only you can run it. For deploys, commits, anything with side effects. |
user-invocable | false = only Claude can load it. For background knowledge that isn’t a meaningful command. |
allowed-tools | Tools Claude may use without asking permission while the skill is active, e.g. Bash(git add *). |
arguments | Named positional args: arguments: [issue, branch] → use $issue, $branch in the body. |
context | fork runs the skill in an isolated subagent instead of your conversation. |
agent | Which agent type executes a forked skill: Explore, Plan, general-purpose, or a custom one. |
paths | Glob patterns — the skill only auto-activates when Claude touches matching files. |
One subtlety that trips people up: the name field is a display label, not the command. The command you type comes from the directory name (or the file name for .claude/commands/). Rename the folder to rename the command.
Arguments: from static text to parameterized workflows
The $ARGUMENTS placeholder turns a skill into a function. Whatever you type after the command replaces the placeholder:
---
name: fix-issue
description: Fix a GitHub issue by number
disable-model-invocation: true
---
Fix GitHub issue $ARGUMENTS following our coding standards.
1. Read the issue with `gh issue view $ARGUMENTS`
2. Implement the fix
3. Write tests
4. Create a commit that references the issue
Run /fix-issue 123 and Claude receives the instructions with 123 slotted in. For multiple values, use positions — $0, $1, $2:
---
name: migrate-component
description: Migrate a component from one framework to another
---
Migrate the $0 component from $1 to $2.
Preserve all existing behavior and tests.
/migrate-component SearchBar React Vue fills each slot in order. Quote multi-word values (/my-skill "hello world" second), shell-style. If a skill has no $ARGUMENTS but you pass some anyway, Claude Code appends them as ARGUMENTS: <your input> so nothing is lost.
Beyond arguments, a few environment substitutions matter for portable skills: ${CLAUDE_SKILL_DIR} resolves to the skill’s own directory (so bundled scripts work wherever the skill is installed), and ${CLAUDE_PROJECT_DIR} resolves to the project root.
Dynamic context: the feature that separates good skills from great ones
The !`command` syntax is preprocessing, not an instruction. Claude Code executes the command and substitutes its output before the model sees the skill at all. A skill that summarizes pull requests shouldn’t tell Claude to go fetch the PR — it should arrive with the PR already in hand:
---
name: pr-summary
description: Summarize changes in a pull request
context: fork
agent: Explore
allowed-tools: Bash(gh *)
---
## Pull request context
- PR diff: !`gh pr diff`
- PR comments: !`gh pr view --comments`
- Changed files: !`gh pr diff --name-only`
## Your task
Summarize this pull request: what changed, why it likely changed,
and what a reviewer should look at first.
This example also shows context: fork — the skill runs in an isolated subagent (here the read-only Explore agent), does its work away from your conversation, and returns a summary. Your main context stays clean.
Two syntax rules that cause silent failures: the ! must be at the start of a line or after whitespace (KEY=!`cmd` is treated as literal text), and for multi-line commands you open a fenced block with ```! instead.
Skills vs MCP vs subagents vs hooks vs CLAUDE.md
This is the question everyone eventually googles, so here it is as a decision table:
| You want… | Use | Why |
|---|---|---|
| Claude to follow a procedure or house style | Skill | Instructions, loaded on demand, invocable as /name |
| Claude to reach a system it can’t touch (DB, browser, Jira) | MCP | New tools via a separate server process |
| Work done in isolation with its own context window | Subagent | Parallel or large tasks that would pollute your session |
| Something to happen every time, deterministically | Hook | Shell commands on lifecycle events — not up to the model’s judgment |
| Claude to always know a short fact (build cmd, package manager) | CLAUDE.md | Always in context; right for facts, wrong for long procedures |
The most useful rules of thumb:
- Skill vs CLAUDE.md: if a section of your CLAUDE.md has grown into a procedure rather than a fact, cut it out and make it a skill. Facts stay resident; procedures load on demand.
- Skill vs hook: a skill is advice the model follows; a hook is a law the harness enforces. “Prefer conventional commits” is a skill. “Run the linter after every file edit, no exceptions” is a hook.
- Skill vs MCP: instructions vs connections, as above — and they compose. A great pattern is an MCP server providing the tools and a skill teaching Claude your team’s way of using them.
Three skills worth stealing
A commit skill you control. Side effects mean disable-model-invocation: true — Claude never decides on its own that your code “looks ready”:
---
name: commit
description: Stage and commit the current changes
disable-model-invocation: true
allowed-tools: Bash(git add *) Bash(git commit *) Bash(git status *)
---
## Current state
!`git status --short`
!`git diff HEAD --stat`
Stage and commit the changes above:
1. Group related changes into one commit (ask if a split makes sense)
2. Write a conventional-commit message: type(scope): summary
3. Never commit files matching .env* or *credentials*
Note allowed-tools: the three git commands run without permission prompts while this skill is active, and only those. Everything else still goes through your normal permission settings.
Background knowledge Claude applies silently. No slash command makes sense for “know how our legacy system works,” so hide it from the menu:
---
name: billing-system-context
description: How the legacy billing system works — event flow, invoice states, and the reconciliation quirks. Use when working on billing, invoices, or payment code.
user-invocable: false
paths: ["src/billing/**", "src/invoices/**"]
---
The billing system is event-sourced. Invoice state is never updated
in place — append a BillingEvent and let the projector rebuild state.
Reconciliation runs at 02:00 UTC; code that writes events after
midnight must set `backdated: true` or the run double-counts them.
The paths globs mean it only auto-activates when Claude actually touches billing code — zero noise everywhere else.
A research skill that forks. The PR-summary example above is the template: context: fork + agent: Explore + dynamic context is the recipe for any “go analyze X and report back” task. See the rise of AI agents for where this pattern is heading.
The token economics of skills
Skills are cheap, not free, and knowing the accounting prevents two problems.
Bodies persist. Once invoked, a skill’s rendered content stays in context for the rest of the session — Claude Code doesn’t re-read the file each turn. Write standing instructions, not one-time steps, and keep the body tight: state what to do, skip the why. The official guidance is under 500 lines, with anything bulky moved to supporting files:
my-skill/
├── SKILL.md # overview and navigation (required)
├── reference.md # detailed docs — loaded only when needed
├── examples.md # sample outputs — loaded only when needed
└── scripts/
└── helper.py # executed, never loaded into context
Reference the files from SKILL.md (“For the full API details, see reference.md”) so Claude knows what exists and when to read it.
Listings have a budget. The always-present list of skill names and descriptions is capped at roughly 1% of the context window. Pile up dozens of skills and Claude Code starts trimming descriptions — least-used first — which can silently strip the keywords a skill needs to trigger. /doctor reports the listing’s cost and its biggest contributors; skillOverrides in settings can demote rarely-used skills to "name-only" to free room.
Troubleshooting
The skill doesn’t trigger automatically. Work through these in order:
- Rewrite the description with trigger words. Claude matches your request against the description text. “Summarizes uncommitted changes. Use when the user asks what changed or wants a commit message” beats “Git helper” every time.
- Confirm Claude can see it — ask
What skills are available?in a session. - Test the direct path:
/skill-name. If that works but auto-triggering doesn’t, the problem is purely the description. - Check for broken YAML. Malformed frontmatter makes Claude Code load the body with empty metadata — the slash command still works, but there’s no description to match, so auto-invocation silently never happens. Run
claude --debugto see the parse error. - Check for truncation. With many skills installed, run
/doctor— your skill’s description may have been cut to fit the listing budget.
The skill triggers too often. Make the description more specific, add paths globs so it only activates for relevant files, or set disable-model-invocation: true and invoke it manually.
The skill seems to “wear off” mid-session. The content is usually still in context — the model is just choosing other approaches. Strengthen the instructions, or if the behavior must be guaranteed, enforce it with a hook instead. After a long session compacts, older skills can be dropped from the carried-forward budget; re-invoke the skill to restore it.
Edits aren’t picked up. SKILL.md text changes apply live. But if your skill folder doubles as a plugin (it has a .claude-plugin/plugin.json), changes to its hooks or MCP config need /reload-plugins.
Don’t guess whether a skill works — measure it
Seeing a skill trigger proves Claude found it, not that it helped. The honest test is a baseline comparison: run a few realistic prompts in fresh sessions with the skill enabled, then disabled, and compare. Fresh sessions matter — leftover context from writing the skill will mask gaps in the written instructions.
Anthropic’s skill-creator plugin automates that loop:
/plugin install skill-creator@claude-plugins-official
It stores test cases in evals/evals.json inside your skill directory, runs each in an isolated subagent, grades assertions, benchmarks with-skill vs without-skill on pass rate, time, and tokens, and even A/B tests two versions of a skill blind before you commit an edit. It will also generate should-trigger and should-not-trigger prompts and propose description fixes when the skill fires on the wrong requests. For a skill your whole team depends on, this is the difference between folklore and engineering.
Common mistakes checklist
- ❌ Setting
name:in frontmatter and expecting it to change the command — the directory name is the command. - ❌ A vague description (“Git helper”) and then wondering why auto-invocation never fires.
- ❌ Putting a 300-line procedure in CLAUDE.md instead of a skill — you pay for it in every session.
- ❌ Letting Claude auto-invoke deploy/commit/notify skills — side effects need
disable-model-invocation: true. - ❌ Writing
KEY=!`cmd`— the!must start a line or follow whitespace, or it’s literal text. - ❌ Malformed YAML frontmatter — the skill half-works (slash yes, auto no), which is worse than failing loudly.
- ❌
context: forkon a skill that’s only guidelines — the subagent gets conventions but no task, and returns nothing useful. - ❌ Hardcoding paths to bundled scripts instead of
${CLAUDE_SKILL_DIR}— breaks the moment the skill is shared. - ❌ Trusting a repo without reading its
.claude/skills/— project skills can grant themselves tool permissions viaallowed-toolsonce you accept the trust dialog.
Quick reference: task → mechanism
| I want to… | Do this |
|---|---|
| Make a reusable command | Directory under .claude/skills/ + SKILL.md |
| Share it with my team | Commit the project .claude/skills/ to git |
| Keep it personal, all projects | ~/.claude/skills/<name>/ |
| Pass parameters | $ARGUMENTS, $0/$1, or named arguments: |
| Inject live data (diffs, status, env) | !`command` in the body |
| Keep Claude from running it on its own | disable-model-invocation: true |
Hide it from the / menu | user-invocable: false |
| Scope it to part of a monorepo | paths: globs, or a nested .claude/skills/ |
| Run it isolated from my conversation | context: fork (+ agent: Explore for read-only research) |
| Skip permission prompts for specific tools | allowed-tools: Bash(git add *) ... |
| See why it isn’t loading | claude --debug, /doctor, ask “What skills are available?” |
| Prove it actually helps | skill-creator plugin evals |
Keep learning: official sources and talks
Primary sources (current as of July 2026):
- Claude Code Docs — Extend Claude with skills · Subagents · Hooks · Permissions
- The Agent Skills open standard — the cross-tool spec Claude Code skills follow, including evaluating skill quality
- Anthropic — Skill authoring best practices · skill-creator plugin
Useful searches (try on YouTube — Anthropic and developer channels):
- “Claude Code skills tutorial SKILL.md”
- “Claude Code skills vs MCP vs subagents”
- “Claude Code custom slash commands 2026”
- “agent skills open standard”
Go deeper on this site: What is MCP? · Fix ‘MCP Server Failed to Connect’ · What is context engineering? · Fixing context window exceeded errors · The rise of AI agents
The teams getting the most out of Claude Code in 2026 aren’t the ones with the cleverest prompts — they’re the ones who stopped re-explaining themselves. Every procedure you paste twice is a skill you haven’t written yet. Start with the one instruction you repeat most, give it a directory and a good description, and let the repetition end there. The runbook beats the ritual, every time.