InkdownInkdown
Start writing

Claude-Code

62 files·4 subfolders

Shared Workspace

Claude-Code
codex

10-commands

Shared from "Claude-Code" on Inkdown

Commands Architecture

Overview

Commands in Claude Code are slash-prefixed actions (/commit, /review, /diff) that trigger specific behaviors. They're like shortcuts for common tasks.

Plain text
┌─────────────────────────────────────────────────────────────────────────────┐
│                         COMMANDS ARCHITECTURE                                │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │                    COMMAND TYPES                                     │   │
│  │                                                                      │   │
│  │  ┌────────────┐   ┌────────────┐   ┌────────────┐                   │   │
│  │  │  PROMPT    │   │  ACTION    │   │  OUTPUT    │                   │   │
│  │  │  Commands  │   │  Commands  │   │  Commands  │                   │   │
│  │  │            │   │            │   │            │                   │   │
│  │  │ /commit    │   │ /clear     │   │ /cost      │                   │   │
│  │  │ /review    │   │ /exit      │   │ /usage     │                   │   │
│  │  │ /fix       │   │ /compact   │   │ /context   │                   │   │
│  │  └────────────┘   └────────────┘   └────────────┘                   │   │
│  │                                                                      │   │
│  │  Prompt → AI processes    Action → Immediate effect                │   │
│  │  Output → Display info     (no AI call)                             │   │
│  │                                                                      │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│                                                                             │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │                    COMMAND REGISTRY                                  │   │
│  │                                                                      │   │
│  │  commands.ts           →   Central registry                         │   │
│  │  commands/*.ts       →   Individual command implementations         │   │
│  │  skills/*            →   Skill-based commands                       │   │
│  │  plugins/*           →   Plugin commands                            │   │
│  │                                                                      │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘
0000_start_here_index_and_recommended_reading_order.md
0100_project_overview_tech_stack_runtime_modes_and_folder_map.md
0200_startup_flow_entry_points_and_cold_start_sequence.md
0300_codebase_modules_layers_state_models_and_schemas.md
0400_system_architecture_and_design_rationale.md
0500_interactive_repl_request_flow_end_to_end.md
0600_headless_sdk_and_print_mode_request_flow_end_to_end.md
0700_mcp_integration_connection_and_tool_call_flow.md
0800_external_services_sdks_storage_and_local_dependencies.md
0900_environment_variables_settings_feature_flags_and_failure_modes.md
1000_non_obvious_patterns_gotchas_and_debugging_traps.md
1100_full_codebase_file_inventory_grouped_by_directory.md
kimi
00-overview.md
01-entrypoints.md
02-state-management.md
03-query-system.md
04-tools-system.md
05-tasks-system.md
06-ui-components.md
07-bridge-remote.md
08-services.md
09-skills-plugins.md
10-commands.md
11-testing-architecture.md
12-permission-system.md
13-build-system.md
14-ink-internals.md
15-git-internals.md
16-context-compaction.md
17-vim-mode.md
18-mailbox-notifications.md
19-session-persistence.md
20-hooks-system.md
21-error-recovery.md
README.md
qwen
00-overview.md
01-entry-points.md
02-query-engine.md
03-tools-and-tasks.md
04-commands-and-skills.md
05-state-management.md
06-ink-rendering.md
07-bridge-remote.md
08-mcp-services.md
09-services-overview.md
10-multi-agent.md
11-system-prompt-constants.md
12-tool-interface.md
13-memory-system.md
14-buddy-companion.md
15-keybindings.md
16-stop-hooks.md
17-vim-mode.md
18-upstreamproxy.md
19-cost-tracking-history.md
20-contexts-styles-onboarding.md
21-hooks.md
22-screens.md
tweets-explain
claude-code-memory-analysis.md
compact
memory-system
agentic-architecture

Core Files

FilePurpose
commands.tsCommand registry, getCommands() function
commands/[name]/index.tsIndividual command implementations
commands/[name]/prompt.tsPrompts for prompt-type commands
types/command.tsCommand type definitions

Command Type Definition

TypeScript
// types/command.ts
type Command =
  | PromptCommand
  | ActionCommand
  | OutputCommand

// 1. PROMPT COMMANDS
// Generate a prompt that gets sent to Claude
type PromptCommand = {
  type: 'prompt'
  name: string                    // e.g., 'commit'
  description: string             // Shown in help
  argSuggestions?: string[]       // Tab completion hints
  getPromptForCommand: (
    args: string[],
    context: CommandContext
  ) => Promise<{
    messages: Message[]          // Messages to send
    progressMessage?: string      // Shown while processing
    contentLength?: number       // For cost estimation
  }>
}

// 2. ACTION COMMANDS
// Immediate action, no AI call
type ActionCommand = {
  type: 'action'
  name: string
  description: string
  isReadonly: boolean            // True if no side effects
  async action(
    args: string[],
    context: CommandContext
  ): Promise<ActionResult>
}

// 3. OUTPUT COMMANDS
// Display information only
type OutputCommand = {
  type: 'output'
  name: string
  description: string
  async output(
    args: string[],
    context: CommandContext
  ): Promise<OutputResult>
}

Command Registry

commands.ts
TypeScript
// The central registry - all commands imported here
import commit from './commands/commit.js'
import review from './commands/review.js'
import diff from './commands/diff.js'
import cost from './commands/cost/index.js'
import config from './commands/config/index.js'
// ... 100+ commands

export function getCommands(options?: CommandOptions): Command[] {
  const commands: Command[] = [
    // Built-in commands
    commit,
    review,
    diff,
    cost,
    config,
    // ...
  ]

  // Add skill-based commands
  const skills = getBundledSkills()
  for (const skill of skills) {
    commands.push(skillToCommand(skill))
  }

  // Add plugin commands
  const plugins = getLoadedPlugins()
  for (const plugin of plugins) {
    commands.push(...plugin.commands)
  }

  // Add MCP commands
  const mcp = getMcpConnections()
  for (const connection of mcp) {
    commands.push(...connection.commands)
  }

  return commands
}

Prompt Commands

Example: /commit
TypeScript
// commands/commit.ts
import { generateDiff } from '../utils/git.js'

const commitCommand: PromptCommand = {
  type: 'prompt',
  name: 'commit',
  description: 'Generate a commit message for staged changes',
  argSuggestions: ['--amend', '--no-verify'],

  async getPromptForCommand(args: string[], context) {
    // 1. Gather context
    const diff = await generateDiff({ staged: true })

    if (!diff) {
      return {
        messages: [createUserMessage({
          content: 'No staged changes. Stage files first with git add.'
        })],
        progressMessage: 'checking staged changes',
      }
    }

    // 2. Build prompt
    return {
      messages: [createUserMessage({
        content: `Generate a conventional commit message for these changes:\n\n${diff}`,
      })],
      progressMessage: 'analyzing changes',
      contentLength: diff.length,
    }
  },
}
Example: /review
TypeScript
// commands/review.ts
const reviewCommand: PromptCommand = {
  type: 'prompt',
  name: 'review',
  description: 'Review code for issues',
  argSuggestions: ['--staged', '--unstaged', 'file.ts'],

  async getPromptForCommand(args: string[], context) {
    const target = args[0] || '--staged'

    // Get files to review
    const files = await getFilesToReview(target)
    const contents = await readFiles(files)

    return {
      messages: [createUserMessage({
        content: `Review these files for bugs, security issues, and improvements:\n\n${contents}`,
      })],
      progressMessage: 'reviewing code',
    }
  },
}

Action Commands

Example: /clear
TypeScript
// commands/clear/index.ts
const clearCommand: ActionCommand = {
  type: 'action',
  name: 'clear',
  description: 'Clear the terminal screen',
  isReadonly: true,  // No side effects

  async action(args, context) {
    const { setAppState } = context

    // Clear terminal
    console.clear()

    // Reset message view (optional)
    setAppState(prev => ({
      ...prev,
      // Could reset scroll position, etc.
    }))

    return { type: 'success' }
  },
}
Example: /exit
TypeScript
// commands/exit/index.ts
const exitCommand: ActionCommand = {
  type: 'action',
  name: 'exit',
  description: 'Exit Claude Code',
  isReadonly: true,

  async action(args, context) {
    const { gracefulExit } = context

    // Show summary if configured
    if (args.includes('--summary')) {
      await showSessionSummary()
    }

    // Exit
    gracefulExit(0)

    return { type: 'exit' }
  },
}

Output Commands

Example: /cost
TypeScript
// commands/cost/index.ts
const costCommand: OutputCommand = {
  type: 'output',
  name: 'cost',
  description: 'Show session cost breakdown',

  async output(args, context) {
    const { getAppState } = context
    const state = getAppState()

    // Calculate costs
    const costs = calculateSessionCosts(state.messages)

    return {
      type: 'output',
      content: formatCostTable(costs),
    }
  },
}
Example: /context
TypeScript
// commands/context/index.ts
const contextCommand: OutputCommand = {
  type: 'output',
  name: 'context',
  description: 'Show current context window usage',

  async output(args, context) {
    const usage = calculateTokenUsage(context.getAppState().messages)

    return {
      type: 'output',
      content: `
Context Window Usage:
━━━━━━━━━━━━━━━━━━━━━
Messages: ${usage.messageCount}
Tokens: ${usage.totalTokens} / ${usage.maxTokens}
Percentage: ${(usage.percentage * 100).toFixed(1)}%

${renderProgressBar(usage.percentage)}
      `,
    }
  },
}

Command Execution Flow

Plain text
┌─────────────────────────────────────────────────────────────────┐
│                   COMMAND EXECUTION FLOW                        │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  1. PARSE INPUT                                                 │
│     User types: /commit --amend                                 │
│                                                                 │
│     Parse:                                                      │
│       command = 'commit'                                        │
│       args = ['--amend']                                        │
│                                                                 │
│  2. FIND COMMAND                                                │
│     const command = findCommand('commit')                       │
│                                                                 │
│  3. VALIDATE ARGS                                               │
│     if (command.argValidator) {                                 │
│       const valid = command.argValidator(args)                  │
│       if (!valid) showError('Invalid arguments')               │
│     }                                                           │
│                                                                 │
│  4. EXECUTE BASED ON TYPE                                       │
│                                                                 │
│     IF PROMPT COMMAND:                                          │
│       ┌─────────────────────────────────────┐                 │
│       │ const { messages } = await          │                 │
│       │   command.getPromptForCommand(args, context)           │
│       │                                       │                 │
│       │ // Add messages to conversation       │                 │
│       │ setAppState(prev => ({                │                 │
│       │   ...prev,                            │                 │
│       │   messages: [...prev.messages, ...messages]            │
│       │ }))                                   │                 │
│       │                                       │                 │
│       │ // Trigger query                      │                 │
│       │ submitQuery()                         │                 │
│       └─────────────────────────────────────┘                 │
│                                                                 │
│     IF ACTION COMMAND:                                        │
│       ┌─────────────────────────────────────┐                 │
│       │ const result = await                │                 │
│       │   command.action(args, context)     │                 │
│       │                                       │                 │
│       │ // Handle result                     │                 │
│       │ if (result.type === 'error') {      │                 │
│       │   showError(result.error)           │                 │
│       │ }                                   │                 │
│       └─────────────────────────────────────┘                 │
│                                                                 │
│     IF OUTPUT COMMAND:                                        │
│       ┌─────────────────────────────────────┐                 │
│       │ const result = await                │                 │
│       │   command.output(args, context)     │                 │
│       │                                       │                 │
│       │ // Display to user                   │                 │
│       │ console.log(result.content)        │                 │
│       └─────────────────────────────────────┘                 │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

Command Context

TypeScript
// Available to all commands
type CommandContext = {
  // State access
  getAppState(): AppState
  setAppState(updater: (prev: AppState) => AppState): void

  // Query control
  submitQuery(messages: Message[]): void
  abortQuery(): void

  // UI
  showNotification(message: string): void
  showError(error: string): void

  // Config
  getConfig(): SettingsJson
  setConfig(key: string, value: unknown): void

  // Tools
  getTools(): Tool[]
  canUseTool(tool: Tool): boolean

  // Exit
  gracefulExit(code: number): void
}

Dynamic Commands

Commands can be added at runtime by plugins and skills.

From Skills
TypeScript
// Convert skill to command
function skillToCommand(skill: Skill): PromptCommand {
  return {
    type: 'prompt',
    name: skill.name,
    description: skill.description,

    async getPromptForCommand(args: string[], context) {
      // Extract parameters
      const params = extractParameters(skill, args.join(' '))

      // Build prompt from template
      const prompt = substituteTemplate(skill.prompt, params)

      return {
        messages: [createUserMessage({ content: prompt })],
      }
    },
  }
}
From Plugins
TypeScript
// Plugin provides commands
const myPlugin = {
  commands: [
    {
      type: 'action',
      name: 'mycommand',
      description: 'My custom command',
      async action(args, context) {
        // Custom logic
        return { type: 'success' }
      },
    },
  ],
}

Command Help System

TypeScript
// commands/help/index.ts
const helpCommand: OutputCommand = {
  type: 'output',
  name: 'help',
  description: 'Show available commands',

  async output(args, context) {
    const commands = getCommands()

    // Filter by category if specified
    const category = args[0]
    const filtered = category
      ? commands.filter(c => c.category === category)
      : commands

    // Group by type
    const prompt = filtered.filter(c => c.type === 'prompt')
    const action = filtered.filter(c => c.type === 'action')
    const output = filtered.filter(c => c.type === 'output')

    return {
      type: 'output',
      content: `
Available Commands:

PROMPT COMMANDS (trigger AI):
${prompt.map(c => `  /${c.name} - ${c.description}`).join('\n')}

ACTION COMMANDS (immediate):
${action.map(c => `  /${c.name} - ${c.description}`).join('\n')}

OUTPUT COMMANDS (information):
${output.map(c => `  /${c.name} - ${c.description}`).join('\n')}

Type /help <command> for details on a specific command.
      `,
    }
  },
}

Command Suggestions

Tab Completion
TypeScript
// hooks/unifiedSuggestions.ts
export function useCommandSuggestions(
  input: string
): Suggestion[] {
  if (!input.startsWith('/')) return []

  const commands = getCommands()
  const searchTerm = input.slice(1).toLowerCase()

  return commands
    .filter(cmd =>
      cmd.name.toLowerCase().includes(searchTerm) ||
      cmd.description.toLowerCase().includes(searchTerm)
    )
    .map(cmd => ({
      type: 'command',
      value: `/${cmd.name}`,
      description: cmd.description,
    }))
}
Inline Hints
Plain text
User: /
      ├── commit
      ├── review
      ├── diff
      ├── cost
      └── config

User: /co
      ├── commit - Generate commit message
      └── cost - Show session cost

Common Command Patterns

Git-Related Commands
TypeScript
// Pattern: Gather git info → Build prompt
async function gitCommand(args: string[], context) {
  const status = await getGitStatus()
  const diff = await getGitDiff(args)
  const log = await getRecentCommits(5)

  return {
    messages: [createUserMessage({
      content: formatGitPrompt({ status, diff, log }),
    })],
  }
}
File-Related Commands
TypeScript
// Pattern: Gather file info → Build prompt
async function fileCommand(args: string[], context) {
  const files = await glob(args[0] || '**/*')
  const contents = await Promise.all(
    files.map(f => readFile(f, 'utf-8'))
  )

  return {
    messages: [createUserMessage({
      content: formatFilesPrompt(files, contents),
    })],
  }
}
Utility Commands
TypeScript
// Pattern: Direct action, no AI
async function utilityCommand(args: string[], context) {
  // Do something immediately
  const result = await someAction(args)

  // Show result
  return { type: 'success', result }
}

Error Handling

TypeScript
async function safeCommand(args: string[], context) {
  try {
    const result = await executeCommand(args)
    return result
  } catch (error) {
    // Log for debugging
    logError('Command failed', { command: this.name, error })

    // User-friendly message
    return {
      type: 'error',
      error: formatErrorForUser(error),
      suggestion: suggestFix(error),
    }
  }
}

Testing Commands

TypeScript
// commands/__tests__/commit.test.ts
import { commitCommand } from '../commit.js'

test('commit command generates prompt with diff', async () => {
  // Mock git
  jest.spyOn(git, 'generateDiff').mockResolvedValue('diff content')

  const result = await commitCommand.getPromptForCommand(
    [],
    createMockContext()
  )

  expect(result.messages[0].content).toContain('diff content')
  expect(result.progressMessage).toBe('analyzing changes')
})

Key Concepts

1. Three Types, Clear Purposes
  • Prompt: Send to AI
  • Action: Do something now
  • Output: Show information
2. Lazy Loading

Commands register at startup but execute only when called.

3. Composable

Commands can call other commands or use shared utilities.

4. Extensible

Plugins and skills add commands dynamically.

5. Self-Documenting

Description field feeds the /help system automatically.


Related Documentation

  • Skills & Plugins - How skills become commands
  • Tools System - Commands vs tools distinction
  • Entrypoints - How commands are registered