前言
这篇文章试图回答一个更具体的问题:
Claude Code 到底是怎么工作的?
如果只从产品表面看,Claude Code 很容易被理解成“一个会读代码、会跑命令的 Claude”。但把源码摊开后你会发现,它其实不是一个“纯聊天壳”,而是一套很完整的 agent runtime:
- 有自己的 CLI 入口和启动编排;
- 有独立的上下文装配层;
- 有一整套工具注册、权限判定、并发执行与回填机制;
- 有子代理、后台任务、worktree 隔离;
- 有 MCP、plugin、skills、bridge、remote session 等扩展层;
- 有自动 compact、session memory、CLAUDE.md / MEMORY.md 这类长期上下文机制;
- 最外面再包一层 React + Ink 的终端 UI。
为了更容易建立稳定的心智模型,本文会一边沿着源码主链路展开,一边拿 Codex 做对照。对照视角主要参考两类材料:
- 你给的 Codex 解读思路;
- 我博客里已经写过的两篇 Codex 文章,以及 rslog 这篇 Codex 架构解读。
如果要先用一句话概括,我会这样总结:
Claude Code 本质上是一个用 TypeScript/Bun 写成的本地 agent 宿主。模型负责决定“下一步做什么”,而 Claude Code 负责决定“这些动作在本地如何被授权、如何执行、如何并发、如何压缩上下文、如何接入外部系统,以及如何在终端里被展示出来”。
先说可信边界:这份仓库到底是什么
先把一个很重要的前提讲清楚。
这次分析的对象不是 Anthropic 官方公开维护的完整开发仓库,而是一个源码快照。根目录的 README.md 明确说了两点:
- 这是一个 Claude Code Source Snapshot for Security Research;
- 来源是一次公开的 source map 暴露,时间点是 2026-03-31。
这意味着这份代码非常有研究价值,但也要注意三层边界:
- 它不是官方长期维护仓库
所以你看到的是某个时间点的实现切片,而不是完整演进历史。
- 它可能包含内部 feature flag 分支
源码里大量使用 feature('...') 做 dead code elimination,说明同一份代码会被编译成不同产品形态。你看到的不一定全部对外开放。
- 它足够解释架构,但不代表产品全部行为都能直接从快照推出
例如某些后端服务、GrowthBook 灰度、桥接基础设施、远端运行环境,源码能看见入口和协议,但未必看得到服务端完整实现。
所以,最稳妥的阅读姿势是:
- 把它当成 Claude Code 宿主程序的高保真实现快照;
- 结合官方文档验证对外稳定能力,例如 How Claude Code works、Context window、Settings、Memory;
- 再把源码里只出现于 flag 后面的部分,视作“架构方向”和“产品内部能力痕迹”。
仓库全景:它不是一个小工具,而是一套 agent 平台
这份快照虽然只有一个 src/,但结构很完整。按目录数量看,几个最大的模块是:
| 目录 | 文件数 | 直觉角色 |
|---|---|---|
utils/ |
564 | 公共运行时、状态辅助、权限、上下文、日志、模型辅助 |
components/ |
389 | TUI 组件层 |
commands/ |
207 | /command 命令体系 |
tools/ |
184 | 模型可调用的工具层 |
services/ |
130 | API、MCP、compact、analytics 等服务层 |
hooks/ |
104 | React hooks + 权限/交互逻辑 |
ink/ |
96 | Ink 适配与终端 UI 基础设施 |
bridge/ |
31 | 远程桥接、session、remote control |
skills/ |
20 | 技能系统 |
cli/ |
19 | CLI 子命令与命令行处理 |
tasks/ |
12 | 后台任务/子代理任务系统 |
如果把这些目录抽象成一张架构图,我会画成这样:
|
|
这个结构和 Codex 很像的一点是:模型不是系统本身,模型只是系统中的决策器。
不同的是,Claude Code 比开源 Codex CLI 更“产品化”:
- UI 更重;
- feature flag 更多;
- bridge / remote / assistant / kairos / companion 等产品特性痕迹更明显;
- MCP、plugin、skills、subagent 都是统一 runtime 的一部分,而不是几个松散外挂。
一条主链路:从 main.tsx 到 agent loop
Claude Code 的真实主入口在 src/main.tsx。
这个文件很大,也很“重”,说明它不是一个薄薄的参数解析层,而是整个宿主程序的启动协调器。这里面能看到几类非常重要的事情:
- 提前做一批启动副作用,例如 profiler、keychain、managed settings;
- 初始化 analytics、settings、plugins、skills、MCP、bridge、LSP;
- 解析命令行参数;
- 决定当前是正常 TUI、print 模式、SDK 模式、remote 模式还是别的运行形态;
- 组装
QueryEngine所需的运行时能力。
你如果把它和 Codex 的启动入口对比,会发现两者都有类似的“巨型引导层”,只是风格不同:
- Codex 更像 Rust 的 harness/runtime 分层;
- Claude Code 更像一个 单体 TypeScript runtime,所有入口能力最后都汇总进一个共享的 agent loop。
Claude Code 主链路里最关键的两个对象是:
QueryEnginequery.ts
QueryEngine:会话级控制器
src/QueryEngine.ts 可以看成“对话会话的总调度器”。
它持有的配置非常多,包括:
- 当前工作目录;
- 工具列表、命令列表、MCP client、agent definitions;
canUseTool权限判定函数;getAppState/setAppState;- 文件读取状态;
- 自定义 system prompt / append system prompt;
- model / fallback model;
- thinking config;
- 最大轮数、预算、structured output schema;
- 是否回放用户消息、是否包含 partial messages。
这说明 QueryEngine 的角色不是“发一个 API 请求”,而是:
维护一场会话级 agent 运行所需要的全部宿主依赖,并在每一轮用户输入时启动一次受控的 query loop。
query.ts:真正的 agent loop
src/query.ts 是 Claude Code 的核心中的核心。
如果你只想找“Claude Code 到底在哪里实现了多轮工具调用闭环”,这个文件就是主战场。
它做的事情大致是:
- 组装本轮 messages 和 system prompt;
- 把工具 schema 发给模型;
- 读取流式响应;
- 一边消费增量输出,一边把工具调用交给
StreamingToolExecutor; - 收集工具结果回填到消息流;
- 持续检查停止条件、轮数、预算、token 使用;
- 在必要时触发 compact / context collapse / reactive compact;
- 最终产出本轮 assistant 消息和更新后的状态。
这套设计和 Codex 的 agent loop 非常接近,但实现风格不一样:
- Codex 的感觉更像“显式状态机 + runtime harness”;
- Claude Code 更像“消息流 + 工具流 + UI 状态流三者同时推进”。
也正因为这样,Claude Code 源码里会明显出现“streaming tool execution”“partial messages”“in-progress tool IDs”“message appenders”“notification queue”这一整套流式系统词汇。
Claude Code 的上下文管理,核心不是“存 messages”,而是“分层装配上下文”
如果问我 Claude Code 最值得研究的部分是什么,我会选 上下文装配层。
因为它不是把“历史消息原封不动发给模型”,而是显式地区分了几类上下文来源:
- 默认 system prompt;
- 自定义/追加 system prompt;
- 用户工作区上下文;
- Git 上下文;
- 记忆系统;
- 运行时工具和权限上下文;
- 压缩后的会话历史;
- 任务/子代理带回来的输出。
这部分的关键文件主要有:
|
|
1. context.ts:把“环境”变成上下文
src/context.ts 里有两个很关键的函数:
getSystemContext()getUserContext()
它们分别负责把两类环境信息注入给模型。
getSystemContext() 做的是偏“宿主视角”的上下文注入,例如:
- 当前 Git 分支;
- main branch;
git status;- 最近 commit;
- git user。
也就是说,Claude Code 会在会话开始时主动告诉模型:你当前不是在一个抽象目录里,而是在一个真实 git 工作区里。
getUserContext() 则更接近“用户意图层”的附加信息,里面最关键的是:
CLAUDE.md- 当前日期
这和官方文档是对上的。Anthropic 官方文档明确把 CLAUDE.md 视作 Claude Code 的用户级持久上下文载体,而源码则进一步告诉你:它不是单独的 feature,而是 query context 构造的一部分。
2. systemPrompt.ts:system prompt 不是一段字符串,而是一套优先级规则
src/utils/systemPrompt.ts 很值得读,因为它把系统提示词的拼装优先级写得非常清楚。
它处理的优先级大致是:
overrideSystemPrompt直接覆盖一切;- coordinator mode 使用 coordinator prompt;
- 主线程 agent definition 如果存在,则使用 agent prompt;
- 否则使用 custom system prompt;
- 最后回落到 default system prompt;
appendSystemPrompt始终可以附加在末尾。
也就是说,Claude Code 的 system prompt 不是一个静态模板,而是一个 按运行模式重写的 prompt stack。
这点和 Codex 很像。Codex 里也不是“只有一段 meta prompt”,而是有 platform/system/developer/user 多层;Claude Code 这里虽然最终对接的是 Anthropic 消息接口,但宿主层同样在做 prompt hierarchy。
3. queryContext.ts:会话拼装器
src/utils/queryContext.ts 的意义是把各种 prompt part 统一拉平。
它负责:
- 获取 default system prompt;
- 拉 user context;
- 拉 system context;
- 给 side question / print / SDK 等场景复用同一套装配逻辑。
这说明 Claude Code 的设计里有一个很清晰的工程观:
不同入口可以不同,但真正送给模型的上下文装配逻辑最好只有一套。
这点非常重要,因为一旦 system/user context 的注入路径散落在不同入口,产品行为就会变得不一致。
真正的“长期记忆”:CLAUDE.md + MEMORY.md + compact
很多人第一次用 Claude Code,会感觉它“好像记得我项目里的一些约定”。这背后其实不是神秘能力,而是三套机制叠加:
CLAUDE.mdMEMORY.md- compact 之后的会话摘要 / 保留信息
CLAUDE.md:项目级持久规则
这是最直接的一层。用户把约定写进仓库里的 CLAUDE.md,Claude Code 在构造用户上下文时把它读进来。
它更像 Codex 里的 AGENTS.md / 开发者指令那一类东西:
- 让 agent 按项目规范工作;
- 在每轮对话前都能重新看到;
- 不依赖模型“记住”。
MEMORY.md:显式的 session / workspace memory 入口
src/memdir/memdir.ts 非常有意思,因为它把记忆机制做成了文件系统协议。
其中几个关键信号是:
- memory entrypoint 明确叫
MEMORY.md; - 有尺寸和行数上限;
- 有 index/truncation 逻辑;
- 鼓励把记忆拆成独立文件,然后用
MEMORY.md做入口索引。
这意味着 Claude Code 的 memory 不是“偷偷把东西藏在数据库里”,而是尽量把记忆外显为可管理文件结构。这和官方文档对 memory 的定位是吻合的,也非常工程化。
compact:不是可选优化,而是会话能跑长任务的关键
src/services/compact/compact.ts 和 src/services/compact/autoCompact.ts 说明了一件事:
Claude Code 从一开始就把“上下文迟早会爆”当成既定事实,所以它实现的是完整 compact pipeline,而不是一个临时裁剪函数。
从源码能看到的 compact 关键点包括:
- auto-compact 阈值计算;
- 根据模型上下文窗口决定触发条件;
- 某些模式下抑制 auto-compact;
- pre-compact / post-compact hooks;
- 图像与附件裁剪;
- compact 失败重试;
- compact 后对文件、skills 等上下文的恢复预算;
- 对连续 compact 失败的 circuit breaker。
这一点和 Codex 几乎是同一个大方向:agent 不是在无限上下文里工作,而是在有限上下文里做“保真压缩”。
但 Claude Code 的实现明显更产品化,因为它需要同时处理:
- 富文本消息;
- 文件附件;
- MCP 输出;
- 子代理结果;
- UI 状态;
- 背景任务通知。
ToolUseContext 是 Claude Code 的宿主 ABI
如果要在 Claude Code 里找一个“最能代表 agent runtime 接口”的类型,我会选 src/Tool.ts 里的 ToolUseContext。
原因很简单:这个类型决定了工具在运行时到底能拿到什么。
从源码看,ToolUseContext 里已经不是简单的“cwd + abortSignal”了,而是一整套宿主能力:
commandstoolsmcpClientsagentDefinitionsgetAppState/setAppStatehandleElicitationmessagesreadFileStateaddNotification- 文件历史
- attribution
- stream mode
- conversation / agent / session 相关信息
换句话说,Claude Code 的工具不是独立函数,而是运行在一个功能非常丰富的 host context 里。
如果拿 Codex 做类比:
- Codex 更像“runtime 为 tool handler 提供执行上下文”;
- Claude Code 则把这个上下文抽成了明确的 TypeScript runtime contract。
工具系统:不是“工具列表”,而是“注册表 + 编排器 + 流式执行器”
Claude Code 的工具系统至少要拆成三层看:
- 工具注册表;
- 工具权限判定;
- 工具执行编排。
1. tools.ts:工具注册表
src/tools.ts 是工具体系的总入口。
getAllBaseTools() 基本就是 Claude Code 的“官方工具目录”。这里能看到的工具大类包括:
AgentToolBashToolFileReadToolFileEditToolFileWriteToolGlobToolGrepToolWebFetchToolWebSearchToolTodoWriteTool- MCP 资源读取/列举工具
AskUserQuestionToolSkillTool- plan mode / worktree / workflow / sleep / monitor 等工具
这和官方 Tools Reference 也基本一致,只是源码层面还多给你展示了很多实验性或特性开关后的能力。
2. useCanUseTool.tsx:权限不是工具内部做,而是统一前置
Claude Code 的权限体系比很多人想象中更复杂。
src/hooks/useCanUseTool.tsx 这一个文件就能看出它至少同时处理几件事:
- 配置层的 allow / deny / ask;
- classifier 自动放行;
- coordinator / swarm worker 特殊判定;
- 交互式权限对话框;
- 中断与取消;
- permission logging;
- auto mode denial tracking。
这意味着工具权限不是“调用 Bash 前弹个确认框”那么简单,而是一整套 policy engine + interactive approval flow。
也就是说,Claude Code 很像 Codex 一样,把“是否允许模型做这件事”放在宿主层,而不是留给模型自己克制。
3. toolOrchestration.ts + StreamingToolExecutor.ts:工具执行是流式的
这是 Claude Code 很强、也很像现代 agent runtime 的地方。
src/services/tools/toolOrchestration.ts 做的是:
- 判断哪些工具可以并发;
- 哪些必须串行;
- 并发 batch 执行后再应用上下文更新;
- 管理 in-progress 工具集合。
src/services/tools/StreamingToolExecutor.ts 则更进一步:
- 工具调用一边从模型流出来,一边就可以开始执行;
- 维护 queued / executing / completed / yielded 状态;
- 管 sibling abort controller;
- 支持用户中断;
- 在流式失败时合成错误消息回填给模型。
这和传统“先等 assistant 完整输出所有 tool call,再统一执行”的 agent loop 很不一样。
Claude Code 的设计是:
只要模型已经明确发出足够信息,就可以让工具层先跑起来。
这会直接改善两类体验:
- 长任务延迟更低;
- 模型可以更快看到工具结果并继续下一轮决策。
Bash / File / Search:Claude Code 最核心的一组三件套
虽然工具很多,但 Claude Code 真正最核心的还是三类:
- shell 执行;
- 文件读写;
- 代码搜索。
BashTool
src/tools/BashTool/BashTool.tsx 是一个典型的“表面简单、内部非常厚”的工具。
它不只是 spawn(command),而是额外做了很多工程处理:
- 命令分类,区分 search / read / list / edit / destructive 倾向;
- 权限联动;
- 后台与前台任务处理;
- 长输出与 UI 展示;
- sed/edit 预览;
- git 操作跟踪;
- 文件历史跟踪。
这说明 Claude Code 并不是把 shell 当成一个“最后兜底的万能工具”,而是把 shell 当成一个需要 细粒度治理 的高风险工具。
FileReadTool
src/tools/FileReadTool/FileReadTool.ts 也非常能说明问题。
它支持读取的对象已经远超“纯文本文件”:
- 文本;
- 图片;
- notebook;
- PDF。
同时还有很多防御式逻辑:
- token 限制;
- 权限检查;
- 特殊设备路径屏蔽;
- 行范围读取;
- skill 激活联动;
- 图片/二进制处理。
也就是说,在 Claude Code 眼里,“读文件”本身已经是一个多模态输入管道,而不是简单的 cat 包装。
Grep / Glob / ToolSearch
Claude Code 很重视“先搜索,再读取,再编辑”的行为路径。
除了常规 GrepTool、GlobTool,源码里还有一个很有意思的 ToolSearchTool:
- 它会搜索 deferred tools;
- 支持直接
select:<tool_name>; - 也支持按关键词从工具描述里检索;
- 对 MCP 工具名有专门解析逻辑。
这说明 Claude Code 已经默认接受一个现实:
当工具很多,模型不一定总能记住全部工具名,所以宿主最好再给模型一个“找工具的工具”。
子代理不是外挂,而是 Claude Code 的一级能力
Claude Code 架构里另一个非常关键的点,是它把 subagent 做成了一等公民。
这部分最核心的文件是:
|
|
1. Task.ts:任务系统先于具体 agent 存在
src/Task.ts 里能看到一套通用 task 类型:
local_bashlocal_agentremote_agentin_process_teammatelocal_workflowmonitor_mcpdream
这说明 Claude Code 不是“只有一个主 agent,偶尔再开个子线程”,而是从抽象层上就把“系统中有很多任务并发存在”当成前提。
2. AgentTool.tsx:subagent 真正被工具化
AgentTool 的输入参数很丰富:
descriptionpromptsubagent_typemodelrun_in_backgroundnameteam_namemodeisolationcwd
这意味着 subagent 在 Claude Code 里不是隐藏机制,而是模型可以显式调用的工具,并且可以带上:
- 类型;
- 名字;
- 背景运行属性;
- worktree 隔离策略;
- 运行目录。
再结合内置 agent 定义:
generalPurposeAgentplanAgentverificationAgentexploreAgentclaudeCodeGuideAgent
你会发现 Claude Code 已经把“让另一个 agent 去做某类任务”做成了产品语义,而不是 prompt hack。
3. LocalAgentTask.tsx:子代理状态是 UI 里的一级对象
这个文件很有代表性,因为它暴露了 Claude Code 对子代理的真实心智模型:
- 子代理有独立 task state;
- 会统计 tool use count 和 token count;
- 会记录 recent activities;
- 会支持 foreground / background;
- 会有 pending messages;
- 有 transcript 的磁盘侧持久化;
- 会发送 task notification 给主模型;
- 可以在面板里被查看。
这和很多“后台帮你调用一下子 agent”的产品很不一样。Claude Code 更像是在运行一个 agent team runtime。
4. SkillTool.ts:skill 的本质是 forked agent
这点很重要。
src/tools/SkillTool/SkillTool.ts 清楚地表明:
- skill 会在 forked sub-agent context 里执行;
- skill 不是简单的文本模板展开;
- 它会先准备 forked command context;
- 再调用
runAgent(); - 并在需要时把 progress 作为工具进度事件回推。
也就是说,在 Claude Code 里,“skill”更像 预包装的 agent workflow,而不是传统意义上的 prompt snippet。
MCP:Claude Code 的外部能力总线
如果说 shell/file 是 Claude Code 对本地环境的接口,那么 MCP 就是它对外部系统的统一接口。
src/services/mcp/client.ts 是 Claude Code 源码里最值得细读的文件之一。
从这里可以看出几件事:
1. Claude Code 是认真按 MCP 协议做的,不是自定义兼容层
它直接使用官方 MCP SDK 的多种 transport:
- stdio
- SSE
- streamable HTTP
- WebSocket
说明 MCP 在 Claude Code 里不是附属实验,而是核心扩展机制。
2. MCP 不只是工具,还有资源、prompt、认证和会话管理
这个文件里除了常见的 tool call,还能看到:
- list resources;
- read resources;
- prompts;
- OAuth token refresh;
- 401 处理;
- session expired 处理;
- output truncation;
- binary result 持久化。
所以 Claude Code 对 MCP 的理解是非常完整的,它把 MCP 当成一个“外部能力总线”,而不是只当作“再来几个工具”。
3. MCP 和 Claude Code 其他系统是深度耦合的
源码里能看到 MCP 和很多系统直接相连:
- tool collapse 分类;
- elicitation;
- auth;
- plugin;
- skills;
- diagnostics;
- claude-in-chrome;
- code indexing。
这说明 MCP 在 Claude Code 里已经不是边缘功能,而是 runtime 的一级组成部分。
Bridge / Remote Session:Claude Code 其实还能“远程存在”
对我来说,这份源码里最有意思的部分之一就是 bridge/。
因为它暴露了一个很重要的事实:
Claude Code 不只是一个本地 TUI,它还能通过 bridge 机制,把会话、控制权和任务状态桥接到远端或网页侧。
src/bridge/bridgeMain.ts 里能看到很多强烈的产品信号:
- session spawn;
- environment registration;
- heartbeat;
- reconnect/backoff;
- multi-session;
- trusted device token;
- remote session URL;
- work secret;
- session runner。
这不是一个小功能能解释的复杂度,而是一整套 remote control / remote session 基础设施。
它告诉我们两件事:
- Claude Code 的核心 loop 被设计成了 可搬运 的
只要上下文、工具、权限、session 能正确桥接,这套 agent loop 并不强依赖“必须本地终端直连人类”。
- Claude Code 的产品方向明显不是“终端里的一次性助手”
它已经在朝“本地 agent + 远端 companion + 持续 session”这个方向演进。
如果对标 Codex,这里的差别很明显:
- Codex 开源实现更强调本地 harness 与执行边界;
- Claude Code 这份快照则明显包含更多“产品在线化”和“多端接入”的痕迹。
UI 层:React + Ink 不是壳,而是状态机前端
很多人会把终端 UI 当成表面层,但 Claude Code 的 UI 其实很重要。
src/state/AppState.tsx 和 src/state/AppStateStore.ts 读完之后,一个结论很明确:
Claude Code 的 UI 不是“打印日志”,而是一个真正订阅全局状态的前端。
AppState 里包含的东西非常多:
- settings
- 当前模型
- expanded view / task panel / teammate panel
- permission context
- remote connection status
- bridge 状态
- tasks
- agent name registry
- MCP 状态
- plugins 状态
- file history
- todos
- notifications
- elicitation
- session hooks
- bagel / browser 状态
- tmux / tungsten 状态
这意味着 Claude Code 的 TUI 更像一个“终端里的单页应用”。
它和 Codex 的差别也很明显:
- Codex 的 TUI 更偏 runtime 可视化;
- Claude Code 的 TUI 已经承担了任务中心、权限交互、远程状态、子代理面板这些产品职能。
真正的工程重点:Claude Code 如何控制复杂性
读到这里,最容易产生的感觉是:Claude Code 代码量很大,模块很多,为什么没有彻底失控?
我觉得它主要靠五个设计把复杂度压住了。
1. 用 feature('...') 做编译期裁剪
源码里大量存在:
|
|
然后按 feature flag 去决定是否 require 某些模块。
这不是简单的运行时 if,而是明显在配合 Bun bundle 做 dead code elimination。也就是说,Claude Code 的单体代码库本身是“超集”,实际产物可以按 feature 裁掉很多分支。
2. 用类型把 runtime contract 钉死
几个非常关键的类型,例如:
ToolUseContextToolPermissionContextTaskAppStateAgentDefinition
都承担了“宿主 ABI”的作用。这样即便模块很多,模块之间靠类型边界仍然能讲得清楚。
3. 用统一 query loop 吞掉不同入口
无论是正常交互、print、side question、skill fork、subagent,最后都尽量复用同一条 query path。这让 Claude Code 不至于出现很多“每个入口各跑一套 agent loop”的灾难。
4. 用 task abstraction 管并发
它没有把后台 agent、shell、workflow、monitor 都写成独立小机制,而是抽象成统一 task 系统。这一步很关键。
5. 从一开始就接受“上下文一定会溢出”
compact、collapse、memory、tool result 持久化、binary output storage,这些都说明 Claude Code 不幻想“把所有历史永远塞进上下文”。这在 agent runtime 里是非常成熟的工程取向。
对标 Codex:两者像在哪里,不像在哪里
讲到这里,就可以正面对标 Codex 了。
我先给一个结论版:
Codex 和 Claude Code 都不是“单纯的模型聊天客户端”,而是“模型决策 + 宿主编排 + 工具执行 + 权限边界 + 上下文压缩”的 agent system。差别在于,Codex 更偏 runtime/harness 视角,Claude Code 更偏产品化单体宿主视角。
下面分几项看。
1. 它们相同的地方
| 维度 | Claude Code | Codex |
|---|---|---|
| 本质 | 模型驱动的 agent runtime | 模型驱动的 agent runtime |
| 核心循环 | assistant 输出 -> tool call -> tool result -> 继续推理 | assistant 输出 -> tool call -> tool result -> 继续推理 |
| 权限哲学 | 权限由宿主控制,不由模型自觉控制 | 权限由 harness / sandbox / approvals 控制 |
| 上下文哲学 | 上下文是宿主主动组装和压缩的 | 上下文是 ContextManager 主动维护和压缩的 |
| 长任务能力 | 依赖 compact / memory / task system | 依赖 compact / ContextManager / turn state |
| 多 agent 趋势 | 有 subagent / skill / teammate / background task | 有 sub-agent / harness / agent 分工趋势 |
2. 它们最不一样的地方
| 维度 | Claude Code | Codex |
|---|---|---|
| 技术栈 | TypeScript + Bun + React + Ink | Rust 为主,运行时边界更硬 |
| UI 比重 | 很高,像终端 SPA | 相对更轻,更像工程 runtime 的前端 |
| 外部扩展 | MCP 是一级总线,plugin/skills/bridge 深度一体化 | MCP/工具有,但整体更强调 harness/runtime 分层 |
| 远程能力 | bridge / remote session 痕迹很强 | 开源实现更偏本地与沙箱执行 |
| 子代理表现 | task/panel/background/team 视角更强 | 更强调 runtime orchestration |
| 产品特性密度 | 很高,大量 feature flag | 相对更“纯引擎” |
3. 一个更直观的类比
如果让我用一句稍微口语化的话来说:
- Codex 更像“一个被很好工程化的 agent 执行内核”
- Claude Code 更像“一个把 agent 内核、工具总线、终端前端、远程桥接和产品实验都塞进来的单体应用平台”
这不是谁更先进的问题,而是产品重心不同:
- Codex 更适合用来观察“agent runtime 的最小核心结构”;
- Claude Code 更适合用来观察“一个商用 coding agent 是如何把 runtime 做成完整产品”的。
我对 Claude Code 架构的最终理解
如果把所有源码细节压缩成一个尽可能稳定的心智模型,我会这样描述 Claude Code:
1. 它的核心不是聊天,而是一个会持续迭代的 query loop
用户发来任务后,系统不是“回一句话”,而是进入:
- 读上下文;
- 做决策;
- 调工具;
- 读结果;
- 必要时再开子代理;
- 必要时压缩上下文;
- 直到任务终止。
2. 它的核心资产不是某个 prompt,而是宿主 runtime
真正难写的部分不是 system prompt,而是:
- tool runtime;
- permission runtime;
- context runtime;
- task runtime;
- MCP runtime;
- bridge runtime。
模型很重要,但 Claude Code 的产品壁垒更多体现在这些宿主能力上。
3. 它已经不是“单 agent”
从 AgentTool、SkillTool、Task、LocalAgentTask、teammate/coordinator 这些结构来看,Claude Code 的真实架构正在走向:
一个主会话 + 多个可分工、可隔离、可后台运行的 agent/task 组合系统。
4. 它的上下文管理思路非常成熟
CLAUDE.md、MEMORY.md、Git context、compact、tool output persistence,这些东西放在一起,说明 Claude Code 已经明确接受了 agent 的三个现实:
- 模型上下文是有限的;
- 用户工作区本身就是上下文;
- 长期任务必须靠宿主做记忆和压缩,而不能指望模型“自己记住”。
5. 它对外部世界的扩展方式非常统一
本地世界靠 shell / file / git,外部世界靠 MCP,远端世界靠 bridge。三者合在一起,Claude Code 就不再是“解释文本”,而是在一个广义执行环境中行动。
这篇源码阅读对我们理解 coding agent 有什么启发
最后我想把视角再抬高一点。
Claude Code 这份源码快照真正有价值的,不只是让我们知道“它有哪些工具”,而是它把 modern coding agent 的几个基本事实暴露得很清楚:
- 上下文管理一定是宿主层能力
不能只把消息历史 append 到数组里就完事。你必须管理:
- 项目上下文;
- 用户规则;
- 会话记忆;
- token 预算;
- compact 和恢复。
- 工具系统一定是运行时系统,不是 schema 列表
真正难的是:
- 权限;
- 并发;
- 中断;
- 失败恢复;
- UI 反馈;
- 流式回填。
- 多 agent 是 runtime 问题,不是 prompt 问题
Claude Code 之所以能把 subagent 做得比较自然,是因为它有 task、state、transcript、notification、worktree isolation 这些宿主结构。
- 商用 agent 最终会演化成平台,而不是单点功能
这份源码最明显的感觉就是:Claude Code 已经不只是“Claude + shell”,而是在慢慢长成一个围绕 coding workflow 的本地平台。
References
- Claude Code Docs: How Claude Code works
- Claude Code Docs: Context window
- Anthropic Docs: Claude Code Settings
- Anthropic Docs: Claude Code Memory
- Understanding Codex: From Context and Tools to Harness and Runtime
- Understanding Codex ContextManager
- Understanding Codex: From Context and Tools to Harness and Runtime
后记
如果只看 Claude Code 的交互界面,你会以为它的重点是“Claude 会不会写代码”。但读完这份源码之后,更准确的判断应该是:
Claude Code 的重点并不是“让模型多会写一点代码”,而是“把模型嵌进一个能稳定完成真实工程任务的宿主系统里”。
这也是我认为它最值得对标 Codex 的地方。