Digital Strategy Review | 2026
Claude Code 源码导读 01|从 cli.tsx 到 main.tsx,看清系统如何完成启动装配
文 / 果叔 · 阅读时间 / 8 Min

写在前面
这一篇我想先把启动链路讲透。先把入口和装配过程看清楚,后面再读 query.ts、AgentTool、REPL.tsx 才不会被局部细节带偏;Claude Code 难读的地方,不在文件多,而在它从入口开始就已经是一套 runtime 的装配过程。
01
从 cli.tsx 到 main.tsx:系统是怎么启动的
这一篇只回答一个问题:Claude Code 这套系统是怎么从一个命令启动,逐步装配成完整运行时的。
如果不先建立这个全景图,后面再读 query.ts、AgentTool、REPL.tsx 很容易陷入局部细节。因为这不是一个“命令解析 -> 执行业务逻辑”的普通 CLI,而是一个有多种运行模式、多个执行后端、复杂能力裁剪逻辑的 agent runtime。
02
一、先看 src/entrypoints/cli.tsx
src/entrypoints/cli.tsx 的角色不是“薄薄一层入口”。它本身就是第一层调度器。
这里最重要的事实是:它没有一上来就导入完整系统,而是先做一轮轻量级、性能敏感的 fast-path 分流。
你从源码里能看出它明显在追求两件事:
01 不需要完整运行时的路径,尽量不要加载完整运行时。
02 不同模式的入口,尽量在最早阶段就分叉。
1. 为什么这里要做 fast-path
cli.tsx 处理了很多可以提前返回的路径,比如:
• --version
• --dump-system-prompt
• --daemon-worker
• remote-control / remote / sync / bridge
• daemon
• ps / logs / attach / kill / --bg
• 模板类命令
• environment-runner
• self-hosted-runner
• --worktree --tmux 相关路径
这意味着 Claude Code 从架构上承认一件事:
“Claude Code”不是一个单一运行形态,而是一套共享核心能力的多入口系统。
也就是说,命令行前台 REPL 只是其中一种入口,后台 worker、bridge、daemon、远程执行环境,本质上也都属于同一体系。
2. 为什么它用动态导入
这里的大量 await import(...) 不是单纯的代码风格,而是很实在的启动控制:
• 只有真正进入某个分支,才加载对应依赖
• 减少普通路径的模块求值成本
• 给后面的 feature gate 留出足够清晰的边界
这和很多 CLI 项目“所有模块先 import,再在逻辑里判断”完全不同。 Claude Code 更像在做一个多模式 runtime launcher。
3. 这一步对后面的 Agent 系统意味着什么
后面我们会看到 agent 有很多执行形态:
• 本地前台
• 本地后台
• 同进程 teammate
• tmux teammate
• worktree agent
• remote agent
如果入口层一开始不把运行模式拆开,后面的系统复杂度会爆炸。 所以 cli.tsx 的核心价值,不是“启动快一点”,而是先把系统边界拆清楚。
03
二、src/main.tsx 不是页面入口,而是运行时装配器
main.tsx 很大,但读法不能按“一个大组件”去读。更准确地说,它是 Claude Code 的runtime assembler。
它负责把下面这些东西装起来:
• config / settings / managed settings
• auth / OAuth / subscription / org policy
• analytics / GrowthBook / feature gates
• model 选择与能力判断
• MCP / plugin / skills
• tools / commands / agents
• store / AppState
• 最终进入某个 REPL 形态
所以它大的原因不是职责混乱,而是它承担了“把一个可运行会话装出来”的总控职责。

启动不是单点执行,而是一套分流、装配与能力接线过程。
04
三、启动过程的五个阶段
我建议把 main.tsx 的启动路径理解成 5 个阶段。
阶段一:预热慢路径
文件最开头就做了几件很有经验的事:
• profileCheckpoint(...)
• 提前启动 MDM 读取
• 提前启动 keychain prefetch
这类代码的味道很明显: 作者已经非常清楚哪些操作会拖慢首屏,所以把它们前移并并发化。
这类预热不是“锦上添花”,而是对交互式系统非常关键的优化。因为 Claude Code 启动后要立刻进入高互动状态,不能像后台脚本那样慢慢初始化。
阶段二:初始化环境与策略
在进入主逻辑之前,系统会逐步拉起:
• 配置与环境变量映射
• managed settings
• remote managed settings
• policy limits
• auth / bootstrap 信息
• GrowthBook
• analytics gate
这一步决定的是:当前用户、当前组织、当前环境,到底允许看见什么能力。
这很重要,因为在 Claude Code 里,工具、agent、远程能力、bridge、auto mode 等都不是固定暴露的。 它们必须先经过这层策略和配置判断。
阶段三:组装能力面
接下来会装配:
• commands
• tools
• agent definitions
• MCP clients / resources / commands
• plugins
• skills
这一步的本质不是“注册功能”,而是形成一个当前会话的能力快照。
尤其是 getTools(...) 这一层很关键。 Claude Code 并不把工具当成恒定存在的 SDK 函数,而是把它们看成会被环境、权限、模式、feature gate 裁剪的动态执行面。
阶段四:建立状态仓库
main.tsx 会创建 store,并准备 REPL 所需的初始状态。 这是后面 AppState 能承载任务、通知、MCP、plugin、viewing-agent、permission queue 的前提。
也就是说,这里不只是“初始化 React state”,而是在创建一个会话级运行时状态容器。
阶段五:进入 REPL
最后,系统会根据不同前提进入不同版本的 launchRepl(...) 路径。
这说明 REPL 不是单一页面,而是一个承接多种启动结果的统一交互舞台,比如:
• 正常本地会话
• resume 恢复会话
• remote viewer
• 不同模式的前台控制面
05
四、main.tsx 真正解决的不是“启动”,而是“装配”
如果用一句话概括 main.tsx 的职责,那就是:
在进入第一轮用户交互之前,把当前这次会话该拥有的世界模型装配完整。
这个世界模型包括:
• 当前用户是谁
• 当前模型是什么
• 当前权限模式是什么
• 当前能看到哪些工具
• 当前能加载哪些 agent
• 当前有没有 MCP / plugin / remote bridge
• 当前 REPL 该以什么姿态启动
为什么这件事重要? 因为后面的 query loop、tool orchestration、AgentTool 都假设这些基础条件已经定好了。
也就是说,main.tsx 是整个系统的“前置求值器”。
06
五、从架构角度看,cli.tsx + main.tsx 建立了三层边界
这两份文件合起来,给整套系统建立了三层很重要的边界。
边界一:运行模式边界
cli.tsx 先决定你到底走哪条入口:
• 轻量命令
• daemon/bridge/background
• 还是完整交互运行时
边界二:能力边界
main.tsx 决定这一轮会话到底能看到什么:
• 哪些工具
• 哪些 command
• 哪些 agent
• 哪些 plugin / MCP 能力
边界三:交互边界
launchRepl(...) 决定最终用户如何进入系统:
• 本地前台
• 恢复会话
• 远程观察/控制
所以从源码结构看,这两层不是“启动脚本”,而是把后续复杂系统约束住的第一道防线。
07
六、最值得抓住的阅读重点
如果你打算自己继续深入这两份文件,我建议抓下面这些问题:
01 哪些路径在 cli.tsx 就被提前截断了,为什么?
02 哪些配置必须在 main.tsx 早期完成,否则后面能力暴露会出错?
03 getTools(...)、agent definitions、MCP、plugins 分别在哪个阶段被组装?
04 为什么 main.tsx 里有那么多 launchRepl(...) 调用?
05 为什么它要在 REPL 启动前就把这么多策略和能力判断做完?
这五个问题想清楚了,后面读 query.ts 时就不会把它误解成一个单纯的“聊天循环”。
08
七、一张图看懂启动总流程

09
八、这一篇的结论
cli.tsx 和 main.tsx 联手完成的,不是“把程序跑起来”,而是:
• 先在入口层拆分运行模式
• 再在主装配层求值当前会话能力
• 最后把完整运行时交给 REPL
这是后面整套 agent runtime 能成立的前提。 因为你接下来读到的一切复杂度,都是建立在“当前世界已经被装配好了”的假设之上的。
下一篇就该进入这个世界真正的心脏:query.ts、tools.ts、toolOrchestration.ts。