核心命令详解(上)

📑 目录

在 Claude Code 的使用过程中,用户与系统最直接、最高频的交互方式便是斜杠命令(Slash Commands)。从项目初始化 /init 到模型切换 /model,从配置管理 /config 到主题切换 /theme,这些命令构成了 Claude Code 日常操作的基石。

本文作为「命令系统」章节的第二篇,将从源码层面对 Claude Code 的核心日常命令进行逐个拆解。我们关注的不只是"这些命令能做什么",而是"它们如何在代码层面被实现"。通过阅读 src/commands/ 目录下的实现文件,我们可以清晰地看到每条命令的注册方式、参数处理逻辑、UI 渲染策略以及状态管理方法。


一、命令系统的整体架构

在深入具体命令之前,有必要先理解 Claude Code 命令系统的整体架构。所有命令都遵循统一的注册模式:

// src/commands.ts (架构示意)
export interface Command {
  type: 'local-jsx' | 'local' | 'global';
  name: string;
  description: string | (() => string);
  aliases?: string[];
  argumentHint?: string;
  immediate?: boolean;
  load: () => Promise<{ call: CommandCall }>;
}

每条命令本质上是一个符合 Command 接口的对象,核心字段包括:

  • type: 命令类型。'local-jsx' 表示该命令会渲染 React 组件到终端 UI;'local' 表示纯文本输出;'global' 则是全局可用的系统级命令。
  • name: 命令名称,即用户在终端中输入的 /xxx
  • description: 命令描述,支持静态字符串或动态函数。
  • aliases: 命令别名数组,例如 config 的别名是 settings
  • argumentHint: 参数提示,如 [model],用于帮助用户理解命令用法。
  • immediate: 布尔值,表示该命令是否需要立即执行(不进入主循环的异步调度)。
  • load: 懒加载函数,返回命令的执行体 call
flowchart TD
    A[用户输入 /command] --> B[命令解析器匹配 Command 对象]
    B --> C{命令类型?}
    C -->|local-jsx| D[懒加载 load 函数]
    C -->|local| E[直接执行 call 函数]
    C -->|global| F[系统级调度]
    D --> G[渲染 React 组件到 Ink TUI]
    E --> H[输出文本结果]
    F --> I[全局状态/副作用操作]
    G --> J[onDone 回调返回结果]
    H --> J
    I --> J

这种架构的优势在于按需加载统一接口:每条命令都是独立的模块,只在用户触发时通过 load() 动态导入,避免了启动时的全量加载开销。同时,统一的 Command 接口使得新增命令变得极其简单——只需实现一个符合接口的对象并导出即可。


二、/init 命令:项目初始化的七阶段流水线

/init 命令是 Claude Code 中最复杂的命令之一,其核心逻辑位于 src/commands/init.ts(约 20KB,256 行)。这个命令负责为当前项目生成 CLAUDE.md 文件(以及可选的 CLAUDE.local.md、skills 和 hooks),为后续 AI 会话提供项目上下文。

2.1 新旧 Prompt 的演进

源码中定义了两个 Prompt 常量:OLD_INIT_PROMPTNEW_INIT_PROMPT(第 1-150 行)。OLD_INIT_PROMPT 是一个相对简单的指令模板,要求 Claude 分析代码库并创建 CLAUDE.md;而 NEW_INIT_PROMPT 则引入了分阶段交互式流程,将初始化拆分为 7 个明确的阶段。

// src/commands/init.ts, 第 1-30 行
import { feature } from 'bun:bundle'
import type { Command } from '../commands.js'
import { maybeMarkProjectOnboardingComplete } from '../projectOnboardingState.js'
import { isEnvTruthy } from '../utils/envUtils.js'

const OLD_INIT_PROMPT = `Please analyze this codebase and create a CLAUDE.md file...`

const NEW_INIT_PROMPT = `Set up a minimal CLAUDE.md (and optionally skills and hooks) for this repo...`

这种双 Prompt 设计暗示了产品的演进轨迹:从"一次性生成"转向"多轮对话式引导"。feature()isEnvTruthy 的引入表明,新流程可能处于功能开关(Feature Flag)的保护之下,只有特定环境或用户才能体验。

2.2 七阶段初始化流程详解

NEW_INIT_PROMPT/init 的实现逻辑抽象为 7 个阶段,虽然源码只展示了 Prompt 文本而非具体执行代码,但从 Prompt 内容可以完整还原出命令的执行流水线:

Phase 1: Ask what to set up(询问设置范围)

命令首先通过 AskUserQuestion 工具与用户交互,询问两个关键问题:

  1. 需要创建哪种 CLAUDE.md?选项包括:项目级(Project CLAUDE.md)、个人级(Personal CLAUDE.local.md)或两者都创建。
  2. 是否需要同时设置 skills 和 hooks?选项包括:两者都要、仅 skills、仅 hooks、只要 CLAUDE.md

这里的设计哲学是用户主权——不预设"最佳实践",而是让用户根据团队工作流自行决定。Prompt 中明确强调:"Do not mark any options as 'recommended' — this is about how their team works, not best practices."

Phase 2: Explore the codebase(代码库勘探)

启动子代理(subagent)对代码库进行系统性扫描,读取的关键文件包括:

  • 清单文件:package.jsonCargo.tomlpyproject.tomlgo.modpom.xml
  • 构建配置:Makefile、CI 配置
  • 现有 AI 工具配置:.cursor/rules/AGENTS.md.github/copilot-instructions.md
  • 格式化器配置:prettierbiomeruffblack

子代理的输出是一个结构化的"发现报告",标记出"仅通过代码无法推断"的信息缺口——这些缺口将成为 Phase 3 的访谈问题。

Phase 3: Fill in the gaps(信息补全)

基于 Phase 2 的报告,再次通过 AskUserQuestion 向用户提问。问题分为两类:

  • 团队级问题:非显而易见的命令、注意事项、分支/PR 规范、环境变量设置、测试怪癖等。
  • 个人级问题:用户在团队中的角色、对代码库的熟悉程度、个人沙盒 URL、测试账户、沟通偏好等。

Phase 3 的核心产出是一个偏好队列(preference queue),每个条目包含类型(hookskillnote)、描述、目标文件和从 Phase 2 提取的具体命令。

Phase 4-7: 文件写入

根据 Phase 1 的选择和 Phase 3 的队列,依次写入:

  • Phase 4: 项目级 CLAUDE.md
  • Phase 5: 个人级 CLAUDE.local.md(自动加入 .gitignore
  • Phase 6: Skills 文件到 .claude/skills/
  • Phase 7: Hooks 文件到 .claude/hooks/

2.3 与 setup.ts 的关系

/initsetup.ts 的关系可以从源码的导入链中窥见:maybeMarkProjectOnboardingComplete 来自 projectOnboardingState.js。在 Claude Code 的架构中,setup.ts 通常负责全局初始化(如配置目录创建、首次启动向导),而 /init 则是项目级初始化——针对当前工作目录的代码库进行上下文准备。

两者的边界可以概括为:

  • setup.ts: "Claude Code 这个工具本身是否准备好了?"
  • /init: "当前这个项目是否准备好了让 Claude Code 理解?"

/init 成功完成后,会调用 maybeMarkProjectOnboardingComplete 将项目标记为"已初始化",这会影响后续会话的 onboarding 流程。


三、/help 命令:帮助信息的动态生成

/help 命令的源码结构极其精简,却展示了 Claude Code 命令系统中声明式注册的典范。

3.1 命令注册

// src/commands/help/index.ts
import type { Command } from '../../commands.js'

const help = {
  type: 'local-jsx',
  name: 'help',
  description: 'Show help and available commands',
  load: () => import('./help.js'),
} satisfies Command

export default help

整个 index.ts 仅 10 行代码。命令的核心逻辑被封装在 help.tsx(编译后输出为 help.js)中,通过 load 懒加载。这种目录即命令的组织方式(help/index.ts + help/help.tsx)在 Claude Code 的命令目录中非常普遍。

3.2 分类显示与搜索

虽然 help.tsx 的源码在本次获取中未能完整拉取,但从 help 命令的实际行为和项目架构可以推断其实现方式:help 命令会渲染一个交互式的帮助面板,按类别展示所有可用命令。命令的分类信息并非硬编码在 help.tsx 中,而是从命令注册表中动态提取——遍历所有已注册的 Command 对象,读取其 namedescriptionaliasesargumentHint 字段。

这种方式的好处显而易见:新增命令时,开发者只需在正确的目录下导出 Command 对象,/help 会自动将其纳入展示列表,无需修改帮助系统的任何代码。

搜索功能的实现则可能基于 ink 的输入处理能力,对用户输入的关键词进行实时过滤,匹配命令名称、别名和描述文本。


四、/config 命令:配置的面板化管理

/config 命令(别名 /settings)是 Claude Code 中配置管理的入口。与很多 CLI 工具通过命令行参数修改配置不同,Claude Code 选择了一个更直观的方式:交互式配置面板

4.1 命令注册

// src/commands/config/index.ts
import type { Command } from '../../commands.js'

const config = {
  aliases: ['settings'],
  type: 'local-jsx',
  name: 'config',
  description: 'Open config panel',
  load: () => import('./config.js'),
} satisfies Command

export default config

值得注意的是 aliases: ['settings'] 的设计——Claude Code 在命名上同时支持 config(开发者惯用语)和 settings(普通用户更熟悉的词),降低了使用门槛。

4.2 配置面板的渲染

// src/commands/config/config.tsx
import * as React from 'react';
import { Settings } from '../../components/Settings/Settings.js';
import type { LocalJSXCommandCall } from '../../types/command.js';

export const call: LocalJSXCommandCall = async (onDone, context) => {
  return <Settings onClose={onDone} context={context} defaultTab="Config" />;
};

config.tsx 的代码量只有 6 行,但其背后是组件化架构的优雅体现。命令本身不做任何业务逻辑,只是将控制权委托给 Settings 组件Settings 组件接收三个 props:

  • onClose: 关闭面板的回调,对应 onDone,用户操作完成后调用以返回命令结果。
  • context: 命令执行的上下文,包含当前会话状态、配置对象等。
  • defaultTab: 默认激活的标签页,这里固定为 "Config"

4.3 配置项的读取与持久化

虽然 config.tsx 本身不包含配置读取逻辑,但从 Settings 组件的导入路径和参数设计可以推断,配置的底层管理采用了以下策略:

  1. 配置源优先级: 环境变量 > 项目级配置 > 用户级全局配置 > 默认值。
  2. 持久化层: 用户级配置通常存储在 ~/.claude/settings.json(或类似路径),项目级配置则可能存储在项目根目录的 .claude/ 下。
  3. 验证机制: 配置修改时,Settings 组件内部会对值进行类型检查和范围校验,无效值不会写入持久化层。

这种"命令即入口、组件即交互、独立模块即持久化"的分层设计,使得配置系统的各个部分可以独立演进和测试。


五、/theme 命令:终端主题的状态驱动切换

Claude Code 运行在终端环境中,但其 UI 并非传统的纯文本输出,而是基于 ink(React for CLI)构建的富文本界面。/theme 命令负责管理这一界面的视觉风格。

5.1 命令注册与执行

// src/commands/theme/index.ts
import type { Command } from '../../commands.js'

const theme = {
  type: 'local-jsx',
  name: 'theme',
  description: 'Change the theme',
  load: () => import('./theme.js'),
} satisfies Command

export default theme

5.2 ThemePicker 的交互实现

// src/commands/theme/theme.tsx(核心逻辑还原)
import * as React from 'react';
import { Pane } from '../../components/design-system/Pane.js';
import { ThemePicker } from '../../components/ThemePicker.js';
import { useTheme } from '../../ink.js';
import type { LocalJSXCommandCall } from '../../types/command.js';

function ThemePickerCommand({ onDone }: Props) {
  const [, setTheme] = useTheme();

  return (
    <Pane color="permission">
      <ThemePicker
        onThemeSelect={setting => {
          setTheme(setting);
          onDone(`Theme set to ${setting}`);
        }}
        onCancel={() => {
          onDone("Theme picker dismissed", { display: "system" });
        }}
        skipExitHandling={true}
      />
    </Pane>
  );
}

export const call: LocalJSXCommandCall = async (onDone, _context) => {
  return <ThemePickerCommand onDone={onDone} />;
};

这段代码展示了几个关键点:

  1. useTheme Hook: 来自 ../../ink.js,是 Claude Code 对 ink 主题能力的封装。它返回一个 [currentTheme, setTheme] 元组,类似于 React 的 useState
  2. Pane 组件: 设计系统(design-system)中的容器组件,color="permission" 指定了面板的语义颜色。
  3. skipExitHandling: 这个 prop 的存在暗示了 ThemePicker 组件内部有复杂的键盘事件处理(如 Escape 键退出),而该命令选择自行管理退出逻辑。

5.3 与 utils/theme.ts 的关系

// src/utils/theme.ts(类型定义节选)
export type Theme = {
  autoAccept: string
  bashBorder: string
  claude: string
  claudeShimmer: string
  permission: string
  permissionShimmer: string
  planMode: string
  text: string
  inverseText: string
  inactive: string
  subtle: string
  suggestion: string
  remember: string
  background: string
  success: string
  error: string
  warning: string
  // ... 更多语义化颜色字段
  diffAdded: string
  diffRemoved: string
  diffAddedDimmed: string
  diffRemovedDimmed: string
  // Agent 专用颜色
  red_FOR_SUBAGENTS_ONLY: string
  blue_FOR_SUBAGENTS_ONLY: string
  // ...
}

utils/theme.ts 定义了 Theme 类型,这是一个非常详细的语义化颜色系统。不同于简单的"深色/浅色"二元划分,Claude Code 的主题系统为每一种 UI 状态都定义了专属颜色:

  • 交互状态: autoAccept(自动接受)、permission(权限请求)、suggestion(建议)
  • 内容类型: diffAdded / diffRemoved(代码差异)、remember(记忆提示)
  • 代理标识: red_FOR_SUBAGENTS_ONLY 等颜色专用于子代理的输出,帮助用户在多代理场景下区分信息来源
  • TUI V2 组件: clawd_bodyuserMessageBackgroundmessageActionsBackground 等面向新版界面的颜色变量

/theme 命令通过 useTheme 修改的并不是单一的颜色值,而是整个语义化颜色映射表的切换。当用户选择某个主题时,setTheme 会将当前会话的所有颜色变量原子性地替换为新主题的对应值,随后 ink 的 React 渲染树会自动重绘。


六、/model 命令:模型选择的权限与验证

/model 命令是 Claude Code 中功能最丰富的命令之一,它不仅允许用户切换 AI 模型,还涉及权限校验、计费提示、Fast Mode 联动等复杂逻辑。

6.1 命令注册:动态描述与即时性

// src/commands/model/index.ts
import type { Command } from '../../commands.js'
import { shouldInferenceConfigCommandBeImmediate } from '../../utils/immediateCommand.js'
import { getMainLoopModel, renderModelName } from '../../utils/model/model.js'

export default {
  type: 'local-jsx',
  name: 'model',
  get description() {
    return `Set the AI model for Claude Code (currently ${renderModelName(getMainLoopModel())})`
  },
  argumentHint: '[model]',
  get immediate() {
    return shouldInferenceConfigCommandBeImmediate()
  },
  load: () => import('./model.js'),
} satisfies Command

这里有两个值得注意的设计:

  1. get description(): 描述是动态计算的,每次展示 /help 或命令补全时,都会调用getMainLoopModel()获取当前模型,并通过renderModelName()` 渲染为友好名称。这意味着用户随时能看到自己正在使用的模型,无需额外查询。
  2. get immediate(): 即时性也是动态决定的,基于 shouldInferenceConfigCommandBeImmediate()。该函数可能检查当前是否处于 plan mode、是否有正在进行的流式响应等状态——在某些场景下,模型切换需要排队等待,而在其他场景下可以立即生效。

6.2 模型选择器的三种模式

model.tsx 实现了三种执行模式,根据用户输入的 args 自动路由:

模式一:信息查询(无参数或 --info

// src/commands/model/model.tsx, 调用入口逻辑
export const call: LocalJSXCommandCall = async (onDone, _context, args) => {
  args = args?.trim() || '';
  if (COMMON_INFO_ARGS.includes(args)) {
    return <ShowModelAndClose onDone={onDone} />;
  }
  // ...
};

COMMON_INFO_ARGS 包含 --info-i 等参数。此模式下,命令仅展示当前模型和基础模型信息,不触发选择器 UI。

模式二:内联设置(直接传入模型名)

if (args) {
  return <SetModelAndClose args={args} onDone={onDone} />;
}

SetModelAndClose 组件处理直接的模型名称输入,包含完整的验证链路:

// SetModelAndClose 核心逻辑(还原)
async function handleModelChange(): Promise<void> {
  if (model && !isModelAllowed(model)) {
    onDone(`Model '${model}' is not available. Your organization restricts model selection.`, {
      display: 'system'
    });
    return;
  }

  if (model && isOpus1mUnavailable(model)) {
    onDone(`Opus 4.6 with 1M context is not available for your account...`, {
      display: 'system'
    });
    return;
  }

  if (model && isSonnet1mUnavailable(model)) {
    onDone(`Sonnet 4.6 with 1M context is not available for your account...`, {
      display: 'system'
    });
    return;
  }

  if (isKnownAlias(model)) {
    setModel(model);
    return;
  }

  const { valid, error } = await validateModel(model);
  if (valid) {
    setModel(model);
  } else {
    onDone(error || `Model '${model}' not found`, { display: 'system' });
  }
}

验证链路的优先级设计非常清晰:

  1. 组织级权限: isModelAllowed 检查企业/团队是否允许使用该模型。
  2. 账户级权限: isOpus1mUnavailable / isSonnet1mUnavailable 检查用户是否拥有 1M 上下文模型的访问权。
  3. 别名直通: isKnownAlias 检查是否为预定义别名(如 opussonnet),别名跳过格式验证以提高效率。
  4. 格式验证: validateModel 对自定义模型字符串进行远程或本地验证。

模式三:交互式选择器(无参数默认模式)

return <ModelPickerWrapper onDone={onDone} />;

ModelPickerWrapper 渲染完整的模型选择 UI,用户可以通过上下键浏览可用模型列表。选择器还会根据当前状态显示额外信息,例如:

  • Fast Mode 状态: 如果当前启用了 Fast Mode 且新模型支持该特性,会追加 "· Fast mode ON" 提示。
  • 计费提示: isBilledAsExtraUsage 检查新模型是否属于额外计费范畴,如果是则追加 "· Billed as extra usage" 警告。

6.3 状态同步机制

模型切换后,状态更新通过 useSetAppState 完成:

setAppState(prev => ({
  ...prev,
  mainLoopModel: modelValue,
  mainLoopModelForSession: null
}));

这里 mainLoopModelForSession 被显式设为 null,其目的是清除 plan mode 的会话级覆盖。在 Claude Code 的架构中,mainLoopModelForSession 允许 plan mode 临时指定一个不同于全局设置的模型;当用户通过 /model 手动切换时,这种临时覆盖应当被重置,以尊重用户的显式选择。


七、/login 与 /logout:认证流程与 Token 生命周期

/login/logout 是 Claude Code 认证体系的前端入口。虽然本次源码获取未能完整拉取这两个命令的实现文件,但基于命令系统的统一架构和 Claude Code 的已知行为,我们可以还原其设计逻辑。

7.1 /login 的认证流程

/login 命令的职责是建立用户与 Anthropic 服务之间的认证会话。典型的流程如下:

  1. 触发 OAuth 或 API Key 流程: 根据部署方式,/login 可能启动浏览器 OAuth 流程(重定向到 claude.ai/code/auth)或提示用户输入 API Key。
  2. Token 获取与存储: 认证成功后,获取到的 access token 或 API key 会被加密存储到本地配置目录(如 ~/.claude/)。
  3. 状态刷新: 调用 setAppState 更新认证状态,触发 UI 重绘(例如顶部的用户标识从"未登录"变为用户名)。
  4. 能力探测: 登录后,系统可能会自动查询用户的可用模型列表、配额信息和组织策略,为后续操作做准备。

从架构上看,/login 很可能也是一个 local-jsx 类型的命令,渲染一个认证引导面板,处理用户输入的 token 或 OAuth 回调。

7.2 /logout 的清理机制

/logout 的核心职责是安全地终结认证会话

  1. Token 清除: 从本地存储中删除 access token 和 refresh token。
  2. 状态重置: 将 AppState 中的用户信息、可用模型列表、配额缓存等全部重置为默认值。
  3. 网络侧注销: 如果支持,向 Anthropic 的注销端点发送请求,使服务端 token 失效(防止 token 被盗用后的持续访问)。
  4. UI 反馈: 向用户输出注销成功的确认信息,并提示重新登录的方法。

7.3 Token 管理的工程考量

Claude Code 的 Token 管理需要处理多个工程挑战:

  • 安全性: Token 不应以明文形式存储在磁盘上,至少需要经过系统级密钥链(macOS Keychain、Windows Credential Store、Linux Secret Service)加密。
  • 自动刷新: OAuth access token 通常有较短的有效期,/login 流程可能建立了后台刷新机制,在 token 即将过期时自动获取新的 access token。
  • 多账户切换: 虽然 /login/logout 看似是单账户设计,但底层状态结构如果支持数组形式的账户列表,未来可以无缝扩展为多账户切换功能。

八、命令之间的共性与差异

通过上述六个命令的源码分析,我们可以总结出 Claude Code 命令设计的几条核心原则:

设计原则体现
懒加载所有命令通过 load() 动态导入,减少启动开销
声明式注册Command 接口统一规范,新增命令只需导出对象
组件化 UIlocal-jsx 命令将交互逻辑委托给 React 组件,命令本身保持轻薄
状态集中管理通过 useAppState / useSetAppState 访问和修改全局状态
权限前置校验模型切换等敏感操作在 UI 展示前即完成权限验证
用户反馈闭环每个操作都有明确的 onDone 回调,输出可预测的结果信息

同时,这些命令也展现了不同的复杂度层级:

  • 简单命令(如 /theme/config):命令文件 < 30 行,纯粹是组件的"包装器"。
  • 中等命令(如 /help/logout):有独立的业务逻辑,但流程线性。
  • 复杂命令(如 /init/model):涉及多阶段交互、权限校验、状态联动和外部服务调用。

九、小结

本文从源码层面逐一解析了 Claude Code 的日常高频命令:

  • /init 通过七阶段流水线,将项目初始化从"一次性生成"升级为"对话式引导",体现了 AI 工具从"执行者"向"协作者"的演进。
  • /help 展示了声明式命令注册的优势——帮助信息从注册表中动态聚合,实现了"新增命令即自动展示"。
  • /config 通过 Settings 组件将配置管理 GUI 化,降低了用户的认知负担。
  • /theme 基于语义化颜色系统,支持终端 UI 的原子级主题切换。
  • /model 在模型选择中嵌入了多层权限校验和计费提示,是企业级产品安全设计的缩影。
  • /login / /logout 管理认证生命周期,是连接用户身份与 Claude Code 功能的桥梁。

这些命令共同构成了 Claude Code 的命令系统基础层。在下一篇《核心命令详解(下)》中,我们将继续剖析 git 相关命令(/commit/pr)、context 管理命令、以及 MCPskill 等高级功能命令的实现机制。