Skip to content

AI CODING ASSISTANTS

Claude Code Custom Commands: 30 Files, One Dead Field

We read every custom command Anthropic ships. 30 files, 14 plugins, and one documented frontmatter field that none of them uses — plus one they use that isn't documented.

Claude code custom commands are markdown files: drop review.md into .claude/commands/ and /review exists. The interesting part is what to put in the frontmatter, so we read every command file Anthropic ships — 30 files across 14 plugins, 183,702 bytes — and checked them against the official reference. One documented field is used by none of them, and one field two of them set has no entry in the reference at all. This guide covers the file format, both argument styles, and what the shipped corpus says about length. Measured 2026-09-15 on Claude Code 2.1.270.

Key takeaways

  • A command is a markdown file; the filename is the command name, and the body is the prompt.
  • The reference documents five fields. In 30 shipped commands: description 30, argument-hint 19, allowed-tools 14.
  • model is documented across 66 lines and set by zero of the 30.
  • hide-from-slash-command-tool is set by two shipped commands and is not in the reference.
  • Shipped commands average 6,123 bytes — a procedure, not a one-liner.

What a custom command is

A custom command is a saved prompt with a name. When you type /review, Claude Code finds review.md, expands its body into the conversation, and the model responds to that text as though you had typed it.

That is the whole mechanism, and it explains what commands are good for. They do not add capability — the session could always have done the work. They remove the retyping, and more importantly they freeze the wording, so a procedure you refined once runs the same way next month.

It also marks the boundary with the neighbouring surface. A skill carries a description the model reads in order to decide whether to invoke it on its own. A command waits to be named. If you want something to happen when you ask for it, write a command; if you want it to happen because the situation arose, you are looking at a different tool.

Where the file goes

Two locations, and the only difference is scope:

Command file locations
.claude/commands/            ← this project only, commit it
  review.md                  ← becomes /review
  deploy-check.md            ← becomes /deploy-check
~/.claude/commands/          ← every project on this machine
  standup.md                 ← becomes /standup

The filename is authoritative — there is no name field, and renaming the file renames the command. Plugins are the third source: an installed plugin's commands/ directory contributes its commands too, which is where all 30 files in this census come from.

The five documented fields

Anthropic's own authoring reference ships inside the plugin-dev plugin, at skills/command-development/references/frontmatter-reference.md, and runs to 463 lines. It documents exactly five fields:

.claude/commands/review.md
---
description: Review the working tree for correctness bugs
argument-hint: "[path]"
allowed-tools: Read, Grep, Glob
model: sonnet
disable-model-invocation: false
---

Review the changes in $1 for correctness bugs only...
  • description — what the command does. It is what the reader sees in the picker.
  • allowed-tools — restricts the command's run to a named tool set.
  • model — pins the command to a specific model.
  • argument-hint — the placeholder text shown after the command name.
  • disable-model-invocation — prevents the model invoking the command itself.

What 30 shipped commands actually set

That is the documentation. Here is the corpus: every .md file under a commands/ directory in the official plugin marketplace, as cached on this machine.

FieldDocumentedFiles (of 30)
descriptionYes30
argument-hintYes19
allowed-toolsYes14
disable-model-invocationYes2
hide-from-slash-command-toolNo2
modelYes0

description is the only field with unanimous adoption, which is the practical rule: treat it as required even though the loader does not. Past that, adoption falls off fast — allowed-tools is on fewer than half, and the two remaining documented fields are close to unused.

The two fields the reference gets wrong

Two rows above are worth separating out, because they point in opposite directions.

model is documented and dead. It gets a full section in the reference — type, whether it is required, worked examples, 66 lines of specification — and not one of the 30 commands Anthropic ships sets it. That is not proof the field is broken; it is evidence about what experienced command authors actually reach for. Pinning a model inside a command means the command stops inheriting the session's model, which is usually the wrong default: the person invoking it picked their model for a reason.

hide-from-slash-command-tool is used and undocumented. Two shipped commands set it. The string does not appear anywhere in the 463-line reference. The name is self-describing — keep this command out of the tool the model uses to invoke commands — and it is the natural companion to disable-model-invocation, which is documented and also appears twice.

Arguments, and which style wins

Two substitution styles exist and the corpus splits almost evenly between them — $ARGUMENTS in 11 files, positional $1/$2 in 12.

.claude/commands/fix-issue.md
---
description: Fix a GitHub issue end to end
argument-hint: "[issue-number] [branch]"
---

Fix issue #$1 and open the PR against $2.
Read the issue first with `gh issue view $1`.

The choice is structural, not stylistic:

  • $ARGUMENTS takes everything after the command name as one string. Right when the input is free text — a description, a question, a path list.
  • $1, $2 take fixed slots. Right when the command has a real signature, and argument-hint exists to advertise it.

Two other body syntaxes appear, each in two files: a ! prefix that runs a shell command and interpolates its output, and @ to pull a file into the prompt. Both are minority usage, and both replace a step the session would otherwise spend a turn on.

How long a command should be

The shipped commands average 6,123 bytes. That is not a one-line instruction — it is a procedure, with steps, constraints, and usually a specified output format.

This is the most useful signal in the corpus. The instinct with a new command is to write "review my code for bugs", which saves four seconds and changes nothing about the result. The commands worth keeping are the ones carrying the context you would otherwise retype every time: which files to look at, which failure modes matter here, what to do when the answer is ambiguous, what the output should look like.

Put differently — a command earns its place when it encodes a decision, not a request. That is the same economics as a CLAUDE.md section, with one difference in your favour: a command's body costs nothing until it is invoked, where CLAUDE.md is paid on every single turn.

The /verify command is the useful boundary case: Anthropic ships a bundled version, but a project .claude/skills/verify/SKILL.md can replace it with the exact launch and observation recipe your application needs.

Writing one worth keeping

.claude/commands/preflight.md
---
description: Run the publish gate before shipping an article
allowed-tools: Bash, Read, Grep
argument-hint: "[slug]"
---

Run the publish gate for $1 and stop at the first red result.

1. `npm run typecheck`, then `npm run lint`.
2. `npm run check:anchors` — every toc href must match a generated heading id.
3. Confirm `cover` and `coverAlt` are set in the frontmatter of $1.
4. Report each step as pass or fail with the command's own output.

Do not fix anything. Report only.

Four things make that worth saving rather than typing. It names the commands, so the run is identical every time. It sets allowed-tools, so the command cannot wander. It uses $1 with a matching argument-hint, so the signature is visible at the prompt. And the last line removes an ambiguity — report, don't fix — that would otherwise be resolved differently on different days.

What did not work

The first census counted 34 files and every figure was wrong. The glob was -path "*commands*", which matches by substring, so it swept in the commit-commands/ plugin directory, the command-development/ skill directory, and a README.md. Anchoring it to */commands/* gives 30. Two files in the bad set had no description, which would have shipped as "description is on 32 of 34 commands" — a real-looking finding about optional frontmatter that was entirely an artifact of counting a README as a command.

No command was invoked. Every nested claude -p invocation on this machine is refused by its auto-mode classifier, so this is a census of what 30 authored commands declare, not a measurement of what the loader does with them. The field counts are solid; any claim about runtime behaviour would not be.

The corpus is Anthropic's, not the world's. 30 files from 14 first-party plugins is a strong signal about house style and a weak one about what every team does. The model result in particular says these authors don't pin models — not that pinning is wrong.

Best practices

  • Always set description. All 30 shipped commands do, and it is what makes the command findable by the person who did not write it.
  • Set argument-hint whenever you use $1. The signature is invisible otherwise, and 19 of 30 shipped commands set one.
  • Reach for allowed-tools on anything read-only. A review command that cannot write is a different risk profile from one that can.
  • Leave model alone unless the command genuinely requires a specific one. Anthropic's own commands never set it.
  • Put the procedure in the body, not the request. The average shipped command is 6 KB because that is where the value lives.
  • Commit project commands. A command in .claude/commands/ that is gitignored helps exactly one machine.

Common mistakes

Adding a name field. There isn't one. The filename is the command name; rename the file.

Writing a command that restates your prompt. If the body is one sentence you would have typed anyway, it adds a step and no information.

Pinning a model out of habit. It overrides the choice the person invoking it already made, and none of the 30 shipped commands does it.

Expecting a command to fire on its own. That is a skill's job. A command waits to be named.

Trusting a *commands* glob. It matched three non-command directories here and produced a wrong count that looked entirely plausible.

Conclusion

Write the command as a markdown file, name it for what it does, always set description, add argument-hint when it takes slots, and put the whole procedure in the body — that is what the 30 commands Anthropic ships actually look like. Skip model; none of them uses it. The number to carry is 6,123 bytes: a command that is worth having is one you would otherwise have retyped, and those are never one line long. Start with the procedure you already run by hand most often, and save it before you refine it.

Frequently asked questions

How do I create a custom slash command in Claude Code?
Write a markdown file in .claude/commands/ for one project or ~/.claude/commands/ for every project. The filename becomes the command name, so review.md becomes /review. Frontmatter is optional but description is effectively required — all 30 commands Anthropic ships set it. The body is the prompt the command expands to.
What frontmatter fields does a Claude Code command file support?
The official reference documents five: description, allowed-tools, model, argument-hint and disable-model-invocation. Measured across the 30 command files in Anthropic's own plugin marketplace, description appears in all 30, argument-hint in 19 and allowed-tools in 14. The model field appears in none of them.
How do I pass arguments to a custom command?
Two styles exist. $ARGUMENTS interpolates everything the user typed after the command name as one string, and $1, $2 take positional arguments. In the 30 shipped commands the split is close — $ARGUMENTS in 11 files and positional arguments in 12 — so pick by whether the command takes one free-text blob or a fixed set of slots.
What is the difference between a custom command and a skill?
A command is invoked by name and expands to a prompt you wrote. A skill carries a description the model reads to decide whether to invoke it unprompted. Commands are for work you will ask for explicitly; skills are for work that should fire when the situation matches. Our skills-versus-hooks measurement found the model invoked a skill 0 of 5 times as a standing rule.
Should a custom command be short?
The shipped ones are not. The 30 commands in Anthropic's marketplace average 6,123 bytes, which is a full procedure rather than a one-line instruction. A command that only restates your request adds a step without adding information — the value is in the steps, constraints and output format you would otherwise retype.

Muhammad Kashif

Founder and editor of Devventa, covering AI coding assistants, Next.js and the modern AI development stack.