KaairosGet the kit
Guide · 7 min read

How to create a Claude Code skill (SKILL.md)

A skill is a folder with a SKILL.md inside. The description decides when Claude loads it; the body holds the instructions. Here is how to build one that fires.

To create a Claude Code skill, make a folder at .claude/skills/<name>/ and put a SKILL.md file inside it. The frontmatter needs a description that says when to use the skill, and the Markdown body holds the instructions Claude follows when it runs. Save it in ~/.claude/skills/ to use the skill in every project, or in your repo's .claude/skills/ to scope it to that project. From there Claude loads the skill on its own whenever the description matches your task, or you invoke it directly by typing /<name>.

The rest of this guide covers the anatomy of a SKILL.md, the description field that decides whether it ever fires, where to put skills and how they take precedence, how to keep large reference material out of context until you need it, and how to confirm the skill actually triggers.

The folder and SKILL.md anatomy

A skill is a directory, not a single file, and SKILL.md is its entry point. The directory name becomes the command you type, so .claude/skills/summarize-changes/ gives you /summarize-changes. The file itself has two parts: YAML frontmatter between --- markers, and the Markdown instructions below it.

---
name: summarize-changes
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 bullets, then list any
risks such as missing error handling, hardcoded values, or tests
that need updating. If the diff is empty, say so.

Two details in that example are worth calling out. name is optional for personal and project skills — it only sets the display label, while the command name always comes from the directory. And the ` !git diff HEAD ` line is dynamic context injection: Claude Code runs the command and replaces the line with its output before Claude reads the skill, so the instructions arrive with your real diff already inlined. Skills are the reusable-knowledge primitive; for how they differ from subagents and commands, see skills vs subagents vs commands.

It helps to know which of two shapes you are writing. Reference skills hold knowledge Claude applies alongside your work — conventions, a style guide, domain rules — and you usually let Claude load them automatically when relevant. Task skills are step-by-step procedures you tend to trigger yourself, like a deploy or a release checklist, and those often get disable-model-invocation: true so Claude never fires them by accident. The file format is identical; the difference is only in how you expect the skill to be invoked, and that shapes both the description and the body.

The description is the trigger

Claude reads only each skill's description (plus an optional when_to_use) until one matches, then loads the full body. So the description is doing the routing, and a vague one means the skill never fires. Put the key use case first and name the concrete situations, file types, and phrasings that should trigger it — the combined text is truncated at 1,536 characters in the skill listing, so front-load the part that matters.

Write for when, not what'Formats API responses' describes what the skill is and rarely fires. 'Use when writing or editing an endpoint under src/api, or when the user asks about response shapes or error formats' describes when to reach for it, and matches. This is the same field that decides whether a subagent gets called — get it wrong and nothing you wrote in the body ever runs.

If you want a skill that only ever runs when you type its name — a deploy step, anything with side effects — add disable-model-invocation: true to the frontmatter so Claude never triggers it automatically.

Where skills live, and who can use them

Location determines scope. The two you will use most are personal and project:

LocationPathApplies to
Personal~/.claude/skills/<name>/SKILL.mdEvery project on your machine
Project.claude/skills/<name>/SKILL.mdThis repository only, shared via git
Plugin<plugin>/skills/<name>/SKILL.mdWherever the plugin is enabled

When a skill name exists at more than one level, personal overrides project, and a skill of the same name overrides a bundled one — so a code-review skill in your project replaces the built-in /code-review. Get the path depth exactly right: it must be ~/.claude/skills/<name>/SKILL.md, with the file one level below the skill folder. Nesting it in a further subdirectory, or naming the file anything other than SKILL.md, means Claude Code never finds it.

Project skills also load from nested .claude/skills/ directories below where you started, which is what makes monorepos tidy: a skill defined next to a package becomes available when Claude works on that package's files, even though the session started at the repository root. You will not need this on day one, but it is why a large repo can give each package its own skills instead of piling everything into one top-level folder.

Progressive disclosure with supporting files

A skill's body loads only when the skill is used, so long reference material costs almost nothing until it is needed — that is the whole advantage over putting the same content in CLAUDE.md, which loads every session. You extend this by adding supporting files to the skill folder and referencing them from SKILL.md, so Claude pulls each one in only when the task calls for it.

api-conventions/
├── SKILL.md          # short: the rules + when to read the rest
├── reference.md      # the full style guide, loaded on demand
├── examples/
│   └── endpoint.ts   # a known-good example to copy
└── scripts/
    └── validate.sh   # a check Claude can run

Keep SKILL.md itself concise — once loaded, its content stays in context across turns, so every line is a recurring cost. State what to do, point to reference.md for the detail, and let Claude open the heavy files only when it actually needs them.

Test that it fires

Open a project, make a small edit, and try the skill two ways. First, invoke it directly to confirm the body works: type /<name> and check the output. Then test auto-loading by asking a question that matches the description in natural language — for the example above, 'what did I change?' — and confirm Claude reaches for the skill without being told to. If direct invocation works but auto-loading does not, the description is the problem, not the body.

New directories need a restartClaude Code watches skill directories and picks up edits within a running session, but the watcher only covers folders that existed when the session started. If you just created your first .claude/skills/ directory, restart Claude Code before the skill will load.

Common mistakes

  • A description that describes. Naming what the skill is instead of when to use it is the number-one reason a skill never auto-loads.
  • Wrong path depth or filename. It must be <skills-dir>/<name>/SKILL.md; an extra nested folder or a renamed file makes it invisible.
  • A bloated body. The skill stays in context once loaded, so treat the body like CLAUDE.md and cut anything that is not an instruction.
  • Expecting a brand-new skills folder to load live. The first skill in a new directory needs a restart.
  • Reference material inlined instead of split out. Move long guides into supporting files so they cost nothing until Claude opens them.

A skill is the right tool when you keep pasting the same checklist or procedure into chat and you want Claude to apply it on its own. If instead you always want to trigger something by typing — and to pass it input — a command with slash command arguments is the simpler reach. Both share the same file format now, so you can start with one and grow into the other.

Sources

Keep reading