Custom slash commands still work in Claude Code, but they're now the legacy format. Anthropic's docs are explicit: "custom commands have been merged into skills." A file at .claude/commands/deploy.md and a skill at .claude/skills/deploy/SKILL.md both create /deploy and behave the same way — skills just add more.
A slash command is a single Markdown file. The file name becomes the command name:
.claude/commands/fix-issue.md # project: commit it, your team gets it
~/.claude/commands/fix-issue.md # personal: every project on your machine
---
description: Fix a GitHub issue following our coding standards
---
Fix GitHub issue $ARGUMENTS following our coding standards.
Run /fix-issue 123 and Claude receives the text with $ARGUMENTS substituted for 123. Subdirectories namespace the command: .claude/commands/frontend/component.md becomes /frontend:component.
A command file is just a prompt. It can't ship a reference doc, a script, or example output alongside it, and it can't be loaded automatically when Claude decides a task matches — only when you type the slash command yourself. Skills fix both:
SKILL.md can sit next to scripts or reference docs and mention them by path, keeping the main file small.description up front and can load the full body itself when a task matches, not only when you type /name.allowed-tools to pre-approve tools for the run.Existing .claude/commands/ files keep working — nothing breaks. But the docs recommend skills for anything new.
Move the file into its own directory and rename it:
.claude/commands/fix-issue.md
↓
.claude/skills/fix-issue/SKILL.md
The frontmatter and body carry over unchanged — same placeholders, same Markdown body:
---
name: fix-issue
description: Fix a GitHub issue following our coding standards. Use when
asked to fix, close, or resolve a numbered issue.
disable-model-invocation: true
---
Fix GitHub issue $ARGUMENTS following our coding standards.
1. Read the issue with `gh issue view $ARGUMENTS`.
2. Reproduce the bug before changing anything.
3. Fix it, add a regression test, and reference the issue number in the commit.
Two frontmatter fields matter once a skill can trigger itself:
| Field | Effect |
|---|---|
description | What Claude reads to decide whether this skill matches the current task. Write it as "what it does + when to use it". |
disable-model-invocation: true | Keep the old command behavior: only /fix-issue triggers it, never Claude on its own. Use this for anything with side effects, like deploys or file deletion. |
For the full breakdown of writing a description that actually triggers, see the skills guide.
Both formats support the same placeholders in the command body:
$ARGUMENTS — everything typed after the command name, as one string.$1, $2, … — individual arguments by position, for commands that expect a fixed shape like /migrate-component SearchBar TypeScript.Skills aren't strictly better for every case. A one-line command with no supporting files and no reason for Claude to ever invoke it automatically doesn't gain much from becoming a folder — a single Markdown file in .claude/commands/ is still fewer moving parts to review. Reach for a skill once you need any of: supporting files, automatic (non-slash) invocation, or the extra frontmatter controls like allowed-tools.
If your commands or skills shell out and run PreToolUse hooks around them, the free hook builder is a quick way to write and test the matcher without a live Claude session.
Keelwork bundles 10 workflow skills, 5 tested safety hooks (including a full guard-bash and a secret scanner), 3 subagents and 5 CLAUDE.md templates, with a one-command installer that safely merges into your settings.
Get Keelwork — $24 →