AnswerQA

How do I add my own /command to Claude Code?

Answer

Drop a SKILL.md file in .claude/skills/your-command/. Edits hot-reload in the current session, but creating the skills directory for the first time needs a restart. Slash commands and skills are now the same feature; the .claude/commands/ path still works but skills add the features you actually want.

By Kalle Lamminpää Verified May 7, 2026

A custom /command is now just a skill. The old .claude/commands/foo.md path still works, but .claude/skills/foo/SKILL.md is the modern path that adds autoload, supporting files, scoped permissions, and per-skill model overrides.

Build one in 5 steps

1. Make the skill directory.

mkdir -p ~/.claude/skills/review-pr

Personal skills (~/.claude/skills/) work in every project. For team-shared skills, use .claude/skills/ inside the repo and commit it.

2. Write SKILL.md.

~/.claude/skills/review-pr/SKILL.md:

---
description: Review the current branch's diff for SQL safety and missing tests. Use when the user asks to review their branch, check for unsafe queries, or find untested code paths.
allowed-tools: Bash(git diff *)
---

Review the diff below against `main`. Focus on:

1. SQL queries. Are parameters bound? Any string concatenation into SQL?
2. New code paths with no tests.
3. Side effects inside conditionals (logging, mutation, network).

Report findings as a numbered list. Do not modify any files.

## Diff

!`git diff main...HEAD`

The !`git diff main...HEAD` line is the part most people miss. Backtick-bang runs the shell command before Claude sees the prompt and inlines the output. That is how a skill stays grounded in live state instead of guessing.

3. Test it two ways.

Direct invocation:

/review-pr

Or let Claude pick it up. Because the description mentions “review their branch”, asking “review my branch please” should auto-invoke it. If it doesn’t, the description is too weak. Add the verbs and nouns a user would actually type.

4. Add arguments when you need scope.

---
description: Review the diff under a specific path. Use when the user wants to scope review to one directory.
---

Review the diff under `$ARGUMENTS` for SQL safety and missing tests.

!`git diff main...HEAD -- $ARGUMENTS`

/review-pr api/ swaps $ARGUMENTS for api/. Positional args are zero-based: $0 is the first, $1 is the second. If you forget $ARGUMENTS entirely, Claude Code appends ARGUMENTS: <input> to the bottom so the input is not lost, just unstructured.

5. Stop Claude from auto-firing destructive ones.

Anything with side effects (deploy, send-email, push) needs:

---
description: Push and open a PR for the current branch.
disable-model-invocation: true
---

Now only you can run /ship. Claude will not decide to ship “because the code looks ready”.

Footguns

Skills and old .claude/commands/ files share a namespace, and skills win. If you have both .claude/commands/deploy.md and .claude/skills/deploy/SKILL.md, only the skill runs. Same name across precedence levels (enterprise, personal, project) follows the cascade: enterprise overrides personal, personal overrides project. If your edit is not taking effect, you are probably editing the lower-priority copy.

Trusting a project workspace silently grants its skills’ tool permissions. When you accept the workspace trust dialog for a repo, every .claude/skills/*/SKILL.md with an allowed-tools field gets that access without per-use approval. A repo cloned from a stranger can land a .claude/skills/leak-secrets/ that uses allowed-tools: Bash(curl *) and get away with it. Read the skill files in any unfamiliar repo before you trust it. Add deny rules in /permissions for the most dangerous tools so even trusted skills hit a stop sign.

Skill descriptions get truncated when you have many skills. The combined description budget defaults to 1% of the context window or 8,000 chars, whichever is more. With 30+ skills installed, descriptions are shortened from the back, and Claude stops auto-invoking yours because the keywords got cut. Diagnostic: ask “What skills are available?” mid-session. If yours shows up name-only, raise SLASH_COMMAND_TOOL_CHAR_BUDGET or set low-priority skills to "name-only" in skillOverrides.

Creating the top-level .claude/skills/ directory for the first time requires a session restart. Adding new files inside an existing skills directory hot-reloads. But if .claude/skills/ did not exist when the session started, Claude Code is not watching that path, so new skills are invisible until you restart. Easy 5-minute confusion if you forget.

disableSkillShellExecution silently kills your ! injections. If a managed setting (or your own ~/.claude/settings.json) sets "disableSkillShellExecution": true, every !`command` line is replaced with [shell command execution disabled by policy] instead of running. Your skill still loads, just without the live data it depended on. Check /config if a known-working skill suddenly returns generic answers.

SKILL.md content stays in context for the whole session. Once a skill loads, its full body is part of the conversation until compaction. A 2,000-line SKILL.md is a 2,000-line tax on every turn. Keep SKILL.md under 500 lines and move long reference material into supporting files (reference.md, examples/) that the skill links to but does not inline.

When NOT to use a slash command

  • The instruction belongs in CLAUDE.md. If it is “always do X for this project” with no trigger, it is a project rule, not a skill. Skills cost tokens every time they load; CLAUDE.md is loaded once.
  • The job needs connection state, OAuth refresh, or a dynamic tool list. Use an MCP server. Skills can curl an API in a one-shot shell call, but they cannot hold a connection across turns, refresh OAuth tokens automatically, or update their tool list at runtime. If your skill is “shell out, parse the response, return a result”, a skill is fine. If it is “maintain a session with a service that has its own auth lifecycle”, use MCP.
  • The job needs an isolated context. Use a subagent (context: fork in skill frontmatter delegates to a subagent, but a real subagent in .claude/agents/ gives you more control over the model, tools, and lifecycle).
  • You will type the prompt once. Just type it. The /skill overhead (file, frontmatter, naming) only pays off when the prompt repeats. Two times, file it. Three times, you are being silly not to.

Sources

  • Extend Claude with skills
    Canonical doc. The merger of slash commands into skills is buried under a Note block; the modern path is .claude/skills/{name}/SKILL.md.
  • Commands reference
    Built-in /commands and bundled skills. Useful for checking which names you can't reuse.
  • Configure permissions
    Why allowed-tools is more powerful than it looks: granting tool access to a skill bypasses per-use approval once you trust the workspace.
  • Claude Code settings
    disableSkillShellExecution lives here. The companion env var SLASH_COMMAND_TOOL_CHAR_BUDGET is documented on the skills page.
  • Model Context Protocol
    Source for the skill-vs-MCP decision. MCP servers hold connection state across turns, refresh OAuth tokens, and update their tool list dynamically; skills cannot.

Was this helpful?