Skip to main content

Command System

How slash commands work — the command registry, command types, and the execution flow.

Command Types

Every slash command is one of three types:

📋
User types /command
🔧
Command Registry
No match — Unknown command error
Match found — Check type
Command type?
PromptCommand
Inject into system prompt
🤖
Model processes
LocalCommand
Execute locally
📤
Display output
LocalJSXCommand
Render React component
🧩
Display in REPL

PromptCommand

Content is injected into the conversation as a message, and the model processes it. Used for skills and AI-powered commands.

src/types/command.ts
type PromptCommand = {
type: 'prompt'
getPromptForCommand(args: string, context: CommandContext): ContentBlockParam[]
}

Examples: Skills (/commit, /review-pr), any command that needs the model to act.

LocalCommand

Executes immediately without involving the model. Used for configuration and navigation.

src/types/command.ts
type LocalCommand = {
type: 'local'
load(): Promise<{ call(args: string, context: CommandContext): void }>
}

Examples: /help, /clear, /model, /config.

LocalJSXCommand

Renders a React component inline in the REPL. Used for interactive UI elements.

src/types/command.ts
type LocalJSXCommand = {
type: 'local-jsx'
load(): Promise<{ call(onDone: Function, context: CommandContext, args: string): ReactNode }>
}

Examples: /mcp (shows MCP server status UI), /memory (shows memory browser).

Command Registry

Commands are registered from multiple sources during initialization:

Sources
Built-in Commands (src/commands/)
Skills (~/.claude/skills/)
Plugin Commands
MCP Tool Commands
Registry
Command Registry — Name/Alias Lookup

Registration

The command registry uses eager imports — built-in commands are imported at the top of src/commands.ts, not lazily loaded. This means all command modules are evaluated at startup:

src/commands.ts (lines 2-46)
import { clearCommand } from './commands/clear.js'
import { helpCommand } from './commands/help.js'
import { modelCommand } from './commands/model.js'
import { commitCommand } from './commands/commit.js'
// ... 60+ imports

// Some commands are environment-gated
// (e.g., agents-platform only loads when USER_TYPE === 'ant')

Skills and plugin commands are added dynamically after initialization:

src/commands.ts (skill registration)
// Skills become PromptCommands
for (const skill of loadedSkills) {
registry.set(skill.name, {
type: 'prompt',
name: skill.name,
description: skill.description,
getPromptForCommand: (args) => skill.getContent(args),
})
}

Command Base Interface

All commands share a base:

src/types/command.ts
type CommandBase = {
name: string
description: string
aliases?: string[]
isEnabled?(): boolean // Dynamic enable/disable
isHidden?: boolean // Hide from /help
availability?: ('claude-ai' | 'console')[] // Platform-specific
}

Built-in Commands (100+)

Commands are organized by function:

CategoryCommandsType
Session/clear, /resume, /continueLocal
Config/model, /config, /permissionsLocal
Memory/memory, /forgetLocal/JSX
Development/commit, /review-prPrompt (Skills)
MCP/mcp, /mcp-serversLocal/JSX
Debug/debug, /verbose, /costLocal
Navigation/help, /commandsLocal
Task/tasks, /backgroundLocal/JSX

That table is only the architectural overview. The real registry in src/commands.ts is broader and also merges bundled skills, user skill-directory commands, plugin commands, workflow-generated commands, and dynamic skills discovered during execution.

See the Command Catalog appendix for the categorized source-backed map.

Workflow-Generated Commands

When the WORKFLOW_SCRIPTS feature is enabled, the command registry also merges workflow-generated commands:

src/commands.ts (simplified)
const workflowCommands = feature('WORKFLOW_SCRIPTS')
? await getWorkflowCommands(cwd)
: []

return [...baseCommands, ...workflowCommands]

The recovered source proves two architectural points:

What ExistsEvidence
Workflow commands are generated dynamicallysrc/commands.ts loads getWorkflowCommands(cwd) instead of hardcoding names
They are tagged as a distinct command kindformatDescriptionWithSource(cmd) appends (workflow) when cmd.kind === 'workflow'
There is also a top-level workflow command surfacesrc/commands.ts conditionally loads ./commands/workflows/index.js
Recovered surface

The recovered source tree does not include the full workflow-command implementation, so this page only documents the registry integration that is directly visible in src/commands.ts and src/tools/WorkflowTool/.

Execution Flow

⌨️
User types /foo some args
🔍
Parse: name = "foo", args = "some args"
📋
Registry lookup by name, then by alias
Not found — "Unknown command" error
Found — check isEnabled()
What type?
PromptCommand
getPromptForCommand(args)
Content blocks returned
Injected as user message
🤖
Model processes + responds
LocalCommand
load() — import module
call(args, context)
📤
Output displayed in REPL
LocalJSXCommand
load() — import module
call(onDone, context, args)
🧩
React component rendered inline

Key Source Files

FilePurpose
src/commands.tsCommand registry and loaders
src/types/command.tsCommand type definitions
src/skills/Bundled skill commands added to the registry
src/tools/WorkflowTool/Workflow-generated command support when enabled
src/commands/60+ command implementations (207 files)