ls ~/.claude/commands/*.md | wc -l returns 42. Every one of those files is markdown with a slash in front of its name. I wrote every one of them, one repeated instruction at a time, and a few of them I’d forgotten existed until I ran that count to write this post.
That’s the honest state of a Claude Code command setup after real use: not a tidy library, a pile with a handful of load-bearing pieces and a long tail nobody touches. Here’s what a command actually is, the rule I use before writing a new one, and which of mine earned the space they take up.
What a command actually is
Strip the ceremony and a command is one file. Open ~/.claude/commands/retro.md, one of the 42, and the whole configuration at the top is three lines:
---
description: Reflect on project learnings - 2 pain points and 1 win with concrete lessons
---No name: field, no allowed-tools: list, no version number. A description, then markdown. The filename does the rest: retro.md becomes /retro. That one-line description is also what Claude reads to decide, on its own, whether this file is the right match for whatever you just asked, the same way it weighs it against the other 41.
The bodies vary a lot. think.md runs 114 lines. task.md runs 608. Length isn’t a signal of quality here. It’s how much judgment the job needs written down.
When a repeated instruction earns a file
| Signal | Write the command | Leave it as a prompt |
|---|---|---|
| You’ve typed the same multi-step instruction more than once | Yes | |
| It’s a single ask, done once | Yes, just type it | |
| Getting a step wrong or out of order costs something real: a bad deploy, a skipped check | Yes | |
| You’d only ever open the file to remember what it says | Yes, it isn’t earning its keep |
That last row is the one I skip past too easily. A command that exists but never gets invoked isn’t neutral. It’s a file that has to be found, read, and kept current, for zero benefit over just typing the thing.
Named by a dispatched subagent, last 30 days
Of the 42 files in ~/.claude/commands/, only task, think, brainstorm, sop, and triage show up by name when I run ~/.claude/scripts/agent-skill-report.sh. The other 37 never appear in that window, because the script only sees commands Claude reaches for inside a subagent it dispatches through the Task tool.
That undercounts real use badly, and the same script says so. Its main-session column shows 46.8% of 267 sessions in the same 30 days called at least one command directly, which is how most of these 42 actually get used: typed by me, not discovered by an agent working on its own.
Where a command stops being enough
A command asks. Claude reads /retro’s steps and decides how to follow them. It can skip a step, reorder one, or decide the file doesn’t apply this turn.
A hook forces. A PreToolUse or Stop hook is a script the harness runs whether Claude agrees or not, and its exit code can block the action outright.
A command raises the odds Claude does the thing correctly. It doesn’t guarantee it, the same gap that let real CLAUDE.md rules ship straight past a tight command setup until a hard gate caught what they missed. A command file sitting in the folder is not proof it’s being followed, the same trap as trusting a doc you never verified against the running system.
None of this is the skill-or-script call either. That’s a different axis with its own rule: automate judgment with a command, automate a fixed sequence with a script, gate the result with enforcement.
A real one, with the full file behind it
Here’s ~/.claude/commands/retro.md, all 137 lines of it. The opening shows how a command starts; the rest, the output format and the rules that keep the answers specific, is free for members:
---
description: Reflect on project learnings - 2 pain points and 1 win with concrete lessons
---
# /retro
Surface the top 3 learnings from this project or session. Two things that hurt, one thing that went well. Each with a specific lesson.130 more linesretro.mdGet free access
Receipt The opening of my 137-line retro.md, one of the 42 commands I actually use.
Save that in ~/.claude/commands/ under any filename, and it’s a working command. No build step, no registration process. Just a file in a folder and a description that tells Claude when to reach for it.
Members get the full retro.md (all 137 lines) and the longer posts. Get free access
The rule
Write a command when you’ve repeated the same multi-step instruction more than once, and getting a step wrong would cost something real. Keep the frontmatter to a single description: line unless you genuinely need more. Don’t expect it to hold under pressure the way a hook does, and don’t confuse “should this be a file” with “should this be a skill or a script,” that’s a separate call.
Forty-two files, five of them visible to a script that watches what gets dispatched, all of them cheaper to write than to keep forever. Write the ones that earn it. Delete the ones that don’t, once you’re honest about which is which.
Related:
- Claude Code Skills vs Scripts: When to Use Each: the decision rule for what a command should do once you’ve decided to write one.
- Claude Code Hooks: Make the Agent’s Behavior Deterministic: the layer that forces instead of asks.
- Why Claude Code Ignores Your CLAUDE.md (and the Fix): what happens when guidance, including a command, meets a task that pulls the other way.
Sources
- Claude Code docs, Extend Claude with skills: how a description in frontmatter is matched against intent, and when a skill’s body loads
- Claude Code docs, Hooks: the enforcement layer a command cannot provide on its own