02 / 20Automation7 MIN READ

Skills

A skill is a directory containing a SKILL.md file whose description Claude Code loads at startup and whose body loads only when you or Claude invoke it.

One skill lifting out of a stackFour skills sit stacked as one-line descriptions. One lifts out of the stack and expands into its full instruction body, showing that only the invoked skill loads its content.DESCRIPTIONSSKILL.md

What it is

A skill is a folder with SKILL.md at its root. The file has YAML frontmatter and a markdown body. The directory name becomes the command you type: .claude/skills/deploy-staging/SKILL.md gives you /deploy-staging. Alongside SKILL.md you can ship templates, reference documents, and executable scripts.

Skills load in two stages, which is what makes them cheap. At startup Claude Code puts only each skill’s one-line description into context so Claude knows what exists. The body loads when the skill actually runs. A 400-line reference document costs almost nothing until the moment it is needed, unlike CLAUDE.md content, which is paid for on every request.

Custom commands have been merged into skills. A file at .claude/commands/deploy.md and a skill at .claude/skills/deploy/SKILL.md both create /deploy and support the same frontmatter. Existing .claude/commands/ files keep working; skills add the supporting-file directory, invocation control, and automatic loading. Claude Code skills follow the open Agent Skills standard, with Claude Code extensions on top.

What it does for you

  • It gives a repeatable procedure one definition. The release checklist you paste into chat every Thursday becomes /release, and when a step changes you edit one file instead of remembering the new version.
  • It keeps long reference material out of the context window until it is relevant, which is the difference between a 400-line API convention document being free and being a per-request tax.
  • It lets you decide who may trigger a procedure. disable-model-invocation: true means Claude can never run your deploy on its own; user-invocable: false means a background-knowledge skill never clutters the / menu.

How it works

  1. 01Claude Code discovers skill directories at startup

    It reads .claude/skills/ in your working directory and every parent up to the repository root, ~/.claude/skills/, .claude/skills/ inside any --add-dir directory, plugin skills/ directories, and the managed-settings location.

  2. 02Only descriptions enter the context window

    Each skill contributes its description, plus when_to_use if set. The combined text is truncated at 1,536 characters in the listing, so the key use case goes first. A skill with disable-model-invocation: true is left out of this listing entirely.

  3. 03The description decides when Claude loads the skill

    Claude matches your prompt against those descriptions. This is why the description is the trigger surface: "Deploys to production. Use when the user asks to ship, release, or deploy" fires reliably, while "Deployment helper" does not.

  4. 04Invocation injects the body as a user message

    Whether you type /name or Claude decides the skill is relevant, the body is appended to the conversation. Nothing earlier changes, so the prompt cache stays intact. Once loaded, the body stays in context for the rest of the session.

  5. 05Bash injection and substitutions run before Claude sees the body

    A ` !command line is executed and replaced by its output. $ARGUMENTS, $0, ${CLAUDE_SKILL_DIR}, ${CLAUDE_PROJECT_DIR}, and ${CLAUDE_SESSION_ID}` are substituted at the same point.

  6. 06Supporting files load only when referenced

    Claude reads reference.md or runs scripts/validate.sh with its ordinary tools when the body tells it to. Keep SKILL.md under 500 lines and push detail into those files. Claude Code watches the skill directories that existed at session start, so an edit to SKILL.md is picked up within the current session without a restart, and /reload-skills picks up a brand-new directory.

How to implement it

  1. 01Create the directory

    Run mkdir -p .claude/skills/summarize-changes for a project skill, or use ~/.claude/skills/ for one that follows you across every project.

  2. 02Write SKILL.md with a trigger-shaped description

    The description is what Claude matches against. Name the task and the phrases that should fire it, and put the primary use case in the first sentence.

  3. 03Pull live state into the prompt if the skill needs it

    Add a ` !git diff HEAD ` line so the instructions arrive with the real diff inlined instead of asking Claude to go find it.

  4. 04Decide who can invoke it

    Add disable-model-invocation: true to anything with side effects, such as deploys, commits, or outbound messages. Add user-invocable: false to pure background knowledge.

  5. 05Test both invocation paths

    Type /skill-name to confirm the body runs, then phrase a request that matches the description and confirm Claude loads it on its own. Edits are picked up live, without a restart.

Examples

.claude/skills/release-notes/SKILL.mdmarkdown
---
name: release-notes
description: Writes the changelog entry for a release from the merged pull requests since the last tag. Use when the user asks for release notes, a changelog entry, or "what shipped".
argument-hint: [version]
arguments: version
disable-model-invocation: true
allowed-tools: Bash(${CLAUDE_SKILL_DIR}/scripts/merged-prs.sh *) Read Edit
---

## Commits since the last tag

!`git log $(git describe --tags --abbrev=0)..HEAD --oneline`

## Merged pull requests

!`${CLAUDE_SKILL_DIR}/scripts/merged-prs.sh`

## Instructions

Write the entry for version $version into `CHANGELOG.md`, above the previous
release. Follow the format in [reference.md](reference.md) exactly.

Group changes under **Added**, **Changed**, **Fixed**, and **Removed**. Drop
anything that is not user-visible: dependency bumps, CI changes, and internal
refactors do not appear. Each line names the change, not the commit, and ends
with the pull request number in parentheses.

If there are no user-visible changes, say so and write nothing to the file.
A user-only skill with a bundled script, live git state, and a named argument. The folder layout is shown below it.
Skill folder layoutbash
.claude/skills/release-notes/
├── SKILL.md              # required: frontmatter + instructions
├── reference.md          # the changelog format, read only when needed
└── scripts/
    └── merged-prs.sh     # executed by the !`...` line, never loaded as text
Only SKILL.md is required. Everything else loads or executes on demand.

Use it when

  • A release or deploy checklist you run on a schedule and want triggered only by hand.
  • Codebase conventions too long for CLAUDE.md, such as a full API design guide that matters twice a month.
  • A review procedure that must be applied the same way every time, bundled with the rubric it scores against.
  • A migration recipe that ships with the codemod script it tells Claude to run.
  • Background knowledge about a legacy subsystem, marked user-invocable: false so it informs Claude without appearing in the / menu.

Avoid it when

  • The fact is short and needed in every session. A build command belongs in CLAUDE.md; wrapping it in a skill means Claude has to decide to load it first.
  • The rule must be enforced. A skill is instructions Claude may or may not follow; a hook is a shell command Claude Code runs regardless.
  • The description would be so broad it fires on unrelated prompts. An over-broad trigger costs you the skill body on turns that did not need it, and it crowds out context you did need.
  • You need the work done in a separate context window with its own tool restrictions. That is a subagent, though a skill can delegate to one with context: fork.

Common mistakes

  • SYMPTOMClaude never loads the skill automatically, even on prompts that obviously match.

    FIXRewrite the description as a trigger, not a title. Name the task and the phrases that should fire it, and confirm disable-model-invocation is not set.

  • SYMPTOMA skill fires on unrelated prompts and its body sits in context for the rest of the session.

    FIXNarrow the description to the specific task, or add paths: frontmatter so it only activates when Claude is working on matching files.

  • SYMPTOMClaude deploys, commits, or posts something because the skill looked applicable.

    FIXAdd disable-model-invocation: true. Claude Code then blocks the call and tells Claude not to reproduce the steps another way, so it suggests you run /deploy yourself.

  • SYMPTOMA skill’s bundled script prompts for permission on every run.

    FIXAdd allowed-tools: Bash(${CLAUDE_SKILL_DIR}/scripts/run.sh *) and reference the script through the same ${CLAUDE_SKILL_DIR} variable in the body, so the rule matches the exact command.

  • SYMPTOMUploading the skill to claude.ai fails with Unexpected key(s) in SKILL.md frontmatter.

    FIXOutside Claude Code only name, description, license, compatibility, metadata, and allowed-tools are accepted. Strip the Claude Code-only fields from any skill you package for upload.

Best practices

  • Write the description as a trigger sentence with the key use case first — it is the only part loaded at startup.
  • Keep SKILL.md under 500 lines and move detail into sibling files the body links to.
  • Set disable-model-invocation: true on anything with side effects you want to time yourself.
  • Use ` !command ` to inline live state instead of telling Claude to go fetch it.
  • Reference bundled files with ${CLAUDE_SKILL_DIR} so the skill works from any working directory.
  • Put the instructions that matter most at the top: after compaction, skill bodies are re-injected truncated to 5,000 tokens each and 25,000 total.

Try it in five minutes

Build a skill that summarises your uncommitted changes, and watch progressive disclosure happen.

  1. 1.Run mkdir -p ~/.claude/skills/summarize-changes and create SKILL.md inside it.
  2. 2.Give it a description like Summarizes uncommitted changes and flags anything risky. Use when the user asks what changed or wants a commit message. and a body containing a ` !git diff HEAD ` line plus instructions.
  3. 3.Open a git repository, edit a file, start claude, and run /context — only the one-line description is loaded.
  4. 4.Type /summarize-changes and confirm the diff was inlined before Claude read it.
  5. 5.Run /clear, then ask "what did I change?" in plain English and confirm Claude loads the skill on its own.

Verified against code.claude.com/docs/en/skills on 2026-08-09. See content/SOURCES.md for the full table.

← / → MOVE BETWEEN CONCEPTS