How to create a custom slash command in Claude Code
A custom slash command is a saved prompt you run by typing /name. In current Claude Code they are called skills, and you make one with a single markdown file. Every example below was run in Claude Code 2.1.278 in September 2026, and the results are shown.
The short version: create .claude/skills/greet/SKILL.md. The folder name, greet, is the command. Everything after the frontmatter is the prompt Claude receives when you type /greet.
Your first command
Save this as .claude/skills/greet/SKILL.md in your project:
--- description: Greets a person by name. Use when the user types /greet. disable-model-invocation: true --- Reply with exactly this and nothing else: HELLO $ARGUMENTS
Then type this in Claude Code:
/greet Ada Lovelace
Claude replied HELLO Ada Lovelace. $ARGUMENTS is replaced with whatever follows the command name. The file must start with --- on its very first line, or Claude Code treats the frontmatter as part of the prompt.
disable-model-invocation: true means only you can run the command. Without it, Claude may also decide to load the skill on its own when your request matches its description. Use it for anything with side effects, such as committing or deploying.
Pass several arguments by position
Use $0, $1, $2 (the documentation also allows $ARGUMENTS[0]) for individual words:
--- description: Prints a migration plan line. Use when the user types /migrate. disable-model-invocation: true --- Reply with exactly this and nothing else: MOVING $0 FROM $1 TO $2
We ran /migrate SearchBar JavaScript TypeScript and got MOVING SearchBar FROM JavaScript TO TypeScript.
What if you forget the placeholder?
The documentation says Claude Code appends your input to the end of the skill as ARGUMENTS: <your input> so Claude still sees it. We tested that with a skill that had no placeholder and asked Claude to repeat the text after ARGUMENTS:. With /plain sandwich-42 it answered sandwich-42. With no argument at all it answered NONE. So your words are not lost, but the prompt reads better when you place them yourself.
Put live data in the prompt
A line like !`git diff HEAD` runs the command before the prompt is sent and replaces the line with its output, so Claude works from real data rather than guessing:
--- description: Reviews the uncommitted changes. Use when the user asks for a review of their diff. --- ## Changes to review !`git diff HEAD` ## Instructions Review the changes above as a strict reviewer. Rank findings most serious first.
We used this to build a /review-diff command and it reviewed the real uncommitted diff. It is part of the Safe setup pack.
Where to save it
| Where | Available in |
|---|---|
.claude/skills/<name>/SKILL.md | This project. Commit it and your team gets it too. |
~/.claude/skills/<name>/SKILL.md | All your projects |
.claude/commands/<name>.md | This project, in the older single-file format |
The older .claude/commands/ files still work. We saved .claude/commands/oldstyle.md containing LEGACY OK $ARGUMENTS, ran /oldstyle 42, and got LEGACY OK 42. For new commands, use a skill folder, which can also hold supporting files.
The naming detail
The documentation says that in a project or personal skill, the folder name is the command, and the frontmatter name field is only a display label. We made .claude/skills/dir-name/SKILL.md with name: other-label in its frontmatter. Typing /dir-name ran it, as documented. Typing /other-label also ran it, which the documentation does not promise. For comparison, a command that does not exist in that project was reported as unavailable. The safe habit is to name the folder what you want to type, and treat the name field as a label.
Frontmatter you will actually use
description: what the skill does and when to use it. Claude reads this to decide whether to load it. Put the main use first.disable-model-invocation: true: only you can run it.argument-hint: text shown while you type, such as[issue-number].allowed-tools: tools Claude may use without asking, only during the turn that runs this skill. Keep it narrow.
Keep it short and specific
A skill is a prompt, so the same rules apply as for CLAUDE.md: concrete steps beat vague goals, and a multi-step procedure belongs in a skill while facts Claude should always know belong in CLAUDE.md. A good first command is one you already type by hand every day, such as "fix issue 123 following our conventions", turned into /fix-issue 123.