返回《Claude Code 架构设计指南》

Harness 是什么,从泄露源码说起

IT周瑜

2026 年 3 月 31 日,安全研究者 Chaofan Shou 在 X 上公开了一个发现。Anthropic 官方的命令行工具 Claude Code,它的 npm 安装包里躺着一个 source map 文件,这个文件的内层完整保存了每个源文件被压缩前的原始代码。任何人执行一次 npm install,再用工具解开这个文件,就能读到这家公司没有打算公开的全部实现。本仓库就是那次泄露的一份备份,从入口文件到测试脚本,一应俱全。

泄露的起因说起来平淡。JavaScript 项目发布前会用构建工具把源码压缩混淆,source map 是压缩产物和原始源码之间的对照表,方便线上报错时还原出错位置。对照表里有一个字段叫 sourcesContent,按规范它保存的就是原始源码本身。只要构建时忘了关掉 source map 生成,或者忘了在发布清单里排除 *.map 文件,源码就跟着包一起发了出去。Claude Code 的构建管线漏掉了这一步。

拿到源码能看到什么。这是一个用 TypeScript 写成的终端程序,界面层用 React 加一个 Ink 渲染器跑在终端里,源码目录 src/tools/ 下摆着五十多个工具目录,加上多代理编排、权限审批、上下文压缩这些模块,工程量远超一个普通 CLI。本仓库还做了两件方便研究的事。一是补上构建脚本,让泄露的源码能重新跑起来。二是写了一份调试指南,配好 VSCode 加 Bun 的断点环境,读者可以一边读本书一边在源码里下断点验证。

接下来解释书名里的 harness。模型本身只做一件事,收到一段文本,生成下一段文本。要让它在真实项目里干活,需要一整套软件替它处理其余的所有事。把模型生成的意图变成真实的工具调用,调用之前判断该不该放行,把工具的结果拼回对话,对话太长时压缩历史,出错时决定重试还是放弃。这整套围绕模型的编排软件,业界习惯叫 harness,直译是马具,引申为让模型这匹马能拉车的整套挽具。Claude Code 就是一个 harness 的完整实现,而且是经过大规模生产验证的那一类。

入口层 entrypoints/cli.tsx + main.tsx 启动 UI 层 src/screens/REPL.tsx React + Ink 终端渲染 核心层 主循环 queryLoop src/query.ts 工具系统 src/tools/ 55 个工具 权限系统 src/utils/permissions/ 上下文压缩 src/services/compact/ MCP 连接 src/services/mcp/ Hook 引擎 src/utils/hooks.ts sideQuery 旁路轻量模型调用 Anthropic API 流式 messages for await 消费 执行 审批 超阈值 注册工具 挂点 分类与摘要 请求
图 1-1 Claude Code 的分层结构,核心层是全书的主角

整个工程可以分成四层来看。最外层是入口,entrypoints/cli.tsx 负责解析命令行参数,main.tsx 完成初始化后把控制权交给界面。第二层是 UI 层,screens/REPL.tsx 是常驻主屏,持有全部消息状态,负责把每一条流式输出画到终端。第三层是核心层,query.ts 里的主循环居中,左边工具系统提供手脚,右边权限系统把关,下方压缩模块看护上下文。最底下是服务层,MCP 连接管理外部工具源,hook 引擎执行用户注册的脚本,sideQuery 提供不进对话历史的轻量模型调用。

这份分层的要点在于依赖方向。核心层的代码不引用任何 UI 文件,它只对外吐出一个个消息事件,谁消费这些事件、画成终端字符还是转成 SDK 结构,核心层一概不知。第 11 章会讲到,正是这个设计让同一个主循环能同时服务终端界面、无头模式和子代理三种前端。

读这本书的合适姿势是这样的。先跟第 2 章把主循环走通,其余每章讲的东西最终都会接回这个循环。之后工具、权限、子代理、压缩各章相互独立,可以按需跳读。每章出现的文件路径和函数名都来自这份泄露源码,读者随时可以打开对应文件对照,也可以按调试指南下断点单步走一遍。