Skills
Package instructions, scripts and reference files as skills that Claude loads on demand or you run as slash commands, with the full frontmatter reference.
A skill is a folder with a SKILL.md file in it. The file holds instructions; the folder can also hold scripts, templates and reference docs. Claude sees each skill's name and description all the time, loads the full body only when the skill is relevant, and you can run any skill yourself as /skill-name.
I write a skill whenever I notice I am pasting the same checklist into chat for the third time, or when a section of CLAUDE.md has turned from a fact into a procedure. Unlike CLAUDE.md, a skill's body costs almost nothing until it is used, so long reference material is cheap to keep around.
Note: Custom commands and skills are now the same thing.
.claude/commands/release.mdand.claude/skills/release/SKILL.mdboth give you/release. Existing command files keep working; skills add a folder for supporting files, frontmatter that controls who can invoke them, and automatic loading by Claude. Built-in commands like/helpand/compactare listed in the commands reference.
Claude Code skills follow the open Agent Skills standard (agentskills.io), and add extras on top: invocation control, running in a subagent and live shell output injected into the prompt. Frontmatter outside Claude Code explains which fields are portable.
Your first skill
This one turns a description of a bug into a properly formatted issue for my team's tracker, pulling in the current branch and last few commits automatically.
-
Create the folder. Personal skills live in your home directory and work in every project:
mkdir -p ~/.claude/skills/bug-report -
Save this as
~/.claude/skills/bug-report/SKILL.md:--- description: Turns a rough bug description into a structured bug report. Use when the user describes a bug, asks to write up an issue, or wants a bug ticket drafted. --- ## Context Branch: !`git branch --show-current` Recent commits: !`git log --oneline -5` ## Instructions Write a bug report with these headings: Summary, Steps to reproduce, Expected, Actual, Suspected area. Keep Summary to one sentence. Use the commits above to suggest a suspected area only if one plausibly relates.The lines starting with
!`are dynamic context: Claude Code runs them and pastes the output in before Claude reads the skill. -
Open any git project, run
claudeand either describe a bug ("the date picker shows yesterday after midnight UTC") so Claude picks the skill up itself, or type/bug-reportfollowed by the description.
The folder name, or name in frontmatter if set, becomes the command. The description is what Claude uses to decide when the skill applies.
Where skills live
| Location | Path | Available in |
|---|---|---|
| Enterprise | .claude/skills/<name>/SKILL.md inside the managed settings directory | Every user on machines where it is deployed |
| Personal | ~/.claude/skills/<name>/SKILL.md | All your projects on this machine (not Cowork or cloud sessions) |
| Project | .claude/skills/<name>/SKILL.md | This repository; commit it to share |
| Nested | <subdir>/.claude/skills/<name>/SKILL.md | Sessions started in or below <subdir>, or once Claude touches files there |
| Additional directory | .claude/skills/ in a folder passed with --add-dir | That session |
| Plugin | <plugin>/skills/<name>/SKILL.md | Wherever the plugin is enabled, as /plugin-name:skill-name |
| claude.ai account | Skills enabled on your account | Cowork, cloud sessions, and terminal sessions signed in with that account |
Some folder rules:
- An entry in the enterprise, personal or project location can be a symlink to a folder elsewhere. The skill loads once even if several locations point to the same target.
- Do not name a folder
synced(any case); that is where claude.ai skills are downloaded, and an authored skill with that name is skipped. - Outside a plugin, anything named
anthropic-skillsor starting withanthropic-skills:does not load. That namespace is reserved for synced skills. .claude/commands/*.mdfiles still work and accept the same frontmatter exceptnameandpaths.- A skill folder containing
.claude-plugin/plugin.jsonloads as a plugin called<name>@skills-dir, so it can bundle agents, hooks and MCP servers. In a project's.claude/skills/that needs workspace trust first.
Monorepos and subfolders
Project skills load from .claude/skills/ in your starting folder and every parent up to the repository root, so starting in services/payments/ still picks up root skills. /cd adds the new folder's skills (v2.1.246 or later). In a linked worktree the search stops at the worktree root; if the worktree has no .claude/skills of its own, the main checkout's are used (v2.1.277 or later).
Skills in folders below your starting point load the first time Claude reads or edits a file there. Until then they are not in the / menu. Run /add-dir on the subfolder to load them sooner (v2.1.257 or later).
If a nested skill shares a name with a root skill, both stay usable. With release at the root and in apps/mobile/.claude/skills/, /release runs the root one, /apps/mobile:release runs the nested one, and Claude is told to pick the variant whose folder holds the files it is working on.
Additional directories
--add-dir and /add-dir load the added folder's .claude/skills/, .claude/commands/ and .claude/agents/. Agent SDK additionalDirectories (TypeScript) and add_dirs (Python) behave the same. The permissions.additionalDirectories setting only grants file access and loads none of these. Only the skills folder is watched for changes; restart after editing commands or agents there. These loads depend on the project setting source, and strictPluginOnlyCustomization, bare mode and --safe-mode restrict them further. See permissions.
When two skills share a name
| Clash | Winner |
|---|---|
| Enterprise, personal, project | Enterprise beats personal, personal beats project |
| Your skill and a bundled skill | Yours replaces the bundled command but not its aliases (a code-review skill replaces /code-review; /review still runs the bundled one) |
| Your skill and a built-in command | In a local terminal, yours replaces the command but not its aliases |
Skill and .claude/commands/ file | The skill |
| Root and nested skill | Both load |
| Plugin skill and anything else | Both, since plugin skills are namespaced |
| Anything and a synced claude.ai skill's short name | The other one; the synced skill runs only as /anthropic-skills:<name> |
Cowork, cloud sessions and routines
Cowork and cloud sessions, including routines, never read your local ~/.claude/skills/. They load the skills enabled on your claude.ai account; cloud sessions also load skills committed to the repo's .claude/skills/. A routine invoking a skill that only exists locally reports it as not found. Fix that by enabling the skill on your account, or committing it to the repository. Desktop scheduled tasks run locally and do see personal skills.
Skills synced from claude.ai
If you sign in with a claude.ai account, the skills on that account (your own, your organisation's, and Anthropic's like pdf and xlsx) are available without setup.
In the terminal (v2.1.273 or later), they download in the background to ~/.claude/skills/synced/ at startup, then Claude Code checks for changes about every 10 minutes while you are active and every 40 minutes when idle, adding, updating or removing skills in the running session. Startup is never delayed; Claude only waits for a download when it invokes that skill. For a -p run that must have the full list, set CLAUDE_CODE_SYNC_SKILLS=1.
Syncing does not happen when you authenticate other than via /login (API key, ANTHROPIC_AUTH_TOKEN, CLAUDE_CODE_OAUTH_TOKEN, apiKeyHelper), when feature flags are not fetched (Bedrock, CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC), in bare or --safe-mode, or when managed settings lock skills to plugins or --setting-sources omits user. Log in mid-session and you need a restart. Previously synced skills keep loading offline.
Sync is download-only. Edits under synced/ are not uploaded and may be overwritten; change the skill on claude.ai instead. /skills lists them under claude.ai sync. Set syncClaudeAiSkills to false in user settings to stop: on next start the synced skills move to ~/.claude/skills/.trash/. Organisations can stop sync via managed settings or by turning Skills off on claude.ai (which also trashes them).
A synced skill runs as /<name> or /anthropic-skills:<name>. If anything else (built-in, bundled, local, plugin skill, or MCP prompt) uses the short name, the short name goes to that and the synced one is full-name only; /skills adds a note explaining which local file to rename to free the name. Name comparison ignores case, spacing, invisible characters and compatibility forms, but look-alike letters from other alphabets count as different (v2.1.228 or later).
The reserved anthropic-skills name blocks local skill folders, frontmatter names, command files and saved workflows (a startup notice names the culprit). A plugin called anthropic-skills still loads; an MCP server with that name connects but its prompts are hidden.
Synced skills get extra caution because they come from your account rather than a file you wrote:
- Frontmatter applies normally, so
allowed-toolsgrants go through the permission flow (ignored underallowManagedPermissionRulesOnly). - Display text is sanitised: control characters removed, angle brackets escaped in anything Claude sees.
- On your own machine (outside Cowork),
!commands are not run,@references are not attached, and${CLAUDE_PROJECT_DIR}and${CLAUDE_SESSION_ID}are left literal. Cloud sessions behave like a local skill; desktop Cowork does too except!lines become the disabled placeholder.
Editing, reloading and removing
Claude Code watches ~/.claude/skills/, the project .claude/skills/ and any --add-dir skills folder, so edits apply mid-session (not in bare mode). A brand new top-level skills folder needs /reload-skills, and keeps needing it after each change until restart. Only SKILL.md text is live; for a skill folder that is also a plugin, changes to hooks/, .mcp.json, agents/ or output-styles/ need /reload-plugins.
| Skill source | How to remove |
|---|---|
| Personal or project | Delete its folder |
| Enterprise | An admin deletes it from the managed settings directory, e.g. /etc/claude-code/.claude/skills/<name>/ on Linux |
| Plugin | Disable or uninstall the plugin (/plugin uninstall <plugin>@<marketplace>) |
| Synced | Turn it off on claude.ai; deleting the folder just causes a re-download |
| Bundled | disableBundledSkills: true, or "off" in skillOverrides |
To keep a skill but stop Claude using it unprompted, add disable-model-invocation: true or set it to "user-invocable-only" in skillOverrides.
Writing skills
Two kinds of content
Reference skills hold knowledge Claude should apply while working: conventions, domain rules, style guides. They run inline next to your conversation.
---
name: money-handling
description: Rules for handling currency amounts in this codebase
---
- Store amounts as integer pence, never floats.
- Format for display only at the UI edge with formatMoney().
- VAT is calculated per line item, then summed.
Task skills are step-by-step procedures you usually want to trigger yourself, such as releases or data fixes. Mark them with disable-model-invocation: true, and consider context: fork to run them in a subagent:
---
name: release
description: Cut a release and publish the changelog
context: fork
disable-model-invocation: true
---
1. Run the full test suite and stop if anything fails.
2. Bump the version in package.json using semver based on the commits since the last tag.
3. Generate CHANGELOG entries from those commits.
4. Tag and push.
Keep bodies short. Once loaded, a skill sits in context for the rest of the conversation, so every line is paid for on every turn. Say what to do, not why.
Frontmatter reference
Frontmatter is YAML between --- lines, and only counts if the opening --- is the very first line. Every field is optional; description is the one you should always write. Unknown field names are silently ignored, so spell them exactly. Malformed YAML still loads the body, with no fields set. Booleans accept true/false, yes/no, on/off and 1/0 in any case (v2.1.218 or later).
| Field | What it does |
|---|---|
name | Command name in the / menu. Defaults to the folder name |
description | What it does and when to use it. Falls back to the first non-empty body line. Combined with when_to_use, cut at 1,536 characters in the listing, so lead with the main use |
when_to_use | Extra trigger phrases or example requests, appended to the description |
argument-hint | Autocomplete hint such as [ticket-id] or [env] [version] |
arguments | Named positional arguments for $name substitution, as a space-separated string or YAML list |
disable-model-invocation | true stops Claude invoking it, removes it from subagent preloading, and (from v2.1.196) stops it running from a scheduled task. Default false |
user-invocable | false hides it from the / menu so only Claude can use it. Default true |
allowed-tools | Tools Claude may use without asking during the invoking turn. Cleared at your next message |
disallowed-tools | Tools removed while the skill is active, until your next message. Cannot remove EndConversation while other tools remain |
model | Model for the rest of the current turn; same values as /model, or inherit. Ignored if blocked by availableModels or unsupported in auto mode. With context: fork, sets the subagent's model |
effort | low, medium, high, xhigh or max, overriding the session level |
context | fork runs the skill in a subagent |
agent | Subagent type to use with context: fork |
background | With context: fork, false waits for the result in the same turn. Default true (v2.1.218 or later) |
hooks | Hooks registered when the skill is invoked and kept for the session |
paths | Globs limiting automatic loading to matching files, same format as path-specific rules in memory |
shell | bash (default) or powershell for ! commands |
metadata | Free-form map for your own tooling. Ignored by Claude Code; non-maps are dropped |
license | Agent Skills spec field; accepted, not acted on |
compatibility | Spec field for environment requirements, up to 500 characters; accepted, not acted on |
shell: powershell uses the PowerShell tool when it is enabled. That is on by default on Windows without Git Bash, and on with Git Bash for claude.ai and Console accounts; Bedrock, Agent Platform and Foundry sessions, and macOS, Linux and WSL, need CLAUDE_CODE_USE_POWERSHELL_TOOL=1.
Frontmatter outside Claude Code
Claude Code accepts every field above. claude.ai uploads, the Skills API and package_skill.py from the anthropics/skills repo accept only name, description, license, compatibility, metadata and allowed-tools, and fail hard on anything else:
Unexpected key(s) in SKILL.md frontmatter: argument-hint. Allowed properties are: allowed-tools, compatibility, description, license, metadata, name
Enabling a personal skill on your claude.ai account counts as an upload. Body features like ! injection only work in Claude Code. If you want a skill to work everywhere, stick to those six fields.
How the command name is chosen
| Layout | Example | Command |
|---|---|---|
| Skill folder, personal or project | .claude/skills/ship-it/SKILL.md | /ship-it, or /ship with name: ship |
| Nested folder with a clashing name | apps/mobile/.claude/skills/release/SKILL.md | /apps/mobile:release |
| Command file | .claude/commands/standup.md | /standup |
| Command file in a subfolder | .claude/commands/db/seed.md | /db:seed |
| Plugin skill | ops-kit/skills/audit/SKILL.md | /ops-kit:audit, or /ops-kit:sweep with name: sweep |
Plugin root SKILL.md | ops-kit/SKILL.md with name: audit | /ops-kit:audit (falls back to the plugin folder name) |
| Synced from claude.ai | Account skill triage | /anthropic-skills:triage, or /triage if free |
In a personal or project folder, the folder name also invokes the skill. For a plugin skill, the bare name works too when nothing else has it. If name already starts with the plugin prefix, it is not doubled (v2.1.246 or later; v2.1.216 to v2.1.245 doubled it). In non-interactive sessions, help and feedback are free for plugin skills to use; other terminal-only built-in names stay reserved.
Substitutions
| Placeholder | Becomes |
|---|---|
$ARGUMENTS | Everything typed after the command. If nothing in the body receives an argument, ARGUMENTS: <value> is appended instead |
$ARGUMENTS[N] or $N | One argument by zero-based position |
$name | A named argument from arguments (empty if missing) |
${CLAUDE_SESSION_ID} | The session ID |
${CLAUDE_EFFORT} | Current effort level |
${CLAUDE_SKILL_DIR} | Folder containing SKILL.md (for plugins, the skill's own subfolder) |
${CLAUDE_PROJECT_DIR} | Project root, as hooks and MCP servers see it (v2.1.196 or later) |
${CLAUDE_PLUGIN_ROOT} | Plugin install folder (plugin skills only) |
${CLAUDE_PLUGIN_DATA} | Plugin's persistent data folder that survives updates (plugin skills only) |
Arguments use shell-style quoting: /rename-field "billing address" postal gives $0 = billing address and $1 = postal. A missing indexed argument leaves $2 as literal text. Argument values containing $1 or $ARGUMENTS are inserted literally, not expanded again; ${CLAUDE_*} variables are still replaced afterwards. To write a literal $ before a digit, ARGUMENTS or a declared name (say $5.00), escape it once: \$5.00. A doubled backslash does not escape.
The skill and project directory variables are also substituted inside Bash rules in allowed-tools, and plugin skills get the plugin variables in both places. That lets a skill run its own script without a prompt:
---
name: lint-sql
description: Lint SQL migration files against our style rules
allowed-tools: Bash(${CLAUDE_SKILL_DIR}/bin/sqlcheck *)
---
Run `${CLAUDE_SKILL_DIR}/bin/sqlcheck <file>` on each new migration and fix what it reports.
Supporting files
Keep SKILL.md as the index and push detail into sibling files that Claude opens only when needed:
invoice-rules/
├── SKILL.md overview and pointers
├── vat-cases.md edge cases, read on demand
├── examples/ sample invoices
└── scripts/
└── validate.py run, never loaded into context
Link them from SKILL.md with a line saying what each holds and when to read it. I aim to keep SKILL.md under 500 lines.
Who can invoke a skill
| Frontmatter | You | Claude | In context |
|---|---|---|---|
| Default | Yes | Yes | Description always; body on invocation |
disable-model-invocation: true | Yes | No | Nothing until you invoke it |
user-invocable: false | No | Yes | Description always; body on invocation |
Use disable-model-invocation for anything with side effects: deploys, sending messages, committing. If Claude tries to call such a skill, Claude Code blocks it and tells Claude not to recreate the steps another way, so it will suggest you run the command. Use user-invocable: false for background knowledge that makes no sense as a command, such as how a legacy system behaves.
Subagents with preloaded skills get the full body injected at startup rather than just descriptions.
Where you type the name matters. /release 2.4.0 at the start of a message runs the skill. Typed later as a separate word ("when you're ready, /release it"), it only gives Claude permission to run it during that response. Leave the slash off to talk about a skill without permitting it.
What happens after a skill loads
The rendered body enters the conversation as one message and stays there. It is not re-read on later turns, so write rules that should hold throughout a task as standing instructions ("run the tests after every edit", not "run the tests"). allowed-tools grants do not persist: they clear at your next message.
Invoking an unchanged skill again adds only a note that it is already loaded; if the rendered content changed (new arguments or new command output), the full content is appended again.
When the conversation is compacted, the latest invocation of each skill is re-attached after the summary, up to 5,000 tokens each and 25,000 in total, filled from the most recent backwards. Skills invoked long ago may be dropped. Put the important instructions at the top.
Pre-approving and removing tools
allowed-tools lets Claude use the listed tools without prompts for the turn that invoked the skill. It does not limit which tools exist; everything else is still governed by your permissions. For session-wide approval, use allow rules.
---
name: changelog
description: Update CHANGELOG.md from commits since the last tag
disable-model-invocation: true
allowed-tools: Bash(git log *) Bash(git describe *) Edit
---
Workspace trust does not gate this field, even in a -p run in an untrusted folder, so read the allowed-tools of any skills in a repository before running Claude there. From v2.1.282, allowManagedPermissionRulesOnly in managed settings makes Claude Code ignore allowed-tools from project and personal skills; /status lists the skills affected.
disallowed-tools does the reverse while the skill is active; for permanent blocks use deny rules.
Passing arguments
---
name: port-test
description: Port a test file to Vitest
arguments: [file, style]
---
Port $file to Vitest using the $style assertion style. Keep every case.
/port-test tests/cart.spec.js expect fills both. You can also stack skills at the start of a message: /explain-diff /port-test tests/cart.spec.js expect loads both and gives each the trailing text. Up to six stack (the first plus five); stacking stops at the first token that is not an inline user-invocable skill, so forked skills like /code-review (forked from v2.1.218) or ones like /loop end the chain.
Advanced patterns
Injecting live context
!`command` runs before Claude sees the skill and is replaced by the output. It must sit at the start of a line or after whitespace; X=!`cmd` is left alone. Output is inserted once and not rescanned. For several commands, use a fenced block opened with ```!:
## Service health
```!
docker compose ps --format "{{.Name}} {{.Status}}"
curl -s localhost:8080/healthz
```
A PR summariser is a good use:
---
name: pr-brief
description: Brief me on the current pull request
context: fork
agent: Explore
allowed-tools: Bash(gh *)
---
Title and body: !`gh pr view --json title,body -q '.title + "\n" + .body'`
Files: !`gh pr diff --name-only`
Explain what this PR changes and what a reviewer should look at first.
Set "disableSkillShellExecution": true in settings (most usefully managed settings) to replace every command from user, project, plugin and additional-directory skills with [shell command execution disabled by policy]. Bundled and managed skills are unaffected. Synced skills never run commands on your machine regardless.
Add ultrathink anywhere in a skill to ask for deeper reasoning when it runs (see model configuration).
How commands run. shell: powershell with the PowerShell tool enabled uses PowerShell. shell: bash with no bash available (Windows without Git Bash) fails with Skill <name> requires bash (`shell: bash` in frontmatter) but Git Bash was not found. Otherwise bash is used if present, PowerShell if not. Commands run in the session shell's current directory (which moves with cd, so use ${CLAUDE_SKILL_DIR} or ${CLAUDE_PROJECT_DIR} for stable paths), stderr is merged into stdout under bash, each has the Bash tool's two-minute timeout (long ones may move to the background, with the injected text saying where output is going), and large output arrives as a file path plus preview.
When one fails. Any failure aborts the whole invocation with Shell command failed for pattern "..." and the stderr. Under bash, non-zero exit fails, except exit 1 from search and comparison commands such as grep and diff; exit 2 or more always fails. PowerShell has its own list. Append || true to scripts that exit 1 on findings.
Permissions. Injected commands never prompt. Each is checked against your rules: a deny aborts with Shell command permission check failed for pattern "...", and outside auto mode so does anything short of allow (including ask). Pre-approve with allowed-tools. In auto mode, a command needing approval instead becomes an instruction for Claude to run it first, subject to the classifier, except in forked skills that set agent or when the shell tool is unavailable.
Running a skill in a subagent
context: fork starts a fresh subagent of the agent type (default general-purpose; also Explore, Plan or any custom agent) with the skill body as its task. It does not see your conversation, so the instructions must stand alone. Despite the name, this is not a fork of the conversation; if the work depends on what you have discussed, fork the conversation instead.
Forked skills run in the background and report back when done (v2.1.218 or later). They wait in the foreground instead under -p or the SDK, with CLAUDE_CODE_DISABLE_BACKGROUND_TASKS=1, when the same skill is already running, from a scheduled task, or with background: false. Background forks get the narrower background-subagent tool set, so set background: false if your steps need more. Their edits fall outside checkpoints, so /rewind cannot undo them.
Warning:
context: forkonly works for skills with a concrete task. A skill that is just conventions gives the subagent nothing to do.
| Approach | System prompt | Task | Also loads |
|---|---|---|---|
Skill with context: fork | The agent type's | The skill body | CLAUDE.md per the agent's startup rules (Explore and Plan skip it) |
Subagent with a skills field | The subagent's own body | Claude's delegation message | Preloaded skills plus CLAUDE.md |
Controlling which skills Claude may use
Claude can invoke any skill without disable-model-invocation. A few built-ins, such as /init and /security-review, are also reachable through the Skill tool; others like /compact are not. Control it with permission rules:
Skill deny: no skills at all
Skill(changelog) exact name
Skill(port-test *) name with any arguments
Deny rules reach further than the literal name: Skill(review) blocks /code-review via its alias, Skill(release) also blocks a nested apps/mobile:release (v2.1.260 or later), Skill(anthropic-skills:triage) also blocks it when the desktop app delivers it as a plugin, and the parameter form Skill(skill:release) catches every name the skill goes by. Allow rules only match the skill's own name and the name Claude used: approve synced skills as Skill(anthropic-skills:pdf) or Skill(anthropic-skills *) (Skill(anthropic *) does not cover them).
Note that user-invocable: false stops you, not Claude. Use disable-model-invocation: true to keep Claude away.
Overriding visibility from settings
skillOverrides changes visibility without editing the skill, which is handy for shared project skills. In /skills, highlight a skill, press Space to cycle and Esc to save to .claude/settings.local.json.
| Value | Claude sees | In / menu |
|---|---|---|
"on" (default when absent) | Name and description | Yes |
"name-only" | Name | Yes |
"user-invocable-only" (shown as user-only) | Nothing | Yes |
"off" | Nothing | No |
{
"skillOverrides": {
"money-handling": "name-only",
"release": "off"
}
}
"off" also hides the skill from Remote Control and Agent SDK command lists, and calling it by full name returns a skillOverrides error. In managed settings or --settings files an entry under an alias (like checkup for /doctor) applies to the skill behind it, but can only restrict, and an entry under the real name wins. User, project and local settings match real names only. Plugin skills ignore skillOverrides; manage them in /plugin.
Finding skills you never use
Every listed skill costs context on every turn. /skill-doctor (v2.1.252 or later) shows each skill's context cost and usage, flags never-used ones and says where to turn them off, plus plugins you have not used lately. Interactively it opens in the /plugin manager's Stats tab; with -p it prints text. It skips bundled and enterprise skills, needs feature-flag fetching, and is not available over Remote Control.
Bundled skills
Claude Code ships with prompt-based skills such as /doctor, /code-review, /batch, /debug, /loop and /claude-api. Some Claude can trigger itself; others, like /verify, only run when you ask. A few depend on features: /workflow-authoring exists only when workflows are enabled. Turn them all off with disableBundledSkills. From v2.1.205 /doctor stays available even then; hide it with DISABLE_DOCTOR_COMMAND or "doctor": "off" in skillOverrides. The commands reference marks bundled skills as Skill.
/doctor
Runs a setup checkup and offers fixes after asking:
- Installation: duplicate installs,
PATHproblems, unparseable settings, available updates on your release channel. - Extensions: unused skills, MCP servers and plugins against their context cost; slow hooks.
- CLAUDE.md: local files duplicating committed ones, content Claude could derive from the code, and always-loaded guidance it can move into skills or nested files.
- Permissions: offers auto mode as default and pre-approval of read-only commands you keep denying.
claude doctor in the shell gives read-only install diagnostics without a session. /doctor prompt-audit (v2.1.283 or later) audits your instruction files for stale or conflicting guidance instead.
/run, /verify and /run-skill-generator
/run launches and drives your app to show a change working. /verify builds and runs it to confirm a change behaves correctly, without retreating to tests or type checks. Both infer how to launch from your project type and files like package.json or a Makefile, which gets shaky for apps needing databases, env files or multi-step builds.
/run-skill-generator fixes that by getting the app running from scratch and committing the recipe as .claude/skills/run-<name>/. Run it once per project and again when the launch changes. /verify can also record its own recipe in .claude/skills/verify/SKILL.md (at the root, or the touched package in a monorepo), which then replaces the bundled /verify. Claude only edits that file when it led a run astray, so it stays stable enough to commit.
From v2.1.286, if a session starts with a verify or simplify skill from the enterprise, personal, project or additional-directory location (or a .claude/commands/ file of that name), Claude is told to run it before each commit except for docs or test changes. Bundled, plugin and synced versions do not count, the skill must be model-invocable, and includeGitInstructions must be on.
/claude-api
Loads Claude API and Managed Agents reference for your project's language, and activates automatically when code imports anthropic or @anthropic-ai/sdk. Subcommands:
| Subcommand | Purpose | From |
|---|---|---|
migrate | Move API code to a newer model | Before v2.1.221 |
upgrade | Cross a major SDK version (currently Python anthropic 0.x to 1.x) | v2.1.236 |
managed-agents-onboard | Create a new Managed Agent | Before v2.1.221 |
prompt-audit | Flag instructions written for older models, as a diff | v2.1.221 |
cost-optimize | Profile spend and propose savings one change at a time | v2.1.247 |
build-eval | Build an eval set | v2.1.259 |
hillclimb | Improve against an existing eval | v2.1.259 |
preserved-thinking-migration | Find edits that invalidate preserved thinking and fix them | v2.1.282 |
Testing a skill
A skill triggering only proves Claude found it. Check two things separately: does it trigger on the prompts it should, and is the output right when it does? Run a handful of realistic prompts in fresh sessions with the skill on and again with it off, and compare. Fresh sessions matter, because context left over from writing the skill hides gaps in it. Turn a personal or project skill off with "off" in skillOverrides.
For plugin skills, claude plugin eval automates this with and without the plugin, scores with graders and can fail CI below a threshold.
For single skills, the official skill-creator plugin runs a similar loop inside Claude Code:
/plugin install skill-creator@claude-plugins-official
(Add the marketplace with /plugin marketplace add anthropics/claude-plugins-official if needed.) Then ask "evaluate my bug-report skill with skill-creator". It keeps test cases in evals/evals.json, runs each in its own subagent, writes grading.json and benchmark.json comparing with and without the skill, can blind A/B two versions, tunes the description against should-trigger and should-not-trigger prompts, and opens an HTML viewer for your feedback. Its format is not interchangeable with claude plugin eval.
Sharing skills
- Team: commit
.claude/skills/. - Across repos: ship a
skills/folder in a plugin. - Organisation: deploy through managed settings.
Skills can bundle scripts in any language, which opens up things a prompt alone cannot do. One pattern I use is a skill whose script writes a self-contained HTML report (a dependency graph, a coverage map) and opens it in the browser, with Claude orchestrating and the script doing the heavy lifting. Reference the script via ${CLAUDE_SKILL_DIR} so it works at any install level, and pre-approve it in allowed-tools.
Troubleshooting
It never triggers
- Put the words people actually say into
descriptionorwhen_to_use. - Ask "What skills are available?" to confirm it loaded.
- Invoke it directly with
/nameto rule out matching. - Broken YAML loads the body with no metadata, so
/nameworks but Claude cannot match the description.--debugshows the parse error, andclaude plugin validate .claude/skills(or~/.claude/skills) finds bad frontmatter (v2.1.233 or later). - For plugin skills, measure trigger rate with a
tool_used: Skillgrader in plugin evals.
It triggers too often
Narrow the description, or add disable-model-invocation: true.
Claude drifts away from it
- A rule that must always hold: move it into a hook, optionally declared in the skill's own
hooksfrontmatter so it activates with the skill. - Judgement guidance: phrase it as a standing instruction, since the file is not re-read.
- After compaction: invoke the skill again, and keep key instructions near the top.
Descriptions are being cut
The skill listing gets a budget of 1% of the context window. Every name is always included, but descriptions are dropped starting with your least-used skills. /doctor estimates the cost, /skill-doctor finds candidates to switch off, --debug logs an overflow warning, and the Skills row in /context shows the post-budget size (from v2.1.196). Raise the budget with skillListingBudgetFraction (e.g. 0.02) or a fixed SLASH_COMMAND_TOOL_CHAR_BUDGET, demote skills to "name-only", or trim descriptions. The per-entry 1,536-character cap is adjustable with skillListingMaxDescChars.
Personal skills vanished
Look in ~/.claude/skills/.trash/. Sync never touches your own folders, but before v2.1.280 a manifest.json in ~/.claude/skills/ could move listed folders into a timestamped trash folder. Move them back before the retention sweep deletes trash, 30 days by default.
For a broader checklist, see debugging your configuration.