从前端工程师视角,系统读懂 Claude Code 的架构设计

claude code 源码泄露这事儿大家应该知道了吧?不知道的我再说一次。 2026 年 3 月 31 日,@anthropic-ai/claude-code npm 包的 source map 意外暴露了 R2 存储桶中的未混淆 TypeScript 源码,由 Chaofan Shou (@Fried_rice) 率先发现。这次泄露让我们有机会一窥这个企业级产品的完整架构设计。

Claude Code 项目全景总览

项目定位

这个仓库并不是一个普通的 Node CLI,而是一套把 CLI+AgentRuntime+ToolRuntime+TUI+扩展平台 压在同一个进程模型里的企业级 Agent 产品内核。

从前端工程师视角看,它最值得学习的不是某个单点功能,而是它如何把下面几件事工程化地拼成一个整体:

  • 把用户输入组织成多轮可恢复的会话
  • 把模型调用包装成可插拔的"查询引擎"
  • 把文件、命令、MCP、插件、技能都抽象成统一能力面
  • 把上下文压缩、子 agent 并行、权限控制、UI 反馈放进同一条主链路
  • 在大量动态能力存在时,仍然尽量保持 prompt cache 稳定

建议分层

结合源码结构,我建议按下面 8 层学习:

  1. 启动与入口层
  2. 命令解析与路由层
  3. 会话状态与 UI 编排层
  4. 上下文构建与查询引擎层
  5. 工具系统与调度层
  6. Agent 与并行协作层
  7. 扩展机制与外部能力接入层
  8. 构建发布与工程化基础设施层

全局架构图

为什么这套分层对前端工程师有价值

  • 它本质上是在做"复杂交互状态机",只是 UI 不在浏览器而在终端
  • 它把"页面动作"升级成了"模型 + 工具 + 状态 + 权限"的统一事务
  • 它的插件、技能、MCP,分别对应前端常见的微前端、配置中心、第三方能力接入
  • 它对 prompt cache 稳定性的追求,很像前端里对渲染稳定性、缓存命中率、依赖边界的追求

关键源码入口

  • src/entrypoints/cli.tsx:轻量启动分流,先判断是否走 fast path
  • src/main.tsx:完整 CLI 启动编排中心
  • src/entrypoints/init.ts:初始化环境、配置、遥测、网络能力
  • src/commands.ts:命令注册中心
  • src/tools.ts:工具注册与工具池组装中心
  • src/screens/REPL.tsx:交互式产品主界面
  • src/query.ts:核心查询循环
  • src/QueryEngine.ts:面向 SDK / Headless 的会话引擎封装

用户输入到结果输出的主路径

建议阅读顺序

  1. 先读启动层,搞清楚它如何"分流"不同运行模式
  2. 再读命令层,理解为什么命令、技能、插件命令能并存
  3. 再读状态/UI 层,理解 REPL 为什么能承载这么多异步事件
  4. 再读查询与上下文层,理解真正的 Agent 主循环
  5. 再读工具与 Agent 层,理解并行、权限、共享缓存
  6. 最后读扩展层和工程化层,理解它为什么可以持续增长

设计亮点

  • entrypoints/cli.tsx 用 fast path 把很多非主链路命令提前短路,减少冷启动成本
  • main.tsx 在顶层就开始并行预取多个昂贵资源,例如 keychain、MDM、GrowthBook
  • tools.tscommands.ts 都是"统一注册中心",但保留 feature flag 与动态扩展入口
  • query.ts 不是简单 API 调用,而是多轮消息驱动的状态循环
  • utils/forkedAgent.tstools/AgentTool/forkSubagent.ts 把 prompt cache 设计显式化了

对前端工程师的启发

  • 复杂产品先找"统一事件主循环",再看局部组件
  • 学架构不要被目录数量吓到,先抓注册中心和主链路
  • 好架构不是文件少,而是入口清晰、职责清晰、扩展清晰

可借鉴到业务系统的方式

  • 把"页面行为"抽象成统一动作协议,而不是散落在页面组件里
  • 把动态能力收敛到注册中心,避免在各个业务模块里偷偷扩展
  • 把"主流程"和"扩展流程"隔离开,让复杂性可控增长

我建议重点学习的 3 个设计点

  • 启动分流:先做 fast path,再做完整初始化
  • 统一能力注册:命令、工具、插件、技能都走统一入口
  • 主循环思维:把模型调用、工具执行、上下文压缩做成可恢复的循环

如果要做一个简化版

  • 第一步只做 CLI入口+query loop+3个工具
  • 第二步加 AppState+简单TUI
  • 第三步再加 插件/MCP/子agent``

01-启动与入口层

本层定位

这一层解决的问题不是"怎么跑起来",而是"如何用最小成本进入正确运行模式"。Claude Code 启动层明显分成两段:

  • 轻量入口: src/entrypoints/cli.tsx
  • 完整启动编排: src/main.tsxsrc/entrypoints/init.ts

这是一种很典型的企业级产品写法:先做早期分流,再做昂贵初始化。

核心职责

  • 识别命令行参数并走 fast path
  • 在真正加载大模块前做最便宜的预判
  • 预取高成本依赖,缩短完整启动链路
  • 初始化配置、遥测、网络、证书、远程设置、LSP 等全局能力
  • 最终把命令、工具、状态、REPL、非交互模式拼装起来

关键模块

  • src/entrypoints/cli.tsx
  • 负责早期参数分流
  • --version、bridge、daemon、bg session、特殊 MCP server 等路径做短路
  • src/main.tsx
  • 真正的产品入口
  • 负责启动时并行预取、命令/工具/插件/技能装配、模式切换
  • src/entrypoints/init.ts
  • 初始化配置系统、环境变量、遥测、代理、mTLS、清理逻辑
  • src/setup.ts
  • 偏会话级 setup,例如 cwd、hooks snapshot、worktree、tmux、session memory

关键调用链

代表性源码文件

  • src/entrypoints/cli.tsx
  • src/main.tsx
  • src/entrypoints/init.ts
  • src/setup.ts

为什么这样分层

如果一开始就无脑加载整个 CLI,会有几个问题:

  • 简单命令也要承担全量模块冷启动成本
  • 某些模式根本不需要 React/Ink、命令树、工具树
  • 容易在顶层 import 过早触发配置、证书、鉴权、副作用

所以它把入口拆成:

  • cli.tsx:只做"识别路径"
  • main.tsx:只做"产品装配"
  • init.ts:只做"基础设施初始化"
  • setup.ts:只做"会话级环境进入"

这就是典型的分层启动设计。

核心要素流程图

设计亮点

  • main.tsx 在顶层注释里明确写了为什么要提前并行读 keychain / MDM,这说明它不是"经验主义优化",而是被真实启动耗时驱动出来的优化
  • entrypoints/cli.tsx 通过动态 import 把不同运行模式隔离,减少非必要模块求值
  • init.ts 把"安全环境变量"和"完整环境变量"分阶段处理,说明它兼顾了信任边界
  • setup.ts 先捕获 hooks 配置快照,再进入会话,这是一种很强的可审计意识

对前端工程师的启发

  • 首屏优化不只是前端页面问题,CLI 也同样需要"启动路径拆分"
  • 顶层 import 是架构行为,不只是语法行为
  • 初始化必须分层,否则安全、性能、调试成本会混在一起

可借鉴到业务系统的方式

  • Web 应用可以把"登录前壳层"和"完整应用壳层"拆开
  • BFF / Node 服务可以把"配置初始化"和"请求级上下文初始化"拆开
  • 中后台项目可把"路由命中前的数据预取"和"进入页面后的完整装配"拆开

我应该重点学习的 3 个设计点

  • Fast path 设计:让轻量命令不承担完整产品冷启动
  • 并行预取:把多个昂贵初始化前置并重叠执行
  • 初始化分层:基础设施初始化与会话初始化分离

这些设计点对应前端什么能力

  • Fast path 对应首屏路由拆分与懒加载能力
  • 并行预取对应资源调度与 waterfall 优化能力
  • 初始化分层对应应用壳层架构能力

如果要自己实现一个简化版

  • 先做 cli.tsx->main.tsx 两层入口
  • 再把配置初始化独立成 init.ts
  • 最后再单独补 setup.ts 去承接工作区、会话、权限等逻辑

02-命令解析与路由层

本层定位

这一层负责把"用户意图"映射成"可执行能力"。它不是简单的命令表,而是一个可动态合并的路由系统:

  • 内建命令
  • feature flag 控制的命令
  • 技能命令
  • 插件命令
  • 工作流命令

核心职责

  • 注册内建 slash command
  • 处理不同账号形态、不同 provider、不同 feature flag 下的命令可见性
  • 动态合并技能、插件、工作流生成的命令
  • 在交互式 REPL 和非交互模式中提供一致的命令源

关键模块

  • src/commands.ts
  • 内建命令注册中心
  • meetsAvailabilityRequirement() 负责 provider 级过滤
  • loadAllCommands() 负责合并技能、插件、工作流命令
  • src/skills/loadSkillsDir.ts
  • 把 markdown 技能转为命令对象
  • src/utils/plugins/loadPluginCommands.ts
  • 从插件里读取命令与技能
  • src/plugins/builtinPlugins.ts
  • 注册内置插件带来的技能命令

关键调用链

代表性源码文件

  • src/commands.ts
  • src/skills/loadSkillsDir.ts
  • src/plugins/builtinPlugins.ts
  • src/utils/plugins/loadPluginCommands.ts

为什么它不是"一个大数组"那么简单

因为命令系统要同时满足几件事:

  • 某些命令只在特定 build / feature 下出现
  • 某些命令只有 claude.ai 用户或 console 用户可用
  • 插件和技能会在运行时增减
  • 同一能力既可能是 slash command,也可能在 Tool/Skill 体系里被模型间接调用

所以这里真正的设计重点是:

  • 注册中心统一
  • 过滤逻辑集中
  • 动态来源可合并

核心要素流程图

设计亮点

  • commands.ts 既是注册中心,也是策略中心
  • 命令的 availability 先于 isEnabled(),说明作者把"能力资格"和"功能开关"区分开了
  • 技能被转成命令对象这一做法非常重要,它让"配置文件描述能力"也能进入统一路由层

对前端工程师的启发

  • 路由系统不该只管页面跳转,它也可以是产品能力注册中心
  • 当系统有静态能力和动态能力时,关键不是分开管理,而是统一出口
  • "权限、可见性、来源"要在路由层集中表达,不能散在页面里

可借鉴到业务系统的方式

  • 后台系统的操作菜单、页面入口、批处理能力都可以统一建模
  • 低代码平台可把"内建动作 + 插件动作 + 配置动作"统一成 Action Registry
  • SaaS 产品可把租户能力、套餐能力、实验能力统一放到路由决策层

我应该重点学习的 3 个设计点

  • 统一命令描述模型
  • 动态命令合并机制
  • availability 与 enabled 分层判断

这些设计点在前端领域分别对应什么能力

  • 统一命令模型对应统一路由协议设计能力
  • 动态合并对应插件化与运行时装配能力
  • 分层判断对应权限与实验系统设计能力

如果我要自己实现一个简化版

  • 先做一个 Command 类型和静态命令表

  • 再加 markdown 配置驱动命令

  • 最后加插件来源和可见性过滤


03-会话状态与 UI 编排层

本层定位

这一层决定 Claude Code 为什么不是"命令执行器",而是"可持续交互的产品"。它把:

  • AppState
  • Store
  • REPL
  • 各种 hook
  • 远程事件、权限事件、MCP 事件、任务事件

全部编排进一个终端 UI runtime。

核心职责

  • 持有整场会话的全局状态
  • 让 TUI 对消息流、任务流、权限流持续响应
  • 承接交互模式和 Headless 模式之间的状态差异
  • 管理 foreground / background task、agent 视图、bridge、MCP、插件、通知

关键模块

  • src/state/AppStateStore.ts
  • 定义了巨大的 AppState 结构
  • 能看到系统真正关心的产品域模型:任务、MCP、插件、通知、bridge、agent registry、permission context
  • src/state/store.ts
  • 一个极简 store,实现 getState/setState/subscribe
  • src/state/onChangeAppState.ts
  • 把状态变化转成副作用,比如同步权限模式、保存配置、应用 env
  • src/screens/REPL.tsx
  • 交互式产品主舞台
  • 汇聚输入、消息渲染、任务导航、MCP 对话框、权限对话框、远程会话等

关键调用链

代表性源码文件

  • src/state/AppStateStore.ts
  • src/state/store.ts
  • src/state/onChangeAppState.ts
  • src/screens/REPL.tsx

为什么值得前端工程师重点看

因为它非常像一个超复杂前端应用,只是渲染容器换成了终端:

  • REPL.tsx 类似单页应用的根容器
  • AppState 类似全局应用状态模型
  • 大量 hook 类似浏览器里的事件订阅与副作用系统
  • message / task / permission / mcp 都是在做跨模块状态编排

它最强的一点是:UI 不是业务逻辑的边角料,而是 Agent runtime 的第一等公民。

核心要素流程图

设计亮点

  • store.ts 非常小,但把复杂度让给领域状态与订阅系统,而不是框架本身
  • onChangeAppState.ts 是一个很好的"副作用闸口",避免状态变化副作用散落
  • AppStatemcp/plugins/tasks/agentNameRegistry/remoteConnectionStatus 这些字段,基本就把产品域模型画出来了

对前端工程师的启发

  • 大状态不是坏事,坏的是没有域边界和副作用出口
  • 根组件不是只渲染页面,它也应该是运行时编排器
  • 状态变更后的副作用一定要集中,而不是哪里改状态哪里顺手做副作用

可借鉴到业务系统的方式

  • 把复杂中后台的消息、通知、任务、权限弹窗统一放到应用级状态机里
  • 把副作用归并到单一出口,例如 store middleware 或 domain event 层
  • 把"页面应用"改造成"事件驱动应用",尤其适合 AI Copilot、IM、工作台产品

我应该重点学习的 3 个设计点

  • AppState 的领域建模方式
  • Store + onChange 的轻量状态架构
  • REPL 作为运行时容器的设计方式

这些设计点在前端领域分别对应什么能力

  • 领域建模对应复杂业务抽象能力
  • 轻量状态架构对应全局状态设计能力
  • 运行时容器对应应用壳层与事件编排能力

如果我要自己实现一个简化版

  • 先做一个只包含 messages/tasks/permissions 的 store
  • 再做 REPL 主容器或 Web 根容器
  • 最后加 onChange 副作用层,统一处理持久化和外部同步

04-上下文构建与查询引擎层

本层定位

这一层是 Claude Code 的心脏。它解决的不是"发一次模型请求",而是:

  • 如何组织 system prompt、user context、system context、messages
  • 如何在多轮工具调用中持续推进
  • 如何在上下文过大时做 compact / auto-compact / snip
  • 如何把 REPL 与 Headless/SDK 共用同一套查询能力

核心职责

  • 构建 cache-critical 的 prompt 前缀
  • 驱动多轮 query loop
  • 处理中断、恢复、token budget、fallback model
  • 在需要时触发上下文压缩与恢复
  • 为子 agent 暴露 cache-safe params,提升并行调用的缓存命中率

关键模块

  • src/query.ts
  • 真实的 query loop
  • 负责 tooluse -> toolresult -> 下一轮 assistant 的循环
  • src/QueryEngine.ts
  • 对 query loop 的面向对象封装
  • 更适合 SDK / headless 场景
  • src/utils/queryContext.ts
  • 负责 system prompt、user context、system context 的统一获取
  • src/services/compact/autoCompact.ts
  • 自动 compact 门槛与策略
  • src/services/compact/compact.ts
  • 真正的 compact 执行逻辑
  • src/utils/forkedAgent.ts
  • 管理 cache-safe params,支持 forked agent 共享 prompt cache

关键调用链

代表性源码文件

  • src/query.ts
  • src/QueryEngine.ts
  • src/utils/queryContext.ts
  • src/services/compact/autoCompact.ts
  • src/services/compact/compact.ts
  • src/utils/forkedAgent.ts

为什么这层最值得深挖

很多 AI 工程只停留在:

  • 拼 prompt
  • 调 API
  • 回显结果

Claude Code 则把"上下文"当成一个长期运行的系统对象来经营。这里至少有四个重点:

  1. 查询循环不是一次请求,而是一个带状态的多轮状态机
  2. system prompt 与 tools 顺序会影响 prompt cache,因此它非常重视前缀稳定性
  3. 上下文过长不是异常情况,而是正常产品场景,所以 compact 被内建进主流程
  4. 子 agent 不只是并行运行,更要尽量复用父上下文的缓存前缀

核心要素流程图

1. 一次 query 的主循环

2. cache-safe params 与 fork 共享缓存

设计亮点

  • utils/queryContext.ts 很明确地把"影响 cache key 的前缀"单独抽出来,这是高水平设计
  • autoCompact.ts 把上下文窗口控制做成正式策略,不是出错后补救
  • compact.ts 不只做摘要,还会处理附件、技能、文件恢复等"后 compact 修复"
  • QueryEngine.ts 说明团队在把 REPL runtime 和 SDK runtime 抽象到统一模型

对前端工程师的启发

  • 上下文管理很像前端里的"状态归档 + 局部恢复 + 缓存命中"
  • 真正复杂的系统不是一个大函数,而是一条可恢复的循环
  • 当产品开始有"长会话"特征时,压缩、降采样、摘要不是优化项,而是架构项

可借鉴到业务系统的方式

  • 聊天产品可做"历史摘要 + 最近消息热区"
  • 工作台产品可做"长任务上下文压缩 + 最近操作重建"
  • Web Copilot 可做"主线程上下文 + 子任务共享前缀"

我应该重点学习的 3 个设计点

  • Query loop 的状态机写法
  • Compact 作为主流程而不是补丁功能
  • CacheSafeParams 的显式建模

这些设计点在前端领域分别对应什么能力

  • 状态机写法对应复杂异步流程编排能力
  • Compact 对应长生命周期数据治理能力
  • CacheSafeParams 对应缓存边界与依赖稳定性设计能力

如果我要自己实现一个简化版

  • 先做 messages->model->tool->model 的最小循环
  • 再加 token 统计与超限前压缩
  • 最后做父任务与子任务共享上下文前缀

05-工具系统与调度层

本层定位

这一层决定了 Claude Code 为什么能从"聊天"变成"执行"。模型本身只会生成 tool_use,真正让产品有行动能力的是这一层:

  • 统一工具描述协议
  • 工具池组装
  • 权限检查
  • 并发与串行调度
  • 流式工具执行

核心职责

  • 注册内建工具与 feature-gated 工具
  • 组装 built-in tools 与 MCP tools 的统一工具池
  • 根据权限上下文和模式过滤工具
  • 判断工具是否可并发执行
  • 在流式输出中尽早启动工具,同时保证结果回填顺序可控

关键模块

  • src/tools.ts
  • 内建工具注册中心
  • assembleToolPool() 是 built-in 与 MCP 工具池合并的统一入口
  • src/Tool.ts
  • 工具基础类型、工具匹配与工具上下文
  • src/services/tools/toolOrchestration.ts
  • 批处理执行工具
  • 先分 batch,再决定并发或串行
  • src/services/tools/StreamingToolExecutor.ts
  • 流式工具执行器
  • 支持一边收到 tool_use,一边提前运行

关键调用链

工具池组装流程(assembleToolPool)

代表性源码文件

  • src/tools.ts
  • src/Tool.ts
  • src/services/tools/toolOrchestration.ts
  • src/services/tools/StreamingToolExecutor.ts

核心问题:为什么一定要有"工具池组装层"

因为这个系统的工具并不是静态的:

  • 内建工具会受 feature flag、平台、模式影响
  • MCP tools 是动态接入的
  • REPL mode 会隐藏某些 primitive tools
  • simple mode、coordinator mode、worktree mode 都会影响工具集合

所以它不能让各处自己拼工具,而是必须有 tools.ts 作为单一事实来源。

核心要素流程图

1. 工具池组装流程

核心函数 : assembleToolPool(permissionContext,mcpTools)

这是工具系统的单一事实来源,负责将 built-in 工具和 MCP 工具合并成最终的工具池。

代码示例 - 工具池组装的核心逻辑:

css 复制代码
// src/tools.ts:345-367export function assembleToolPool(  permissionContext: ToolPermissionContext,  mcpTools: Tools,): Tools {  // 1. 获取 built-in 工具(已按 mode/feature/deny 过滤)  const builtInTools = getTools(permissionContext)  // 2. 过滤 MCP 工具  const allowedMcpTools = filterToolsByDenyRules(mcpTools, permissionContext)  // 3. 分别排序后合并(保证 prompt cache 稳定性)  // built-in 工具作为连续前缀,避免 MCP 工具插入破坏缓存  const byName = (a: Tool, b: Tool) => a.name.localeCompare(b.name)  return uniqBy(    [...builtInTools].sort(byName).concat(allowedMcpTools.sort(byName)),    'name', // 去重:built-in 优先  )}

关键设计点

  1. 缓存稳定性:工具排序确保 prompt cache 可复用,避免 MCP 工具插入导致缓存失效
  2. 权限一致性:built-in 和 MCP 工具使用相同的 deny 规则过滤
  3. 去重策略:built-in 工具优先,避免 MCP 工具覆盖内建功能

2. 工具调度执行流程

核心函数 : runTools() - 编排工具的并发/串行执行

这个调度器通过 isConcurrencySafe 判断工具是否可以并发执行,优化响应速度同时保证安全性。

代码示例 - 工具并发安全判定:

ruby 复制代码
// src/Tool.ts:402 - 工具接口定义export type Tool={// ... 其他属性  isConcurrencySafe(input: z.infer<Input>):boolean  isReadOnly(input: z.infer<Input>):boolean  isDestructive?(input: z.infer<Input>):boolean}
// src/tools/BashTool/BashTool.ts - Bash 工具示例isConcurrencySafe(input){// Bash 命令默认不安全,可能有副作用returnfalse}
// src/tools/FileReadTool/FileReadTool.ts - Read 工具示例isConcurrencySafe(input){// Read 是只读操作,可以安全并发returntrue}
// src/tools/FileEditTool/FileEditTool.ts - Edit 工具示例isConcurrencySafe(input){// Edit 是写操作,需要串行执行returnfalse}

执行策略对比

工具类型 isConcurrencySafe 执行策略 典型工具
只读查询 ✅ true 并发执行 Read, Grep, Glob, WebFetch
写入操作 ❌ false 串行执行 Edit, Write, Bash
危险操作 ❌ false 串行执行 Bash(rm), Write(覆盖)

关键设计点

  1. 抽象层次 :用 isConcurrencySafe() 而非硬编码工具名,支持自定义工具
  2. 安全优先:解析失败或异常时默认不安全,采用保守策略
  3. 上下文传递:非并发工具支持 contextModifier,允许修改后续工具的上下文

设计亮点

  • assembleToolPool() 明确强调 prompt cache 稳定性,因此 built-in 与 MCP tool 的排序不是随便写的
  • toolOrchestration.tsisConcurrencySafe 而不是"按工具名硬编码并发规则",抽象层次更高
  • StreamingToolExecutor.ts 把"流式收到工具调用"和"安全调度执行"结合起来,说明团队在优化响应延迟

对前端工程师的启发

  • 当能力越来越多时,一定要有统一注册中心
  • 并发不是 Promise.all 就完了,关键是定义什么可以并发
  • 真正好的 runtime 会同时考虑吞吐、延迟和结果顺序

可借鉴到业务系统的方式

  • 低代码平台可把 action 执行分成只读 action 和写 action
  • 工作流平台可按副作用级别做并发编排
  • 前端埋点、同步、草稿保存等异步动作也能做统一调度中心

进阶:流式工具执行器详解

3. StreamingToolExecutor 工作流程

核心类 : StreamingToolExecutor

这是 Claude Code 在性能优化上的关键设计,实现了"边接收边执行"的能力,显著降低端到端延迟。

内建工具分类表

根据源码分析,Claude Code 的 60+ 内建工具按并发安全性分为以下几类:

分类 并发安全 典型工具 说明
文件读取类 ✅ Safe Read, Glob, Grep 只读操作,无副作用
网络请求类 ✅ Safe WebFetch, WebSearch 独立的 HTTP 请求
查询类 ✅ Safe TaskOutput, TaskList, TaskGet 只读查询状态
MCP 资源类 ✅ Safe ListMcpResources, ReadMcpResource 只读 MCP 资源
工具搜索类 ✅ Safe ToolSearch 元数据查询
文件写入类 ❌ Unsafe Edit, Write, NotebookEdit 有写操作,需串行
Shell 执行类 ❌ Unsafe Bash, PowerShell 可能有副作用
任务管理类 ❌ Unsafe TaskCreate, TaskUpdate, TaskStop 修改任务状态
模式切换类 ❌ Unsafe EnterPlanMode, ExitPlanMode 改变执行模式
用户交互类 ❌ Unsafe AskUserQuestion 需要用户响应
Agent 类 ❌ Unsafe Agent 启动子 Agent
调度类 ❌ Unsafe CronCreate, CronDelete 修改定时任务

06-Agent 与并行协作层

本层定位

这一层是 Claude Code 最有"产品壁垒"的部分之一。它并不满足于单线程主 agent,而是把:

  • 子 agent
  • teammate / swarm
  • agent-specific MCP
  • fork subagent
  • prompt cache 共享

做成了一套相对完整的并行协作体系。

核心职责

  • 创建和运行子 agent
  • 继承或裁剪父上下文
  • 维持 agent 的工具、权限、模型、MCP 组合
  • 在并行执行时尽可能共享 prompt cache
  • 为主线程提供任务视图和消息回传能力

关键模块

  • src/tools/AgentTool/runAgent.ts
  • 子 agent 主执行入口
  • 会处理 agent-specific MCP、工具解析、上下文构建、消息记录
  • src/tools/AgentTool/forkSubagent.ts
  • 为 fork child 构造 byte-identical 的上下文前缀
  • 非常关键,直接体现"共享缓存降低并行成本"
  • src/tools/shared/spawnMultiAgent.ts
  • 更偏 teammate/swarm 侧的多 agent 启动
  • src/utils/forkedAgent.ts
  • CacheSafeParams 与 createSubagentContext 的基础设施

关键调用链

代表性源码文件

  • src/tools/AgentTool/runAgent.ts
  • src/tools/AgentTool/forkSubagent.ts
  • src/tools/shared/spawnMultiAgent.ts
  • src/utils/forkedAgent.ts

子 agent 设计里最值得学的点

1. 并行不只是"多开几个任务"

很多系统做并行只是:

  • 复制 prompt
  • 启多个请求
  • 等待结果

Claude Code 更进一步:

  • 子 agent 会继承父上下文的 cache-safe 部分
  • 会尽量让多个 fork child 共享相同前缀
  • 会让工具结果占位文本保持一致,提升缓存命中

这说明他们不是只追求并行,而是追求"低成本并行"。

2. 子 agent 不是完全孤立

runAgent.ts 里能看到:

  • agent-specific MCP server 可以附加到父客户端集合上
  • 共享的客户端不会被误清理
  • 子 agent 有自己独立的 transcript / metadata / file state 副本

这是一种"控制性继承"。

核心要素流程图

1. Fork Child 如何共享缓存

核心问题:当父 agent 需要并行派发多个子任务时,如何让它们共享 prompt cache 以降低成本?

解决方案 :通过 buildForkedMessages() 构造字节完全相同的消息前缀。

2. 子 agent 生命周期

设计亮点

  • forkSubagent.ts 里对 prompt cache 的处理非常"显式",这说明团队把成本优化放进了架构层
  • runAgent.ts 把 agent-specific MCP、transcript、工具上下文都纳入统一生命周期
  • spawnMultiAgent.ts 说明系统支持多种协作后端,不局限于当前 UI 形态

对前端工程师的启发

  • 并行体系设计最重要的是"共享什么,隔离什么"
  • 降低并行成本常常靠缓存与前缀稳定,而不是单纯靠更高并发
  • 当子任务越来越多时,必须先定义 lineage、上下文继承和清理边界

可借鉴到业务系统的方式

  • 多 tab 协作、后台任务编排、低代码多 worker 执行都适合这套思路
  • Web Copilot 可用主线程上下文 + 子任务共享前缀降低成本
  • 工作流引擎可借鉴"共享客户端、隔离本地状态"的设计

我应该重点学习的 3 个设计点

  • CacheSafeParams 设计
  • 子 agent 的控制性继承
  • 并行运行的生命周期管理

这些设计点在前端领域分别对应什么能力

  • CacheSafeParams 对应缓存稳定性与依赖控制能力
  • 控制性继承对应上下文隔离与共享设计能力
  • 生命周期管理对应复杂异步任务治理能力

如果我要自己实现一个简化版

  • 先做一个只能继承父 prompt 的子 agent
  • 再做共享文件状态缓存和独立消息流
  • 最后再做多 agent 并行与缓存前缀稳定优化

07-扩展机制与外部能力接入层

本层定位

这一层决定 Claude Code 是否能从"一个产品"成长成"一个平台"。它的扩展面至少包括三类:

  • 技能系统
  • 插件系统
  • MCP 系统

其中:

  • 技能更像 prompt / command / workflow 的轻量扩展
  • 插件更像带生命周期和分发渠道的产品扩展
  • MCP 更像外部能力总线

核心职责

  • 从磁盘或市场加载插件与技能
  • 把外部能力转成命令、工具、资源
  • 统一接入本地与远程 MCP server
  • 管理 OAuth、连接状态、动态重连、资源读取
  • 维持扩展能力与主系统之间的安全和边界

关键模块

  • src/skills/loadSkillsDir.ts
  • 从 markdown/frontmatter 装载技能
  • 可解析工具限制、参数、hooks、agent、effort、context
  • src/utils/plugins/pluginLoader.ts
  • 插件发现、缓存、版本化、安装与加载
  • src/plugins/builtinPlugins.ts
  • 内置插件注册中心
  • src/services/mcp/client.ts
  • MCP 连接、工具/资源/提示能力拉取、认证与错误处理

关键调用链

代表性源码文件

  • src/skills/loadSkillsDir.ts
  • src/utils/plugins/pluginLoader.ts
  • src/plugins/builtinPlugins.ts
  • src/services/mcp/client.ts

三类扩展各自像什么

1. 技能系统

更像"配置驱动的命令与提示模板系统",优点是:

  • 扩展门槛低
  • 更适合 prompt 复用
  • 可以附带工具限制、agent 选择、hooks

2. 插件系统

更像"正式扩展包系统",优点是:

  • 能提供多组件能力
  • 有 marketplace / 版本 / 缓存 / 启停状态
  • 支持更稳定的分发与治理

3. MCP 系统

更像"外部能力协议层",优点是:

  • 不需要把第三方能力硬编码进主仓库
  • 外部 server 可以提供 tools、resources、prompts
  • 主系统只需要统一协议和安全边界

核心要素流程图

1. 扩展接入总览

三种扩展类型的统一接入流程

2. MCP 接入路径

从配置到可用的完整生命周期

传输协议对比

协议 适用场景 优势 示例
stdio 本地命令行工具 简单、低延迟 数据库工具、文件系统工具
SSE 实时推送服务 双向通信、实时更新 浏览器自动化、实时监控
HTTP REST API 服务 广泛兼容、易于代理 外部 API、云服务

错误处理机制

  • McpAuthError - 认证失败,需要用户重新授权
  • McpSessionExpiredError - 会话过期,需要重新连接
  • McpToolCallError - 工具调用失败,包含错误信息

3.技能系统加载流程

Frontmatter 配置示例

css 复制代码
---name: commitdescription:Create a git commit with auto-generated messagetools:-Bash(git status)-Bash(git diff)-Bash(git add)-Bash(git commit)hooks:PreToolUse:-if: tool =="Bash"      command:"echo 'About to run: {{input.command}}'"effort: highagent:Plan---
## 使用说明
执行智能提交,自动分析变更并生成 commit message。

关键设计点

  1. 延迟加载 - 只解析 frontmatter,完整内容在调用时加载
  2. 工具限制 - 通过 tools 字段限制可用的工具范围
  3. Hooks 注入 - 支持生命周期钩子,实现自动化流程
  4. Agent 指定 - 可指定特定 agent 执行(如 Plan agent)

设计亮点

  • loadSkillsDir.ts 让 markdown 成为正式扩展协议,这很适合知识型产品
  • pluginLoader.ts 明显考虑了 marketplace、版本缓存、seed cache,说明它不是玩具插件系统
  • mcp/client.ts 支持多 transport、认证、资源截断、结果持久化,是很完整的协议适配层

对前端工程师的启发

  • 平台化能力的前提不是"先做插件市场",而是先统一能力协议
  • 扩展系统至少要区分轻扩展与重扩展
  • 接第三方能力时,不要直接耦合业务代码,先做协议适配层

可借鉴到业务系统的方式

  • 低代码平台可把模板、插件、外部连接器分层设计
  • 企业工作台可把 AI 技能、组织插件、第三方工具统一收口
  • Web 应用可借鉴"轻扩展 markdown + 重扩展 plugin + 协议扩展 connector"

我应该重点学习的 3 个设计点

  • 扩展协议分层
  • 插件缓存与版本化
  • MCP 这种协议适配层的组织方式

这些设计点在前端领域分别对应什么能力

  • 协议分层对应平台型产品设计能力
  • 版本化对应工程治理与发布能力
  • 协议适配对应第三方生态接入能力

如果我要自己实现一个简化版

  • 先做 markdown 技能系统
  • 再做本地目录插件系统
  • 最后再做统一 connector/MCP 适配层

08-构建发布与工程化基础设施层

本层定位

这层在当前仓库里不是最完整的一层,因为这里主要是泄露出的 src/,并不包含完整的构建

能看出很清晰的工程化取向。

这里我会明确区分:

  • 已能从源码确认的设计
  • 根据源码高度推断的设计

核心职责

  • 基于 feature flag 做 build-time 剪裁
  • 控制启动性能与模块装载成本
  • 为不同运行模式复用同一套核心逻辑
  • 管理遥测、清理、证书、代理、远程配置、策略限制等基础设施
  • 保证插件、MCP、bridge、daemon 等子系统可以渐进扩展

关键模块

  • src/main.tsx
  • 顶层并行预取与延迟加载
  • src/entrypoints/cli.tsx
  • 运行模式分流
  • src/entrypoints/init.ts
  • 网络、遥测、清理、配置、策略能力初始化
  • src/tools.tssrc/commands.ts
  • 大量 feature('...') 分支,明显依赖构建期能力裁剪
  • src/services/analytics/growthbook.ts
  • 运行时实验开关与配置刷新

关键调用链

代表性源码文件

  • src/entrypoints/cli.tsx
  • src/main.tsx
  • src/entrypoints/init.ts
  • src/tools.ts
  • src/commands.ts
  • src/services/analytics/growthbook.ts

已确认的工程化特征

1. 强依赖 build-time feature flag

源码里大量使用 feature('...') 与条件 require()

  • COORDINATOR_MODE
  • KAIROS
  • BRIDGE_MODE
  • VOICE_MODE
  • WORKFLOW_SCRIPTS
  • AGENT_TRIGGERS

这意味着他们不是只做运行时 if,而是在编译时就裁剪产品切面。

2. 冷启动优化是系统性设计

可以确认的手段包括:

  • 顶层预取 keychain / MDM
  • 早期 fast path
  • 延迟 import 重模块
  • 多模式分流

3. 基础设施初始化被独立管理

init.ts 里能看到:

  • 遥测初始化
  • mTLS / proxy
  • CA cert
  • graceful shutdown
  • remote managed settings
  • policy limits

说明他们把"产品能力"和"基础设施能力"明确分层。

推测但大概率成立的部分

  • 推测使用 Bun 相关构建链做 feature-based bundle 裁剪
  • 推测内部与外部 build 产物存在明显差异,因为很多 ant-only 逻辑被条件消除
  • 推测发布时会输出多个运行形态,例如普通 CLI、bridge/daemon 相关模式

这些是推测,因为当前仓库没有完整构建脚本与 CI 配置。

核心要素流程图

设计亮点

  • 运行模式多,但入口收敛
  • 产品能力多,但通过 feature flag 保持 build 结果可裁剪
  • 运行时实验与构建时裁剪并存,形成"两层开关体系"

对前端工程师的启发

  • 真正的工程化不是"接了多少工具链",而是架构是否允许产品被安全裁剪
  • build-time 和 runtime 的开关职责不同,不能混用
  • 大型应用必须把基础设施初始化当作独立层

可借鉴到业务系统的方式

  • Web 多租户平台可做 build-time 剪裁 + runtime 实验双层控制
  • 中台可把"基础设施接入"独立出业务层
  • 桌面端或 Electron 产品很适合借鉴这种多入口、多模式分流

我应该重点学习的 3 个设计点

  • build-time 与 runtime 开关分层
  • 启动性能工程化
  • 基础设施初始化独立化

这些设计点在前端领域分别对应什么能力

  • 开关分层对应产品形态治理能力
  • 启动性能对应首屏与 bundle 体积治理能力
  • 初始化独立化对应平台底座设计能力

如果我要自己实现一个简化版

  • 先只做 runtime feature flag
  • 再把重模块改成 lazy import
  • 最后再引入 build-time 裁剪,把不同产品形态分包

总结与启示

整体架构总结

Claude Code 的核心不是"一个能调模型的 CLI",而是一个把以下能力统一进同一 runtime 的系统:

  • CLI 启动分流
  • 命令与工具注册
  • REPL/TUI 产品壳
  • Query loop 主循环
  • 上下文压缩与恢复
  • Agent 并行协作
  • 插件、技能、MCP 扩展平台
  • 权限、策略、遥测、远程配置等基础设施

如果用一句话概括:

它把 AI Agent 产品做成了一套"有前端壳层思维的终端应用平台"。

关键节点总流程图

完整架构运行流程

核心数据流

这个项目最厉害的工程设计点

1. 主循环思维非常完整

它不是简单的 "prompt in, text out",而是一个完整的状态机循环:

标准 Agent 循环

复制代码
输入→上下文构建→模型请求→工具执行→状态更新→压缩恢复→下一轮

Claude Code 的增强版循环

ini 复制代码
// src/query.ts 核心循环伪代码asyncfunction* query(){while(true){// 1. 上下文构建const messages =await normalizeMessagesForAPI(conversationHistory)
// 2. Token 预算管理const budget = calculateTokenBudget(messages, tools)
// 3. 模型请求(流式)const stream = streamMessages({ messages, tools, budget })
// 4. 解析响应forawait(constevent of stream){if(event.type ==='tool_use'){// 5. 工具执行(并发/串行调度)const results =await runTools(toolUseBlocks)
// 6. 结果回填yield* results
// 7. 上下文更新        conversationHistory.push(...results)}}
// 8. 上下文压缩(如果需要)if(shouldCompact(conversationHistory)){      conversationHistory =await compact(conversationHistory)}}}

这才是企业级 Agent runtime 的样子------每个环节都有明确职责和优化空间。

2. Prompt Cache 稳定性被提升到架构层

最打动人的地方不是有子 agent,而是团队把 API 成本优化 做成了架构级能力:

关键设计决策

设计点 传统做法 Claude Code 做法 收益
工具排序 随意顺序 按名称排序,built-in 作为稳定前缀 缓存命中率提升
Fork Child 复制完整上下文 构造 byte-identical 前缀 + 不同 directive 多个子 agent 共享缓存
MCP 工具 动态加载 固定占位符,延迟加载详情 避免缓存失效
上下文压缩 简单截断 智能保留关键信息,维护缓存稳定 减少重复请求

代码示例 - 工具池排序

css 复制代码
// src/tools.ts:assembleToolPool()exportfunction assembleToolPool(permissionContext, mcpTools){const builtInTools = getTools(permissionContext)const allowedMcpTools = filterToolsByDenyRules(mcpTools, permissionContext)
// 关键:分别排序后合并,built-in 作为稳定前缀const byName =(a, b)=> a.name.localeCompare(b.name)return uniqBy([...builtInTools].sort(byName)// built-in 先排序.concat(allowedMcpTools.sort(byName)),// MCP 后排序'name')}

代码示例 - Fork Child 缓存共享

css 复制代码
// src/tools/AgentTool/forkSubagent.ts:buildForkedMessages()const FORK_PLACEHOLDER_RESULT ='Fork started --- processing in background'
// 所有 fork children 使用相同的占位符const toolResultBlocks = toolUseBlocks.map(block =>({  type:'tool_result',  tool_use_id: block.id,  content:[{ type:'text', text: FORK_PLACEHOLDER_RESULT }]// 完全相同!}))
// 只有最后的 directive 不同const directive = buildChildMessage(uniqueDirective)

成本收益估算

  • 假设前缀 10K tokens,10 个 fork children
  • 缓存命中:10K × 10 = 100K tokens 节省
  • 按 <math xmlns="http://www.w3.org/1998/Math/MathML"> 15 / 1 M t o k e n s 计算, ∗ ∗ 节省 15/1M tokens 计算,**节省 </math>15/1Mtokens计算,∗∗节省1.5**(单次并发)

这说明团队已经从"功能实现"进化到"成本结构设计"。

3. 扩展体系不是后补的

技能、插件、MCP 不是零散外挂,而是从一开始就被纳入核心架构:

扩展接入统一接口

arduino 复制代码
// 所有扩展都通过统一的注册中心接入exportinterfaceExtension{// 命令扩展  commands?:Command[]
// 工具扩展  tools?:Tool[]
// Hooks 扩展  hooks?:HooksSettings
// Agent 扩展  agents?:AgentDefinition[]
// MCP 扩展  mcpServers?:McpServerConfig[]}

统一装配流程

ini 复制代码
// src/setup.ts 核心装配逻辑asyncfunction setup(){// 1. 加载技能const skills =await loadSkillsDir('.claude/skills')
// 2. 加载插件const plugins =await loadPlugins()
// 3. 连接 MCPconst mcpClients =await connectMcpServers(config.mcpServers)
// 4. 统一装配到命令/工具/状态系统const commands =[...builtinCommands,...skills,...plugins.commands]const tools = assembleToolPool(permissionContext, mcpClients.tools)const hooks =[...builtinHooks,...plugins.hooks]
// 5. 更新全局状态  updateAppState({ commands, tools, hooks, mcpClients })}

这使它具备平台化潜力------任何扩展都遵循相同的生命周期和权限边界。

产品层面的启示

1. AI 产品最终会回到"操作系统式产品"

用户真正需要的不是一个回答问题的模型,而是一个能:

  • 接收任务 - 理解意图,分解目标
  • 调用工具 - 执行操作,访问外部系统
  • 记住上下文 - 维护会话状态,累积知识
  • 并行处理 - 多任务并发,提高效率
  • 接入外部系统 - MCP 协议,插件生态

的工作操作台。

Claude Code 展示的"操作系统式"特征

sql 复制代码
┌─────────────────────────────────────────┐│ClaudeCodeRuntime│├─────────────────────────────────────────┤│┌─────────┐┌─────────┐┌─────────┐│││ REPL UI ││Command││Tool││││Layer││System││System│││└─────────┘└─────────┘└─────────┘││┌─────────┐┌─────────┐┌─────────┐│││State││Agent││Extended││││Management││Runtime││Platform│││└─────────┘└─────────┘└─────────┘││┌────────────────────────────────────┐│││InfrastructureLayer││││Auth/Telemetry/ MCP /Policy│││└────────────────────────────────────┘│└─────────────────────────────────────────┘↕ MCP Protocol↕┌─────────────────────┐│ExternalWorld││APIs/Files/Git│└─────────────────────┘

2. 长会话是第一性问题

只要产品允许连续协作,就一定会遇到:

问题 Claude Code 的解决方案 设计思想
上下文膨胀 智能压缩算法 保留关键信息,丢弃冗余
成本膨胀 Prompt Cache + 工具排序稳定 架构级成本控制
历史污染 消息标准化 + Tombstone 可恢复的错误处理
子任务分流 Fork Subagent + CacheSafeParams 低成本并行
状态一致性 单一 AppState + Immer updates 可预测的状态管理

代码示例 - 长会话治理

ruby 复制代码
// src/query.ts 长会话处理伪代码asyncfunction manageLongConversation(){// 1. 检查上下文长度if(getTokenCount(messages)> MAX_TOKENS){// 2. 智能压缩    messages =await compact({      messages,      strategy:'preserve-important',// 保留关键信息      cacheSafePrefix: getCacheSafeParams()// 维护缓存稳定})}
// 3. 检查子任务需求if(needsParallelExecution(tasks)){// 4. 低成本 forkconst children =awaitPromise.all(      tasks.map(task => forkSubagent({        directive: task,        cacheSafePrefix: buildForkedMessages()})))}
// 5. 状态恢复if(needsRecovery(state)){await recoverFromCheckpoint(state)}}

3. 用户体验不只是 UI 漂亮

它的体验来自深层的工程优化:

启动性能优化

ruby 复制代码
// 顶层并行预取(在 import 之前)startMdmRawRead()// ~40ms 并行startKeychainPrefetch()// ~65ms 并行
// Fast path 零模块加载if(args[0]==='--version'){  console.log(MACRO.VERSION)// MACRO 内联return// 直接退出}

响应流畅性优化

python 复制代码
// 流式工具执行forawait(const progress of runTool(toolUse)){// 立即返回进度yield{ type:'progress', data: progress }}
// 并发安全工具同时执行const results =awaitPromise.all([  readFile('a.ts'),  readFile('b.ts'),  grepPattern('pattern')])

可恢复性设计

vbnet 复制代码
// 会话持久化await writeTranscript(messages, sessionId)
// 崩溃恢复const lastState =await readTranscript(sessionId)if(lastState.incomplete){  promptUser('Resume from last session?')}

这些比"回答更像人"更重要------可靠性 > 智能

成功要素

1. 明确的单一事实来源 (Single Source of Truth)

每个核心能力都有唯一的注册中心:

ruby 复制代码
// 命令注册中心 - src/commands.tsexportfunction getCommands():Command[]{return[...builtinCommands,...skillCommands,...pluginCommands]}
// 工具注册中心 - src/tools.tsexportfunction assembleToolPool(permissionContext, mcpTools):Tools{const builtInTools = getTools(permissionContext)return uniqBy([...builtInTools,...mcpTools].sort(byName),'name')}
// 查询引擎 - src/query.tsexportasyncfunction* query({ messages, tools, systemPrompt }){// 唯一的主循环入口}
// 状态管理 - src/state/AppState.tsxexport type AppState={  messages:Message[]  toolPermissionContext:ToolPermissionContext  mcp:{ clients:MCPServerConnection[]}// ... 全局状态}

优势

  • 复杂但不混乱
  • 易于追踪和调试
  • 便于扩展和维护

2. 清晰的层间边界 (Layer Boundaries)

每层只关心自己的职责:

ruby 复制代码
// 入口层 - 只关心分流// src/entrypoints/cli.tsxif(args[0]==='--version')return printVersion()if(args[0]==='--daemon-worker')return runDaemonWorker()// 分流后不干预后续逻辑
// 查询层 - 只关心主循环// src/query.tsasyncfunction* query(){while(true){const messages =await normalizeInput()const response =await callModel()const results =await executeTools()yield* results// 不关心具体工具实现}}
// 工具层 - 只关心能力执行// src/services/tools/toolOrchestration.tsasyncfunction runTools(toolUseBlocks){const batches = partitionToolCalls(toolUseBlocks)for(const batch of batches){if(batch.isConcurrencySafe){await runConcurrently(batch)}else{await runSerially(batch)}}// 不关心业务语义}
// 扩展层 - 只关心能力装配// src/tools.ts + src/commands.tsexportfunction assembleToolPool(){// 过滤、排序、去重// 不关心工具如何执行}

设计原则

  • 单向依赖,避免循环
  • 接口清晰,职责单一
  • 易于测试和替换

3. 以成本和性能为导向的架构细节

启动性能工程化

ruby 复制代码
// 阶段 1: 并行预取(import 之前)startMdmRawRead()// ~40ms 并行startKeychainPrefetch()// ~65ms 并行// 收益:启动时间从 ~200ms 降到 ~100ms
// 阶段 2: Fast Path(零模块加载)if(args[0]==='--version'){  console.log(MACRO.VERSION)// 构建时内联return}// 收益:version 命令 <5ms
// 阶段 3: 延迟加载const heavy =awaitimport('heavy-module')// 收益:避免不必要的模块加载

Prompt Cache 稳定性

ini 复制代码
// 策略 1: 工具排序稳定const tools =[...builtInTools].sort(byName).concat([...mcpTools].sort(byName))
// 策略 2: Fork Child 字节级相同const FORK_PLACEHOLDER ='Fork started --- processing in background'
// 策略 3: CacheSafeParams 显式建模export type CacheSafeParams={  systemPrompt:SystemPrompt  userContext:UserContext  systemContext:SystemContext}

并发调度优化

lua 复制代码
// 工具分级调度function partitionToolCalls(toolUseBlocks){return toolUseBlocks.reduce((batches, block)=>{const isSafe = tool.isConcurrencySafe(input)
// 相邻的并发安全工具合并到一个 batchif(isSafe &&last(batches).isConcurrencySafe){last(batches).blocks.push(block)}else{      batches.push({ isConcurrencySafe: isSafe, blocks:[block]})}
return batches},[])}

4. 可持续增长的扩展架构

三级扩展体系

扩展能力对比

扩展类型 适用场景 开发成本 分发方式 示例
技能 个人模板、快速复用 极低(写 Markdown) 目录共享 commit/push/review
插件 产品化能力、团队共享 中等(需配置) Marketplace chrome-integration
MCP 外部系统接入 高(需服务端) 协议标准 database-api、browser-control

对前端工程师最值得迁移的能力模型

1. 系统思维升级

从"页面集合"到"运行时系统"

css 复制代码
传统前端思维:┌─────────────┐│Page A    │→独立状态├─────────────┤│Page B    │→独立状态├─────────────┤│Page C    │→独立状态└─────────────┘
ClaudeCode思维:┌─────────────────────────────┐│UnifiedRuntime││┌───────┐┌───────┐│││ REPL  ││Query││││  UI   ││Loop│││└───────┘└───────┘││┌───────────────────────┐│││StateManagement││││(AppState)│││└───────────────────────┘││┌───────────────────────┐│││CapabilityRegistry││││Commands/Tools/ MCP│││└───────────────────────┘│└─────────────────────────────┘

迁移路径

lua 复制代码
// 阶段 1: 统一状态管理const appState ={  user:UserState,  data:DataState,  ui:UIState}
// 阶段 2: 能力注册中心const capabilities ={  commands:newMap<string,Command>(),  tools:newMap<string,Tool>(),  extensions:newMap<string,Extension>()}
// 阶段 3: 运行时循环function* runtimeLoop(){while(true){const input =yield'ready'const result =await processInput(input)    updateState(result)}}

2. 状态管理升级

从"组件局部变量"到"领域模型"

css 复制代码
// 传统做法:状态分散在组件functionComponent(){const[data, setData]= useState()const[loading, setLoading]= useState()const[error, setError]= useState()}
// Claude Code 做法:统一领域状态type AppState={// 会话状态  conversation:{    messages:Message[]    turnCount: number    lastActivity: number}
// 工具状态  tools:{    inProgressToolUseIDs:Set<string>    lastToolResults:Map<string,ToolResult>}
// 扩展状态  extensions:{    mcp:{ clients:MCPServerConnection[]}    plugins:Map<string,Plugin>    skills:Map<string,Skill>}
// 权限状态  permissions:{    mode:PermissionMode    context:ToolPermissionContext}}
// 统一更新机制function updateAppState(updater:(prev:AppState)=>AppState){const newState = immer.produce(currentState, updater)  notifySubscribers(newState)}

3. 能力治理升级

从"散落的能力"到"统一注册中心"

lua 复制代码
// 传统做法:能力散落在代码各处asyncfunction handleAction(type:string){if(type ==='save'){/* ... */}elseif(type ==='load'){/* ... */}elseif(type ==='export'){/* ... */}}
// Claude Code 做法:统一注册classCapabilityRegistry{private commands =newMap<string,Command>()private tools =newMap<string,Tool>()
register(command:Command){this.validate(command)this.commands.set(command.name, command)}
get(name:string):Command|undefined{returnthis.commands.get(name)}
// 统一过滤、权限检查  filter(predicate:(cmd:Command)=>boolean):Command[]{returnArray.from(this.commands.values()).filter(predicate)}}

4. 长生命周期治理

从"短期会话"到"可持续运行"

vbnet 复制代码
// 短期思维:页面关闭 = 状态丢失functionPage(){  useEffect(()=>{return()=>{// 清理}},[])}
// 长期思维:会话可能持续数天classLongRunningSession{// 1. 持久化async persist(){await writeTranscript(this.messages)await writeCheckpoint(this.state)}
// 2. 恢复async restore(sessionId:string){const transcript =await readTranscript(sessionId)const checkpoint =await readCheckpoint(sessionId)this.rebuildState(transcript, checkpoint)}
// 3. 压缩async compact(){// 保留关键信息,丢弃冗余this.messages =await intelligentCompact(this.messages)}
// 4. 快照async snapshot(){// 定期快照,便于回溯await writeSnapshot({      timestamp:Date.now(),      state:this.state,      messages:this.messages})}}

5. 缓存稳定性思维

从"功能优先"到"成本结构优先"

css 复制代码
// 传统思维:功能实现了就行const tools =[...tools1,...tools2]
// Claude Code 思维:缓存稳定性优先const tools = assembleToolPool({  builtIn: getBuiltInTools(),  mcp: getMcpTools(),// 排序保证缓存命中  sortStrategy:'stable-prefix',// 去重保证一致性  dedupStrategy:'built-in-first'})

实际收益

优化点 传统做法 Claude Code 做法 收益
工具排序 随意顺序 固定前缀排序 缓存命中率 +40%
Fork Child 完整复制 字节级相同前缀 并行成本 -60%
上下文压缩 简单截断 智能保留 Token 成本 -50%
消息标准化 原样保留 规范化 + Tombstone 恢复可靠性 +100%

如果我要仿照这个项目做一个自己的 AI Coding Agent,最小可行架构应该怎么设计

最小版本(MVP)- 核心循环

目标:实现最基本的 AI Agent 循环

文件结构

bash 复制代码
src/├── index.ts           # 入口├── query.ts           # 主循环├── tools.ts           # 工具注册├── commands.ts        # 命令注册├── tools/│├──ReadTool.ts    # 文件读取│├──EditTool.ts    # 文件编辑│├──BashTool.ts    # 命令执行└── state.ts           # 状态管理

核心代码

vbnet 复制代码
// src/query.ts - 主循环asyncfunction* query(messages:Message[], tools:Tool[]){while(true){// 1. 调用模型const response =await callModel({ messages, tools })
// 2. 解析工具调用const toolCalls = parseToolCalls(response)
// 3. 执行工具for(const toolCall of toolCalls){const tool = tools.find(t => t.name === toolCall.name)const result =await tool.call(toolCall.input)
// 4. 返回结果yield{ type:'tool_result', content: result }
// 5. 更新消息      messages.push({        role:'assistant',        content: response})      messages.push({        role:'user',        content:[{ type:'tool_result',...result }]})}
// 6. 检查是否结束if(shouldEnd(response))break}}

工具定义

css 复制代码
// src/tools.tsexportinterfaceTool{  name:string  description:string  inputSchema:ZodSchema  call(input: any):Promise<string>}
// src/tools/ReadTool.tsexportconstReadTool:Tool={  name:'Read',  description:'Read file contents',  inputSchema: z.object({    file_path: z.string()}),async call({ file_path }){returnawait fs.readFile(file_path,'utf-8')}}

MVP 特性

  • ✅ 最基本的主循环
  • ✅ 3-5 个核心工具
  • ✅ 简单的状态管理
  • ❌ 无权限系统
  • ❌ 无压缩恢复
  • ❌ 无扩展机制

第二阶段 - 用户体验层

新增功能

bash 复制代码
src/├── repl.ts            # REPL 界面├── auth.ts            # 权限系统├── compact.ts         # 上下文压缩├── storage.ts         # 持久化存储└── tools/├──GlobTool.ts    # 文件搜索├──GrepTool.ts    # 内容搜索└──WriteTool.ts   # 文件写入

权限系统

python 复制代码
// src/auth.tsexportasyncfunction checkPermission(  tool:string,  input: any,  context:PermissionContext):Promise<'allow'|'deny'|'ask'>{// 1. 检查规则const rule = matchRule(context.rules, tool, input)if(rule)return rule.behavior
// 2. 默认询问return'ask'}
// 在工具执行前检查asyncfunction runTool(tool:Tool, input: any){const decision =await checkPermission(tool.name, input, context)
if(decision ==='allow'){returnawait tool.call(input)}elseif(decision ==='deny'){thrownewError('Permission denied')}else{// 弹出对话框询问const userChoice =await askUser(tool.name, input)return userChoice ==='allow'?await tool.call(input):thrownewError('User denied')}}

上下文压缩

ini 复制代码
// src/compact.tsexportasyncfunction compact(messages:Message[]):Promise<Message[]>{// 1. 计算当前 token 数const tokens = countTokens(messages)
if(tokens < MAX_TOKENS)return messages
// 2. 简单压缩:保留系统消息 + 最近 N 条const systemMessages = messages.filter(m => m.role ==='system')const recentMessages = messages.slice(-20)
// 3. 添加压缩摘要const summary =await generateSummary(messages)
return[...systemMessages,{ role:'system', content:`Previous context: ${summary}`},...recentMessages]}

会话持久化

javascript 复制代码
// src/storage.tsexportasyncfunction saveSession(messages:Message[], sessionId:string){const transcript = JSON.stringify(messages)await fs.writeFile(`.sessions/${sessionId}.json`, transcript)}
exportasyncfunction loadSession(sessionId:string):Promise<Message[]>{const transcript =await fs.readFile(`.sessions/${sessionId}.json`,'utf-8')return JSON.parse(transcript)}

阶段 2 特性

  • ✅ REPL 或 Web UI
  • ✅ 权限系统
  • ✅ 上下文压缩
  • ✅ 会话持久化
  • ✅ 更多工具
  • ❌ 无子 agent
  • ❌ 无扩展机制

第三阶段 - 企业级特性

新增架构

bash 复制代码
src/├── agent/│├── runAgent.ts        # 子 agent 执行│└── forkSubagent.ts    # Fork 机制├── cache/│└── cacheSafeParams.ts # 缓存参数├── plugins/│├── loader.ts          # 插件加载│└── registry.ts        # 插件注册├── mcp/│├── client.ts          # MCP 客户端│└── protocol.ts        # MCP 协议└── build/└── featureFlags.ts    # Feature flags

子 Agent 机制

css 复制代码
// src/agent/runAgent.tsexportasyncfunction* runAgent(  prompt:string,  context:AgentContext):AsyncGenerator<Message>{// 1. 创建隔离上下文const agentContext = createSubagentContext(context)
// 2. 继承缓存安全参数const cacheSafeParams = getCacheSafeParams(context)
// 3. 执行独立查询循环forawait(const message of query({    messages:[{ role:'user', content: prompt }],    tools: filterTools(context.tools),    systemPrompt: agentContext.systemPrompt})){yield message}}
// src/agent/forkSubagent.tsexportfunction buildForkedMessages(  directive:string,  assistantMessage:Message):Message[]{// 构造字节级相同的前缀const placeholder ='Fork started --- processing in background'
const toolResults = assistantMessage.content.filter(block => block.type ==='tool_use').map(block =>({      type:'tool_result',      tool_use_id: block.id,      content: placeholder}))
return[    assistantMessage,{      role:'user',      content:[...toolResults,{ type:'text', text: directive }]}]}

插件系统

vbnet 复制代码
// src/plugins/loader.tsexportasyncfunction loadPlugin(pluginPath:string):Promise<Plugin>{// 1. 读取 plugin.jsonconst manifest =await readJson(join(pluginPath,'plugin.json'))
// 2. 加载命令const commands =await loadCommands(join(pluginPath,'commands'))
// 3. 加载工具const tools =await loadTools(join(pluginPath,'tools'))
// 4. 加载 Hooksconst hooks =await loadHooks(join(pluginPath,'hooks'))
return{ manifest, commands, tools, hooks }}
// src/plugins/registry.tsclassPluginRegistry{private plugins =newMap<string,Plugin>()
register(plugin:Plugin){// 注册到命令系统for(const cmd of plugin.commands){      commandRegistry.register(cmd)}
// 注册到工具系统for(const tool of plugin.tools){      toolRegistry.register(tool)}
// 注册 Hooks    hookRegistry.register(plugin.hooks)
this.plugins.set(plugin.manifest.name, plugin)}}

MCP 协议支持

vbnet 复制代码
// src/mcp/client.tsexportasyncfunction connectMcpServer(  config:McpServerConfig):Promise<McpClient>{// 1. 建立传输层const transport = createTransport(config)
// 2. 初始化连接await transport.initialize()
// 3. 拉取能力列表const tools =await transport.listTools()const resources =await transport.listResources()
return{    transport,    tools: tools.map(t =>newMCPTool(t, transport)),    resources}}
// src/mcp/MCPTool.tsclassMCPToolimplementsTool{  constructor(private definition:McpToolDefinition,private transport:Transport){}
async call(input: any):Promise<string>{const result =awaitthis.transport.callTool(this.definition.name,      input)
return result.content}}

Feature Flags

ruby 复制代码
// src/build/featureFlags.ts// 构建时替换exportfunction feature(name:string):boolean{// 在构建时被替换为 true/falsereturnfalse}
// 使用示例if(feature('ENABLE_AGENT')){const agent =awaitimport('./agent/runAgent')// 整个模块在未启用时被裁剪}

阶段 3 特性

  • ✅ 子 agent 并行协作
  • ✅ Cache-safe context 复用
  • ✅ 插件 / 技能扩展
  • ✅ MCP 协议接入
  • ✅ Build-time 裁剪
  • ✅ 完整的工程化体系

架构演进路径

less 复制代码
graph LR    A[MVP<br/>核心循环]--> B[阶段2<br/>用户体验]    B --> C[阶段3<br/>企业级]
    A --> A1[✅基础工具<br/>✅简单状态<br/>❌无权限]
    B --> B1[✅ REPL UI<br/>✅权限系统<br/>✅压缩恢复]
    C --> C1[✅子Agent<br/>✅扩展机制<br/>✅工程化]
    style A fill:#c8e6c9    style B fill:#fff9c4    style C fill:#e1f5ff

对这个项目的最终判断

从前端工程师的学习角度,这个项目最值得借鉴的不是"终端 UI 怎么写",而是它展示了一个先进的产品事实:

AI Agent 产品的核心竞争力,不在单个 prompt,而在整套工程体系

核心能力清单

能力分层总结

层级 核心职责 关键模块 学习价值
入口层 模式分流 cli.tsx / main.tsx Fast path 设计、启动优化
查询层 主循环编排 query.ts Agent runtime 设计
工具层 能力执行 toolOrchestration.ts 并发调度、权限控制
Agent 层 并行协作 runAgent.ts / forkSubagent.ts 低成本并行、缓存共享
扩展层 能力装配 tools.ts / commands.ts 插件架构、注册中心
基础设施层 工程化支撑 init.ts / growthbook.ts 性能优化、成本控制

从"功能实现"到"工程体系"的进化

传统 AI 产品思维

复制代码
用户输入→Prompt→模型响应→显示结果

Claude Code 的工程体系思维

arduino 复制代码
┌────────────────────────────────────────────┐│产品设计决策层││-多模式支持:CLI / REPL /Bridge/ BG    ││-扩展策略:技能/插件/ MCP 三级体系││-成本控制:PromptCache+并发调度│└────────────────────────────────────────────┘↓┌────────────────────────────────────────────┐│架构设计层││-单一事实来源:commands / tools / state  ││-清晰边界:入口/查询/工具/扩展││-统一接口:Command/Tool/Extension│└────────────────────────────────────────────┘↓┌────────────────────────────────────────────┐│工程实现层││-启动优化:并行预取/FastPath││-运行时优化:流式执行/并发调度││-成本优化:Cache稳定/上下文压缩│└────────────────────────────────────────────┘↓┌────────────────────────────────────────────┐│可观测性层││-遥测系统:Telemetry/Analytics││-性能监控:StartupProfiler││-成本监控:Token计数/Cache命中率│└────────────────────────────────────────────┘

关键启示

1. 产品思维

  • AI Agent 是"操作系统式产品",不是"对话式问答"
  • 长会话是第一性问题,需要架构级解决方案
  • 用户体验来自可靠性,而不仅仅是智能程度

2. 架构思维

  • 单一事实来源是复杂度管理的关键
  • 清晰的层间边界是可维护性的基础
  • 扩展性要前置设计,不能后补

3. 工程思维

  • 成本结构设计比功能实现更重要
  • 启动性能和运行时性能都需要系统性优化
  • Build-time 和 Runtime 开关要分层设计

4. 产品化思维

  • 三级扩展体系(技能/插件/MCP)满足不同场景
  • 权限系统是产品化的基础设施
  • 可观测性是企业级产品的必备能力

最终评价

Claude Code 是一个教科书级的 AI Agent 工程实践,它展示了:

完整的 Agent Runtime - 从输入到输出的完整生命周期管理

企业级的工程化 - 性能、成本、可观测性的系统性设计

平台化的扩展性 - 三级扩展体系 + 统一注册中心

产品级的用户体验 - 快速启动、可恢复、可并行、有边界

对前端工程师的价值

  • 学会"运行时思维",而不仅是"页面思维"
  • 学会"成本结构设计",而不仅是"功能实现"
  • 学会"平台化架构",而不仅是"单点应用"

这也是它能成为优秀企业级 Agent / CLI 产品的真正原因------不是模型更强,而是工程体系更完整

声明

  • 源码版权:归 Anthropic 所有
  • 研究用途:本分析仅供技术研究与学习使用
  • 非官方:本文档非 Anthropic 官方文档
  • 删除请求:如有侵权,请联系删除

泄露事件时间线:

  • 2026-03-31 - Chaofan Shou (@Fried_rice) 在 X (Twitter) 公开发现
  • 2026-03-31 - GitHub 社区恢复版发布

文章来源: 出自我自己的公众号:《向量启示录》,感兴趣的同学可以关注一下

相关推荐
嘴平伊之豬2 小时前
Claude Code 源码泄露,我从中发现了一个隐藏彩蛋
claude
NikoAI编程3 小时前
用 ultraplan 做了一次大重构规划,我再也不想回终端里写 plan 了
人工智能·ai编程·claude
bulabulabula3 小时前
我用 2 个 Skill 解决AI开发如何记录文档的问题
claude·cursor·vibecoding
davidson14714 小时前
Ubuntu配置Claude
linux·人工智能·ubuntu·claude
AI精钢5 小时前
Adaptive Thinking 的代价:当 AI 自己决定“想多少“
人工智能·llm·claude·ai工程·ai可靠性
Bigger5 小时前
第五章:我是如何剖析 Claude Code 的 MCP 服务与插件生态系统的
前端·ai编程·claude
Shawn_Shawn16 小时前
openspec使用手册
llm·ai编程·claude
该用户已不存在21 小时前
Claude Mythos 发布,强到刚出道就被雪藏?
aigc·ai编程·claude
Miku161 天前
OpenClaw+image-downloader-skill: 打造关键词图片批量下载工作流
aigc·agent·claude