Claude Code 源码总架构分析

泄漏规模:1,884 个 TypeScript 文件 · 512,664 行代码 运行时:Bun · UI:React/Ink · API:@anthropic-ai/sdk


一句话定义

Claude Code 是一个 Tool-call 驱动的智能体循环系统。用户输入 → LLM 判断 → 调用工具 → 结果返回 LLM → 循环,直到 LLM 认为任务完成。


六大子系统关系图

┌─────────────────────────────────────────────────────────────┐
│                  01 · 入口层  main.tsx                       │
│  用户在终端输入  →  CLI 解析  →  React/Ink 渲染器             │
│  启动时并行预取:MDM | Keychain | API预连接 | 特性开关         │
└───────────────────────────┬─────────────────────────────────┘
                            │ 用户消息

┌─────────────────────────────────────────────────────────────┐
│               02 · 查询引擎  QueryEngine.ts                  │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  while(true) Tool-call 主循环                        │   │
│  │  压缩管道 → callModel → 工具执行 → 结果收集 → 检查    │   │
│  └─────────────────────────────────────────────────────┘   │
└────────┬──────────────┬──────────────┬──────────────────────┘
         │              │              │
         ▼              ▼              ▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ 03 · 工具系统│ │04 · 命令系统│ │05 · 权限系统│
│  tools/     │ │ commands/   │ │ hooks/      │
│  ~40 个工具  │ │  ~50 个命令  │ │ 4种权限模式 │
└──────┬──────┘ └─────────────┘ └─────────────┘


┌─────────────────────────────────────────────────────────────┐
│               06 · 多智能体协调  coordinator/                 │
│  子智能体生成(AgentTool) · 通信(SendMessageTool)           │
│  编排(AgentRegistry / MessageRouter / LifecycleManager)    │
└─────────────────────────────────────────────────────────────┘

技术栈一览

层面技术关键点
语言TypeScript 5.x strict运行时 Zod 校验配合静态类型
运行时Bun(非 Node.js)原生执行 TS,冷启动 <50ms,内置 SQLite
终端 UIReact 18 + Ink 4Virtual DOM diff → ANSI 控制序列,支持流式渲染
CLI 解析Commander.js子命令/选项/帮助生成
Schema 校验Zod v4工具输入参数运行时校验
API 客户端@anthropic-ai/sdk官方 SDK,流式 SSE
代码搜索ripgrepRust 实现,比 grep 快 10x
遥测OpenTelemetry + gRPC懒加载,不影响冷启动
特性开关GrowthBook + Bun bundle编译期消除,生产包中死代码物理消失

核心数据流

用户输入

processUserInput()     ← 斜杠命令拦截、@文件注入、记忆附件

recordTranscript()     ← 写 ~/.claude/sessions/<id>.jsonl(支持 /resume)

query() 主循环

[压缩检查] → [callModel SSE] → [工具并行执行] → [权限检查] → [结果收集]

needsFollowUp?
  是 → 追加 tool_result,继续循环
  否 → 生成最终结果,Ink 渲染输出

01 · 入口层 — main.tsx

文件:src/main.tsx(803K 行,含全部 React 组件) 职责:CLI 解析 · 并行预取 · React/Ink 渲染器初始化 · 会话启动

整体定位

入口层是用户与系统的第一接触点,做两件事:

  1. 解析用户意图:通过 Commander.js 将命令行参数转换为程序可理解的配置
  2. 搭建执行舞台:初始化 QueryEngine、注入工具/命令/权限配置,启动 React/Ink 渲染器进入交互循环

入口层本身不包含业务逻辑,是纯粹的组装层。

启动流程全景

用户执行 claude 命令


Commander.js 解析参数
  ├─ claude              → 交互模式(REPL)
  ├─ claude "prompt"     → 单次执行模式
  ├─ claude --resume     → 恢复上次会话
  ├─ claude --model xxx  → 指定模型
  └─ claude /cmd args    → 直接执行斜杠命令


并行预取阶段(关键性能优化)


组装 QueryEngineConfig


React/Ink 渲染器启动


进入交互循环(用户可输入)

并行预取优化

这是入口层最重要的工程设计,将串行启动变为并行,冷启动时间从 ~400ms 压缩到 ~100ms

启动瞬间,同时发起四个独立 I/O:

  ① MDM 配置读取
     企业管理设备(macOS Managed Device)的策略配置
     决定哪些功能被企业禁用、哪些服务器可访问

  ② macOS Keychain 预取
     读取存储在 Keychain 中的 API Key 和 OAuth Token
     避免首次请求时的 Keychain 弹窗延迟

  ③ Anthropic API 预连接
     提前建立 TCP 连接到 api.anthropic.com
     减少用户首次发送消息时的网络握手延迟

  ④ GrowthBook 特性开关初始化
     拉取当前账户的特性开关配置
     决定哪些实验性功能(VOICE_MODE、DAEMON 等)对本用户开启

React/Ink:为什么在终端用 React

Ink 是 React 的终端适配器,将组件树的 Virtual DOM diff 结果转换为 ANSI 转义序列输出到终端。

React 组件树
      ↓ Virtual DOM diff
Ink 渲染器
      ↓ 转换
ANSI 控制序列
      ↓ 输出
终端显示

核心价值:LLM 输出 token 时,只需 setState(prev => prev + newToken),React diff 自动计算最小变化,Ink 只更新终端中实际变化的部分,而不是重绘整个界面。

渲染层级:

<App>                          ← 顶层,持有 QueryEngine 引用
  <ConversationHistory />      ← 历史消息列表(滚动)
  <StreamingOutput />          ← 当前正在输出的内容(实时更新)
  <ToolExecutionStatus />      ← 工具执行状态(并行进度条)
  <PermissionPrompt />         ← 权限确认弹窗(阻塞式)
  <StatusBar />                ← 底部:模型名 / token 用量 / 成本
  <InputBox />                 ← 用户输入框
</App>

QueryEngineConfig 组装

入口层的核心职责是组装 QueryEngine 的完整配置(依赖注入):

QueryEngineConfig = {
  tools:       从 tools/ 目录加载的 ~40 个工具实例
  commands:    从 commands/ 目录加载的 ~50 个命令
  mcpClients:  从配置文件加载的 MCP 服务器连接
  skills:      从 ~/.claude/skills/ 动态加载的技能
  canUseTool:  权限检查回调(注入权限系统)
  model:       当前选择的模型(可被 --model 覆盖)
  maxTurns:    最大工具调用轮次(默认无限制)
  maxBudgetUsd:USD 成本上限(默认无限制)
}
原则体现
入口层只做组装不包含业务逻辑,只负责初始化和连接各子系统
并行优先所有无依赖的 I/O 操作并行发起
懒加载重模块OTel、gRPC 等通过动态 import() 按需加载
依赖注入工具集、权限逻辑、状态管理全部注入,不硬编码

02 · 查询引擎 — QueryEngine.ts

文件:src/services/QueryEngine.ts(46,630 行,系统最核心文件) 职责:LLM API 调用 · Tool-call 主循环 · 上下文压缩 · 错误恢复 · Token 计费

整体定位

QueryEngine 是整个 Claude Code 的中枢神经系统。所有其他子系统都服务于它——工具系统提供可调用的能力,权限系统提供安全约束,命令系统提供快捷操作。QueryEngine 本身只做一件事:

驱动 LLM 与工具之间的对话循环,直到任务完成。

Tool-call 主循环:一个 Turn 的六个阶段

Turn 开始

  ├─ Phase 1:上下文压缩检查
  │    检查当前消息历史是否接近 token 上限
  │    根据压力大小触发对应级别的压缩策略

  ├─ Phase 2:调用 LLM(流式)
  │    发送消息历史给 Claude API
  │    以 SSE 流的形式接收响应
  │    工具调用在流式输出期间并行启动(不等 LLM 完成)

  ├─ Phase 3:错误处理与恢复
  │    处理 prompt_too_long(触发压缩重试)
  │    处理 max_output_tokens(3级升级恢复策略)
  │    处理模型失败(降级到 fallbackModel)

  ├─ Phase 4:工具结果收集
  │    等待所有并行工具执行完成
  │    通过权限系统检查每个工具调用
  │    收集合法的工具结果

  ├─ Phase 5:附件注入
  │    从持久化记忆中读取相关记忆块
  │    动态发现并注入匹配的技能模板

  └─ Phase 6:轮次与预算检查
       turnCount++
       是否超过 maxTurns?→ 停止
       是否超过 maxBudgetUsd?→ 停止
       needsFollowUp?→ 继续 or 退出

流式并行工具执行

Claude Code 在 LLM 仍在流式输出时,已经开始执行工具了:

传统串行(浪费等待时间):
  [──── LLM 输出 50ms ────][工具A 30ms][工具B 20ms]  = 100ms

Claude Code 并行(重叠执行):
  [──── LLM 输出 50ms ────]
            [──工具A 30ms──]     (LLM 输出到一半就开始了)
            [──工具B 20ms─]
  总计 = max(50, 50+20) = 70ms   省了 30%

5 级上下文压缩管道

上下文使用率

100% ─── API 拒绝边界 ──────────────────────────────────
 95% ─── Level 5: Autocompact ──────────────────────────
         触发完整会话摘要,用摘要替换全部历史消息

 85% ─── Level 4: Context Collapse ─────────────────────
         折叠早期多轮对话为一个摘要块

 70% ─── Level 3: Microcompact ─────────────────────────
         针对重复文件编辑去重,删除中间状态

 55% ─── Level 2: Snip Compact ─────────────────────────
         删除最旧的若干轮消息

  0% ─── Level 1: 内容替换(始终运行)────────────────────
         裁剪超过阈值的单条工具结果(如巨大的 bash 输出)
级别信息损失速度适用场景
1 · 内容替换最小(仅截断单条超大输出)即时任何时候
2 · Snip丢失旧历史历史不重要时
3 · Microcompact丢失文件编辑中间状态大量文件操作后
4 · Collapse历史细节折叠为摘要中(需调用 LLM)早期对话不再相关
5 · Autocompact全历史替换为摘要慢(需调用 LLM)必要时的最后手段

3 级输出恢复策略

LLM 输出被截断(stop_reason: max_tokens)时:

首次遇到截断
  → Slot 升级:将输出 token 上限从 8k 提升到 64k
  → 若仍截断,进入多轮续写(最多 3 次)
  → 3 次均失败 → 返回已完成的部分,标记错误

模型降级与孤儿清理

当主模型在流式输出中途崩溃,消息历史会出现”孤儿”tool_use。修复方式(Tombstone 模式):

原始(非法):
  assistant: { tool_use: { id: 'X', name: 'BashTool' } }
  (缺少对应 tool_result)

修复后(合法):
  assistant: { tool_use: { id: 'X', name: 'BashTool' } }
  user:      { tool_result: { id: 'X', is_error: true, content: '[interrupted]' } }
  → 切换到 fallbackModel 重试

03 · 工具系统 — tools/

目录:src/tools/(约 40 个工具) 职责:为 LLM 提供与真实世界交互的能力,每个工具是自包含的独立模块

统一工具接口

每个工具必须提供:

  name              工具名称(LLM 用这个名字调用它)
  description       自然语言描述(LLM 通过这段描述决定何时使用它)
  inputSchema       输入参数定义(Zod Schema,运行时校验)
  execute()         实际执行逻辑
  requiresPermission() 是否需要用户确认
  permissionDescription() 权限提示文案

工具分类详解

第一类:文件操作(4 个核心工具)

FileReadTool     → 先读(了解现状)

FileEditTool     → 精确改(最常用,old_string → new_string)
FileWriteTool    → 全量写(新建或完全重写)
BashTool         → 批量操作(mv、cp、mkdir 等)

FileEditTool 的核心约束:必须先用 FileReadTool 读取文件,才能编辑

第二类:搜索(4 个工具)

工具功能特点
GlobTool文件路径模式匹配按修改时间排序,无需权限
GrepTool内容搜索基于 ripgrep,比 grep 快 10x
WebSearchTool网络搜索返回摘要 + URL 列表
WebFetchTool网页内容抓取自动转 Markdown,支持 maxLength

第三类:智能体(2 个工具)

  • AgentTool — 创建独立 Bun 子进程,运行完整 QueryEngine,执行子任务
  • SendMessageTool — 向已创建的子智能体发送消息(同步/异步两种模式)

第四类:任务管理(6 个工具)

任务状态流转:pending → in_progress → completed / cancelled

TaskCreate / TaskUpdate / TaskList / TaskGet / TaskOutput / TaskStop

第五类:协议集成(2 个工具)

  • MCPTool — 动态代理调用任何已连接的 MCP 服务端工具
  • LSPTool — 连接本地语言服务器,提供跳转定义、查找引用等 IDE 能力

第六类:模式控制(4 个工具)

  • EnterPlanModeTool / ExitPlanModeTool — 计划模式(只读自动批准,写操作只展示计划)
  • EnterWorktreeTool / ExitWorktreeTool — Git Worktree 沙箱模式

第七类:笔记本(2 个工具)

  • NotebookReadTool — 读取 .ipynb 格式,返回代码 + 执行输出
  • NotebookEditTool — 修改指定单元格,不重写整个 notebook

工具的权限声明

低权限工具(自动批准):
  GlobTool, GrepTool, FileReadTool, WebSearchTool
  → 只读,不改变任何状态

中权限工具(默认模式下需确认):
  FileWriteTool, FileEditTool, AgentTool
  → 有持久副作用,但可预期

高权限工具(每次必须确认):
  BashTool
  → 可能执行任意命令,风险不可预测

04 · 命令系统 — commands/

目录:src/commands/(约 50 个斜杠命令) 职责:用户通过 /command 触发,直接执行,不经过 LLM

命令的拦截时机

用户输入 "/compact"

processUserInput() 检测到以 "/" 开头

查找 commands/ 目录中匹配的命令处理器

直接执行,不送入 QueryEngine 主循环

工具 vs 命令:本质区别

工具(tools/):
  调用方:LLM(通过 tool_use API)
  触发逻辑:LLM 根据理解决定何时调用
  典型例子:BashTool, FileReadTool, GrepTool

命令(commands/):
  调用方:用户(通过 /command 语法)
  触发逻辑:用户显式触发
  典型例子:/commit, /compact, /cost

工具是 Claude 的双手,Claude 决定何时伸手;命令是遥控器上的按钮,用户决定何时按下。

命令分类详解

第一类:Git 工作流命令

命令功能
/commit读取 git diff --staged → LLM 生成 commit message → 用户确认 → 执行
/commit-push-pr一键 commit + push + 创建 PR(PR 描述由 LLM 自动生成)
/pr仅创建 PR,分析 git diff main...HEAD 生成标准描述

第二类:代码质量命令

  • /review — AI 审查,输出结构化报告(问题点、严重程度、建议)
  • /ultrareview — 多维度深度审查(安全性、性能、可维护性、逻辑正确性)
  • /autofix-pr — 自动识别问题 → 生成修复 → 创建 PR

第三类:上下文管理命令

/context    → 查看现状(消息数、Token 用量、压缩历史)
/compact    → 历史太多,但想保留语义(触发 Level 5 Autocompact)
/clear      → 完全换话题,彻底丢弃历史

第四类:配置与集成命令

  • /config — 运行时配置(切换模型、修改 maxTurns、开关 thinking 模式)
  • /mcp — 管理 MCP 服务器连接(list/add/remove/restart)
  • /memory — 查看和管理持久化记忆
  • /permissions — 查看当前权限配置和白名单

第五类:会话管理命令

  • /resume — 恢复历史会话(读取 .jsonl 文件重建消息历史)
  • /cost — 显示完整成本分析(含子智能体成本)
  • /status — 系统状态快照(Turn 数、活跃子智能体、任务队列)

第六类:技能命令(动态扩展)

~/.claude/skills/
  ├── review-security.md    → 触发 /review-security
  ├── generate-tests.md     → 触发 /generate-tests
  └── refactor-to-ts.md     → 触发 /refactor-to-ts

技能文件触发后,模板内容被注入为系统附件,引导 LLM 行为(而非直接执行逻辑)。


05 · 权限系统 — hooks/toolPermission/

目录:src/hooks/toolPermission/ 职责:在每次工具执行前进行安全检查,决定是否允许执行

四种权限模式

模式适用场景行为自动化程度
default日常开发危险操作弹出确认提示最低
plan只读分析读操作自动批准,写操作展示计划不执行
auto批量处理分类器评估风险,低风险自动批准
bypassPermissionsCI/CD 流水线跳过所有权限检查最高

wrappedCanUseTool:完整决策流程

工具调用请求到达

[检查 1] bypassPermissions 模式? 是 → 直接批准

[检查 2] 命中永久批准白名单? 是 → 直接批准

[检查 3] plan 模式?
        是,只读工具 → 批准
        是,写入工具 → 展示计划,不执行

[检查 4] auto 模式?
        是 → 分类器评估:低风险 → 批准,高风险 → 降级为 default

[检查 5] default 模式:显示交互式确认
        批准(本次)→ 执行
        批准(始终)→ 执行 + 加入永久白名单
        拒绝        → 记录到 permissionDenials[]

永久批准白名单

存储:~/.claude/approvals.json
结构:Map<toolName, Set<serializedInput>>

示例:
{
  "BashTool": ["npm test", "npm run build", "git status"],
  "FileWriteTool": ["/project/src/utils.ts"],
}

白名单是精确匹配的,npm test 不会覆盖 npm test --watch

auto 模式的风险分类器

评估维度:

工具类型
  只读工具(Glob, Grep, FileRead)     → 低风险
  写入工具(FileWrite, FileEdit)      → 中等风险
  执行工具(BashTool)                → 高风险(默认)

参数内容分析(仅 BashTool)
  rm -rf ...    → 极高风险
  sudo ...      → 高风险
  curl | bash   → 极高风险
  git status    → 低风险
  npm test      → 低风险

目录范围:超出 allowedDirectories → 风险升级一级

权限与 QueryEngine 的解耦

权限逻辑通过回调注入,QueryEngine 不知道实现细节:

// QueryEngineConfig 中:
canUseTool: (tool, input) => Promise<boolean>

// 这意味着:
// 测试时注入永远返回 true 的假权限函数
// 不同环境(CLI、IDE、CI)注入不同的权限逻辑

06 · 多智能体协调 — coordinator/

目录:src/coordinator/ · src/tools/AgentTool/ · src/tools/SendMessageTool/ 职责:子智能体生成、智能体间通信、生命周期编排

架构全景

主智能体(Root Agent)
  QueryEngine 主循环
  mutableMessages(主上下文)
  totalUsage(汇总全树成本)

        │ 调用 AgentTool

┌──────────────── coordinator ─────────────────┐
│  AgentRegistry      注册表,id → 进程句柄     │
│  LifecycleManager   进程创建/监控/回收        │
│  MessageRouter      SendMessageTool 消息路由  │
│  SharedStateProxy   只读状态共享              │
└──────┬───────────────────────┬───────────────┘
       │                       │
       ▼                       ▼
子智能体 A(Bun 进程)    子智能体 B(Bun 进程)
独立 QueryEngine          独立 QueryEngine
独立消息历史              独立消息历史
受限工具集                受限工具集

为什么选择进程而非线程

进程方案(Claude Code 采用)的优势:
  每个子智能体 = 独立 Bun 子进程
  → 内存天然隔离,无需加锁
  → 子进程崩溃不影响主进程
  → OS 可对进程设置 CPU/内存上限
  → 可以真正并行利用多核 CPU

工具集的继承与限制

子智能体的工具集由父级显式注入,遵循最小权限原则:

父级创建子智能体时指定:
  tools: ['GlobTool', 'GrepTool', 'FileReadTool']

子智能体:
  GlobTool ✓   GrepTool ✓   FileReadTool ✓
  BashTool ✗   FileWriteTool ✗   AgentTool ✗

嵌套深度限制:最多 3 级嵌套。第 3 级时强制移除 AgentTool,防止无限递归。

智能体间通信:SendMessageTool

所有通信都经过 coordinator,智能体之间不直接引用对方:

智能体 A 调用 SendMessageTool(to='agent_B_id', message='...')
  → coordinator.MessageRouter 接收
  → 查询 AgentRegistry,找到 agent_B 的进程句柄
  → 将消息写入 agent_B 的 stdin
  → agent_B 的 LLM 处理,响应流回 coordinator
  → coordinator 将响应作为 tool_result 返回给智能体 A

特殊路由目标:

  • to='__parent__' — 发送给父智能体
  • to='*' — 广播给所有同级智能体
  • to='agent_xxx_id' — 精确点对点

三种执行模式

串行分解模式:

主智能体 → 子A(扫描结构)→ 子B(分析依赖)→ 子C(生成报告)

并行扇出模式:

主智能体 → 子A(审查模块1)  ┐
         → 子B(审查模块2)  ├→ 汇总
         → 子C(审查模块3)  ┘
总时间 ≈ 最慢的那个,而非 3 个之和

层级委托模式:

主智能体:"重构整个代码库"
  → 子A:"重构 frontend"
      → 子-子A1:"重构组件"
      → 子-子A2:"重构样式"
  → 子B:"重构 backend"

Token 与成本的全树追踪

/cost 显示的是"全树"成本:

  总成本:$0.127
    主智能体自身:         $0.031
    子智能体 A(含子树):  $0.063
    子智能体 B:           $0.033

故障隔离与容错

子智能体崩溃时:
  LifecycleManager 检测到异常退出
  → AgentTool 收到失败结果
  → 向主 QueryEngine 返回 error tool_result
  → 主 LLM 决策:重试 / 降级 / 向用户说明
  → 主智能体继续运行(完全不受影响)

心跳检测:每 10 秒一次,5 秒无响应判定死亡进程,强制清理,防止僵尸进程。