2.4 · Slash Commands and Skills

2.4 · 30 min

Slash Commands and Skills

Somewhere on your machine there is a prompt you have typed, with small variations, thirty times. Review this diff. Write a commit message our way. Check the migration against the checklist. Every retype is a chance to forget a step, and every variation trains the model slightly differently. The thirtieth time you type a procedure is an engineering failure with a name: you built a process and stored it in your fingers. Claude Code's fix is the skill, and this lesson covers its anatomy, its triggering, and the packaging decision that 2.2 left dangling: when does something stop being a CLAUDE.md rule and become a skill?

One system, two doors

First, a naming cleanup the docs made recently, because most tutorials predate it: custom slash 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 work the same way. The old command files keep working and take the same frontmatter; skills are the recommended form because a skill is a directory, so it can carry supporting files (templates, scripts, reference docs) alongside its instructions. This course says "skill" for both from here on. Note the built-in commands (/clear, /model, /permissions) are a separate species: fixed logic shipped with the tool, listed in the commands reference. You also get bundled skills out of the box (/code-review, /debug, /loop among them); they are prompt-based like yours, and a skill you define with the same name overrides them.

A skill is a SKILL.md file with YAML frontmatter and markdown instructions:

.claude/skills/review/
├── SKILL.md          # required: frontmatter + instructions
├── checklist.md      # optional supporting files
└── scripts/

Where it lives sets its scope: ~/.claude/skills/ for all your projects, .claude/skills/ for this repo (committed, shared with the team), plugins for distribution. The directory name becomes the command name.

The load mechanics are the entire reason skills exist, so get them exact. Descriptions are always in context; bodies load only when invoked. Claude sees a listing of every skill's name and description, cheap enough to carry permanently. The full instructions enter context only when you type /name or Claude decides the description matches your request. This is the economics 2.2 promised: a 300-line procedure in CLAUDE.md taxes every session forever; the same procedure as a skill costs a one-line description until the day it is used. Once invoked, the body stays in context for the rest of the session, so the conciseness discipline from CLAUDE.md applies to skill bodies too.

Anatomy of a real one

Here is the /review skill this lesson's lab builds, complete and runnable:

.claude/skills/review/SKILL.mdmarkdown
---
description: Review the current uncommitted diff for correctness and
convention violations. Use when asked to review changes, check a diff,
or pre-review before a commit.
disable-model-invocation: true
allowed-tools: Bash(git diff *) Bash(git status *) Read Grep Glob
---

## Current diff

!`git diff HEAD`

## Instructions

Review the diff above against this checklist, in order:

1. Correctness: logic errors, unhandled edge cases, off-by-one risks.
2. Lies: tests weakened or deleted, mocked behavior presented as real,
 hardcoded values where computation belongs.
3. Conventions: violations of CLAUDE.md rules (strict TS, JSDoc on
 exports, no barrel files).
4. Scope: changes unrelated to the stated task.

Report findings by severity (critical, warning, nit), each with
file:line and a one-line fix. If the diff is clean, say so and list
what you checked. Do not propose refactors beyond the diff.

Arguments, if given, name the specific concern to prioritize: $ARGUMENTS

Read it top to bottom, because each piece is a mechanism. The description is what Claude matches against when deciding to auto-load; put trigger phrases in it, up front, since combined description text is truncated at 1,536 characters in the listing. disable-model-invocation: true makes this a you-only tool: it never auto-fires, and its description is not even kept in context; it loads purely when you type /review. The inverse field exists too: user-invocable: false hides a skill from the / menu for background knowledge only Claude invokes. allowed-tools pre-approves the listed tools while the skill is active, so the review never stalls on a permission prompt for git diff; note this grants, it does not restrict. The !`git diff HEAD` line is dynamic context injection: Claude Code runs the command and splices its output into the skill content before the model sees it, so the review is grounded in your actual working tree, not what Claude remembers reading. And $ARGUMENTS receives whatever you type after /review; $0, $1 grab positional pieces when you need them separately.

Auto-triggering is the other door. Drop disable-model-invocation, and the description becomes a standing offer: any request that matches it pulls the skill in without a slash. That is what "self-triggering" means, and it turns skills into on-demand knowledge, not just commands. Two more frontmatter fields earn their keep early: context: fork runs the skill in a subagent context so its noise stays out of your window (next lesson explains why that matters), and model/effort let a skill run on a cheaper model or deeper reasoning than the session default.

The packaging decision

You now have three homes for institutional knowledge, and the docs' own heuristic for the boundary is the one to keep: create a skill when you keep pasting the same instructions, or when a section of CLAUDE.md has grown into a procedure rather than a fact.

  • CLAUDE.md rule: facts and constraints that must hold in every session. "Tests live next to source." Always loaded, so it pays rent on every token, every session.
  • Skill, model-invocable: knowledge or procedure needed in some sessions, where Claude should recognize the moment. "How we write migrations." Costs a description until relevant.
  • Skill, user-invoked only: procedures with side effects or timing you want to own: /review, /deploy, /commit. The docs' example is exact: you do not want Claude deciding to deploy because your code looks ready.

The test compresses to two questions. Is it a fact or a procedure? Facts go in CLAUDE.md, procedures in skills. Who should decide it runs? You: disable model invocation. Claude: write a description worth matching.

There is a real ecosystem to draw from before writing your own. Anthropic's official repo, anthropics/skills, carries the document skills that power Claude's file features plus dozens of examples, installable directly: /plugin marketplace add anthropics/skills, then install example-skills or document-skills. Skills follow an open standard (agentskills.io) shared across tools. Treat third-party skills as code you are importing, because that is what they are: read the SKILL.md, especially its allowed-tools, before trusting it. Project skills' tool grants activate only after you accept the workspace trust dialog, which exists precisely because a checked-in skill can grant itself broad access.

Where it breaks

Triggering is the fragile part, in both directions. A skill that never fires almost always has a description problem: it describes what the skill is ("PR review helper") instead of when to use it ("use when asked to review changes, check a diff, or pre-review a commit"). The docs' debugging path: ask Claude "what skills are available?", confirm yours is listed, then rephrase your request toward the description, and if you have many skills, run /doctor, because with a large collection the listing budget can shorten descriptions and strip exactly the keywords you were matching on. The reverse failure, a skill firing too eagerly, gets fixed by narrowing the description or flipping to disable-model-invocation: true.

The subtler failure is the fossil skill: a procedure that changed in reality but not in .claude/skills/, so Claude now executes the old process with full confidence, grounded by nothing. Skills are code. Version them, review them, and when a lab or runbook changes, grep for the skill that encodes it.

Lablab-2-4A /review command and a self-triggering skill

Goal: Package two procedures for the practice repo: a user-invoked review command and a knowledge skill Claude pulls in on its own, then prove both trigger paths.

Prereqs: the agentic-practice repo with CLAUDE.md from Lab 2.2.

  1. Create .claude/skills/review/SKILL.md with the artifact above, adjusting checklist item 3 to your actual CLAUDE.md rules.
  2. Make a small deliberately flawed change in the repo: add a helper that mutates its input array and skips a JSDoc, with a stray console.log. Do not commit.
  3. Run /review. It should pull the live diff via the injection line and flag your planted issues. Then run /review focus on conventions and confirm the argument shows up in its behavior.
  4. Create the self-triggering skill: .claude/skills/error-messages/SKILL.md with description "How CLI error messages are written in this project. Use when writing or changing error handling, validation, or user-facing failure output." Body: a five-line convention (prefix errors with the tool name, state what failed and what to do, no stack traces to users, exit codes 1 for user error and 2 for internal).
  5. In a fresh session, without naming the skill, dispatch: "Add validation to the duration parser: reject negative values with a clear error." Watch whether the skill loads (Claude Code shows skill invocations) and whether the output follows your conventions.
  6. Fail it on purpose: rewrite the error-messages description to just "Error message conventions", start a fresh session, repeat step 5, and note the difference in triggering. Restore the good description after.

Verify

  • /review catches all three planted issues with file:line references, without any permission prompt for the git commands.
  • The skill listing (ask "what skills are available?") shows both skills.
  • In step 5, the error-messages skill visibly loaded and the emitted error follows your five-line convention.
  • In step 6, the vague description triggered unreliably or not at all (run it twice if the first draw succeeds; triggering is probabilistic).
>Troubleshooting
  • /review shows no diff: the injection runs git diff HEAD, which is empty if you committed your flawed change. Make a new uncommitted edit or change the injection to git diff HEAD~1.
  • The skill never appears in listings: check the file is literally named SKILL.md inside a directory under .claude/skills/, and that the YAML frontmatter parses (malformed YAML loads the body with empty metadata, which kills auto-triggering but leaves /name working).
  • Step 5 loads the skill but ignores the conventions: your body may be phrased as background rather than instructions. "Prefix every error with..." holds better than "errors are usually prefixed with...". Imperatives, not descriptions.

Knowledge check

Knowledge check

Q1A 60-line release procedure lives in your CLAUDE.md and is used roughly once a week. What is the right move, and the mechanical reason?
Q2Your migration-checklist skill never auto-triggers even though teammates ask Claude for migration help daily. Its description reads: A comprehensive database migration quality assurance skill. What is the most likely fix?
Q3Mid-session, you edit a skill's SKILL.md to fix a wrong step, but Claude, which invoked the skill an hour ago, keeps following the old step. Why?
Q4You are evaluating a third-party skill before adding it to your team's repo. Which single check does the lesson treat as non-negotiable?

Sources