第一章:先把 Claude Code 看成一套运行时
从目录规模、模块分层和总体判断出发,把这份源码先看成一套长生命周期 agent runtime。
1. 这份快照到底是什么
相关深拆:
- 《Claude Code 源码拆解》目录
- 核心拆解 01:
query.ts回合状态机 - 核心拆解 02:工具运行时
- 核心拆解 03:
BashTool子系统 - 核心拆解 04:
FileReadTool子系统 - 核心拆解 05:
FileEditTool子系统 - 核心拆解 06:
FileWriteTool子系统 - 核心拆解 07:
NotebookEditTool子系统 - 核心拆解 08:
GlobTool+GrepTool搜索子系统 - 核心拆解 09:
WebFetchTool+WebSearchTool外部信息子系统 - 核心拆解 10:
AgentTool+SkillTool委派与技能子系统 - 核心拆解 11:
AskUserQuestion+ExitPlanMode+SendMessage+TodoWrite协作控制子系统 - 核心拆解 12:
TaskCreate/TaskGet/TaskUpdate/TaskList/TaskStop/TaskOutput任务运行时 - 核心拆解 13:
ConfigTool+EnterWorktree/ExitWorktree+ListMcpResources/ReadMcpResource运行时辅助层 - 核心拆解 14:
ToolSearchTool+SyntheticOutputTool+TestingPermissionTool元工具层 - 核心拆解 15:
MCPTool+McpAuthTool+services/mcp/client.ts动态扩展层 - 核心拆解 16:
LSPTool语义代码理解层 - 核心拆解 17:
REPLTool包装层 - 核心拆解 18:上下文压缩与会话续航
- 核心拆解 19:
Tool Result Budget与大输出持久化 - 核心拆解 20:溢出恢复回路与
reactive compact边界 - 核心拆解 21:
context collapse的接口边界与持久化协议 - 核心拆解 22:C# 运行时映射与接口蓝图
- 核心拆解 23:权限运行时
- 核心拆解 24:会话持久化、
Transcript与 Resume - 核心拆解 25:附件系统与上下文注入
- 核心拆解 26:启动引导与模式分流
- 核心拆解 27:Bridge 与 Remote Runtime
- 核心拆解 28:Managed Settings、Policy 与 Settings Sync
- 核心拆解 29:AppState 与 UI/runtime 边界
- 核心拆解 30:认证 / Token / 登录运行时
- 核心拆解 31:Telemetry / analytics / attribution
- 核心拆解 32:Memory 全景
- 核心拆解 33:插件系统 / Marketplace / 扩展治理
- 核心拆解 34:Hooks 运行时总览
- 核心拆解 35:模型 / Provider / Capability 路由
- 价值榨取地图
- 工具总索引
这不是一个完整 monorepo,更像是一份被导出的 src/ 运行时代码快照。当前仓库里能看到的核心事实是:
- 根目录基本只有
README.md、研究说明文和src/ - 没有常见的
package.json、pnpm-workspace.yaml、测试配置、构建脚本 - 代码明显以 Bun 为运行时,CLI 层使用 Commander,终端 UI 使用 React + Ink
所以这次分析的边界也很明确:
- 我们能较完整地分析“运行时设计”
- 但暂时看不到“完整构建链、发布脚本、测试组织方式”
2. 我对它的总体判断
如果只用一句话概括,这个项目本质上不是“一个会调大模型的 CLI”,而是一个:
以对话回合引擎为核心、以工具系统为执行面、以 MCP / 插件 / 技能为扩展面、以 REPL / Headless / Bridge 为不同宿主外壳的 agent runtime。
也就是说,它真正的核心不是 UI,而是下面这几个东西:
- 启动编排和模式分流
- Query / Turn Loop
- Tool 抽象与工具调度
- 权限与审批模型
- 扩展系统:MCP、插件、技能
- 会话状态、持久化和上下文压缩
3. 从目录规模反推重心
粗看文件数量,重点非常明显:
| 目录 | 文件数 | 说明 |
|---|---|---|
src/utils | 564 | 基础设施极重,说明工程复杂度主要在运行时细节 |
src/components | 389 | REPL UI 很重,不只是简单命令行输出 |
src/commands | 207 | Slash command 很多,CLI 表层很丰富 |
src/tools | 184 | 真正的能力面在工具系统 |
src/services | 130 | 网络、MCP、分析、压缩、插件等都在这里 |
src/hooks | 104 | 交互态逻辑大量依赖 React hook 组织 |
src/ink | 96 | 终端渲染不是薄封装,而是深度定制 |
这意味着 Claude Code 的设计重点不是“单次 prompt -> response”,而是“长生命周期会话运行时”。
3.1 这轮新补的横切系统
如果目标是继续往 C# 版抽象推进,这一轮最值得补的七块横切系统已经补齐:
- AppState 与 UI/runtime 边界
- 认证 / Token / 登录运行时
- Telemetry / analytics / attribution
- Memory 全景
- 插件系统 / Marketplace / 扩展治理
- Hooks 运行时总览
- 模型 / Provider / Capability 路由
更完整的继续挖掘地图见:
4. 总体架构图
flowchart TB
User["用户 / IDE / 远端控制"] --> Entry["src/entrypoints/cli.tsx"]
Entry --> Main["src/main.tsx<br/>启动编排、参数解析、模式分流"]
Main --> Init["src/entrypoints/init.ts<br/>配置、环境变量、代理、遥测、基础初始化"]
Main --> Registry["src/commands.ts + src/tools.ts<br/>内建命令与工具注册"]
Main --> Ext["技能 / 插件 / MCP 配置装载"]
Ext --> Skills["src/skills/loadSkillsDir.ts<br/>技能目录与 Markdown Skill"]
Ext --> Plugins["src/utils/plugins/*<br/>插件发现、加载、命令/技能注入"]
Ext --> MCP["src/services/mcp/*<br/>MCP 连接、工具、命令、资源"]
Main --> ReplPath["交互式路径"]
Main --> HeadlessPath["非交互 / SDK 路径"]
Main --> BridgePath["远程桥接路径"]
ReplPath --> ReplLauncher["src/replLauncher.tsx"]
ReplLauncher --> App["src/components/App.tsx"]
App --> REPL["src/screens/REPL.tsx"]
HeadlessPath --> Headless["src/cli/print.ts"]
Headless --> QueryEngine["src/QueryEngine.ts"]
BridgePath --> Bridge["src/bridge/bridgeMain.ts<br/>远程会话桥接与 session 管理"]
REPL --> Query["src/query.ts<br/>统一回合引擎"]
QueryEngine --> Query
Bridge --> Query
Query --> PromptCtx["src/context.ts + prompts<br/>系统/用户上下文装配"]
Query --> Model["src/services/api/claude.js<br/>模型流式调用"]
Model --> ToolExec["src/services/tools/*<br/>工具调度、并发、流式执行"]
ToolExec --> Builtin["内建工具<br/>Bash / Read / Edit / Agent / Skill / Todo ..."]
ToolExec --> McpTool["MCPTool / MCP Resource Tools"]
ToolExec --> Permission["权限系统<br/>ToolPermissionContext + canUseTool"]
ToolExec --> Compact["上下文压缩<br/>compact / microcompact / snip"]
ToolExec --> State["AppState / SessionStorage / FileHistory"]
State --> REPL
5. 主链路怎么跑
5.1 启动层
src/entrypoints/cli.tsx 负责很薄的一层入口分流:
- 对
--version这类 fast path 做极限短路 - 对
remote-control、daemon、background sessions、environment-runner这类特殊模式提前分发 - 正常情况再把控制权交给
src/main.tsx
src/main.tsx 才是真正的总编排器。它做的事情非常多:
- 初始化配置、遥测、代理、认证、远端设置
- 解析命令行和权限模式
- 预热 MCP 配置、插件、技能、模型信息
- 生成命令列表和工具列表
- 决定进入哪条运行路径:
- 交互式 REPL
- headless print / SDK
- remote bridge
这说明它的设计不是“程序入口”,而是一个 runtime bootstrapper。
5.2 交互式路径
交互式模式大致是:
main.tsx -> replLauncher.tsx -> components/App.tsx -> screens/REPL.tsx
这里的 REPL.tsx 很重,它不是一个“输入框组件”,而是整套会话壳:
- 输入与快捷键
- 消息流显示
- 命令队列
- IDE 集成
- 后台任务
- 队友 / swarm 视图
- 权限弹窗
- MCP 连接状态
- 各种通知和状态条
但它并不直接实现模型循环,最后还是调用 src/query.ts。
5.3 非交互路径
非交互模式由 src/cli/print.ts + src/QueryEngine.ts 负责。
这里可以把 QueryEngine 理解成一个更容易复用的“会话内核包装器”:
- 持有当前消息历史
- 组装
ToolUseContext - 管理一次次
submitMessage() - 最终仍然调用
query()
这意味着作者已经在做一件很重要的抽象工作:
把 UI 会话壳 和 对话回合引擎 拆开。
这对 C# 迁移非常关键,因为你完全可以先迁内核,再换宿主。
6. query.ts 才是最核心的 runtime
如果只挑一个文件当 Claude Code 的“心脏”,我会选 src/query.ts。
它做的是一个完整的 agent turn loop:
- 组装消息、system prompt、上下文
- 发起流式模型请求
- 解析 assistant 消息里的 tool use
- 按并发规则执行工具
- 把 tool result 回灌到消息流
- 必要时继续下一轮 assistant
- 处理中途打断、权限拒绝、fallback、压缩、预算限制
也就是说,这里并不是“请求一次模型”,而是在跑一个 状态机。
6.1 回合内部结构图
flowchart LR
A["当前消息历史"] --> B["组装 System Prompt / User Context"]
B --> C["流式调用模型"]
C --> D{"assistant 是否发出 tool_use"}
D -- 否 --> E["产出最终 assistant 响应"]
D -- 是 --> F["services/tools/toolOrchestration.ts"]
F --> G["串行 / 并行执行工具"]
G --> H["生成 tool_result 消息"]
H --> I["写回消息历史"]
I --> J{"是否继续下一轮"}
J -- 是 --> C
J -- 否 --> E
C --> K["compact / microcompact / fallback / token budget"]
G --> L["permission / hook / telemetry / session storage"]
7. Tool 系统是第二核心
src/Tool.ts 定义了 Claude Code 的工具抽象,里面最重要的不是“execute 一个函数”,而是整套上下文对象:
- 当前命令集合
- 当前工具池
- 当前 MCP client / resources
- 当前 AppState
- 读文件缓存
- 中断控制器
- 权限处理
- UI 通知、弹窗、进度状态
- 文件历史、归因、内容替换状态
这说明 Claude Code 的 Tool 不是“纯函数工具”,而是 运行时参与者。
src/tools.ts 则负责把所有工具拼成工具池:
- 内建工具
- REPL 专属工具
- feature flag 控制的工具
- MCP 资源工具
- 协调模式 / worktree / simple mode 下的不同工具裁剪
再往下,src/services/tools/toolOrchestration.ts 和 toolExecution.ts 负责:
- 判断哪些工具能并发
- 串行或并行调度
- 包装权限检查
- 追踪 telemetry / hook / tracing
- 生成
tool_result消息
这部分在 C# 里不应该写成一堆 switch case,而应该单独做成:
IToolToolRegistryToolExecutionContextToolSchedulerPermissionEvaluator
8. 扩展系统是“平台化”的关键
8.1 MCP
src/services/mcp/client.ts 和 useManageMCPConnections.ts 说明 MCP 在 Claude Code 里不是补充插件,而是一级公民:
- 会连接多个不同 transport 的 MCP server
- 把 server 暴露成 tools / commands / resources
- 动态写回
AppState.mcp - 允许 REPL 会话中途增量接入
这很像一个外部能力总线。
8.2 技能
src/skills/loadSkillsDir.ts 表明技能本质上是 Markdown 驱动的命令/提示模板系统:
- 从目录读
SKILL.md - 解析 frontmatter
- 提取 description / when_to_use / allowed-tools / model / effort
- 最终编译成
Command
换句话说,技能不是“代码插件”,而是“可编排的高层 agent 能力描述”。
8.3 插件
src/utils/plugins/pluginLoader.ts 和 loadPluginCommands.ts 说明插件系统更像“扩展包”:
- 有 manifest
- 能提供 commands / agents / hooks
- 能从 marketplace 或 git 源装载
- 有版本化缓存和启停管理
所以插件和技能不是一层东西:
- 技能更像 prompt-asset
- 插件更像 capability bundle
9. 状态管理并不轻
src/state/AppStateStore.ts 里的 AppState 很大,已经不是“UI 状态”了,而是整个会话 runtime 的共享状态:
- 权限模式
- 当前模型和设置
- REPL bridge 状态
- MCP clients / tools / commands / resources
- 插件状态
- 任务和子 agent
- 通知、elicitation、thinking、session hooks
- 文件历史、归因、todo、远端会话等
这说明 Claude Code 的 React 层不只是视图,而是承担了很大一部分 runtime orchestration shell。
如果未来你做 C# 版,我不建议完全照搬这个超大状态对象;更合理的是拆成几个有边界的 store:
SessionStateToolRuntimeStateExtensionStateUiStateTaskState
10. 远程桥接不是附属功能
src/bridge/bridgeMain.ts 这套代码量已经足够说明,bridge 不是一个小插件,而是独立子系统:
- 会拉起或回收 session
- 维护心跳和 backoff
- 处理远端环境与本地工作目录的映射
- 管理 token 刷新、work secret、session id 兼容
所以 Claude Code 不是单机 CLI,它在设计上从一开始就给“远端执行 / IDE 附着 / 会话桥接”留了正式位置。
11. 对 C# 版本最有价值的拆分方式
如果目标是“从设计思路出发,做 C# 版”,我建议先不要直接翻译 TypeScript 文件,而是先抽成下面这几个边界:
| Claude Code 现有模块 | C# 建议落点 |
|---|---|
entrypoints/cli.tsx + main.tsx | Program.cs + CliBootstrapper |
query.ts + QueryEngine.ts | ConversationRuntime + TurnLoop + ConversationSession |
Tool.ts + tools.ts + services/tools/* | ITool + ToolRegistry + ToolExecutionContext + ToolScheduler |
state/AppState* | SessionStore / RuntimeState / UiState 分层 |
services/mcp/* | McpConnectionManager + McpToolAdapter + McpResourceCatalog |
skills/loadSkillsDir.ts | MarkdownSkillLoader |
utils/plugins/* | PluginManager + PluginCatalog + PluginPackageResolver |
bridge/* | RemoteBridgeHost + SessionSupervisor |
context.ts + prompts | PromptContextBuilder |
compact/* | ConversationCompactor |
最重要的一点是:
先把“统一回合引擎 + 工具调度 + 扩展接入”这三个核心抽出来,再决定 UI 是终端、IDE 还是 Web。
12. 我觉得最值得继续深挖的三个点
后面如果继续往下拆,我建议按这个顺序:
query.ts:把完整 turn loop 状态机画出来Tool.ts+services/tools/*:把工具执行协议和权限模型拆出来services/mcp/*+skills/*+plugins/*:把扩展系统的统一抽象找出来
这是最接近 C# 可落地架构骨架的三层。