Claude Code Skills: Build Your Own Custom Commands (2026)

Title card: 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:

  1. 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 — only description is recommended, because that’s what Claude matches your requests against.

  2. 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.

  3. Custom commands and skills are now the same system. A file at .claude/commands/deploy.md and a skill at .claude/skills/deploy/SKILL.md both 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)

LocationPathApplies to
EnterpriseManaged settings (org-deployed)All users in your organization
Personal~/.claude/skills/<name>/SKILL.mdAll your projects
Project.claude/skills/<name>/SKILL.mdThis project only (commit it)
Plugin<plugin>/skills/<name>/SKILL.mdWherever 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.md and 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 in apps/web/.claude/skills/deploy/ becomes available when Claude works on files in apps/web/, under the qualified name /apps/web:deploy if it clashes with a root-level deploy. 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:

FieldWhat it does
descriptionHow Claude decides when to load the skill. Put the key use case and trigger phrases first.
disable-model-invocationtrue = only you can run it. For deploys, commits, anything with side effects.
user-invocablefalse = only Claude can load it. For background knowledge that isn’t a meaningful command.
allowed-toolsTools Claude may use without asking permission while the skill is active, e.g. Bash(git add *).
argumentsNamed positional args: arguments: [issue, branch] → use $issue, $branch in the body.
contextfork runs the skill in an isolated subagent instead of your conversation.
agentWhich agent type executes a forked skill: Explore, Plan, general-purpose, or a custom one.
pathsGlob 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…UseWhy
Claude to follow a procedure or house styleSkillInstructions, loaded on demand, invocable as /name
Claude to reach a system it can’t touch (DB, browser, Jira)MCPNew tools via a separate server process
Work done in isolation with its own context windowSubagentParallel or large tasks that would pollute your session
Something to happen every time, deterministicallyHookShell commands on lifecycle events — not up to the model’s judgment
Claude to always know a short fact (build cmd, package manager)CLAUDE.mdAlways 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:

  1. 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.
  2. Confirm Claude can see it — ask What skills are available? in a session.
  3. Test the direct path: /skill-name. If that works but auto-triggering doesn’t, the problem is purely the description.
  4. 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 --debug to see the parse error.
  5. 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: fork on 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 via allowed-tools once you accept the trust dialog.

Quick reference: task → mechanism

I want to…Do this
Make a reusable commandDirectory under .claude/skills/ + SKILL.md
Share it with my teamCommit 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 owndisable-model-invocation: true
Hide it from the / menuuser-invocable: false
Scope it to part of a monorepopaths: globs, or a nested .claude/skills/
Run it isolated from my conversationcontext: fork (+ agent: Explore for read-only research)
Skip permission prompts for specific toolsallowed-tools: Bash(git add *) ...
See why it isn’t loadingclaude --debug, /doctor, ask “What skills are available?”
Prove it actually helpsskill-creator plugin evals

Keep learning: official sources and talks

Primary sources (current as of July 2026):

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.

Next: Fix 'MCP Server Failed to Connect' in Claude Code (2026)