Claude Code Guide

The complete guide to Claude Code. Opus 4.7, Sonnet 4.6, Haiku 4.5. 1M token context window. 27 hook events. 43 production-tested chapters across 6 topical Parts (Foundation, Workflow, Extension, Context Engineering, Advanced, Reference). Three install tiers. CC 2.1.121+ compatible.

View the Project on GitHub ytrofr/claude-code-guide

Slash Commands (now Skills)

Short answer: slash commands still exist, but they are now just skills with user-invocable: true. If you’re writing a new one, read Skills Authoring. If you have legacy commands/*.md files from before Claude Code 2.1.88, read the migration section below.


Historical Note

Before CC 2.1.88, user-invocable slash commands lived in two directories:

~/.claude/commands/       # Global
.claude/commands/         # Project-scoped

Each was a single Markdown file with YAML frontmatter. In 2.1.88, Anthropic merged commands into skills — the commands/ directories were deprecated and any /<name> invocation that used to be a command is now a skill with user-invocable: true.

There is no longer a separate command type. Skills are the one primitive.


Invocation Patterns

Plain skill invocation

/skill-name
/skill-name argument text here

The first form runs the skill with empty arguments. The second passes everything after the name as $ARGUMENTS (see Skills Authoring → Arguments).

Plugin-namespaced invocation

Skills installed via a plugin are addressed with the plugin prefix:

/plugin-name:skill-name

Example: the superpowers plugin exposes /superpowers:brainstorming, /superpowers:writing-plans, etc.

Built-in slashes (2.1.108+)

Several built-in commands are now rewired through the Skill tool:

Slash What it does
/init Initialize a new CLAUDE.md for the project
/review Review a pull request
/security-review Security review of pending changes

Plus the classic built-ins (not implemented as skills): /help, /clear, /cost, /config, /doctor, /model, /resume, /compact, /release-notes, and others. These are hard-wired into the CLI.


Authoring a User-Invocable Skill

The short form — full details in Skills Authoring:

---
name: my-command
description: "Short action-verb description. Use when user says 'my command' or types /my-command."
user-invocable: true
argument-hint: "[optional argument description]"
---

# My Command

$ARGUMENTS

## Workflow

Steps to execute using the argument text above.

Key fields:

To prevent accidental automatic invocation (e.g., for deploy commands that must be explicit):

disable-model-invocation: true

This keeps the skill user-invocable via slash but prevents Claude from auto-triggering it based on conversation context.


Migrating Legacy commands/ Files

If you have files in ~/.claude/commands/ or .claude/commands/ from before 2.1.88, migrate them to the skills layout:

Before (legacy command file)

~/.claude/commands/
  deploy.md
  ship-it.md
  weekly-review.md

Each file had frontmatter and a body. The filename (minus .md) was the slash name.

After (skill directory)

~/.claude/skills/
  deploy/
    SKILL.md
  ship-it/
    SKILL.md
  weekly-review/
    SKILL.md

The directory name becomes the slash name. SKILL.md replaces the old command file.

Migration steps

# For each legacy command file:
OLD="deploy"
mkdir -p ~/.claude/skills/$OLD
mv ~/.claude/commands/$OLD.md ~/.claude/skills/$OLD/SKILL.md

Then edit SKILL.md and ensure the frontmatter has:

---
name: deploy                         # optional; directory name is used if omitted
description: "Deploy to production. Use when user says /deploy or 'deploy to prod'."
user-invocable: true
---

Important frontmatter hygiene during migration:

Then remove the empty commands/ directory (if nothing else remains in it):

rmdir ~/.claude/commands 2>/dev/null || true

Common Migration Issues

Problem Cause Fix
Slash doesn’t appear in / menu Missing user-invocable: true Add the field
Tool restrictions ignored Used allowed_tools (underscore) Rename to allowed-tools
Arguments not expanded Legacy command used `` Replace with $ARGUMENTS
Tool list parsed as empty Used JSON array format Use comma-separated string
Slash fires when unwanted Model auto-invokes from context Add disable-model-invocation: true

See Also