万字深剖Claude Code源码:Anthropic如何用React写了一个终端AI编程神器
本文将带你深入 Claude Code 的源码世界,揭秘 Anthropic 工程师如何用 Bun + React + TypeScript 打造出这款令开发者惊艳的 AI 编程 CLI 工具。从架构设计到工程细节,我们将一探究竟。
引言
当你在终端敲下 claude 命令,看着 AI 流畅地帮你重构代码、修复 Bug、甚至自主完成整个功能开发时,有没有想过这背后是怎样的技术架构在支撑?
Claude Code 是 Anthropic 官方开源的 AI 编程命令行工具。它不同于那些套壳 ChatGPT 的「玩具」,而是一个真正工程化、生产级的 AI 编程助手。它能直接在你的终端中运行,读取你的代码库,执行 shell 命令,调用各种工具——就像一个真正的高级工程师坐在你旁边结对编程。
为什么 Claude Code 值得我们深入研究?原因有三:
第一,它代表了 AI 编程工具的工程实践标杆。 这不是一个周末项目或概念验证,而是 Anthropic 投入大量工程资源打磨的生产级产品。从 4600+ 行的 main.tsx 到 50+ 个工具、100+ 个命令,每一行代码都蕴含着深思熟虑的设计决策。
第二,它的技术选型极具前瞻性。 Bun 运行时、React Ink 终端 UI、Zod v4 类型验证、自定义渲染引擎——这些选择不是跟风,而是针对 CLI AI 工具场景的精准匹配。
第三,它的架构设计充满智慧。 三阶段启动策略、Tool/Command 双轨系统、五层权限决策引擎、四层 Bridge 架构——每一个设计都解决了实际痛点,值得我们学习借鉴。
阅读本文,你将收获:
•对 Claude Code 整体架构的全景认知•六大核心系统(Tool、Command、Permission、Bridge、Service、State)的深度理解•那些藏在代码里的精妙工程细节•AI 编程工具设计的核心哲学和最佳实践
让我们开始这趟源码探索之旅。
第一章:架构全景 —— 一览众山小
1.1 技术栈选型:每一个选择都有道理
Claude Code 的技术栈乍看有些「另类」,但深入分析后你会发现,每个选择都是精心权衡的结果:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
特别值得一提的是 Bun 的选择。作为新一代 JavaScript 运行时,Bun 的启动速度优势在 CLI 场景下尤为明显——没有人愿意等待一秒钟才看到命令行提示符。
1.2 整体架构分层
让我们用一张架构图来俯瞰 Claude Code 的全貌:

从上到下,Claude Code 分为五个清晰的层次:
1.入口层:负责 CLI 解析、快速路径判断、初始化流程编排2.交互层:处理用户命令、渲染终端 UI、提供 Vim 编辑体验3.核心引擎:会话管理、工具调用、权限决策——这是 AI 能力的核心4.服务层:API 调用、MCP 协议、LSP 集成、插件管理——对外能力扩展5.基础设施:IDE 桥接、状态管理、持久化存储——底层支撑
1.3 六大核心模块速览
在深入每个系统之前,让我们先建立整体认知:
|
|
|
|
|
| Tool 系统 |
|
src/Tool.ts
src/tools.ts |
|
| Command 系统 |
|
src/commands.ts
src/types/command.ts |
|
| Permission 系统 |
|
src/utils/permissions/permissions.ts |
|
| Bridge 系统 |
|
src/bridge/*.ts |
|
| Service 层 |
|
src/services/** |
|
| State 管理 |
|
src/state/*.ts |
|
1.4 启动流程:三阶段设计的智慧
Claude Code 的启动流程是一个精心设计的三阶段过程,核心目标是让用户尽快看到可交互的界面:

这个设计的精妙之处在于:
1.快速路径:对于 --version、--help 等简单命令,跳过所有初始化直接响应,实现毫秒级响应2.主初始化:最小化必要初始化,让 UI 尽快可交互3.后台预取:将耗时操作(网络请求、插件加载)推迟到后台异步执行
核心入口代码位于 src/entrypoints/cli.tsx,它会判断是否走快速路径:
// 快速路径:某些命令不需要完整初始化if (isQuickCommand(args)) {return handleQuickCommand(args);}// 主初始化路径await setup();
1.5 代码规模一览
在深入细节之前,让我们对代码规模有个直观认知:
•main.tsx: 4684 行 —— 主控制器,会话管理核心•query.ts: 1730 行 —— 查询引擎,消息处理•QueryEngine.ts: 1296 行 —— 流式处理引擎•permissions.ts: 1472 行 —— 权限决策系统•commands.ts: 755 行 —— 命令注册中心•Tool.ts: 793 行 —— 工具接口定义•tools 目录: 42 个子目录,50+ 工具实现•commands 目录: 80+ 命令实现
这是一个真正意义上的大型工程项目,接下来我们将逐一深入每个核心系统。
第二章:Tool 系统 —— AI 的「瑞士军刀」
如果说 Claude Code 是一个 AI 编程助手,那么 Tool 系统就是它的「双手」—— 没有 Tool,AI 只能「说」不能「做」。
2.1 Tool 接口设计哲学
打开 src/Tool.ts,你会看到一个精心设计的 793 行类型定义。核心接口如下:
export interface Tool {// 身份标识name: string;// 自描述能力 —— AI 靠这个理解工具用途description(context: ToolContext): string | undefined;prompt?(context: ToolContext): string | undefined;// 输入规范 —— Zod Schema,既验证又生成文档inputSchema: z.ZodType<ToolInput> | (() => z.ZodType<ToolInput>);// 核心执行 —— 工具的真正逻辑call(input: ToolInput, context: ToolUseContext): Promise<ToolResult>;// 权限检查 —— 执行前的安全守卫validateInput?(input: ToolInput): Promise<ValidationResult>;checkPermissions?(input: ToolInput, context: ToolContext): Promise<PermissionCheckResult>;// UI 渲染 —— 控制工具调用/结果的展示方式renderToolUseMessage?(input: ToolInput, context: RenderContext): ReactNode;renderToolResultMessage?(result: ToolResult, context: RenderContext): ReactNode;}
这个设计体现了三个核心原则:
1. 自包含(Self-Contained)
每个 Tool 是一个完整的单元,包含描述、Schema、执行逻辑、权限检查、UI 渲染——不依赖外部配置或运行时注入。这让工具的添加、测试、维护都变得独立。
2. 类型安全(Type-Safe)
通过 Zod Schema,实现了:
•编译时:TypeScript 类型推导•运行时:输入参数验证•文档:自动生成 JSON Schema 给 AI 理解
3. AI 友好(AI-Friendly)
description 和 prompt 方法让每个工具能向 AI 解释自己的用途和使用方式,这是 Tool Calling 能正确工作的关键。
2.2 工具全景分类
Claude Code 内置了 50+ 工具,覆盖了 AI 编程的方方面面:

2.3 工具装配流程
工具不是静态列表,而是根据上下文动态组装的。这个流程在 src/tools.ts 中实现

关键代码片段:
// src/tools.tsexport function getAllBaseTools(): Tool[] {return [BashTool,FileReadTool,FileWriteTool,FileEditTool,GlobTool,GrepTool,// ... 50+ 工具].filter(tool => {// Feature Flag 过滤if (tool.featureFlag && !isFeatureEnabled(tool.featureFlag)) {return false;}return true;});}export function assembleToolPool(tools: Tool[],mcpTools: Tool[] = []): ToolPool {// 合并内置工具和 MCP 工具const allTools = [...tools, ...mcpTools];// 构建名称索引以支持快速查找return new Map(allTools.map(t => [t.name, t]));}
2.4 核心工具深度解析
BashTool:不只是执行命令这么简单
BashTool 是最复杂的工具之一,因为它要解决一个难题:既要让 AI 有足够的能力执行命令,又要防止它搞砸系统。

BashTool 的安全机制包括:
1.AST 安全解析:不是简单的字符串匹配,而是真正解析 shell 语法2.破坏性命令检测:识别 rm -rf、mkfs、:(){:|:&};: 等危险模式3.沙箱隔离:Linux 用 bubblewrap,macOS 用 sandbox-exec4.子命令级权限:支持 Bash(git commit:*) 这样的精细控制
FileEditTool:原子操作的艺术
文件编辑看似简单,但 Claude Code 的实现考虑了很多边界情况:
// 原子写入:先写临时文件,再原子重命名async function atomicWrite(path: string, content: string) {const tempPath = `${path}.tmp.${Date.now()}`;await writeFile(tempPath, content);await rename(tempPath, path); // 原子操作}// 时间戳校验:防止并发修改async function validateTimestamp(path: string, expectedMtime: number) {const stats = await stat(path);if (stats.mtimeMs !== expectedMtime) {throw new ConcurrentModificationError();}}
此外,FileEditTool 还集成了 LSP 诊断——编辑后自动触发语法检查,让 AI 知道修改是否引入了错误。
AgentTool:子代理的诞生
AgentTool 允许 Claude 创建「子代理」来处理独立任务,这是实现复杂任务分解的关键:

2.5 工具调用完整生命周期
让我们追踪一次完整的工具调用:

2.6 Lazy Schema 与 Semantic Coercion
两个精妙的设计模式值得特别介绍:
Lazy Schema:解决循环依赖问题
// 问题:AgentTool 的 schema 依赖 ToolPool,而 ToolPool 又包含 AgentTool// 解决:延迟评估const AgentTool: Tool = {inputSchema: () => z.object({ // 返回函数而非值task: z.string(),tools: z.array(z.enum(getAvailableToolNames())), // 运行时才求值}),// ...};
Semantic Coercion:宽容处理模型输出
AI 模型有时会输出 "true" 而非 true,"123" 而非 123。Semantic Coercion 优雅地处理这些情况:
const semanticBoolean = z.union([z.boolean(),z.literal("true").transform(() => true),z.literal("false").transform(() => false),]);const semanticNumber = z.union([z.number(),z.string().regex(/^\d+$/).transform(Number),]);
这让工具调用更加健壮,不会因为模型的小「失误」而失败。
第三章:Command 系统 —— 用户的「指挥棒」
如果 Tool 是 AI 的能力,那 Command 就是用户与系统交互的桥梁。
3.1 Command vs Tool:本质区别

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3.2 三种命令类型
Claude Code 定义了三种命令类型,满足不同场景:
// src/types/command.ts// 1. PromptCommand:让 AI 来执行interface PromptCommand {type: 'prompt';userMessage: Message; // 发给 AI 的提示allowedTools?: string[]; // 限制可用工具systemPromptSuffix?: string; // 附加系统提示}// 2. LocalCommand:直接执行 JSinterface LocalCommand {type: 'local';handler: (args: string) => Promise<CommandResult>;}// 3. LocalJSXCommand:React 组件interface LocalJSXCommand {type: 'local-jsx';component: React.FC<CommandProps>;}
3.3 命令注册中心
命令注册在 src/commands.ts,是一个多源聚合的系统:
flowchart TDA[命令注册中心] --> B[内置命令]A --> C[Feature Flag 命令]A --> D[插件命令]A --> E[技能命令]A --> F[MCP 命令]B --> G[/commit]B --> H[/review]B --> I[/config]D --> J[社区插件]E --> K[/pdf]E --> L[/design]F --> M[外部 MCP 服务器命令]
3.4 /commit 命令深度解析
让我们以 /commit 命令为例,看看一个典型的 PromptCommand 是如何工作的:
// src/commands/commit.tsexport const commitCommand: Command = {name: 'commit',description: '让 Claude 帮你写 commit message',type: 'prompt',// 关键:限制可用工具,防止 AI 做多余操作allowedTools: ['Bash(git add:*)','Bash(git status:*)','Bash(git diff:*)','Bash(git commit:*)',],async buildPrompt(args: string) {// 收集 git 上下文const gitStatus = await exec('git status --porcelain');const gitDiff = await exec('git diff --cached');return {userMessage: {role: 'user',content: `请帮我写一个 commit message。当前变更:${gitStatus}Diff 内容:${gitDiff}${args ? `用户要求:${args}` : ''}`,},systemPromptSuffix: `你是一个 Git 专家。请:1. 分析变更内容2. 生成符合 Conventional Commits 规范的 message3. 执行 git commit`,};},};
这个设计的巧妙之处:
1.工具白名单:只允许 git 相关命令,防止 AI「发散」2.上下文预收集:在发送给 AI 前收集必要信息,减少 AI 调用工具的次数3.安全边界:所有 git 命令仍需通过权限检查
3.5 SkillTool:Command 与 Tool 的桥梁
有时候 AI 需要调用命令的能力(比如让 AI 决定何时提交代码),SkillTool 就是这座桥:

第四章:权限系统 —— 安全的「铜墙铁壁」
AI 有了「手」(Tool),有了「嘴」(Command),但如果没有边界,它可能会「好心办坏事」。权限系统就是那道守护边界的铜墙铁壁。
4.1 多层权限决策引擎
src/utils/permissions/permissions.ts 的 1472 行代码实现了一个复杂但清晰的决策引擎:

4.2 五层优先级详解
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
高优先级可以覆盖低优先级,但不能反过来。这确保了企业策略的强制性。
4.3 Bash 子命令级权限控制
Claude Code 支持精细到 Bash 子命令级别的权限控制:
{"permissions": {"allow": ["Bash(git status:*)","Bash(git add:*)","Bash(npm test:*)"],"deny": ["Bash(rm:*)","Bash(sudo:*)","Bash(curl:*)"]}}
实现原理:
function matchBashPermission(command: string,rule: string): boolean {// 规则格式:Bash(command:pattern)const match = rule.match(/^Bash\((\w+):(.+)\)$/);if (!match) return false;const [, ruleCmd, pattern] = match;const actualCmd = parseCommand(command);// 命令名匹配if (actualCmd.name !== ruleCmd) return false;// 参数模式匹配return globMatch(pattern, actualCmd.args.join(' '));}
4.4 沙箱隔离机制
即使权限检查通过,某些操作仍会在沙箱中执行:

4.5 安全防御纵深模型
Claude Code 采用了经典的纵深防御策略:

第五章:Bridge 系统 —— IDE 的「传送门」
Claude Code 不仅是一个独立的 CLI 工具,还能与 VS Code、JetBrains 等 IDE 深度集成。Bridge 系统就是实现这一能力的核心。
5.1 Bridge 四层架构

5.2 双路径通信设计
为了兼顾不同场景,Claude Code 设计了两种通信路径:

v1 环境模式:
•通过 Anthropic 的 Environments API 中转•兼容性好,适合防火墙限制场景•延迟较高(轮询间隔)
v2 无环境模式:
•直接 WebSocket 连接•低延迟(约降低 30%)•需要直连能力
5.3 消息协议与去重
Bridge 使用 NDJSON(Newline Delimited JSON)协议:
interface BridgeMessage {id: string; // UUID,用于去重type: MessageType; // 消息类型payload: unknown; // 消息体timestamp: number; // 时间戳}// 去重逻辑const seenIds = new Set<string>();function handleMessage(msg: BridgeMessage) {if (seenIds.has(msg.id)) {return; // 已处理,跳过}seenIds.add(msg.id);// 处理消息...}
5.4 认证与会话管理

第六章:状态管理与 Service 层 —— 系统的「神经中枢」
6.1 35 行代码的状态管理
Claude Code 没有使用 Redux、MobX 这些「重量级」方案,而是实现了一个极简的 Zustand-like Store:
// src/state/store.ts (核心代码约 35 行)export function createStore<T>(initialState: T) {let state = initialState;const listeners = new Set<(state: T) => void>();return {getState: () => state,setState: (partial: Partial<T> | ((s: T) => Partial<T>)) => {const nextState = typeof partial === 'function'? { ...state, ...partial(state) }: { ...state, ...partial };state = nextState;listeners.forEach(l => l(state));},subscribe: (listener: (state: T) => void) => {listeners.add(listener);return () => listeners.delete(listener);},};}// React 集成export function useStore<T, S>(store: Store<T>,selector: (state: T) => S): S {return useSyncExternalStore(store.subscribe,() => selector(store.getState()));}
为什么这样设计?
1.极简:35 行代码,无依赖2.类型安全:完整的 TypeScript 类型推导3.React 18 兼容:使用 useSyncExternalStore 避免 tearing4.精细订阅:selector 模式避免无关重渲染
6.2 AppState 数据结构
状态结构经过精心设计,包含 30+ 字段:
interface AppState {// 会话状态sessionId: string;conversationHistory: Message[];isProcessing: boolean;// 工具状态availableTools: Tool[];activeToolCalls: Map<string, ToolCallState>;// 权限状态permissions: PermissionSettings;sessionPermissions: Map<string, PermissionDecision>;// 配置状态config: Config;featureFlags: FeatureFlags;// UI 状态inputMode: 'normal' | 'vim';theme: Theme;// 成本追踪totalCostUSD: number;modelUsage: Map<string, TokenUsage>;// ... 更多字段}
6.3 DeepImmutable 与性能优化
为了防止意外修改状态,Claude Code 使用了 DeepImmutable 类型:
type DeepImmutable<T> = {readonly [K in keyof T]: T[K] extends object? DeepImmutable<T[K]>: T[K];};// 选择器优化:只订阅需要的部分const isProcessing = useStore(appStore,state => state.isProcessing // 只关心这个字段);
6.4 Service 层架构

6.5 MCP 集成数据流
MCP(Model Context Protocol)是 Claude Code 扩展能力的关键:

第七章:隐藏的宝石 —— 那些精妙的工程细节
在主要架构之外,Claude Code 还藏着许多精妙的工程细节。
7.1 Feature Flags 与死代码消除
Claude Code 使用 GrowthBook 进行特性开关管理,但更精妙的是它的编译时优化:
// 在代码中if (feature('new-search-ui')) {return <NewSearchUI />;} else {return <OldSearchUI />;}// Bun bundle 时,如果 new-search-ui = false// 会直接消除整个 if 分支,包括 NewSearchUI 的导入
这意味着:
•未启用的功能不会增加 bundle 大小•运行时没有条件判断开销•可以安全地在代码中保留实验性功能
7.2 自定义 Ink 渲染引擎
Claude Code 没有直接使用 Ink 的默认渲染器,而是实现了自定义优化:
// 对象池优化 —— 避免频繁 GCconst stylePool = new StylePool(1000); // 样式对象池const charPool = new CharPool(10000); // 字符对象池const hyperlinkPool = new HyperlinkPool(100); // 超链接对象池// FPS 追踪class FPSTracker {private frames: number[] = [];recordFrame() {this.frames.push(Date.now());// 保留最近 60 帧if (this.frames.length > 60) {this.frames.shift();}}getFPS(): number {if (this.frames.length < 2) return 0;const duration = this.frames[this.frames.length - 1] - this.frames[0];return (this.frames.length - 1) / (duration / 1000);}}
7.3 Vim 模式状态机
对于 Vim 爱好者,Claude Code 实现了完整的 Vim 模式:
stateDiagram-v2[*] --> NORMALNORMAL --> INSERT: i/a/o/OINSERT --> NORMAL: EscNORMAL --> VISUAL: vVISUAL --> NORMAL: EscNORMAL --> COMMAND: :COMMAND --> NORMAL: Enter/Escstate NORMAL {[*] --> IdleIdle --> OperatorPending: d/c/yOperatorPending --> Idle: motionIdle --> FindPending: f/F/t/TFindPending --> Idle: char}
支持的功能包括:
•模式切换(Normal/Insert/Visual/Command)•移动命令(h/j/k/l/w/b/e/0/$)•操作符(d/c/y)+ 动作组合•点重复(.)•寄存器(”a-z)•f/F/t/T 字符查找(带缓存优化)
7.4 伴侣系统(Buddy)
这是一个充满趣味的彩蛋功能:
// src/buddy/types.tsinterface Buddy {species: BuddySpecies; // 18 种物种rarity: 'common' | 'uncommon' | 'rare' | 'epic' | 'legendary';attributes: {DEBUGGING: number; // 调试能力PATIENCE: number; // 耐心值CHAOS: number; // 混乱值WISDOM: number; // 智慧值SNARK: number; // 毒舌值};}// 伴侣会根据你的编程行为给出反应// 比如连续 debug 3 小时,高 PATIENCE 的伴侣会鼓励你// 而高 SNARK 的伴侣可能会嘲讽你...
7.5 成本追踪系统
AI API 调用是有成本的,Claude Code 内置了精细的成本追踪:
interface CostTracker {totalCostUSD: number;modelUsage: Map<string, {inputTokens: number;outputTokens: number;cost: number;}>;// 会话恢复时可以延续之前的统计restore(savedState: CostState): void;// 按模型分类展示getSummary(): CostSummary;}
7.6 内存系统三层架构

第八章:设计哲学与启示
通过深入分析 Claude Code 的源码,我们可以提炼出几个核心设计哲学。
8.1 「自包含」原则
每个 Tool、每个 Command 都是一个独立单元:
•自己定义输入 Schema•自己实现权限检查•自己负责 UI 渲染•自己提供描述文档
这让系统具有极高的可维护性和可扩展性。
8.2 「安全前置」思想
权限检查永远在执行之前:
用户请求 → 输入验证 → 权限检查 → Hook 拦截 → 实际执行
而不是:
用户请求 → 实际执行 → 发现问题 → 回滚(太晚了!)
8.3 「渐进式加载」策略
三阶段启动、延迟导入、Feature Flags——一切都是为了让用户更快看到可交互的界面。
// 延迟导入示例const heavyModule = await import('./heavy-module');// 而不是import heavyModule from './heavy-module'; // 启动时就加载
8.4 「类型驱动」设计
从 Zod Schema 到运行时验证,再到 AI 友好的描述:
TypeScript 类型 ← Zod Schema → JSON Schema → AI 理解↓运行时验证
类型不只是开发时的辅助,而是整个系统的骨架。
8.5 对开发者的启示
1.选择适合场景的技术栈:Bun 之于 CLI,就像 Electron 之于桌面应用2.安全是设计出来的:纵深防御、最小权限、默认拒绝3.性能优化要从架构开始:三阶段启动、对象池、精细订阅4.可扩展性来自好的抽象:Tool 接口、Command 类型、Hook 系统5.用户体验藏在细节里:Vim 模式、伴侣系统、成本追踪
结语
Claude Code 不仅是一个 AI 编程工具,更是一本活的软件工程教科书。
从 4600+ 行的 main.tsx 到 50+ 个精心设计的 Tool,从五层权限决策引擎到四层 Bridge 架构,每一行代码都蕴含着 Anthropic 工程师的深思熟虑。
它告诉我们:
•AI 工具不是「套壳」就能做好的,需要扎实的工程能力•安全和易用可以兼得,关键是好的架构设计•类型系统和运行时验证是 AI 工具的基石•性能优化是一个系统工程,需要从架构层面考虑
Claude Code 代表了 AI 编程工具的未来方向:
•深度集成:与 IDE、终端、版本控制无缝协作•安全可控:让用户放心地让 AI 操作代码•高度可扩展:通过 MCP、插件、技能不断增长能力•极致体验:从毫秒级响应到 Vim 模式,处处体现工匠精神
希望这篇文章能帮助你更好地理解 Claude Code,也希望它能激发你构建下一代 AI 工具的灵感。
毕竟,最好的学习方式,就是站在巨人的肩膀上。
全文完。感谢阅读。
本文基于 Claude Code 源码分析,文中引用的文件路径和代码片段均来自真实源码。
夜雨聆风