随笔
Claude Code 源码解读 01:Harness 为什么是一条受控链路
从 Harness 总览开始,说明 Claude Code 的稳定性来自 Context、Query Loop、Tools、Permissions、Hooks、Memory 等机制的协同。
这一篇把 Claude Code Harness 从“工具清单”拉回到运行链路:模型只是提出行动,Harness 负责让行动穿过上下文、权限、Hook、恢复和审计。
快速了解
- Claude Code 的稳定性不是来自单个工具,而是来自一条受控链路。
- 用户输入、Context、Query Loop、工具、权限、Hook、Memory 和 transcript 是一套运行时协作。
- 读这组源码时,最重要的方法是先分清主线功能、场景插入、治理横切和恢复支撑。
- Harness 的差异主要体现在状态、边界和执行节奏的组织方式上;这些组织方式决定了系统解决问题的路径,也决定了它更适合哪些任务场景。
如果只想快速理解,可以先读这一节;如果要看源码机制,再往下看“主线与场景插入分类”和机制图。
设问与回应
| 设问 | 回应 |
|---|---|
| 模型在什么位置只是在提出行动,什么位置才真正发生副作用? | 模型提出行动发生在 assistant 输出 tool_use 的位置;真正的副作用发生在 Harness 找到工具、完成输入校验、权限和 Hook 判断,并进入 Tool.call 之后。 |
| 哪些机制是每次会话推进都依赖的主线功能? | 每次会话推进都依赖 Context Preparation、Query Loop、Tool Execution、Permissions 和 transcript/session state。没有这些主线,模型输出无法稳定变成可执行、可恢复的系统行为。 |
| 哪些机制只是 IDE、MCP、team、remote、auto memory 等场景下的插入分支? | IDE、MCP、team、remote、auto memory 这类能力不是主链路本身,而是挂在主链路上的场景插入。它们增强某些任务场景,但不应该反过来定义 Harness 的基本结构。 |
| Codex 和 Claude Code 的差异,是模型差异,还是 Harness 对状态、Hook、权限和恢复的组织方式差异? | Codex 和 Claude Code 的关键差异不是模型差异,而是 Harness 怎样组织状态、Hook、权限、恢复和可观测性。组织方式决定系统解决问题的路径,也决定它适配哪类任务。 |
主线与场景插入分类
| 机制/模块 | 分类 | 我保留的判断 |
|---|---|---|
Context Preparation | 主线功能 | 没有输入归一化、系统提示、用户上下文和消息组装,模型调用无法成立 |
Query Loop | 主线功能 | 工具 follow-up、停止条件、恢复路径都由它推进 |
Tool Execution | 主线功能 | tool_use 必须变成受控执行和 tool_result |
Permissions | 安全/治理横切 | 不总是改变语义链路,但决定副作用能否发生 |
Hooks | 安全/治理横切 + 场景插入 | Hook 引擎是统一层,具体 Hook 是否运行取决于事件和配置 |
Memory | 场景增强 + 上下文支撑 | CLAUDE.md 是项目上下文;auto memory、team memory、session memory 都有条件 |
Transcript / Session State | 可观测/恢复支撑 | 它不替模型思考,但决定能否恢复、审计和复盘 |
源码入口不是目录,而是交叉对象
Message 是用户消息、assistant 输出、附件、工具结果、系统提醒的统一载体。Tool 是行动能力的统一接口;模型看到 schema,执行时穿过校验、权限、Hook。ToolUseContext 则把工具、权限、Hook、文件读取状态和 MCP 客户端连到一起。
这些对象说明 Claude Code 的稳定性不是“模型更会想”,而是 Harness 把模型输出转成协议事件,再把事件交给不同控制层。
对比 Codex 看 Harness 的取向
我关注 Codex 与 Claude Code 的对比,不是为了简单判断谁更强,而是为了找出 Harness 的不同设计取向。
一个典型问题是:当上下文压缩失败、工具结果缺失、Stop Hook 阻断继续、远端 UI 等待状态变化时,系统是把问题直接暴露给用户,还是把它转成可继续的协议状态?
对比的初步结论是:Claude Code 更明显地把 Harness 组织成一条围绕 query loop 的运行时链路;Codex 更容易呈现为一组生命周期任务、策略引擎和 Rust 侧状态处理单元。 这不是优劣判断,而是架构重心不同。
我在后面几篇会把这个对比拆开看:
- 在 compact 问题上,看失败是作为单个任务错误结束,还是回到 query loop 的恢复路径。
- 在 Hooks 问题上,看它更像可编程扩展总线,还是更像集中式生命周期策略引擎。
- 在多 Agent 问题上,看子任务结果是自然语言汇报,还是有 task state、output file、notification drain 这类可审计回灌。
- 在可观测性问题上,看 transcript、session state、content replacement 是否能支撑恢复,而不只是记录日志。
所以,Codex 对比在这里承担的是“反向照明”:它帮助我判断 Claude Code 的机制到底是主线设计,还是某个产品形态下的场景插入,也能看到两家公司在 agent 路线上的取向差异。