Skip to main content

Module 6 — Build your own slash commands: skills from A to Z

Previous modules walked through the shipped commands. This module teaches you to add your own: skills. Since v2.1.199, custom commands and skills are the same thing. A .claude/skills/deploy/SKILL.md file and a .claude/commands/deploy.md file both create /deploy; the old format still works, the new one brings a folder of supporting files, a richer frontmatter, and the option for Claude to decide on its own to invoke the skill. Unlike CLAUDE.md, a skill body only loads when the skill is invoked: a long reference topic costs almost nothing until it is used.

Anatomy of a skill

A skill is a folder containing at least one SKILL.md file. The folder name becomes the command to type: .claude/skills/deploy/SKILL.md creates /deploy. The folder can carry other files (scripts, specs, examples) that Claude will read on demand. SKILL.md has two parts: a YAML frontmatter between --- that describes the skill (Claude uses it to decide whether to load the skill on its own), and Markdown content that is the prompt handed to Claude when the skill is invoked. The frontmatter is only read if --- is the very first line; otherwise Claude Code treats the whole file as the body.

---
description: Summarizes uncommitted changes and flags what looks risky. Use when the user asks "what changed?" or wants a commit message.
---

## Current changes
!`git diff HEAD`

## Instructions
Summarize in two or three bullets, then list the risks: missing error handling, hardcoded values, tests to update. If the diff is empty, say so.

The line !`git diff HEAD` is a dynamic injection: Claude Code runs the shell command before sending, and its output replaces the placeholder. The model receives the live diff, not the command.

Scopes: where to store a skill

Seven locations coexist:

LocationPathLoaded in
Enterprise.claude/skills/<name>/SKILL.md in managed settingsMachines where the organization deploys it
Personal~/.claude/skills/<name>/SKILL.mdEvery project on the machine
Project.claude/skills/<name>/SKILL.mdEvery session in the repo
Nested<subfolder>/.claude/skills/<name>/SKILL.mdSessions started in/under <subfolder>, otherwise when Claude touches a file inside that path
Added directory.claude/skills/<name>/SKILL.md in a --add-dir folderThis session only
Plugin<plugin>/skills/<name>/SKILL.mdWhere the plugin is active, under /<plugin>:<name>
claude.ai accountSkills enabled on the claude.ai sideCowork and cloud sessions (module 15)

Precedence on name clashes: enterprise > personal > project. A .claude/commands/ file yields to a skill with the same name. A plugin skill is prefixed. The name synced is reserved. A repo skill applies in -p even inside an unapproved folder: reread allowed-tools before any claude in the repo.

Full frontmatter reference

All fields are optional; only description is recommended. Booleans: yes/no/on/off/1/0 in addition to true/false (v2.1.218+).

FieldEffect
nameDisplay name. Defaults to the folder name. Does not change the command to type, except inside a plugin where name replaces the last segment.
descriptionWhat the skill does and when to use it. Cap combined with when_to_use: 1,536 characters.
when_to_useAdditional context: trigger phrases, examples.
argument-hintAutocomplete hint: [file] [format].
argumentsNamed list for $name substitution. String or YAML list.
disable-model-invocationtrue prevents Claude from loading the skill on its own (and from firing it via a scheduled task).
user-invocablefalse hides from the / menu: only Claude-side invocation works.
allowed-toolsTools authorized without confirmation during the invocation turn. Grant cleared on the next message.
disallowed-toolsTools removed from the pool during the turn. Cannot remove EndConversation if other tools remain.
modelModel for the duration of the turn; same values as /model, or inherit.
effortEffort for the turn: low, medium, high, xhigh, max.
contextfork runs the skill in an isolated subagent.
agentSubagent type when context: fork: Explore, Plan, general-purpose, or a subagent from .claude/agents/.
backgroundWith context: fork, false blocks the turn. Defaults to true. v2.1.218+.
hooksHooks registered at invocation, active for the session.
pathsGlob patterns limiting auto-invocation to matching files.
shellbash (default) or powershell for injected commands.
metadataFree YAML map for your own tooling.
license, compatibilityFields of the Agent Skills standard, accepted with no effect.

Outside Claude Code (claude.ai upload, Skills API, package_skill.py), only name, description, license, compatibility, metadata and allowed-tools are accepted; the others are Claude Code extensions.

Arguments: $ARGUMENTS, $0/$1, $name

A skill receives whatever follows its name on the line. Four placeholder forms: $ARGUMENTS (the whole thing as a single string — without a placeholder, Claude Code appends it at the end of the skill as ARGUMENTS: <value>), $ARGUMENTS[N] (zero-based indexed access), $N (equivalent shortcut, $0, $1), and $name (named argument declared in arguments: [issue, branch], $issue takes the first).

Multi-word values must be quoted (/migrate "SearchBar" JavaScript TypeScript). An indexed placeholder without an argument stays unchanged; a named one without a value becomes an empty string. An argument containing $1 or $ARGUMENTS is inserted literally without re-expansion. For a literal $, escape it: \$1.00.

Dynamic injection and file references

Two forms inject external content before sending to Claude. Inline line !`command`: recognized only if ! is at the start of a line or right after a space; the output replaces the placeholder and is not re-scanned. Multi-line block ```! for several commands. @file references attach a file to the context on invocation, useful to share a convention snippet between several skills.

Two variables are substituted in the body and in the Bash rules of allowed-tools: ${CLAUDE_SKILL_DIR} (the skill's folder) and ${CLAUDE_PROJECT_DIR} (project root, v2.1.196+). The classic trick is to write a script inside the skill folder and pre-approve its execution: allowed-tools: Bash(${CLAUDE_SKILL_DIR}/scripts/gen.sh *) then, in the body, call ${CLAUDE_SKILL_DIR}/scripts/gen.sh. If an injected command fails, the whole invocation is aborted — Claude sees nothing. An exit code 1 from the search commands listed in "Output limits" is treated as normal; append || true on other commands expected to exit non-zero.

Subagent, permissions and visibility

context: fork runs the skill inside an isolated subagent. The body becomes the prompt; the conversation history is not transmitted. Three reasons: long background task, reduced tool palette (agent: Explore in read-only), or large output to contain. The fork runs in the background by default; background: false (v2.1.218+) blocks the turn. A background fork writes outside of checkpoints: /rewind will not undo its edits, you have to go through git.

allowed-tools authorizes tools without confirmation during the invocation turn (grant cleared on the next message); disallowed-tools blocks; disable-model-invocation: true prevents Claude from loading the skill on its own (useful for anything with a side effect); user-invocable: false does the opposite (hidden from the menu, only Claude-side invocation works). The skillOverrides file applies visibility from the outside: "on", "name-only", "user-invocable-only", "off". The /skills menu writes it on its own.

Reloading and iterating

Claude Code watches skill directories and accounts for additions, edits and deletions without restarting, except in bare mode. /reload-skills forces a rescan. The best testing discipline remains A/B comparison; the official skill-creator plugin automates the loop and writes an evals.json in the skill's folder.

Descriptions have a budget

Claude Code loads the skill list on every turn with a budget of 1% of the model window. Beyond that, descriptions are trimmed starting with the least invoked. Placing the key sentence first, capping description + when_to_use at 1,536 characters, and pushing a secondary skill to "name-only" in skillOverrides keeps the list useful. /skill-doctor (v2.1.252+) shows the cost of each skill.

Running example: six skills for Kiosque

Six skills to write in Kiosque's .claude/skills/. None requires tooling beyond git, gh, pytest, ruff and make.

1. /commit — conventional message from the staged diff

---
description: Writes a conventional commit message from the staged changes and offers to commit. Use after `git add` or when the user asks to "commit".
argument-hint: "[scope]"
disable-model-invocation: true
allowed-tools: Bash(git diff --staged*) Bash(git status*) Bash(git commit *)
---

## Staged diff
!`git diff --staged`

## Status
!`git status --short`

## Instructions
Write a **conventional** message (`feat:`, `fix:`, `refactor:`, `test:`, `chore:`, `docs:`) in French, scope = $ARGUMENTS if provided, otherwise inferred from the file paths.

- Title: 72 characters max, present tense, imperative.
- Optional body: only if the "why" is not obvious.
- Refuse and flag if the diff contains `.env` or `secrets/`.

Then run `git commit -m "<message>"`.

2. /review-code [file] — read-only review

---
description: Reviews a file (or the current diff) looking for bugs, missing tests and convention violations. Read-only.
argument-hint: "[path]"
allowed-tools: Read Grep Glob Bash(git diff*)
disallowed-tools: Edit Write Bash(git commit*) Bash(git push*)
---

Target: $ARGUMENTS (if empty, take `git diff HEAD`).

## Reference diff
!`git diff HEAD -- $ARGUMENTS`

## Instructions
Review the code **read-only** — edit nothing. Look for:

1. **Bugs**: inverted condition, wrong type, off-by-one, missing error handling.
2. **Security**: SQL injection, cleartext secret, missing input validation.
3. **Kiosque conventions** (see `.claude/rules/api.md`): function names in English, comments in French, `raise HTTPException` rather than returning an error.
4. **Missing tests**: new branch not covered, error case not tested.

Return a report in four sections (Bugs / Security / Conventions / Tests), each item with file, line, sentence.

The command name is /review-code because /review is already a built-in (exact alias of /code-review since v2.1.223). Chaining works too: /review-code /commit paiements triggers a review then a commit.

3. /new-endpoint <resource> — route + schema + test

---
description: Generates a FastAPI CRUD endpoint (route + Pydantic schema + pytest test) for a new resource.
argument-hint: "<resource-singular>"
allowed-tools: Read Grep Glob Edit Write
---

Target resource: **$ARGUMENTS**.
@.claude/rules/api.md

Existing routes:
!`ls app/routes/`

## Instructions
Create: `app/schemas/$0.py` (Pydantic `Create`, `Read`, `Update`), `app/routes/$0.py` (`GET /$0s`, `GET /$0s/{id}`, `POST`, `PATCH`, `DELETE`; SQLAlchemy via `Depends(get_db)`), `tests/test_$0.py` (one happy-path test per endpoint, 404 on `GET /$0s/{id}`, 422 on `POST`). Register the router in `app/main.py` and run `pytest tests/test_$0.py`.

4. /targeted-tests — pytest on tests touched by the diff

---
description: Runs only the pytest tests that touch files in the current diff. Use before every commit for fast feedback.
allowed-tools: Bash(git diff*) Bash(pytest*)
---

## Modified files
!`git diff --name-only origin/main...HEAD`

## Instructions
Take the modified `tests/` files, add `tests/test_<module>.py` for every modified `app/<module>.py`, then run `pytest -x -q <files>`. If nothing is targeted, `pytest -x -q -k <keyword>` to cover indirect tests. Report failures (test, line, assertion). Do not re-run the whole suite — `make test` stays under the user's keyboard.

5. /api-doc — updates docs/api.md from the routes

---
description: Regenerates `docs/api.md` from the FastAPI routes under `app/routes/`. Use after any endpoint addition or change.
allowed-tools: Read Grep Glob Edit Write Bash(rg *)
paths: app/routes/**
---

Routes:
!`rg -n "@(?:router|app)\.(get|post|patch|put|delete)" app/routes/`

## Instructions
For each endpoint: method, path, tag, summary (docstring), input and output Pydantic schemas, status codes. Write `docs/api.md`: one table per tag `| Method | Path | Input | Output | Statuses |`, then one H3 section per endpoint with a French description (reuse the docstring when it exists). End with "Generated by `/api-doc` — do not edit by hand".

6. /release-notes <tag> — forked subagent

---
description: Writes markdown release notes for a Git tag from the commits since the previous tag. Runs in a separate subagent.
argument-hint: "<tag>"
context: fork
agent: Explore
background: true
allowed-tools: Bash(git log*) Bash(git tag*) Bash(git show*) Read Grep
---

Target tag: **$ARGUMENTS**.

Previous tag:
!`git describe --tags --abbrev=0 $ARGUMENTS^ 2>/dev/null || echo "(no earlier tag)"`

Log:
!`git log --pretty=format:"%h %s" $(git describe --tags --abbrev=0 $ARGUMENTS^ 2>/dev/null)..$ARGUMENTS`

## Instructions
Group into four sections: **New features**, **Fixes**, **Internal improvements**, **Documentation**. Ignore merge commits and `chore(deps)` commits. One sentence per item, clear for a non-technical user ("The payment module now accepts a second provider"), not the raw commit message. Return the markdown in the conversation; do not create a file.

Since v2.1.199, a single line chains two skills: /review-code /commit paiements loads both skills and passes paiements as the argument, useful when the review must not block anything.

Summary

  • A skill is a .claude/skills/<name>/SKILL.md folder: the folder name is the command, the frontmatter describes the skill, the body is the prompt.
  • Seven scopes, precedence enterprise > personal > project; a .claude/commands/<name>.md file still works but yields to a skill with the same name.
  • Arguments: $ARGUMENTS, $0/$1, $name (via arguments:). Shell injection: !`cmd` or ```! block. References: @file. Variables ${CLAUDE_SKILL_DIR} and ${CLAUDE_PROJECT_DIR} are substituted in the body and in allowed-tools.
  • context: fork runs the skill in an isolated subagent, in the background by default (background: false to block the turn).
  • allowed-tools pre-approves for the turn; disable-model-invocation prevents Claude from loading it on its own; user-invocable: false hides from the menu; skillOverrides applies visibility in settings.
  • /reload-skills forces a hot rescan; /skill-doctor (v2.1.252+) shows the cost of each skill.

Next module: Permissions, execution modes, sandbox and settings files — set the rules that let Claude work on its own without opening a hole.