Kipt

Your prompts and skills, one keystroke away.

Explore

Claude Code custom commands: commands vs skills and how to migrate

Claude Code custom commands now live in skills: how .claude/commands files still work, moving to SKILL.md, arguments, frontmatter and fixing missing commands.

By the Kipt team · Updated 26 October 2026

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:

  1. Create the folder: mkdir -p .claude/skills/changelog
  2. Move the file: git mv .claude/commands/changelog.md .claude/skills/changelog/SKILL.md
  3. Keep the frontmatter as it is. Every field above works the same in a skill.
  4. Optionally add name: changelog and any supporting files, such as a template.md the instructions refer to.
  5. Run /changelog 2.4.0 to 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 $2 when 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:

  1. 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.
  2. Reserved names. Outside a plugin, a command or skill named anthropic-skills doesn't load, and a skill folder named synced is skipped.
  3. 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.
  4. New folders. If you created .claude/skills/ or .claude/commands/ during the session, run /reload-skills.
  5. Debug it. Start claude --debug and search the log for [names] to see refused names. On v2.1.233 or later, claude plugin validate .claude/skills finds SKILL.md files 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.

Questions

Are custom commands deprecated in Claude Code?

No, but they have been merged into skills. Anthropic's docs say a file at .claude/commands/deploy.md and a skill at .claude/skills/deploy/SKILL.md both create /deploy and work the same way, and existing command files keep working. The docs say skills add a directory for supporting files, frontmatter to control who invokes them, and the ability for Claude to load them automatically when relevant.

Where do Claude Code custom commands go?

The older format is a Markdown file in .claude/commands/ in your project. The current format is a folder with a SKILL.md file, in .claude/skills/ for one project or ~/.claude/skills/ for all your projects. The file or folder name becomes the command you type.

How do I convert a .claude/commands file to a skill?

Create a folder under .claude/skills/ named after the command, move the Markdown file into it and rename it SKILL.md. The frontmatter and body carry over, because command files accept the same fields as skills except name and paths. Then delete the old file so the two don't sit side by side.

What happens if a command file and a skill have the same name?

The skill wins. Anthropic's precedence table lists a skill and a file in .claude/commands/ with the same name, and the skill is the one that runs. Between locations, enterprise beats personal and personal beats project.

Why doesn't my custom command show up in the / menu?

Check the file name for characters Claude Code refuses, such as a no-break space or angle brackets, and make sure the frontmatter starts on the very first line. If you added the folder during the session, run /reload-skills. Starting with claude --debug shows refused names and YAML errors in the debug log.

More in Claude Code

All guides

Keep your prompts and skills in one place, in your own GitHub. Install every skill with one command.

Get started

Kipt is an independent product, not affiliated with or endorsed by Anthropic, OpenAI, Cursor or GitHub. Claude, ChatGPT, Codex, Cursor and GitHub are trademarks of their owners.