📄

Request My Resume

Thank you for your interest! To receive my resume, please reach out to me through any of the following channels:

Claude Code `src` 源码架构深度拆解|把终端助手做成多 Agent 运行时,到底厉害在哪

Digital Strategy Review | 2026

Claude Code src 源码架构深度拆解|把终端助手做成多 Agent 运行时,到底厉害在哪

文 / 果叔 · 阅读时间 / 8 Min

Claude Code 源码架构总览封面图

写在前面

如果只看产品表面,Claude Code 很容易被当成一个终端里的聊天助手。但把 src 真正翻过一遍后,我更强烈的感受是:它的核心不是聊天,而是把 Agent 做成了可以调度、隔离、恢复和观察的系统对象。

副标题:把一个“命令行助手”做成多 Agent 操作系统,这套实现到底厉害在哪

01

开场:先给结论

如果只看产品表面,Claude Code 很容易被误解成“一个包着终端 UI 的模型调用器”。但这次通读 src 后,我的结论很明确:它的核心并不是“聊天”,而是把 Agent 变成了一种可调度、可隔离、可恢复、可观察、可协同的运行时对象。

换句话说,它不是在 CLI 里“嵌了几个 AI 功能”,而是在 CLI 里搭了一层很完整的 agent runtime:

01 上面是用户交互层,负责 REPL、命令、权限弹窗、任务视图、状态栏。

02 中间是推理循环层,负责 prompt 组织、模型调用、上下文压缩、工具执行、stop hook、预算控制。

03 下面是执行系统层,负责工具、任务、子 agent、团队 agent、远程 agent、worktree 隔离、权限同步、状态持久化。

04 旁边还有几条横切能力线:MCP、插件、技能、记忆、LSP、遥测、远程控制、沙箱、安全策略。

这就是为什么它的 src 看起来不像传统 CLI 项目,而更像“终端里的分布式 agent 控制面”。

Mermaid 图 1

如果要用一句更工程化的话概括这套系统,我会这样说:

Claude Code 的真正创新点,不是“支持子 Agent”,而是把子 Agent、后台任务、远程任务、团队协作、权限审批、上下文复用、结果通知,全部统一进了一套共享的任务与工具语义里。

这篇文章会分成两大部分:

01 先讲清楚 src 的整体架构,回答“这套系统到底怎么跑起来的”。

02 再给出我认为最有用、最有创新性的 10 个 agent 实现亮点,按重要性排序。

文中提到的关键锚点主要来自这些文件:

• src/entrypoints/cli.tsx

• src/main.tsx

• src/query.ts

• src/tools.ts

• src/services/tools/toolOrchestration.ts

• src/tools/AgentTool/AgentTool.tsx

• src/tools/AgentTool/runAgent.ts

• src/tasks/LocalAgentTask/LocalAgentTask.tsx

• src/tasks/InProcessTeammateTask/InProcessTeammateTask.tsx

• src/utils/swarm/spawnInProcess.ts

• src/utils/swarm/inProcessRunner.ts

• src/state/AppStateStore.ts

• src/tools/AgentTool/built-in/*.ts

• src/tools/AgentTool/agentMemory.ts

• src/tools/AgentTool/forkSubagent.ts

02

一、先别急着看 Agent:先看它怎么启动

很多系统的架构问题,入口一看就明白一半。Claude Code 这里尤其明显。

src/entrypoints/cli.tsx 不是一个“简单转发到 main”的文件。它本身已经是一层性能敏感的调度器。它做了三件很重要的事:

01 在最早阶段处理环境变量和 feature gate。

02 用大量 fast-path 把不需要完整 CLI 启动的路径提前截走。

03 只有在真正需要完整交互运行时时,才把重模块动态导入进来。

这意味着作者非常明确地把启动路径分成了两类:

• 轻路径:只做单一动作,比如 --version、某些 daemon worker、bridge、background session 管理、模板命令、环境 runner。

• 重路径:进入完整的交互式运行时。

这看似只是启动优化,实际上透露出一个更深的设计选择:Claude Code 不是一个单体入口,而是多个运行模式共享的一套核心基础设施。CLI 只是其中一个外壳,后台 worker、远程 runner、bridge、headless runner 都是同一体系里的不同入口。

这一步非常关键,因为后面你会看到,它的 agent 并不只活在“当前这个命令行会话里”。它可能活在:

• 当前前台 REPL

• 本地后台任务

• 同进程 teammate

• tmux pane teammate

• 独立 worktree

• 远程 CCR session

如果入口层没有一开始就把运行模式拆清楚,后面的 agent 体系一定会打架。

03

二、main.tsx 并不是“页面入口”,它是总装车间

很多人看到 main.tsx 会下意识觉得这是个 UI 入口。其实它更像是运行时总装器。

这个文件非常大,但大不是坏事。这里的大,说明它承担的是“系统装配”的责任,而不是业务细节本身。通读下来,我觉得它主要做六类事情。

1. 预热所有会影响主循环的环境

main.tsx 开头就做了几件很讲究的事情:

• 启动 profiler checkpoint

• 提前启动 MDM 读取

• 提前启动 keychain prefetch

这不是普通意义上的“优化启动速度”。它体现的是一种对交互系统非常成熟的理解:会阻塞首屏体验的慢 I/O,越早发出去越好,最好和其他 import 并行。

换句话说,作者不是把启动过程当成线性脚本,而是当成一段可以并发重叠的流水线。

2. 初始化配置、策略、认证、遥测、GrowthBook

在这层里,main.tsx 会把很多影响行为的全局能力拉起来:

• config

• managed settings

• policy limits

• auth / OAuth

• growthbook

• analytics

• plugin

• MCP

• skills

• commands

• model 选择

• permission mode

这个顺序其实很重要。比如:

• 没有 auth,某些远程功能和策略判断就是不完整的。

• 没有 policy limits,某些工具和模式理论上就不该暴露给模型。

• 没有 tool permission context,后面生成的 tool pool 就可能越权。

也就是说,Claude Code 不是先生成工具列表,再补权限;而是先建环境,再决定模型到底看见什么工具、哪些 agent、哪些命令。

3. 组装命令、工具、MCP、插件、Agent 定义

main.tsx 会调用:

• getTools(...)

• agent definitions 的加载逻辑

• MCP 连接与资源装载

• plugin 启动

• skills 初始化

这一步决定的是:当前会话可见的能力表面。

注意这里不是简单拼个数组就结束了。Claude Code 把“用户能不能用”“模型能不能看见”“当前模式是否允许”“策略是否屏蔽”“插件是否可用”“MCP 是否连接成功”全部算进去了。

所以这里形成的不是一个“功能列表”,而是一份动态能力快照。

4. 建立全局状态仓库

src/state/AppStateStore.ts 里的 AppState 很值得仔细看。它不是只管 UI,而是统一承载了:

• 当前设置

• 主模型状态

• 权限上下文

• 任务集合 tasks

• agent 名称注册表

• foreground / viewing agent

• MCP 客户端与资源

• plugin 状态

• agent definitions

• todo

• notification

• elicitation

• thinking 开关

• prompt suggestion

• session hooks

• computer use / browser / tungsten 等扩展状态

• REPL VM context

这说明 Claude Code 的状态设计是“交互状态 + 执行状态 + 协作状态”统一管理,而不是把 agent 执行藏在一堆不可见 side effect 里。

5. 启动 REPL

多处 launchRepl(...) 调用说明 main.tsx 最终并不是只走一条路,而是针对不同的恢复、远程、初始化结果进入不同版本的 REPL。

这意味着 REPL 在这里不是一个简单的“输入框组件”,而是整个运行时的主舞台。

6. 作为各类模式的桥梁

main.tsx 同时理解:

• 本地交互模式

• background session

• remote viewer

• bridge 模式

• assistant / kairos 模式

• worktree 模式

• teammate / swarm

从架构角度看,它像一个总控室:不是做具体工作,而是把整套系统组装成“当前这次会话该运行的那个版本”。

04

三、真正的心脏不是 UI,而是 query.ts

如果 main.tsx 是总装车间,那么 src/query.ts 才是心脏。

这份实现的关键价值在于:它不是“发一个请求,拿一个响应”,而是一个完整的agentic turn loop。也就是:

01 收集消息

02 组织 system prompt / user context / tool context

03 调模型

04 接流式输出

05 提取 tool use

06 执行工具

07 把 tool result 回灌到消息流

08 必要时继续下一轮

09 处理中断、压缩、预算、hook、恢复

很多所谓“agent 框架”做到第 6 步就已经很吃力了,但 Claude Code 还额外做了好几层工业化处理。

1. 它显式区分 immutable params 和 mutable loop state

query.ts 里把不可变参数和会跨迭代变化的 state 分得很清楚。这个做法的意义是: 当一个 turn 会经历多次 tool use、压缩、继续生成、异常恢复时,状态管理很容易变成灾难。Claude Code 选择把“循环里的可变部分”显式集中起来,从而让每个 continue 分支都能有稳定的收敛点。

2. 它天然支持“长回合”,而不是一问一答

这里的设计核心不是“聊天历史”,而是“当前这轮任务是否完成”。 所以代码里会出现:

• auto compact

• micro compact

• reactive compact

• token budget

• max output tokens recovery

• stop hooks

• tool use summary

• pending memory prefetch

这些都是为了一个目标:让一个复杂任务能跨多次模型采样稳定推进,而不是被上下文窗口一刀切断。

3. 它把工具执行放进了主循环,而不是外挂

这件事听起来显而易见,但很多系统其实是“模型产生工具调用 -> 外部 orchestrator 处理 -> 再拼回消息”。Claude Code 的不同之处在于,工具不是外挂,而是 query loop 的内生部分。

这使得它可以自然实现:

• 工具结果预算控制

• 工具结果内容替换与压缩

• streaming tool executor

• tool progress 消息

• stop hook 与 post tool use hook

• 恢复时的 tool result reconstruction

这也是为什么它能把 agent 跑得很像“程序执行”,而不是“聊天里偶尔插几个函数调用”。

Claude Code 运行时分层图

交互层、推理循环层、执行系统层和横切能力线,基本就是 Claude Code 的四张骨架图。

05

四、工具系统是第二个核心:不是 function calling,而是可治理的执行面

src/tools.ts,最容易注意到的是工具很多;但更值得注意的是工具被当成统一的能力协议。

getAllBaseTools() 里可以看到系统的工具版图非常大:

• 文件读写类

• Shell / Bash / PowerShell

• AgentTool

• SkillTool

• MCP 资源工具

• 任务相关工具

• Plan / Worktree / Config 等模式工具

• Web / Browser / LSP / REPL 等扩展工具

但架构上最重要的不是“有多少工具”,而是下面三点。

1. 工具可被 feature gate、环境、模式共同裁剪

Claude Code 的工具并非固定注册。它会根据:

• feature 开关

• 当前 user type

• 是否启用 LSP

• 是否启用 worktree

• 是否启用 swarms

• 是否启用 plugin / MCP / browser

• 当前 permission mode

动态构造出最终可用工具集。

这说明工具不是“SDK 内建函数”,而是一个会随着会话环境变化的、受治理的执行表面。

2. 工具既是能力,也是提示工程的一部分

由于系统 prompt 会把工具定义暴露给模型,因此工具列表本身就构成了模型的“操作世界观”。 Claude Code 很清楚这一点,所以它非常在意:

• 哪些工具直接暴露

• 哪些工具在当前模式下隐藏

• 哪些工具只在具备权限时给出

• 哪些工具需要用更专门的 agent prompt 来限制

这就是为什么 Explore、Plan、Verification 这些 built-in agent 会显式禁用一批工具。 它不是为了“少给点工具更安全”这么简单,而是为了把 agent 的行为边界写进工具表面本身。

3. 工具执行被设计成可观察、可统计、可回放

toolExecution.ts 看,工具执行路径会顺带处理:

• telemetry

• permission decision

• hook

• tracing

• progress

• error classification

• code edit 决策统计

• tool result 格式化

这意味着“调用一个工具”不是普通函数调用,而是一次带治理元数据的操作事件。

如果把这层抽掉,Claude Code 只剩一个“能发 bash 命令的聊天机器人”;把这层保留,它才真正像一个 agent 平台。

06

五、最漂亮的一刀:并发安全不是拍脑袋,而是内建到工具编排器里

src/services/tools/toolOrchestration.ts 很小,但非常值钱。

它干的事其实可以一句话概括: 把工具调用按并发安全性自动分批,读类工具并行跑,写类工具串行跑。

这个设计的价值远大于代码体量。

为什么它重要

多工具 Agent 的一个常见问题是:

• 让模型一次发多个工具调用吧,容易冲突。

• 全部串行跑吧,又太慢。

Claude Code 的答案不是二选一,而是做了一层 partitionToolCalls(...)

• 如果工具被判断为 concurrency-safe,就可以归入并发批次。

• 如果不安全,就单独串行执行。

这会带来三个非常实际的好处。

第一,快。 连续的读文件、搜代码、查资源这类调用本来就不该串行排队。

第二,稳。 文件编辑、写入、可能依赖上下文变更的工具不会并发互踩。

第三,模型不需要理解所有并发细节。 模型只要表达想做什么,运行时会帮它做保守且高效的执行编排。

这是我非常欣赏的一点:把复杂性从模型侧移到运行时侧。这是成熟系统该有的姿势。

07

六、任务系统:Claude Code 真正把 Agent 当“任务实体”了

如果说 query.ts 是心脏,那么 Task.ts 和各类 task 实现就是骨架。

在 Claude Code 里,agent 并不是“一个函数调用结果”或“一段额外 transcript”,而是明确的 task。

Task.ts 里定义了统一的任务类型:

• local_bash

• local_agent

• remote_agent

• in_process_teammate

• local_workflow

• monitor_mcp

• dream

这套抽象非常关键,因为它把原本可能互不相干的执行对象统一到了一个框架里。

1. 每个任务都有统一的身份和生命周期

任务都有:

• id

• type

• status

• description

• toolUseId

• startTime/endTime

• outputFile

• outputOffset

• notified

也就是说,在 Claude Code 看来,一个后台 agent 和一个 shell 任务、一个远程任务,本质上都是“可追踪的异步执行单元”。

2. 输出文件是一级设计,不是调试附属物

任务会有自己的 outputFile。这点很重要。 很多系统的后台 agent 只能在 UI 里“看状态”,但 Claude Code 允许任务输出落盘,这意味着:

• 可以恢复

• 可以通知

• 可以从别的视图读取

• 可以做 sidechain transcript

• 可以在后台运行时不依赖前台 UI 常驻

这一步实际上让 agent 从“前端状态”升级成了“持久化任务对象”。

3. 通知系统与任务状态是耦合的

LocalAgentTask.tsx 里会在任务完成、失败、停止时构造 <task-notification> 风格的消息,进入消息队列。 这很巧妙,因为它把后台任务的完成结果重新翻译成了主对话可消费的系统消息。

于是前台主 agent 不需要一直阻塞等待子 agent。它只需要在合适的时候“收到一条任务完成通知”。

这就是一个很像操作系统的设计:

• 后台任务自己跑

• 前台界面保持响应

• 结果用统一通知回到主循环

08

七、AgentTool:这里才是“多 Agent 系统”的真正入口

src/tools/AgentTool/AgentTool.tsx 是整套多 agent 设计的核心门面。

从架构上看,它承担了四个角色:

01 给模型暴露“启动新 agent”的工具接口。

02 解析当前请求到底是普通子 agent、teammate、fork child、remote agent,还是隔离 worktree agent。

03 为新 agent 构造工具池、系统 prompt、权限模式、上下文。

04 把结果接回 task/notification/UI 体系。

这个文件的厉害之处在于:它没有把“spawn agent”做成一条单线逻辑,而是做成了一个统一入口,多种执行后端。

它至少支持这几类 Agent 形态

• 同步子 agent

• 后台本地 agent

• teammate(team/split pane)

• fork subagent

• worktree 隔离 agent

• remote 隔离 agent

这意味着用户和模型看到的是一个统一工具:AgentTool。 但运行时背后可以根据条件把任务送往不同执行后端。

这正是优秀平台设计的典型标志:表面统一,底层可分流。

Agent Runtime 关系图

真正拉开差距的,是 Agent、Task、工具编排和隔离能力在同一套运行时里互相咬合。

09

八、runAgent.ts:Claude Code 如何真正“跑”一个 Agent

如果 AgentTool 负责“发车”,runAgent.ts 负责“开车”。

我认为 runAgent.ts 的价值主要体现在四个方面。

1. Agent 不是裸跑,而是带专属上下文启动

这里会为 agent 组装:

• promptMessages

• toolUseContext

• canUseTool

• querySource

• override system prompt / user context / system context

• model

• maxTurns

• availableTools / allowedTools

• MCP clients

• transcriptSubdir

• worktreePath

这说明 Claude Code 对 agent 的理解不是“同一个主模型再套一层 prompt”,而是一个有自己运行上下文的执行单元。

2. Agent 可以附带自己的 MCP 服务器

initializeAgentMcpServers(...) 非常有代表性。 它允许 agent definition 定义自己的 MCP server,且这些 server 是在 agent 启动时增量挂载的,结束时还能清理。

这背后是个很超前的思路:

Agent 的能力不必完全由父会话预先决定,agent 自己也可以声明“我启动时需要这些外部能力”。

这让 agent definition 更像一份“可执行角色描述”,而不是纯 prompt 文本。

3. Agent transcript 被认真当回事

运行过程中,系统会处理:

• transcript subdir

• sidechain transcript

• metadata write

• session storage

• cache safe params

这说明子 agent 的存在不是 ephemeral 的,它是可恢复、可追溯、可观察的。 换句话说,Claude Code 在意的不是“子 agent 有没有跑完”,而是“子 agent 作为一个独立执行实体,它的运行痕迹能否被系统理解和接管”。

4. 工具集既可继承,也可精确裁剪

runAgent.ts 支持:

• availableTools

• allowedTools

• useExactTools

这让它在不同场景下能切换两种思路:

• 普通子 agent:给你一个按角色和权限裁剪后的工具集。

• fork child:给你和父 agent 几乎字节级一致的工具表面,以便命中 prompt cache。

这不是“一个通用函数支持几个参数”的层面,而是同一套执行器兼容两种完全不同的 agent 设计哲学。

10

九、内置 Agent 定义:它把“角色”提升成数据层

src/tools/AgentTool/loadAgentsDir.ts 非常重要,因为它说明了 Claude Code 对 agent 的看法:

Agent 不是硬编码职业,而是一类可加载、可覆盖、可组合、可插件化的配置对象。

Agent definition 里至少可以带这些字段:

• agentType

• whenToUse

• tools

• disallowedTools

• skills

• mcpServers

• hooks

• model

• effort

• permissionMode

• maxTurns

• background

• initialPrompt

• memory

• isolation

• omitClaudeMd

这意味着一个 agent 不是“某段 prompt 文本”,而是:

• 行为边界

• 工具权限

• 依赖能力

• 模型策略

• 记忆策略

• 隔离策略

• 运行形态

的组合对象。

这层抽象做出来后,系统就能自然支持:

• built-in agent

• user agent

• project agent

• policy agent

• plugin agent

而且还有覆盖顺序。 这一步非常像插件系统或编译器 pass 配置系统,而不像传统聊天产品。

11

十、REPL 不只是 UI,而是统一调度台

src/screens/REPL.tsx 文件巨大,但它大的原因并不混乱,而是因为它承担的是“统一交互控制面”角色。

它同时要处理:

• 消息显示

• PromptInput

• 命令队列

• 通知

• 权限请求

• 背景任务导航

• teammate 视图

• 远程 session

• IDE 集成

• browser / tungsten / companion 等侧边状态

• query 发起与流式响应处理

• file history / session restore / compact 后清理

这在产品体验上带来一个极其重要的结果:

无论是主 agent、后台 agent、同进程 teammate、远程 agent、工具权限审批,用户都在一个统一的终端操作面里理解它们。

这点很容易被低估。很多 agent 系统技术上能并发,但用户完全不知道系统现在在干嘛。Claude Code 则把:

• 任务状态

• 当前查看对象

• 权限审批

• teammate transcript

• 远程连接状态

• 后台通知

统一进了 AppState + REPL。

所以它不只是“Agent 能力强”,而是“Agent 的操作体验被系统化了”。

Mermaid 图 2

12

十一、从协作角度看,它有三层 Agent 形态

把所有实现串起来后,我会把 Claude Code 的 agent 体系分成三层。

第一层:普通子 Agent

这类 agent 通过 AgentTool 启动,通常是:

• 有专门角色 prompt

• 有受控工具集

• 跑在本地 query loop

• 同步返回或后台返回

它解决的是“主 agent 不该自己干所有事”的问题。

第二层:同进程 Teammate

这类 agent 的代表是 InProcessTeammateTaskspawnInProcessTeammate。 特点是:

• 在同一个 Node.js 进程内运行

• 通过 AsyncLocalStorage / teammate context 做身份隔离

• 可以有 team-aware identity

• 可以和 leader 通过 mailbox / permission bridge 互动

它解决的是“多 agent 协作要便宜、快、共享进程资源”的问题。

第三层:隔离 Agent

包括:

• worktree agent

• remote agent

• tmux teammate

这类 agent 用于更强的隔离、更长的运行时间、或者更远的执行环境。 它解决的是“复杂任务不能都挤在同一个上下文里”的问题。

这三层结合起来,Claude Code 就拥有了从轻量协作到强隔离执行的完整梯度。

Mermaid 图 3

13

十二、为什么它的 Agent 系统能控得住:答案是权限系统不是补丁,而是主路径

很多 agent 框架的问题不在于“不够聪明”,而在于“太难治理”。Claude Code 之所以敢把 Shell、编辑、MCP、远程、子 agent 都放进去,是因为它的权限系统从一开始就是主路径。

ToolUseContextToolPermissionContextcanUseTool、permission rules、auto mode、ask/allow/deny 流程,几乎贯穿所有执行面。

尤其在 teammate 这块更明显。 createInProcessCanUseTool(...) 这段设计很强:

• worker 想调用工具

• 先过权限判断

• 如果需要 ask,可以复用 leader 的 ToolUseConfirm dialog

• 如果 bridge 不可用,再退回 mailbox 同步

这个设计解决的是多 agent 系统非常棘手的问题:

子 agent 有独立意图,但最终权限裁决仍然应该统一回到主用户控制面。

于是 Claude Code 既能并发多个执行体,又不会让每个执行体都各自弹一套权限 UI,把用户搞疯。

这是一种非常成熟的“控制权回收”设计。

14

十三、记忆、Hook、MCP、Plugin 都不是外挂,而是 Agent Runtime 的扩展面

很多系统的扩展能力是后来硬加的,所以很松散。Claude Code 不太一样,它的扩展能力大都能自然落在 agent runtime 里。

1. Agent Memory

agentMemory.ts 支持:

• user

• project

• local

三种 memory scope。 这说明它不是简单地“给 agent 一个记事本”,而是认真处理了作用域:

• 用户级经验

• 项目级知识

• 本地机器级临时知识

这比“所有记忆都塞同一个文件夹”高级很多。

2. Hook

Agent definition 可带 hooks;tool execution 也会跑 pre/post tool hooks;query loop 还有 stop hooks。 这意味着系统不是只允许 agent“调用工具”,还允许系统在关键节点插入规则和自动化。

3. MCP

MCP 在 Claude Code 里不是外接插件,而是第一等能力来源:

• 能进入主工具池

• 能进入 agent 专属工具池

• 能带资源、命令、连接状态

• 能被权限、策略、配置、plugin 共同裁剪

4. Plugin

插件不仅能加命令、加工具,还能加 agent。 这一步很有意思,因为它把“能力扩展”和“角色扩展”统一了。

也就是说,第三方不只是在给 Claude Code 塞几个 API,而是在给它新增新的行动者。

15

十四、架构总图:如果把它画成一张图

我会把 Claude Code src 的核心结构画成下面这样:

CLI Entrypoint
-> fast-path dispatch
-> main runtime assembly

Main Runtime
-> config / auth / policy / analytics / feature gates
-> commands / tools / MCP / plugins / agents / state
-> launch REPL

REPL Control Plane
-> user input
-> message queue
-> permission UI
-> task panels / teammate views / notifications
-> stream rendering

Query Loop
-> build prompt
-> sample model
-> parse tool calls
-> run tools
-> compact / budget / recover / continue

Execution Substrate
-> Tool execution
-> Task framework
-> LocalAgentTask
-> InProcessTeammateTask
-> RemoteAgentTask
-> Shell tasks

Agent Runtime
-> Agent definitions
-> AgentTool
-> runAgent
-> fork / worktree / remote / swarm
-> agent memory / MCP / hooks

这张图里最值得注意的一点是: Agent Runtime 是被嵌在 Query + Tool + Task 这三者交叉处的。

它不是单独一层中间件,也不是一个 SDK 插件。这是它能做深的根本原因。

16

十五、十个最有用、最有创新的 Agent 实现亮点

下面进入这篇文章最核心的部分。 我会按“实用价值 + 架构创新”的综合权重排序。

17

亮点一:把 Agent 设计成 Task,而不是一段子对话

这是我认为整个项目最重要的设计。

很多系统实现子 agent 的方式,本质上是:

• 复制一点上下文

• 发一个新的模型请求

• 把文本结果塞回主会话

这样做当然能工作,但问题也很明显:

• 没有统一生命周期

• 没法后台运行

• 没法可靠恢复

• 没法统一通知

• 没法进入任务面板

• 没法和其他任务类型共存

Claude Code 直接绕过了这个陷阱。 它从一开始就把 agent 放进任务系统里,于是 agent 自带:

• 任务 ID

• 状态机

• 输出文件

• UI 面板

• 杀死逻辑

• 通知逻辑

• SDK 事件

这带来的收益是结构性的。 当你以后要加 remote agent、swarm teammate、后台验证 agent 时,不需要重新设计“它怎么显示、怎么终止、怎么恢复”。因为 task 层已经兜住了。

这是最有用的设计。 它决定了这套系统能不能持续演化。

18

亮点二:工具并发不是“盲并发”,而是按语义分批

toolOrchestration.ts 里的分批策略是我非常喜欢的一笔。

大模型常常会在一个回合里提出多个工具调用,如果运行时完全串行,系统慢;如果完全并发,系统乱。Claude Code 的做法是:

• 让每个工具自己声明是否 concurrency-safe

• orchestration 层按调用序列切分批次

• 连续的只读安全工具并发执行

• 非安全调用保持串行

它妙在两点:

01 不要求模型学会并发控制。

02 不要求工程师手写复杂的“哪些工具能一起跑”的外部规则。

这实际上是一种把工具语义上收,再把运行效率往外放的设计。 底层保守,顶层高速。

对于需要大量 grep / glob / read 的代码 agent 来说,这个收益巨大。

19

亮点三:Fork Subagent 的 prompt cache 设计非常高级

forkSubagent.ts 是整套系统里最让我眼前一亮的实现之一。

通常大家讨论 fork 时,会停留在“把父上下文复制给子 agent”。 Claude Code 往前走了一步:它不仅复制上下文,还在尽量保证fork children 的 API 请求前缀字节级一致,从而共享 prompt cache。

做法包括:

• 保留父 assistant message 的完整 tool_use/thinking/text

• 为所有 tool_use 统一构造相同的 placeholder tool_result

• 只把真正变化的 directive 放在最后

• 让 fork child 继承父 prompt bytes,而不是重新生成 system prompt

这代表作者非常清楚现代大模型系统的真实瓶颈之一: 不是“能不能 fork”,而是“fork 后 token 成本会不会炸”。

这类设计非常有平台味。 它不是功能层创新,而是运行成本层创新。

20

亮点四:同进程 Teammate 用上下文隔离而不是进程隔离,速度和复杂度拿捏得很好

spawnInProcessTeammate + inProcessRunner.ts 展示了一个很聪明的平衡:

• 不为每个 teammate 启一个重进程

• 但又不给它和主 agent 混成一锅

方法是:

• 同进程运行

• 单独的 AbortController

• team-aware identity

• teammate context

• 独立 task state

• 权限桥接回 leader

这带来的好处很多:

• 启动快

• 资源共享

• UI 同步简单

• transcript 可直接接到主状态树里

如果所有 teammate 都用 tmux pane 或独立子进程,成本和复杂度会高很多。 如果全部都塞进同一个会话上下文,又会失控。 Claude Code 在这里选了一个极其实用的中间点。

21

亮点五:权限审批被设计成“领导审批制”,非常符合多 Agent 产品形态

多 Agent 系统最怕的不是不会并行,而是并行后谁来做最终决策。

Claude Code 在 teammate 权限这块的思路非常清楚:

• worker 可以发起动作

• 但 ask 型权限尽量回到 leader 的确认 UI

• 如果 UI bridge 不可用,再退化成 mailbox 协议

这让整个系统形成了一个非常自然的控制结构:

• 执行分散

• 决策集中

对用户来说,这意味着你可以享受多 agent 带来的速度,但不会因为出现三个 teammate 就弹出三套权限对话框。

从产品体验到系统治理,这都是非常正确的一步。

Mermaid 图 4

22

亮点六:Agent Definition 不是 prompt 文件,而是一份可执行配置

很多项目会说“我们支持自定义 agent”,最后其实只是让用户写一段角色 prompt。 Claude Code 明显不满足于此。

它的 agent definition 可以控制:

• 模型

• effort

• 工具白名单 / 黑名单

• permission mode

• hooks

• mcpServers

• memory

• background

• isolation

• omitClaudeMd

也就是说,Claude Code 里的 agent 更像 Kubernetes 里的 workload spec,而不是 ChatGPT 里的自定义 GPT prompt。

这一步的影响很深远:

• 角色能力可以被声明式管理

• 插件可以安全地分发 agent

• 项目级、用户级、策略级 agent 可以统一加载和覆盖

• 后续要做 agent 市场或团队标准化也容易

这是把 agent 从“提示词工艺品”推进到“工程对象”的关键一步。

23

亮点七:Agent 可增量挂载自己的 MCP 能力,是真正的“按角色配外设”

runAgent.ts 里的 agent-specific MCP server 初始化是个很值得抄的模式。

它意味着:

• 父会话不需要预装所有外部能力

• 某个 agent 启动时可以声明自己需要哪些 MCP

• 内联定义的 MCP 还能在 agent 结束时清理

• 共享 MCP 与 agent 私有 MCP 被区分对待

这就像什么? 像操作系统里给某个进程挂载它自己的设备或文件系统视图。

从 agent 设计角度,这很高级。 因为它允许你把“角色”与“外部能力”绑定,而不是把所有能力一股脑暴露给主模型。

这既减少提示噪音,也减少权限面,还提高角色专注度。

24

亮点八:Agent Memory 的三层作用域设计,非常务实

agentMemory.ts 支持 user / project / local 三种 scope,这个设计我认为非常成熟。

为什么?

因为 agent 记忆最怕的就是“全混”。 如果所有东西都记在同一层:

• 跨项目污染严重

• 团队共享和个人偏好分不清

• 远程环境和本地环境差异难处理

Claude Code 直接把它切成三层:

• user:跨项目的通用经验

• project:项目共享知识

• local:本机、本工作副本相关的局部知识

这不是学术上最 fancy 的记忆系统,但它是最工程、最可落地、最符合日常开发场景的设计之一。

很多系统喜欢上来谈“向量数据库长期记忆”,Claude Code 这里反而更克制,也更实用。

25

亮点九:工作隔离被做成一等能力,不只是一条 shell 命令

在 Claude Code 里,隔离不是“用户自己去开个新目录”。 它有明确的一等语义:

• worktree

• remote

而且这不是只在 UI 层暴露一个按钮,而是深入到 agent definition、AgentTool、runAgent、task、恢复逻辑、metadata 里。

特别是 worktree 这条线,非常说明工程成熟度:

• agent 可在独立 git worktree 里运行

• 子 agent 会收到专门的 worktree notice

• 路径语义会被提醒重新解释

• 结果还能回到主系统里

这说明 Claude Code 不是只关心“怎么让 agent 改文件”,还关心“怎么让 agent 改文件时不把主工作区搞乱”。

这对真实开发非常重要。

26

亮点十:验证 Agent 被设计成“反向证明机”,而不是礼貌型 reviewer

verificationAgent.ts 我也非常喜欢。 它的重点不是再造一个 reviewer,而是显式把这个 agent 塑造成一个会主动找失败证据的验证者。

这里最值得注意的是两件事:

01 它强制要求实际运行命令与观察输出。

02 它明确对抗“verification avoidance”这种 LLM 常见偷懒模式。

很多系统嘴上说“会验证”,实际上只是读代码后说“看起来没问题”。 Claude Code 这里则把“你必须跑命令、必须记录输出、必须给 PASS/FAIL/PARTIAL verdict”写进了角色契约。

它本质上是在对抗 LLM 的人性弱点,这非常现实,也非常重要。

27

十六、为什么这些亮点真正有用

上面十点里,有些看起来偏底层,有些看起来偏产品。但它们之所以重要,不是因为“写得巧”,而是因为它们一起解决了多 Agent 系统最常见的五个失败模式。

失败模式一:Agent 会跑,但不可控

Claude Code 用 task + permission + UI control plane 解决了。

失败模式二:Agent 能并发,但一并发就乱

Claude Code 用 tool partition、leader approval、task state、teammate identity 解决了。

失败模式三:Agent 很能干,但成本太高

Claude Code 用 fork cache 设计、按角色裁剪工具、按需 MCP、omit CLAUDE.md、不同模型路由解决了。

失败模式四:Agent 能做事,但做错后系统没法恢复

Claude Code 用 transcript、metadata、outputFile、task notification、resume/restore 路线解决了。

失败模式五:Agent 很强,但用户完全不知道它在干嘛

Claude Code 用 REPL 控制面、task 面板、teammate 视图、通知、progress 跟踪解决了。

也就是说,这套系统真正强的地方不是某个单点功能,而是它把多 Agent 从“demo 能跑”推进到了“日常可用”。

28

十七、如果让我概括它的架构哲学

通读 src 之后,我会把 Claude Code 的架构哲学总结成下面七句话。

1. 让模型负责决策,让运行时负责约束

模型提出动作,但权限、并发、恢复、通知、隔离这些硬约束都收在运行时。

2. 让 Agent 成为系统对象,而不是提示词技巧

Agent 有定义、有工具面、有状态、有任务身份、有记忆、有隔离策略。

3. 让异步成为默认能力,而不是额外模式

后台 agent、通知、output file、resume、remote,本质上都在服务异步。

4. 让协作建立在统一控制面之上

多 agent 可以并行,但最终仍回到同一个 REPL / AppState / permission UI。

5. 让扩展能力进入主路径

MCP、plugin、skills、hooks、memory 都不是外挂。

6. 让性能优化服务于 Agent 规模化

启动快路径、prompt cache、并发读工具、按需能力加载,都不是小修小补。

7. 让“可恢复、可追踪、可解释”成为一等公民

如果一个 agent 跑完了却无法恢复、无法追踪、无法通知,那么它在工程上就还不算真正存在。

29

十八、我认为这套系统最值得借鉴的三件事

如果你是做 AI Coding Agent、终端 Agent、工作流 Agent,甚至只是做复杂工具调用编排,我觉得最值得借鉴的是这三件事。

借鉴一:先做 Task Runtime,再做 Agent 花样

没有任务系统,所有高级 agent 最终都会沦为“再开一个模型请求”。 Claude Code 的经验是:先有任务实体,再有 agent 玩法。

借鉴二:把权限和工具编排做成主路径

工具系统如果只是“调用函数”,很快就会碰到安全和混乱问题。 必须从第一天开始就把权限、并发、日志、hook、状态更新嵌进去。

借鉴三:统一交互控制面非常重要

很多团队只顾后端编排,忽略用户怎样理解系统。 Claude Code 强的地方在于:后台 agent、worker、remote、权限、恢复,全都能回到一个统一的终端界面里被解释。

30

十九、它有什么代价

说了这么多优点,也要说代价。

这套设计并不便宜。 它的代价至少有四个。

1. 心智复杂度高

这里不是一个简单 MVC 项目,而是一套模式很多、状态很多、feature gate 很多的系统。 新人上手会慢。

2. main.tsx / REPL.tsx 这种总装层会非常大

这是统一控制面的必然代价。 优点是系统能力整合强;缺点是文件会很重。

3. 需要大量 feature gate 和分层约束来防止系统膨胀

Claude Code 大量使用 feature()、动态 require、按模式裁剪工具。这其实是在和复杂性长期对抗。

4. 测试和调试门槛不低

因为它涉及:

• 流式响应

• 任务状态

• 权限交互

• 多 agent

• 本地/远程

• UI 与运行时联动

这种系统天然比普通 CLI 难测。

但从结果看,这些代价是值得付的。 因为你换来的是一个非常少见的、真正“系统化”的 coding agent runtime。

31

二十、最终总结:Claude Code 的 src 到底讲了一个什么故事

如果让我用博客结尾的方式来概括,这个仓库 src 讲的不是“如何把 Claude 放进终端”,而是下面这个更大的故事:

当你认真对待 Agent,不把它当聊天窗口里的小把戏,而把它当成一种需要调度、治理、隔离、恢复、协作的运行时实体时,整个代码结构都会改变。

于是你会看到:

• 入口层不再只是参数解析,而是多运行模式分流。

• 主程序不再只是启动 UI,而是装配完整运行时。

• 查询循环不再只是聊天,而是多轮 agentic execution。

• 工具不再只是 function call,而是受治理的执行接口。

• Agent 不再只是 prompt,而是具备任务身份的执行体。

• 协作不再只是“多开几个子请求”,而是 leader/worker/team/runtime。

• 验证不再只是“看起来没问题”,而是带证据的对抗式检查。

从这个意义上说,Claude Code 的源码最值得学习的,不是某个具体技巧,而是它背后的态度:

把 Agent 当系统来做。

这也是我读完 src 之后,觉得它最强的一点。

32

附:十个亮点的最终排序清单

为了方便快速回看,这里把前面的亮点再压缩成一份短名单。

01 Agent 即 Task:把 agent 纳入统一任务系统,是整套架构成立的前提。

02 按语义分批的工具并发编排:既快又稳,解决多工具回合的核心矛盾。

03 Fork 子 Agent 的 prompt cache 复用设计:这是真正考虑规模化成本的实现。

04 同进程 teammate + 上下文隔离:在性能和隔离之间拿到极佳平衡。

05 Leader 审批制权限桥接:多 agent 协作里非常实用的控制模型。

06 声明式 Agent Definition:把角色从 prompt 文本升级为工程对象。

07 Agent 专属 MCP 增量挂载:角色和能力可以精确绑定。

08 三层作用域 Agent Memory:朴素但极实用,明显考虑了真实开发场景。

09 Worktree / Remote 一等隔离能力:不是小技巧,是架构内建能力。

10 Verification Agent 的反偷懒设计:非常懂 LLM 弱点,也很懂工程验证。

33

后记:这篇文章适合怎么读

如果你是第一次接触这套源码,我建议这样读:

01 先读 src/entrypoints/cli.tsxsrc/main.tsx,建立“系统怎么启动”的全景图。

02 再读 src/query.tssrc/tools.tssrc/services/tools/toolOrchestration.ts,理解主循环和工具编排。

03 然后集中读 src/tools/AgentTool/src/tasks/Agentsrc/utils/swarm/,你就会看见它真正的 agent runtime。

04 最后再回来看 REPL.tsxAppStateStore.ts,你会明白为什么 UI 层会长成这样。

到这里,Claude Code src 的主干就基本打通了。

Mr. Guo Logo

© 2026 Mr'Guo

Twitter Github WeChat