"Slash commands go unused" rests on two frictions that are gone
Most of a hand-built slash-command library goes unused - but the two reasons the best-known writeup gives, no argument passing and no way to inject git context, are both fixed now, so check the reasons before inheriting the conclusion.
This advice is common and does not hold. The official page saying otherwise is linked below.
What this costs you if it is wrong
Read as a blanket "don't build commands" this costs you the cases that clearly pay off — team-wide conventions checked into a repo, and workflows that need live state injected via `` !`command` ``. The specific frictions the source names were fixed after it was written, so its conclusion rests on premises that no longer hold. Separately, the audit command reads your saved transcript files: it only counts locally and sends nothing anywhere, but the same directory holds full conversation history, so do not paste its surrounding files into a shared channel.
You have a .claude/skills/ directory with eight or ten entries in it — commit-message, lint-fix, write-tests, fix-bug, todo-sweep — and you cannot remember the last time you typed any of them except one. The library felt like leverage while you were building it. In daily use you keep typing the request out longhand instead.
Armin Ronacher wrote up exactly this outcome in July 2025: he built commands for grammar fixing, bug fixing, commit messages, test generation, linting and todo tracking, and reports that most went unused. His conclusion was that mentioning a GitHub issue URL in the prompt did the same job with no file to maintain.
The observation is worth having. His two stated reasons are no longer true, and that matters, because if you inherit the conclusion without checking the reasons you will skip commands that would now work.
What the docs say about his reasons
| His friction | Status today | Where |
|---|---|---|
| No unstructured argument passing | Gone. $ARGUMENTS expands to whatever follows the command name; $0, $1, $ARGUMENTS[N] index individual ones | skills — Pass arguments to skills |
| Arguments silently dropped if the file has no placeholder | Handled. Claude Code appends ARGUMENTS: <your input> to the skill content so Claude still sees what you typed | skills |
Ends up piping git status in by hand | Unnecessary. A !`git status --short` line runs before the content reaches Claude and is replaced by its output | skills — Inject dynamic context |
| No file autocomplete inside the command | Partly stale. @ references inside a local skill attach the files they name; argument-hint frontmatter shows expected arguments during / autocomplete | skills |
The docs are not neutral on the wider point either. The best-practices page ships a fix-issue skill as a worked example — the same command he says he stopped using — and the official recommendation is to write skills for repeatable workflows.
What survives
Strip out the mechanics and one durable claim is left, and it is not about Claude Code's features at all:
A command is only worth its upkeep once you have typed the prompt verbatim several times.
That is a real cost model. Every command file is a thing that drifts from your actual workflow, that a teammate has to discover, and that you must remember exists at the moment you need it. The last item is the quiet killer — an unremembered command is worse than no command, because you paid for it and got nothing.
So the rule to copy is sequencing, not abstinence:
- Write the prompt inline. Every time.
- When you notice you have typed roughly the same thing three or four times, look at what varied between them.
- If what varied is one value — an issue number, a filename, a component name — that is a
$ARGUMENTSslot, and the command is worth writing. - If what varied is the shape of the request, leave it inline. You will only end up editing the command every time you use it.
Where a command still clearly pays
- Team conventions. One checked-in
SKILL.mdwith your API rules or commit format beats every person on the team retyping it slightly differently. This is the case Ronacher's post does not cover, and it is the strongest one. - Anything with a fixed preamble of live state.
!`gh pr diff`,!`git status --short`,!`node --version`— inlining these by hand is exactly the friction he complained about, and it is the friction the!syntax removes. - Anything with pre-approved tools.
allowed-toolsin frontmatter grants the tools for that turn, so a commit command does not stop to ask aboutgit addandgit commit.
What is unverified here
Nobody has reproduced the underlying claim, and it is not the kind of claim that reproduces. "Most of my commands went unused" is one experienced engineer's report of his own habits over some months in mid-2025, on a version of the tool whose argument handling has since changed. It is not a measurement, it does not generalize by construction, and the docs neither confirm nor deny it — they are silent on which commands are worth building and say nothing about adoption rates.
What the docs do settle is that the reasons he gave are stale. That is the part to trust.
What would settle the rest is your own transcript history rather than anyone's blog post. Count how often you actually invoke each command you own, and delete the ones at zero:
# approximate: counts leading /command tokens in your saved transcripts
grep -rhoE '"text":"/[a-z0-9_-]+' ~/.claude/projects/*/*.jsonl \
| sed 's/.*\///' | sort | uniq -c | sort -rn | head -30Run that with bash -c, not pasted into zsh — the glob aborts the whole line if a directory has no matching files. The counts are rough: they catch commands you typed at the start of a message and miss ones Claude auto-invoked. Compare the output against ls ~/.claude/skills ~/.claude/commands .claude/skills .claude/commands and the gap is your answer, for your workflow, which is the only one the question was ever about.
Checkpoint
- Which of your commands did you last invoke more than a week ago, and would you notice if it were deleted?
Show answerAnswer
Only your own transcripts can answer this, so count rather than recall. Run the
grepover your saved.jsonltranscripts withbash -c— pasted into zsh the glob aborts the whole line when a directory holds no matching files — and compare its output against what actually sits in~/.claude/skills,~/.claude/commands,.claude/skillsand.claude/commands. The gap between what you own and what you invoke is the answer. The counts are rough: they catch commands you typed at the start of a message and miss ones Claude auto-invoked. Delete the ones at zero, because an unremembered command is worse than no command — you paid for it and got nothing. - For a command you kept: what varies between invocations — one value, or the whole shape of the request?
Show answerAnswer
If one value varies — an issue number, a filename, a component name — that is a
$ARGUMENTSslot and the command earns its upkeep;$ARGUMENTSexpands to whatever follows the command name, and$0,$1and$ARGUMENTS[N]index individual ones. If the shape of the request varies, leave it inline: you will only end up editing the command every time you use it. What you must not do is retire a command on the "no argument passing" reasoning from the 2025 post — the skills docs settle that this friction is gone, along with the silent drop, since Claude Code now appendsARGUMENTS: <your input>when the file has no placeholder. - Does any skill in your project repo carry an
allowed-toolsgrant you did not write?Show answerAnswer
Open the frontmatter and look — this is a fact about your repo, not something an answer key can supply for you. It is worth the minute because
allowed-toolsis a real permission grant and workspace trust does not gate it: a project skill checked into a repository applies its grant when invoked, including in a-prun in a folder you have never trusted. Check the!`command`lines in the same pass, since those execute on your machine before Claude sees the file, and check both locations —.claude/commands/deploy.mdand.claude/skills/deploy/SKILL.mdeach produce/deploy.