What are custom commands in Claude Code?
Custom commands are your own slash commands: a Markdown file whose name becomes a command such as /changelog, and whose text becomes the prompt Claude follows. In current Claude Code they are part of skills. The skills docs say it directly: "Custom commands have been merged into skills."
So there are now two formats that do the same job:
- Command file (older):
.claude/commands/changelog.md - Skill (current):
.claude/skills/changelog/SKILL.md
Both create /changelog and both work. This guide explains how the two compare, when to move a command to a skill, and how to fix a command that won't show up. For the built-in commands and a first walkthrough, see the slash commands guide.
Commands vs skills: what is the difference?
A command file is a single Markdown file. A skill is a folder with SKILL.md inside and room for other files. According to the docs, command files support the same frontmatter as skills except two fields, name and paths.
| Command file | Skill | |
|---|---|---|
| Path | .claude/commands/<name>.md |
.claude/skills/<name>/SKILL.md |
| Command name from | File name | Folder name or name field |
| Supporting files (scripts, templates) | No | Yes, in the same folder |
paths (load only for matching files) |
No | Yes |
| Arguments and frontmatter | Yes | Yes |
| Same name as the other format | Loses | Wins |
| Status in the docs | "the older format and still works" | "Prefer a skill for new work" |
Two things stand out. First, nothing forces you to migrate: old command files keep working. Second, the folder is the real upgrade. A skill can ship a script, a template or a reference file next to its instructions, and use ${CLAUDE_SKILL_DIR} to point at them wherever the skill is installed.
Where do custom commands live, and what are they called?
Where you save the file decides who gets the command. These come from the official skills docs:
| Location | Command you type | Who gets it |
|---|---|---|
.claude/commands/changelog.md |
/changelog |
Everyone in this repo |
.claude/commands/release/notes.md |
/release:notes |
Everyone in this repo |
.claude/skills/changelog/SKILL.md |
/changelog |
Everyone in this repo |
~/.claude/skills/changelog/SKILL.md |
/changelog |
You, in every project on this machine |
A plugin's skills/notes/SKILL.md |
/my-plugin:notes |
Wherever the plugin is enabled |
Subfolders in .claude/commands/ turn into a colon namespace: each / in the path becomes :. That is how release/notes.md becomes /release:notes.
When two sources use the same name, the docs settle it this way:
- A skill beats a command file with the same name.
- Enterprise beats personal, and personal beats project.
- In a local terminal session, your skill replaces a built-in command of the same name, but not its aliases.
- Plugin skills never clash, because they carry the plugin prefix.
How do you migrate a .claude/commands file to a skill?
Migration is mostly moving a file. Say you have this command at .claude/commands/changelog.md:
---
description: Draft a changelog entry from commits since the last tag
argument-hint: "[version]"
disable-model-invocation: true
allowed-tools: Bash(git log *) Bash(git describe *)
---
## Commits since the last tag
!`git log $(git describe --tags --abbrev=0)..HEAD --oneline`
Write a changelog entry for version $ARGUMENTS. Group the commits
under Added, Changed and Fixed. Skip merge commits and chores.
To turn it into a skill:
- Create the folder:
mkdir -p .claude/skills/changelog - Move the file:
git mv .claude/commands/changelog.md .claude/skills/changelog/SKILL.md - Keep the frontmatter as it is. Every field above works the same in a skill.
- Optionally add
name: changelogand any supporting files, such as atemplate.mdthe instructions refer to. - Run
/changelog 2.4.0to check it.
The skills docs name a skill after its folder or its name field, with no colon namespace like subfolders in .claude/commands/ get, so a namespaced command needs a new name. The docs don't prescribe one. Kipt's suggestion is a hyphenated folder name, so .claude/commands/release/notes.md becomes .claude/skills/release-notes/SKILL.md, and the command changes from /release:notes to /release-notes. Tell your team, since the old name stops working once the file is gone.
If you also want the skill to work in other tools that read the Agent Skills format, use lowercase letters, digits and hyphens for the name and keep it matching the folder. For claude.ai uploads, the docs list only six allowed frontmatter fields: name, description, license, compatibility, metadata and allowed-tools. A Claude Code only field such as argument-hint makes that upload fail.
How do arguments work in custom commands?
Arguments work the same in both formats. Whatever you type after the command name is passed in, and placeholders in the body receive it:
| Placeholder | Receives |
|---|---|
$ARGUMENTS |
Everything after the command name, as typed |
$ARGUMENTS[0] or $0 |
The first argument |
$1, $2 |
The second, third argument |
$name |
A named argument declared in the arguments frontmatter field |
A few rules from the docs that matter in practice:
- Arguments split like a shell, so quote multi-word values:
/standup "auth refactor" today. - If you pass arguments and no placeholder receives them, Claude Code appends
ARGUMENTS: <your input>to the end so Claude still sees them. - An indexed placeholder with no matching argument, such as
$2when you passed one, stays in the text unchanged. A named one expands to an empty string. - To write a literal dollar amount such as
$1.00, escape it:\$1.00. argument-hint, such as[version], shows in autocomplete so people know what to type.
At the terminal prompt you can also stack commands. Typing /lint-rules /changelog 2.4.0 loads both and passes 2.4.0 to each, up to six in one message.
Which frontmatter fields matter most for commands?
All fields are optional. These are the ones that change how a command behaves, from the frontmatter reference:
| Field | Use it when |
|---|---|
description |
Always. It tells Claude what the command is for |
disable-model-invocation: true |
The command has side effects, like deploys or messages, and only you should trigger it |
user-invocable: false |
It is background knowledge for Claude, not something you type |
allowed-tools |
Claude should run certain tools without asking during that turn |
model |
The command needs a different model for the rest of the turn |
effort |
The command needs more or less reasoning than the session default; see effort levels |
context: fork |
The work should run in a subagent and keep its output out of your context |
One caution on model: the prompt caching docs note that a command naming a model other than the session's is a model switch, so the next request reads the whole conversation without cache hits.
Can MCP servers and plugins add commands?
Yes. MCP servers can expose prompts that appear as commands. The MCP docs say Claude Code lists each one as /servername:promptname (MCP), and typing /mcp__servername__promptname also runs it, with arguments separated by spaces.
Plugins ship skills too. They appear as /plugin-name:skill-name, so a plugin's command never collides with one of yours.
Why is my custom command missing?
Work through these in order:
- The name. Claude Code refuses names with characters such as zero-width spaces, no-break spaces, double spaces, or
<and>. Rename the file or folder. - Reserved names. Outside a plugin, a command or skill named
anthropic-skillsdoesn't load, and a skill folder namedsyncedis skipped. - The frontmatter. It is read only when the opening
---is the first line of the file. If the YAML doesn't parse, the command still loads, but with no fields set, so Claude can't match its description. - New folders. If you created
.claude/skills/or.claude/commands/during the session, run/reload-skills. - Debug it. Start
claude --debugand search the log for[names]to see refused names. On v2.1.233 or later,claude plugin validate .claude/skillsfindsSKILL.mdfiles whose frontmatter doesn't parse.
For writing the instructions themselves, see how to write a SKILL.md.
Keep your commands in one library
Commands written in one repo tend to get copied into the next. Kipt keeps prompts and Agent Skills as Markdown in a private GitHub repo you own, imports skills from a GitHub link, a folder or a .zip, and installs every skill into Claude Code or Codex with npx skills add https://github.com/<you>/<repo>.git --all -g. If you have a prompt you want as a skill, the free SKILL.md generator converts it in your browser.