Skip to content

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.md and .claude/skills/release/SKILL.md both 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 /help and /compact are 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.

  1. Create the folder. Personal skills live in your home directory and work in every project:

    mkdir -p ~/.claude/skills/bug-report
    
  2. 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.

  3. Open any git project, run claude and either describe a bug ("the date picker shows yesterday after midnight UTC") so Claude picks the skill up itself, or type /bug-report followed 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

LocationPathAvailable in
Enterprise.claude/skills/<name>/SKILL.md inside the managed settings directoryEvery user on machines where it is deployed
Personal~/.claude/skills/<name>/SKILL.mdAll your projects on this machine (not Cowork or cloud sessions)
Project.claude/skills/<name>/SKILL.mdThis repository; commit it to share
Nested<subdir>/.claude/skills/<name>/SKILL.mdSessions started in or below <subdir>, or once Claude touches files there
Additional directory.claude/skills/ in a folder passed with --add-dirThat session
Plugin<plugin>/skills/<name>/SKILL.mdWherever the plugin is enabled, as /plugin-name:skill-name
claude.ai accountSkills enabled on your accountCowork, 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-skills or starting with anthropic-skills: does not load. That namespace is reserved for synced skills.
  • .claude/commands/*.md files still work and accept the same frontmatter except name and paths.
  • A skill folder containing .claude-plugin/plugin.json loads 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

ClashWinner
Enterprise, personal, projectEnterprise beats personal, personal beats project
Your skill and a bundled skillYours 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 commandIn a local terminal, yours replaces the command but not its aliases
Skill and .claude/commands/ fileThe skill
Root and nested skillBoth load
Plugin skill and anything elseBoth, since plugin skills are namespaced
Anything and a synced claude.ai skill's short nameThe 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-tools grants go through the permission flow (ignored under allowManagedPermissionRulesOnly).
  • 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 sourceHow to remove
Personal or projectDelete its folder
EnterpriseAn admin deletes it from the managed settings directory, e.g. /etc/claude-code/.claude/skills/<name>/ on Linux
PluginDisable or uninstall the plugin (/plugin uninstall <plugin>@<marketplace>)
SyncedTurn it off on claude.ai; deleting the folder just causes a re-download
BundleddisableBundledSkills: 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).

FieldWhat it does
nameCommand name in the / menu. Defaults to the folder name
descriptionWhat 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_useExtra trigger phrases or example requests, appended to the description
argument-hintAutocomplete hint such as [ticket-id] or [env] [version]
argumentsNamed positional arguments for $name substitution, as a space-separated string or YAML list
disable-model-invocationtrue stops Claude invoking it, removes it from subagent preloading, and (from v2.1.196) stops it running from a scheduled task. Default false
user-invocablefalse hides it from the / menu so only Claude can use it. Default true
allowed-toolsTools Claude may use without asking during the invoking turn. Cleared at your next message
disallowed-toolsTools removed while the skill is active, until your next message. Cannot remove EndConversation while other tools remain
modelModel 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
effortlow, medium, high, xhigh or max, overriding the session level
contextfork runs the skill in a subagent
agentSubagent type to use with context: fork
backgroundWith context: fork, false waits for the result in the same turn. Default true (v2.1.218 or later)
hooksHooks registered when the skill is invoked and kept for the session
pathsGlobs limiting automatic loading to matching files, same format as path-specific rules in memory
shellbash (default) or powershell for ! commands
metadataFree-form map for your own tooling. Ignored by Claude Code; non-maps are dropped
licenseAgent Skills spec field; accepted, not acted on
compatibilitySpec 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

LayoutExampleCommand
Skill folder, personal or project.claude/skills/ship-it/SKILL.md/ship-it, or /ship with name: ship
Nested folder with a clashing nameapps/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 skillops-kit/skills/audit/SKILL.md/ops-kit:audit, or /ops-kit:sweep with name: sweep
Plugin root SKILL.mdops-kit/SKILL.md with name: audit/ops-kit:audit (falls back to the plugin folder name)
Synced from claude.aiAccount 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

PlaceholderBecomes
$ARGUMENTSEverything typed after the command. If nothing in the body receives an argument, ARGUMENTS: <value> is appended instead
$ARGUMENTS[N] or $NOne argument by zero-based position
$nameA 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

FrontmatterYouClaudeIn context
DefaultYesYesDescription always; body on invocation
disable-model-invocation: trueYesNoNothing until you invoke it
user-invocable: falseNoYesDescription 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: fork only works for skills with a concrete task. A skill that is just conventions gives the subagent nothing to do.

ApproachSystem promptTaskAlso loads
Skill with context: forkThe agent type'sThe skill bodyCLAUDE.md per the agent's startup rules (Explore and Plan skip it)
Subagent with a skills fieldThe subagent's own bodyClaude's delegation messagePreloaded 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.

ValueClaude seesIn / menu
"on" (default when absent)Name and descriptionYes
"name-only"NameYes
"user-invocable-only" (shown as user-only)NothingYes
"off"NothingNo
{
  "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, PATH problems, 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:

SubcommandPurposeFrom
migrateMove API code to a newer modelBefore v2.1.221
upgradeCross a major SDK version (currently Python anthropic 0.x to 1.x)v2.1.236
managed-agents-onboardCreate a new Managed AgentBefore v2.1.221
prompt-auditFlag instructions written for older models, as a diffv2.1.221
cost-optimizeProfile spend and propose savings one change at a timev2.1.247
build-evalBuild an eval setv2.1.259
hillclimbImprove against an existing evalv2.1.259
preserved-thinking-migrationFind edits that invalidate preserved thinking and fix themv2.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 description or when_to_use.
  • Ask "What skills are available?" to confirm it loaded.
  • Invoke it directly with /name to rule out matching.
  • Broken YAML loads the body with no metadata, so /name works but Claude cannot match the description. --debug shows the parse error, and claude 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: Skill grader 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 hooks frontmatter 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.