一、引言:一次意外的源码曝光
2026年3月31日,安全研究者 @Fried_rice 发现 Claude Code 的 npm 发布包中残留了 .map 文件(Source Map),该文件指向了 Anthropic 存储在 R2 桶中的未混淆 TypeScript 源码。这一构建产物泄露事件,让我们得以窥见这款当前最热门 AI 编程 CLI 工具的完整内部实现。
声明:本文基于公开可获取的源码快照进行纯技术架构分析,仅用于学习和研究目的。
本文导读
- 先建立全局认知:第二节先用一张总览图,把 Claude Code 的 CLI 入口、QueryEngine、工具系统、Bridge 与权限/插件体系串起来。
- 再抓主执行链路:第三到第六节依次拆解启动流程、Agentic Loop、工具系统与权限系统,这是 Claude Code 最核心的工程主线。
- 最后看扩展能力:第八到第十二节重点分析终端 UI、IDE Bridge、多 Agent 协作以及插件/技能系统。
- 适合阅读人群:如果你关心 AI Coding Agent、终端 UI、权限治理或 CLI 工程化,这篇文章会比较有参考价值。
项目概貌
| 指标 | 数据 |
|---|---|
| 语言 | TypeScript (strict mode) |
| 运行时 | Bun |
| 终端 UI | React + Ink (深度定制 fork) |
| 工程特征 | 多模块分层、强工具化、重状态管理 |
| CLI 解析 | Commander.js (extra-typings) |
| Schema 验证 | Zod v4 |
| 代码搜索 | ripgrep |
| 协议支持 | MCP SDK, LSP |
| 遥测 | OpenTelemetry + gRPC |
| 特性开关 | GrowthBook |
| 认证 | OAuth 2.0, JWT, macOS Keychain |
二、整体架构概览
如果你只想先建立 Claude Code 的整体心智模型,先看下面这张总览图。
看图重点:从上到下依次是 CLI 入口、REPL 终端 UI、QueryEngine、工具系统,以及命令/服务/Bridge 三组外围能力;最底层则是状态、权限、插件与技能这些基础支撑层。
2.1 高层架构
Claude Code 的架构可以分为以下核心层次:
- CLI 入口层:
main.tsx基于 Commander.js 完成参数解析、命令路由和启动编排。 - 交互层:
REPL+ 自定义Ink渲染器负责终端 UI、消息流和输入体验。 - 推理层:
QueryEngine负责上下文组装、模型调用、流式输出与工具调用循环。 - 执行层:40+ 工具组成 Claude Code 的动作面,包括文件读写、命令执行、搜索、网络访问和 Agent 调度。
- 外围能力层:命令系统、服务层和 Bridge 共同提供 CLI 工作流、外部集成与 IDE 协作能力。
- 基础支撑层:状态管理、权限系统、插件系统与技能系统构成整套运行时底座。
2.2 目录结构
src/
├── main.tsx # 入口编排 (Commander.js CLI)
├── commands.ts # 命令注册中心
├── tools.ts # 工具注册中心
├── Tool.ts # 工具类型定义
├── QueryEngine.ts # LLM 查询引擎核心
├── context.ts # 系统/用户上下文收集
├── cost-tracker.ts # Token 费用追踪
│
├── commands/ # 斜杠命令实现
├── tools/ # Agent 工具实现
├── components/ # Ink UI 组件
├── hooks/ # React Hooks
├── services/ # 外部服务集成
├── screens/ # 全屏 UI (Doctor, REPL, Resume)
├── utils/ # 工具函数库
│
├── bridge/ # IDE 远程控制桥接
├── coordinator/ # 多 Agent 协调器
├── plugins/ # 插件系统
├── skills/ # 技能系统
├── keybindings/ # 快捷键配置
├── vim/ # Vim 模式
├── voice/ # 语音输入
├── remote/ # 远程会话
├── memdir/ # 持久化记忆目录
├── tasks/ # 后台任务管理
├── state/ # 全局状态管理
├── ink/ # Ink 渲染器深度定制 Fork
└── entrypoints/ # 各种入口点逻辑
三、启动流程深度剖析
启动链路是理解 Claude Code 性能优化思路的最好切口,下面这张图把主流程压缩成了四个阶段。
看图重点:真正影响冷启动体验的,不只是
main.tsx本身,而是它在重量级模块评估之前就并行发起了配置预读、Keychain 预取和 API 预连接。
3.1 入口点:main.tsx
main.tsx 是整个应用的启动编排入口,它承担了:
- Commander.js CLI 解析:定义所有命令行参数和子命令
- 并行预取优化:在模块加载之前就开始预取关键数据
- React/Ink 渲染器初始化:启动终端 UI
把这条链路拆开来看,可以进一步归纳为四个启动阶段:
- 并行预取阶段:提前触发
startMdmRawRead()、startKeychainPrefetch()和apiPreconnect(),把耗时 I/O 往前挪。 - CLI 解析阶段:通过
program.option()和program.action()完成参数定义、命令路由与入口分发。 - 环境引导阶段:进入
bootstrap/state.ts,加载配置、认证状态、GrowthBook 特性开关和 MCP 连接。 - 终端渲染阶段:最终执行
render(<App />),把运行时状态装配到 REPL 主界面上。
并行预取是 Claude Code 的一个重要性能优化模式。在任何重量级模块被评估之前,就已经通过副作用启动了 MDM 设置读取、Keychain 预取和 API 预连接:
// main.tsx — 在其他 import 之前作为副作用触发
startMdmRawRead()
startKeychainPrefetch()
3.2 环境引导:bootstrap/state.ts
bootstrap/state.ts 更像一个“启动状态机”,核心不是简单加载配置,而是把信任建立、环境生效和外部依赖初始化排成一条有先后顺序的链路:
- 先启用配置系统:打开多层配置解析能力,但在信任建立前只应用“安全环境变量”。
- 尽早处理 TLS 前置条件:例如把
NODE_EXTRA_CA_CERTS这类证书配置提前注入进程环境,避免首次握手后再改配置失效。 - 异步预热非关键能力:如一方事件日志、OAuth 账户信息、JetBrains 检测、仓库识别、远程设置加载 Promise,尽量不阻塞首屏。
- 收拢运行时状态:在真正进入 REPL 前,把认证状态、GrowthBook 特性开关、MCP 连接和权限模式统一收敛到可消费状态。
3.3 延迟加载策略
重量级模块(OpenTelemetry、gRPC、分析引擎、特性门控子系统)通过动态 import() 延迟到实际需要时才加载:
// 条件加载示例
import { feature } from 'bun:bundle'
const voiceCommand = feature('VOICE_MODE')
? require('./commands/voice/index.js').default
: null
已知的特性开关包括:PROACTIVE、KAIROS、BRIDGE_MODE、DAEMON、VOICE_MODE、AGENT_TRIGGERS、MONITOR_TOOL。这些开关通过 Bun 的 bun:bundle 实现编译时死代码消除,未激活的功能代码会在构建时被完全剥离。
四、查询引擎:QueryEngine.ts
4.1 核心职责
QueryEngine.ts 是 Claude Code 与 LLM 交互的核心引擎,处理:
- 接收输入:读取用户消息,并准备本轮推理所需的上下文。
- 组装上下文:把
context.ts、CLAUDE.md规则、memdir记忆、MCP 资源等拼进请求体。 - 调用模型:通过
services/api/claude.ts发起流式 API 请求,并处理 thinking mode、prompt cache、重试和错误恢复。 - 分叉处理结果:如果返回的是文本,就直接渲染到终端;如果返回的是工具调用,就进入权限检查、执行工具、结果回灌,再继续下一轮推理。
4.2 工具调用循环(Agentic Loop)
在 Claude Code 里,真正把“聊天”变成“编程代理”的,并不是模型本身,而是下面这个持续运转的执行循环。
看图重点:一次看似简单的对话,底层往往会经历“模型输出 → 工具执行 → 结果回灌 → 再次推理”的多轮迭代,直到产出最终文本结果。
这是 Claude Code 最核心的机制 — 工具调用循环(也称 Agentic Loop):
- 将用户消息 + 系统提示 + 对话历史发送给 Claude API。
- 如果 Claude 返回工具调用请求(如
BashTool、FileEditTool):- 先检查该工具是否真的可用,以及当前输入是否通过权限与安全校验。
- 再根据工具特性决定并发执行还是串行执行:只读、可并发的调用会被批量调度;带副作用的调用则按顺序执行,避免上下文互相污染。
- 工具执行过程中,结果消息与上下文修改器会被持续收集,并在合适时机回写到消息历史与运行时上下文。
- 工具结果回灌后,重新调用 API,形成下一轮推理。
- 如果 Claude 返回纯文本响应,循环结束。
4.3 API 客户端:services/api/claude.ts
这是与 Anthropic API 通信的核心客户端,它的实现重点不在“把请求发出去”,而在于把模型调用改造成可恢复、可缓存、可观测的运行链路:
- 流式响应处理:逐 token 接收并实时渲染,让终端交互具有持续反馈感。
- Prompt Cache 感知:通过
promptCacheBreakDetection.ts识别哪些上下文变动会打断缓存命中,从而减少无谓的重复计算。 - 重试与恢复:
withRetry.ts负责指数退避与失败恢复,把瞬时网络问题从“整轮失败”降成“局部重试”。 - 错误分层:
errors.ts区分限流、认证失败、网络错误等异常类型,避免所有失败都落到同一套处理路径里。 - 预算控制:
tokenEstimation.ts在请求发出前做 token 估算,让上下文裁剪和模型选择更可控。
4.4 上下文压缩:services/compact/
当对话上下文过长时,Claude Code 有一套精密的压缩机制:
compact/
├── compact.ts # 核心压缩逻辑
├── autoCompact.ts # 自动压缩触发器
├── microCompact.ts # 微压缩 — 轻量级摘要
├── apiMicrocompact.ts # API 级微压缩
├── sessionMemoryCompact.ts # 会话记忆压缩
├── prompt.ts # 压缩提示词
└── grouping.ts # 消息分组策略
压缩流程:对话历史 → 分组 → 生成摘要 → 替换原始消息 → 保留关键上下文。用户可通过 /compact 命令手动触发。
五、工具系统深度解析
工具系统决定了 Claude Code 能做什么,也决定了它为什么能从“回答问题”走向“直接改代码”。
看图重点:可以把工具看作 QueryEngine 的“手脚”,其中
BashTool、FileEditTool与AgentTool分别对应命令执行、文件修改和多 Agent 协作三类关键能力。
5.1 工具架构
每个工具都是一个自包含模块,但它们并不是一堆平铺的脚本,而是共享同一套运行时约定:
- 输入层:每个工具都通过 Zod Schema 声明输入边界,先做结构校验,再进入执行逻辑。
- 权限层:工具既可以复用统一权限管线,也可以在自身实现里追加更细粒度的安全判断。
- 执行层:真正的执行逻辑与 UI 展示分离,方便在终端、IDE 桥接层和自动模式之间复用。
- 上下文层:工具不仅返回结果消息,还可能回写上下文修改器,影响后续轮次的可见状态。
从职责上看,工具目录里最关键的几类实现包括:
BashTool/:负责 shell 命令执行,同时内置命令语义分析、权限规则、路径校验和沙箱策略。FileEditTool/:负责局部文件修改,核心难点在于字符串替换、diff 展示和编辑安全边界。AgentTool/:负责生成和调度子 Agent,把复杂任务拆成可并行或可验证的子问题。- 其他基础工具:包括文件读取、写入、搜索、网络获取、LSP 集成、MCP 调用、计划模式与任务列表管理等。
5.2 Tool 基类型:Tool.ts
Tool.ts 定义了所有工具共享的抽象接口,核心包括:
- 输入 Schema:约束模型传入的数据结构。
- 权限模型:声明哪些操作需要用户批准、哪些操作可自动放行。
- 执行入口:把工具输入映射为实际行为。
- 进度状态:让终端与 IDE 能持续展示工具执行状态。
- UI 组件:让工具结果不只是文本,还能带有差异视图、进度条或结构化展示。
5.3 关键工具类型
| 工具 | 作用 | 实现重点 |
|---|---|---|
| BashTool | Shell 命令执行 | 命令安全分析、规则匹配、路径校验、沙箱执行 |
| FileReadTool | 文件读取 | 支持文本、图片、PDF、Notebook 等多种输入 |
| FileWriteTool | 文件创建/覆盖 | 负责一次性写入和落盘边界控制 |
| FileEditTool | 局部文件修改 | 基于字符串替换与 diff 展示实现最小改动 |
| GlobTool / GrepTool | 文件和内容搜索 | 为模型提供低成本、高命中率的代码检索能力 |
| WebFetchTool / WebSearchTool | Web 获取 | 连接外部文档与实时信息源 |
| AgentTool | 子 Agent 调度 | 任务拆解、上下文隔离、结果汇总 |
| SkillTool / MCPTool / LSPTool | 外部能力扩展 | 把技能、MCP 服务和语言服务统一接入工具层 |
| TodoWriteTool / TeamCreateTool / SendMessageTool | 协作编排 | 支撑多 Agent 协作、任务追踪和消息传递 |
5.4 BashTool 安全机制深度分析
如果说 Claude Code 的工程壁垒在哪里,BashTool 的安全设计大概率是最有代表性的一个点。
看图重点:这不是单点拦截,而是“命令分析 + 权限规则 + 只读判定 + 路径校验 + Sandbox”叠加起来的组合防线。
BashTool 是 Claude Code 中实现最重、边界最多的工具之一,其安全机制值得单独分析:
- Layer 1 —
bashSecurity.ts:负责命令黑名单检测、危险模式识别、网络操作审计,以及密码/密钥相关操作拦截。 - Layer 2 —
bashPermissions.ts:负责基于规则的权限匹配、路径白名单/黑名单校验、只读操作自动批准,以及危险操作的显式确认。 - Layer 3 —
readOnlyValidation.ts:从命令语义、参数副作用和环境变量修改三个角度判断这次调用是否真的“只读”。 - Layer 4 —
pathValidation.ts:负责工作区边界检查、符号链接跟随检测,以及~/.ssh、/etc/passwd这类敏感路径保护。 - Layer 5 —
sedValidation.ts:专门处理sed这类内联编辑命令的解析与验证,防止“看起来像读操作,实际上带写入”的绕过场景。
此外还有 Sandbox 模式(shouldUseSandbox.ts),可以在容器化环境中执行不可信命令。
5.5 AgentTool:子 Agent 生成
AgentTool 是实现多 Agent 协作的核心工具:
它的运行模型可以概括成三层:
- 主 Agent:直接与用户交互,负责拆分任务、下发子任务和汇总结果。
- 子 Agent:按目标拿到不同工具集,例如只读探索型 Agent 更偏向
Read/Grep,执行型 Agent 更偏向Bash。 - 结果回流层:子 Agent 完成工作后把结果回传给主 Agent,再由主 Agent 生成最终答复或继续调度下一轮任务。
内置 Agent 类型:
- exploreAgent:专门用于代码库探索,只配备只读工具
- planAgent:专注于制定执行计划
- verificationAgent:验证代码变更的正确性
- generalPurposeAgent:通用子 Agent
六、权限系统
Claude Code 真正难做的不是“能不能调用工具”,而是“调用工具时如何把风险控制在工程上可接受的范围内”。
看图重点:这里不是简单的弹窗确认,而是把
bypassPermissions、auto、plan、default四种模式与规则匹配、YOLO 分类器和用户确认机制编排成一条完整决策链。
6.1 权限模式
Claude Code 实现了一个精密的分层权限系统:
bypassPermissions:跳过所有确认,直接执行,适合完全受信任环境。auto(YOLO 模式):交给yoloClassifier.ts自动判断当前操作是安全还是危险。plan:先提交计划,待用户审批后再执行。default:每次工具调用都要经过用户确认。
6.2 权限规则引擎
权限规则存储在 .claude/settings.json 中,支持:
- 工具级规则:针对特定工具(如 BashTool)设置策略
- 路径级规则:针对特定目录/文件设置读写权限
- 命令级规则:针对特定 shell 命令设置允许/拒绝
- Glob 匹配:支持通配符路径模式
权限决策流程可以概括为五步:
- 接收工具调用请求:先判断当前会话运行在哪种
PermissionMode下。 - 检查显式规则:优先匹配
.claude/settings.json中已有的 allow/deny 规则。 - 快速放行特殊模式:如果是
bypassPermissions,则直接跳过确认流程。 - 进入自动判断或人工确认:在
auto模式下交给 YOLO 分类器评估风险;若不满足自动批准条件,则弹出确认对话框。 - 执行工具:只有在规则、分类器或用户确认三者之一给出“允许”之后,工具才会真正执行。
6.3 YOLO 分类器
yoloClassifier.ts 实现了 auto 模式下的命令安全分类器。它的关键价值不只是“替用户点一次允许”,而是把规则系统、上下文状态和历史拒绝信息一起纳入判断:
- 命令语义:区分读操作、写操作和执行操作。
- 操作范围:区分单文件修改和全局性动作。
- 路径敏感度:区分项目内路径与系统目录、敏感目录。
- 历史批准模式:结合已有拒绝/允许历史,避免在连续高风险场景下过度乐观。
- 规则净化:在进入
auto模式前,系统还会主动剥离那些可能绕过分类器的危险 allow 规则,避免“规则先放行、分类器失效”的情况。
七、命令系统
7.1 命令注册:commands.ts
所有斜杠命令通过 commands.ts 注册和管理,支持条件加载。按职责来看,大致可以分成五类:
- 开发工作流:
/commit、/review、/diff、/branch、/plan - 上下文管理:
/compact、/context、/memory、/resume、/files - 系统配置:
/config、/model、/theme、/vim、/permissions - 扩展集成:
/mcp、/skills、/plugin、/hooks、/agents - 运维诊断:
/doctor、/cost、/stats、/login、/export
7.2 特色命令:ultraplan
ultraplan.tsx 本质上不是一个“在本地生成计划”的普通命令,而是把复杂任务切到远端 plan mode 的调度器。它的实现链路大致分成四步:
- 前置校验:先通过
checkRemoteAgentEligibility()检查远端执行资格,避免在登录态、策略或环境不满足时盲目启动。 - 远端建会话:调用
teleportToRemote({ permissionMode: 'plan', ultraplan: true }),把当前任务描述和可选seedPlan打包发到 Claude Code on the web。 - 本地注册后台任务:成功建会话后,本地立即注册
RemoteAgentTask,并用startDetachedPoll()在后台轮询远端状态。 - 扫描审批结果:轮询逻辑最终进入
pollForApprovedExitPlanMode(),从远端事件流里识别ExitPlanMode的tool_use / tool_result,再根据结果分成两条路径:- 用户选择继续在 web 端执行:本地只负责跟踪状态,远端继续编码。
- 用户选择teleport 回终端:通过
ULTRAPLAN_TELEPORT_SENTINEL把批准后的计划回传本地,再由 REPL 弹层接管后续动作。
所以,ultraplan 真正有意思的地方不在“计划文本长不长”,而在它把远程规划、人工审批、执行位置切换做成了一套可恢复的状态机。
7.3 特色命令:insights
insights.ts 也不是一个简单的“统计报表命令”,而是一条先离线聚合,再用模型做结构化解释的数据分析流水线:
- 轻量扫描阶段:
scanAllSessions()先扫本地会话目录,只读取文件系统元数据,不急着解析整份日志。 - 缓存优先阶段:优先命中
loadCachedSessionMeta()/loadCachedFacets(),只对未命中的会话批量解析jsonl,降低首次分析以外的重复成本。 - 数据净化阶段:过滤
/insights自己生成的 meta-session,并按session_id去重 conversation branches,避免同一会话分叉把统计结果放大。 - 结构化洞察阶段:将会话聚合数据、facet 摘要、friction 细节和用户指令拼成
fullContext,再用Promise.all(...)并行生成多个 section 的 JSON 结果。 - 报告输出阶段:最终把结构化结果渲染成 HTML,并写入
report.html,而不是只在终端吐一段文本。
这说明 insights 的重点并非“统计了多少字段”,而是把会话扫描、缓存利用、特征提取、模型归纳和报告生成串成了一条完整分析链路。
八、终端 UI 系统:React + Ink 深度定制
很多人第一次看到 Claude Code,都容易把它理解成“一个命令行聊天壳”;但从 UI 实现上看,它其实更像一套运行在终端里的轻量 IDE。
看图重点:最上层是
REPL.tsx主界面,中间是输入、消息、状态与设计系统,最底层则是 Anthropic 深度改造过的 Ink 渲染栈和终端 I/O 抽象。
8.1 自定义 Ink Fork
Claude Code 没有直接把社区版 Ink 当黑盒来用,而是维护了一套 深度定制 Fork。从源码看,它主要补了六类能力:
- 渲染主干:
ink/ink.tsx和render-node-to-output.ts负责终端节点树到字符缓冲区的落地过程。 - 屏幕控制:
ink/screen.ts、ink/selection.ts让终端界面具备更强的屏幕管理与文本选择能力。 - 组件重写:
App.tsx、ScrollBox.tsx、Button.tsx、Text.tsx等高频组件都做了终端场景适配。 - 事件系统:
click-event.ts、keyboard-event.ts、terminal-focus-event.ts把鼠标、键盘和焦点事件统一成可消费的输入模型。 - 终端协议处理:
parser.ts、tokenize.ts、sgr.ts、csi.ts、osc.ts负责 ANSI/CSI/OSC 等序列解析。 - 布局系统:
ink/layout/yoga.ts把 Flexbox 风格布局迁移到了终端字符坐标系里。
8.2 REPL 主界面:screens/REPL.tsx
如果只看产品形态,REPL.tsx 像“聊天主屏”;但从实现上看,它更像 Claude Code 的终端运行时容器。
- 消息状态编排:
messagesRef + setMessages()采用 eager apply 方式,确保 React 状态尚未完成渲染时,逻辑层也能立即读到最新消息数组。 - 历史按需加载:
useAssistantHistory()在滚动上翻时才加载更旧历史,而不是一开始把全部消息塞进内存。 - Hook 延迟注入:
useDeferredHookMessages()允许 REPL 先渲染,再把 SessionStart hook 结果补进消息流,同时保证首次真正发起query()前这些上下文已经到位。 - 查询流消费:
onQueryImpl()组装systemPrompt、userContext、toolUseContext,随后for await ... of query(...)持续消费模型输出与工具事件。 - 并发守卫:
QueryGuard让 REPL 能在已有轮次运行时拦截并排队新的用户输入,避免多轮推理并发污染同一份状态。 - 弹层与工作流汇合点:权限确认、MCP elicitation、
ultraplan启动/回传选择、退出流程等都由同一套focusedInputDialog/ overlay 机制统一驱动。 - 桥接入口:
useReplBridge()把远程控制、权限回执、中断信号和会话状态同步接到 REPL 主循环上。
8.3 关键 UI 组件
从职责划分看,REPL 周围最关键的组件并不是“谁最大”,而是谁承担了哪些交互责任:
PromptInput.tsx:负责输入、自动补全、引用粘贴、语音相关状态与提交前处理。Messages.tsx/VirtualMessageList.tsx:负责消息渲染、分组、折叠以及长对话下的虚拟滚动。ScrollKeybindingHandler.tsx:把终端里的滚动与快捷键导航统一成一套可预测行为。LogSelector.tsx/Stats.tsx:承担诊断、筛选和可观测性相关 UI。Feedback.tsx:承接用户反馈与产品内回流机制。
8.4 设计系统
Claude Code 还内建了一套终端设计系统(components/design-system/),把常见交互原语统一起来:
ThemeProvider.tsx:主题管理Dialog.tsx:模态对话框Tabs.tsx:标签页交互FuzzyPicker.tsx:模糊搜索选择器ProgressBar.tsx:进度可视化ThemedBox/ThemedText:主题化布局与文本抽象
九、Bridge 桥接系统:IDE 集成
Bridge 是 Claude Code 从“纯 CLI 工具”走向“可嵌入 IDE 的协作编程环境”的关键转折点。
看图重点:上层是 VS Code / JetBrains 扩展,中间是 Bridge 主循环、消息协议与安全/传输层,下层才回到 CLI REPL 本体,三层之间通过 WebSocket + JWT 维持双向同步。
9.1 架构总览
Bridge 不是单纯的“IDE 消息转发器”,而是一套在 IDE 与本地 REPL 之间维持会话状态一致性的协议层。
可以从三条链路来理解:
- REPL 接入层:
useReplBridge.tsx在 React 侧把onInboundMessage、onPermissionResponse、onInterrupt、onSetPermissionMode这些回调接入 REPL。 - 初始化层:
initReplBridge.ts负责运行时 gate、OAuth 检查、组织策略校验、title 推导以及选择走旧桥还是新桥。 - 核心传输层:
replBridge.ts是旧的 env-based 路线:先注册环境,再轮询 work item,拿到 ingress token 后接入消息流。remoteBridgeCore.ts是新的 env-less 路线:直接POST /v1/code/sessions创建会话,再POST /bridge换取worker_jwt,随后建立 SSE + CCR 写通道。
消息层则由 bridgeMessaging.ts 统一负责:既要过滤哪些消息适合桥接,也要处理 control_request / control_response、初始化请求、权限模式切换和中断指令。
9.2 关键能力
从源码看,Bridge 最关键的工程点有四个:
- 历史与实时消息顺序保证:
FlushGate会在初始历史 flush 期间暂存 live writes,避免“旧消息还没补完,新消息先到”的乱序问题。 - 回声与重放去重:
BoundedUUIDSet用于处理 echo/replay,避免本地刚发出的消息又被服务端回放成一条“新消息”。 - 权限回执与控制协议:远端客户端回复
control_response后,Bridge 侧会同步调用reportState('running'),让服务端知道这一轮可以继续推进。 - 重连与令牌刷新:env-less 路线通过
createTokenRefreshScheduler()定时刷新 JWT;如果 SSE 因401关闭,则重建 transport,而不是直接让会话失效。
因此,Bridge 真正难的地方不是“能连上 IDE”,而是如何在消息顺序、鉴权刷新、状态恢复和双向控制之间保持一致性。
十、多 Agent 协作系统
如果说 Agentic Loop 解决的是“单个代理如何工作”,那多 Agent 系统解决的就是“多个代理如何并行协作”。
看图重点:主 Agent 更像一个协调器,它通过
TeamCreateTool、SendMessageTool、共享记忆和邮箱轮询机制,把多个子 Agent 组织成一套可通信的团队。
10.1 协调器:coordinator/coordinatorMode.ts
coordinatorMode.ts 的重点并不是实现一个复杂调度器,而是在 prompt 层显式约束主 Agent 的职责:
isCoordinatorMode()用特性开关 + 环境变量决定是否进入协调器模式。getCoordinatorUserContext()会把 worker 可用工具、MCP 服务器和 scratchpad 路径注入上下文,让主 Agent 清楚“手下的人”能做什么。getCoordinatorSystemPrompt()则把主 Agent 限定为 orchestration 角色:能启动 worker、继续 worker、停止 worker,但不应把 trivially answerable 的问题滥发出去。- worker 的结果不会伪装成普通模型输出,而是以
<task-notification>XML 形式回到主线程,再由主 Agent 继续综合、追问或二次调度。
这意味着 Claude Code 的多 Agent 协作,核心首先是职责收窄与消息协议设计,其次才是后台任务执行。
10.2 子 Agent 与任务执行
真正把“协调器模式”落到 runtime 的关键,在 runAgent.ts 和任务系统本身:
- 上下文分叉:
runAgent.ts会为子 Agent 生成独立agentId,fork 当前上下文消息,并在需要时过滤不完整工具调用。 - 缓存与权限继承:它会克隆或新建 read-file cache,同时根据 agent 定义覆盖 permission mode、effort 等运行参数。
- 子上下文构建:通过
createSubagentContext()生成独立执行环境,再把 prompt、工具池和系统提示装配进去。 - 持久化观测面:
recordSidechainTranscript()与writeAgentMetadata()会把 sidechain transcript 和 agent 元数据落盘,方便恢复与调试。 - 任务抽象:后台执行单元又被拆成
LocalAgentTask、RemoteAgentTask、LocalShellTask、InProcessTeammateTask、DreamTask等类型,各自对应本地子 Agent、远端子 Agent、本地 shell 和进程内协作者等场景。 - 周期性摘要:
startAgentSummarization()会大约每 30 秒 fork 一次无工具子上下文,只生成 3–5 个词的进度摘要,持续刷新 UI 中的 worker 状态。
10.3 记忆系统:memdir/
多 Agent 并发之后,真正的问题就不再是“能不能多开几个 worker”,而是这些 worker 如何共享长期上下文。
memdir/ 负责这件事:
memdir/
├── memdir.ts # 记忆目录核心
├── memoryTypes.ts # 记忆类型定义
├── findRelevantMemories.ts # 相关记忆检索
├── memoryScan.ts # 记忆扫描
├── paths.ts # 存储路径管理
├── teamMemPaths.ts # 团队记忆路径
└── teamMemPrompts.ts # 团队记忆提示词
services/extractMemories/
├── extractMemories.ts # 自动记忆提取
└── prompts.ts # 记忆提取提示词
它既承担跨会话知识沉淀,也承担团队模式下的共享记忆路径约定,让主 Agent 与多个 worker 在不同时间点仍能围绕同一批长期信息继续协作。
十一、服务层深度解析
11.1 MCP 集成:services/mcp/
MCP(Model Context Protocol)是 Claude Code 连接外部工具和数据源的核心协议:
- 客户端核心:
client.ts负责 MCP 客户端的主逻辑。 - 配置与认证:
config.ts负责配置管理,auth.ts处理 OAuth 与认证接入。 - 连接管理:
useManageMCPConnections.ts负责连接状态管理。 - 安全与通道治理:
channelPermissions.ts和channelAllowlist.ts负责通道级权限控制。 - 交互与企业认证:
elicitationHandler.ts负责交互式数据收集,xaa.ts/xaaIdpLogin.ts负责 XAA 认证集成。
11.2 LSP 集成:services/lsp/
Language Server Protocol 提供代码智能能力:
- 客户端与实例管理:
LSPClient.ts、LSPServerManager.ts、LSPServerInstance.ts负责客户端连接与服务实例生命周期。 - 诊断与配置:
LSPDiagnosticRegistry.ts和config.ts负责诊断信息与配置管理。 - 管理与反馈:
manager.ts负责整体调度,passiveFeedback.ts用于被动反馈收集。
11.3 分析和遥测:services/analytics/
- `growthbook.ts`:GrowthBook 特性开关管理
- `metadata.ts`:运行时元数据收集
- `firstPartyEventLogger.ts`:一方事件日志记录
- `datadog.ts`:Datadog 集成
- `sink.ts`:事件汇聚
- `index.ts`:统一出口
11.4 OAuth 认证:services/oauth/
- `client.ts`:OAuth 客户端
- `auth-code-listener.ts`:授权码监听
- `crypto.ts`:加密工具
- `getOauthProfile.ts`:获取用户信息
- `index.ts`:统一出口
十二、插件和技能系统
Claude Code 的长期可扩展性,不在某一个巨型核心模块里,而在它把“可扩展点”系统化地拆成了插件、技能、Agent、Hooks 等多种层次。
看图重点:插件偏向分发与安装,技能偏向复用工作流,两者又都能挂接到 Claude Code 统一的执行引擎上,这就是它扩展生态的基本骨架。
12.1 插件系统
Claude Code 的插件系统支持通过 npm 分发和安装第三方扩展。
它的实现重点不在“装多少文件”,而在如何把扩展点收束成稳定装载链路:
- 插件装载链路:从
plugins/builtinPlugins.ts出发,进入utils/plugins/pluginLoader.ts,再依次解析plugin.json,装载commands、hooks、skills、agents、MCP servers与output styles。 - 装载稳定性:
loadAllPlugins使用memoize,避免同一进程内重复扫描与重复初始化。 - 插件管理链路:
marketplaceManager.ts、installedPluginsManager.ts、pluginInstallationHelpers.ts、validatePlugin.ts分别负责市场管理、已装插件维护、安装辅助与合法性校验。
12.2 技能系统
技能(Skills)是可复用的工作流定义。
从实现看,技能系统主要由三部分组成:
- 加载入口:
loadSkillsDir.ts负责技能目录扫描,按目录约定和SKILL.md发现技能描述;bundledSkills.ts/bundled/index.ts负责内置技能注册。 - 构建能力:
mcpSkillBuilders.ts负责把 MCP 能力包装成可调用技能,让“外部服务能力”也能以统一技能形态接入。 - 内置技能集合:
bundled/中沉淀了batch、debug、loop、remember、skillify、verify等基础工作流,说明 Claude Code 在把“高频操作流程”产品化,而不只是暴露底层工具。
十三、工具函数库:utils/
src/utils/ 真正重要的地方,不在于“文件很多”,而在于这里沉淀了 Claude Code 最难复用的工程细节。最值得关注的几块如下:
13.1 Shell 命令解析器
utils/bash/
├── bashParser.ts # Bash 解析器
├── ast.ts # AST 定义
├── commands.ts # 命令分析
├── heredoc.ts # Heredoc 解析
├── shellQuote.ts # Shell 引用处理
└── treeSitterAnalysis.ts # Tree-sitter 集成
Claude Code 内置了一个完整的 Bash 命令解析器,可以把 shell 命令解析成 AST 再做安全分析;这也是 BashTool 能实现“命令理解”而非“纯字符串黑名单”的基础。
13.2 权限系统工具
utils/permissions/
├── permissions.ts # 权限核心逻辑
├── permissionSetup.ts # 权限配置与模式切换
├── filesystem.ts # 文件系统权限边界
├── yoloClassifier.ts # auto 模式分类器
├── pathValidation.ts # 路径校验
└── permissionRuleParser.ts # 规则解析
这部分代码共同决定了 Claude Code 如何把“模式、规则、路径和分类器”合并成一套统一决策过程。
13.3 会话存储
utils/sessionStorage.ts 负责会话的完整生命周期管理:创建、保存、恢复、搜索、清理,以及 sidechain transcript、背景任务和恢复态元数据的持久化。
13.4 配置管理
utils/config.ts:多层配置解析与合并utils/claudemd.ts:CLAUDE.md规则文件解析utils/hooks.ts:SessionStart / SessionEnd / UserPromptSubmit 等 Hook 系统核心
这些模块共同决定了 Claude Code 如何把“用户配置、仓库规则、会话钩子”变成可持续演化的运行时约束。
十四、通信传输层
14.1 CLI 传输
cli/transports/
├── ccrClient.ts # CCR 客户端
├── WebSocketTransport.ts # WebSocket 传输
├── SSETransport.ts # SSE 传输
├── HybridTransport.ts # 混合传输
├── SerialBatchEventUploader.ts # 批量事件上传
└── WorkerStateUploader.ts # Worker 状态上传
这里体现的是 Claude Code 的传输分层:上层是统一事件模型,下层则根据场景选择 WebSocket、SSE 或混合传输。
14.2 上游代理
upstreamproxy/
├── upstreamproxy.ts # 代理配置
└── relay.ts # 请求中继
这部分让 CLI 能在企业网络、代理环境和中继场景下维持可用性。
十五、设计模式与工程亮点
15.1 并行预取(Parallel Prefetch)
启动时间优化的核心策略 — 在重模块评估之前并行预取多种数据:
- MDM 配置读取
- Keychain 凭证获取
- API 预连接(TCP + TLS 握手)
- GrowthBook 特性开关获取
15.2 编译时特性消除
利用 Bun 的 bun:bundle 在编译时消除未启用的特性代码,显著减小发布包体积。
15.3 自定义 Ink 渲染引擎
没有简单依赖社区 Ink 框架,而是维护了一个深度定制的 Fork,包含:
- 自定义事件系统(鼠标点击、终端焦点)
- 虚拟滚动(处理超长对话)
- 文本选择支持
- 自定义 Yoga 布局引擎绑定
- ANSI 解析和渲染优化
15.4 多层安全模型
BashTool 的五层安全模型是业界标杆:
- 命令安全分析(黑名单 + 模式匹配)
- 权限规则匹配(用户自定义规则)
- 只读验证(自动识别安全操作)
- 路径安全校验(防止越界访问)
- Sandbox 隔离(容器化执行)
15.5 上下文压缩
会话上下文管理的三级压缩策略:
- 微压缩(Micro-compact):轻量级,保留关键信息
- 标准压缩(Compact):中等力度,替换工具输出
- 会话记忆压缩(Session Memory Compact):最激进,提取核心记忆
十六、推荐阅读路径:如何啃这份源码
如果你的目标不是“数文件”,而是快速理解 Claude Code 的实现原理,我更推荐按能力链路阅读源码。
16.1 建议的阅读顺序
- 启动链路:先看
main.tsx、bootstrap/state.ts、entrypoints/init.ts,理解配置、认证、预热和首屏渲染是怎样排顺序的。 - 主推理循环:再看
query.ts、QueryEngine.ts、services/api/claude.ts,理解一轮输入如何进入模型、工具、再回到模型。 - 工具与权限:继续看
toolOrchestration.ts、toolExecution.ts、permissions.ts、permissionSetup.ts,这是 Claude Code 最核心的行动能力与安全边界。 - 终端运行时:然后看
screens/REPL.tsx以及PromptInput、Messages、useDeferredHookMessages等周边模块,理解状态、输入、消息和弹层如何汇合。 - IDE 桥接:接着看
useReplBridge.tsx、initReplBridge.ts、replBridge.ts、remoteBridgeCore.ts、bridgeMessaging.ts,理解 IDE 与 CLI 如何保持双向同步。 - 多 Agent 协作:最后读
coordinatorMode.ts、runAgent.ts、agentSummary.ts、memdir/,你会更容易看懂它的 orchestrator 思路。
16.2 最值得重点看的模块
| 模块 | 为什么值得重点看 |
|---|---|
bootstrap/state.ts |
能看清 Claude Code 如何把配置、信任、TLS、认证和特性开关排成有先后关系的启动状态机 |
query.ts / QueryEngine.ts |
能看清 AI Coding Agent 最核心的“模型 ↔ 工具 ↔ 上下文”闭环 |
toolOrchestration.ts / toolExecution.ts |
能看清只读工具为何可并发、带副作用工具为何必须串行 |
permissions.ts / permissionSetup.ts |
能看清规则优先、auto 模式、危险规则剥离和人工确认是如何组合的 |
screens/REPL.tsx |
能看清终端 UI 如何承接消息流、输入流、后台任务和各种弹层工作流 |
remoteBridgeCore.ts / bridgeMessaging.ts |
能看清远程控制场景下的顺序保证、去重、令牌刷新与协议恢复 |
runAgent.ts / agentSummary.ts |
能看清子 Agent 的上下文分叉、持久化和进度可观测性是如何落地的 |
十七、技术栈总结
| 类别 | 技术选型 |
|---|---|
| 运行时 | Bun |
| 语言 | TypeScript (strict) |
| 终端 UI | React + Ink (深度定制 Fork) |
| CLI 解析 | Commander.js (extra-typings) |
| Schema 验证 | Zod v4 |
| 代码搜索 | ripgrep |
| 布局引擎 | Yoga (Flexbox) |
| Shell 解析 | 自研 Bash Parser + Tree-sitter |
| 协议 | MCP SDK, LSP |
| API | Anthropic SDK |
| 遥测 | OpenTelemetry + gRPC |
| 特性开关 | GrowthBook |
| 认证 | OAuth 2.0, JWT, macOS Keychain |
| 分析 | Datadog |
| 传输 | WebSocket, SSE, HTTP |
十八、总结与启示
18.1 工程复杂度
Claude Code 的复杂度,并不只是因为它“代码很多”,而是因为它实际上已经长成了一套完整的终端 IDE + Agent 运行时,具备:
- 深度定制的 UI 渲染引擎
- 完整的 Bash 命令解析器
- 多层安全模型
- 多 Agent 协作框架
- 插件和技能扩展系统
- IDE 双向通信桥接
- 复杂的上下文管理和压缩
18.2 架构启示
- 安全第一:BashTool 的五层安全模型展示了 AI 工具执行的安全防线应有多深
- 可扩展设计:工具、命令、插件、技能四大扩展点,各司其职
- 性能优化:并行预取、编译时特性消除、延迟加载三管齐下
- 上下文管理:三级压缩策略是长上下文 AI 应用的工程最佳实践
- 用户体验:深度定制 Ink 框架打造了真正的终端级 IDE 体验
18.3 关于源码泄露
这次源码泄露本质上是一个构建产物管理失误 — npm 发布包中包含了 Source Map 文件,而 Source Map 又指向了可公开访问的源码存储桶。这提醒我们:
- 发布流程需要包含 Source Map 剥离检查
- 存储桶访问策略需要与构建产物生命周期对齐
- CI/CD 管道中应增加产物安全扫描
本文仅用于技术学习和架构研究。Claude Code 源码版权归 Anthropic 所有。
参考资料
- Claude Code 源码泄露事件 - @Fried_rice
- Anthropic Claude Code 官方文档
- Model Context Protocol (MCP)
- Ink - React for CLI
- Bun Runtime
「真诚赞赏,手留余香」
真诚赞赏,手留余香
使用微信扫描二维码完成支付