第 2 章 第一部分:全局视角

工程结构全景

302 个目录、1,903 个文件的代码地图——五层架构、枢纽文件、模块依赖关系的完整拆解

Claude Code 架构 工程结构 TypeScript

2.1 从一张结构轮廓图开始

在深入任何细节之前,先看清全局。Claude Code 的核心代码全部位于 src/ 目录下,按功能划分为 35 个顶层子目录。下面这张流程图描绘了从启动到执行的主要模块关系:

main.tsx (主入口)
  ├── entrypoints/init.ts + setup.ts (启动初始化)
  │     └── commands.ts + tools.ts (注册层)
  │           └── 运行模式分流
  │                 ├── screens/REPL.tsx (交互式 REPL)
  │                 ├── cli/print.ts (Headless/SDK)
  │                 ├── bridge/bridgeMain.ts (IDE Bridge)
  │                 └── entrypoints/mcp.ts (MCP Server)
  │
  └── 所有模式最终进入
        QueryEngine.ts + query.ts (会话引擎)
              └── services/* + utils/* (基础设施)

这张图揭示了一个关键设计决策:所有运行模式最终汇聚到同一个会话引擎(QueryEngine.ts)。REPL、Headless、Bridge、MCP 只是不同的入口壳,核心的 Agent Loop 逻辑是共享的。

Dynamic Workflows GA(2026-07-02)引入了一个例外:编排脚本运行在独立的 JavaScript 运行时中,不经过 QueryEngine 的主循环。子 agent 通过编排引擎间接与 QueryEngine 交互,编排逻辑与主循环完全解耦。这形成了事实上的’编排引擎层’——在入口层和 QueryEngine 之间的一层,负责任务分解、并发控制和结果聚合。

源码引用:src/main.tsx 是主入口编排器,负责 CLI 参数解析、初始化和模式分流。参见源码分析知识库 01-源码结构与技术栈分析.md。

2.2 五层架构

Claude Code 的 35 个子目录可以映射到五个逻辑层,依赖方向单向向下:

入口层(Entrypoints)

文件/目录角色说明
main.tsx主进程入口CLI 参数解析、预取、初始化、模式分流
entrypoints/共享入口8 个文件:init.ts(全局初始化)、cli.tsx(CLI 模式)、mcp.ts(MCP 模式)、agentSdkTypes.ts(SDK 类型)
setup.ts会话准备cwd 解析、worktree 初始化、tmux 集成、hooks 加载、终端恢复

入口层的核心职责是模式判断与环境准备。main.tsx 根据命令行参数和环境变量决定走 CLI、MCP Server 还是 SDK 模式,然后将控制权交给对应的入口点。

值得注意的是 main.tsx 是一个”超大单文件”——这不是代码风格问题,而是有意为之。启动流程需要按严格顺序执行(参数解析 → 预取 → 安全检查 → 初始化 → 模式分流),拆分成多个文件反而会增加执行顺序的不确定性。

受限运行时:正交于入口选择的加载期维度(v2.1.248,2026-08-27)

以上讨论回答的是”从哪个入口进入”。v2.1.248 引入了一个不属于入口层的变量——--restricted(或 CLAUDE_CODE_RESTRICTED=1)。官方 changelog 原文:

Added --restricted (or CLAUDE_CODE_RESTRICTED=1): removes the built-in tools that run commands or code and WebFetch (unless named in --tools), keeps file tools inside the working directory, refuses bypassPermissions, and ignores user, project and local settings files

它的作用位置在入口之后、工具池装配之前:不改变”从哪个入口进”,而改变”哪些层被加载”。四条约束分别落在不同层——工具层(移除运行命令或代码的内置工具与 WebFetch,除非在 --tools 中显式命名)、文件作用域(文件工具保留在工作目录内)、权限层(拒绝 bypassPermissions)、配置层(忽略用户、项目与本地设置文件)。对 2.1 节那张轮廓图的影响是:所有模式仍然汇聚到 QueryEngine.ts,但汇入时可调用的工具体已被裁剪过一轮。第 5 章会展开它在工具池装配中的位置,第 7 章会展开它与权限模型的交叉。

插件目录热插拔:装配期之后的增量通道(v2.1.265,2026-09-08)

--restricted 决定的是”启动完成时这一帧里有哪些层”。v2.1.265 给出了另一个方向上的变量——官方 changelog 原文:

Added support for pointing --plugin-dir at a folder of plugins: each child folder with a manifest loads, and children added or removed while running are picked up

它不新增一层,而是给已有的注册层加了热插拔入口:entrypoints/init.ts + setup.ts → commands.ts + tools.ts 这条一次性注册链路之外,多了一条”运行中增量装配”通道——插件目录里带 manifest 的子文件夹在运行中被增删会被拾取。这与 2.1 节 Dynamic Workflows 那个例外属于同一类:装配期之外还有一个增量装配通道。

两个变量放在一起看,本章那张结构图的定位就更清楚了:它描述的是启动完成时的那一帧。--restricted 决定这一帧里有哪些层,--plugin-dir 决定这一帧之后还能往里加什么。

⚠️ 后续补丁值得记一笔:v2.1.281 修了一个反直觉的 bug——--plugin-dir 指向一个内含 .claude-plugin/marketplace.json 的插件文件夹时,只会加载一个空插件而不是里面的插件(Fixed --plugin-dir on a folder of plugins that also has a .claude-plugin/marketplace.json loading one empty plugin instead of the plugins in it)。“文件夹既能是插件集合又能是市场”这件事,本身就是这条热插拔通道引入的歧义。

扩展层(2026-10-17 新增):第四种扩展机制 Mods

入口层那两个变量回答的是”这一帧里有什么、之后还能加什么”。v2.1.287(2026-10-01)之后,这个问题多了一个维度:这一帧是怎么被处理出来的。 官方 changelog 逐字写 “Added Claude Mods: plugins may now modify deeper behavior”。

四种扩展机制各有各的改动对象(官方 Mods overview 的对照,可直引):

扩展方式主要改变什么适用
Skills模型读到的指令与作业流程教它 recurring 规则或专门任务
MCP servers可用的外部工具接工单系统、数据库等
Settings Hooks事件上跑命令 / HTTP用既有脚本做拒绝、放行、记录
Mods内部事件的处理流,以及界面加自定义面板、改写处理、用自定义响应替代正常处理

三条限定必须连着写:

  1. Mods 改的不只是这一帧的内容,是这一帧的处理过程。 官方公告逐字列出一个 mod 可以:rewrite a prompt before it reaches the model、block / rewrite / retry a tool call、approve or deny a permission request、redact secrets from tool output before Claude reads it、编辑或替换界面的一部分,并替换内置功能(内置 /diff 现已是 mod,官方称 “We plan to move more built-in features to mods over time”)。与 Hooks 的分界官方也给了原话:hooks “can’t rewrite events, draw new UI, or replace features”,mods 可以。
  2. 多个 mod 挂在同一个事件上时按加载顺序执行,先加载的先见事件、最后见结果——这是一条中间件链。因此加载顺序是安全属性,不是实现细节:谁先看到事件,谁就能决定后面的人看到什么。
  3. 🔴 Mods 不在沙箱内。 官方公告逐字:“Mods run with the same access to your machine as Claude Code itself. They aren’t sandboxed, and you should only install mods from sources you trust.” 企业侧的约束手段是顺序约定:Team / Enterprise 计划及任何有托管设置的机器上,内置 sec-default(“security default”)mod 首个加载,阻止用户安装的 mod 覆盖 permission deny 规则;管理员可以改为先加载自己的 mod,官方提示此时要把 sec-default 一并加回列表。这一条把 Ch01 讨论的”工具供应链安全”从”工具本身是不是坏的”推进到”扩展层本身是不是可信的”。

⚠️ 尚未回源的两点,写入时不扩写:mod 的完整事件名清单(不同来源对 tool.call / prompt.submit / turn.step / ui.render 的拼写需以官方 Mods 参考页为准);sec-default 的完整限制清单(官方称可查看源码,本轮未读源码,只记官方明示的那一条)。

命令层(Commands)

目录规模说明
commands/207 个文件,26,528 行Slash 命令实现
commands.ts枢纽文件命令注册中心

先分清两套命令系统。上表统计的 207 个文件实现的是会话内 Slash 命令(/xxx),运行在已启动的会话里,由 commands.ts 注册中心装配。另有一层是进程级 CLI 子命令(claude xxx),管理会话自身的生命周期,不进入会话内部。v2.1.251(2026-08-28)把后者的清单写进了 claude --help:

Added attach, logs, stop, respawn, and rm to claude --help; the --resume message for a running background session now names the exact claude attach <id> command

新增的五个子命令(attach、logs、stop、respawn、rm)操作的都是后台会话进程:--resume 遇到仍在运行的后台会话时,现在会直接指名确切的 claude attach <id> 命令。区分这两层的用处在于:第 8 章的多 Agent 协作管理子代理用的是跨进程的生命周期命令,而不是会话内 Slash 命令。

进程级子命令的第六个成员,也是第一个不操作会话进程的(v2.1.269,2026-09-11):官方 changelog 原文——

Added claude plugin eval: run a plugin’s eval suite against Claude Code and get scored, reproducible results (JSON + HTML report); see claude plugin eval --help

attach/logs/stop/respawn/rm 五个管的都是”会话进程还在不在、怎么接回去”,claude plugin eval 管的是插件的质量。它把”进程级子命令”的职责从生命周期管理扩展到了质量工程:跑一个插件的 eval 套件,产出可复现的 JSON + HTML 报告。官方 plugin-evals 文档给出的机制值得抄进任何插件工程实践:

  • claude plugin eval init 开一个交互会话,问你”什么算好结果”、设计 grader、试跑一次,然后把每个 case 写成一个目录
  • 默认每个 case 跑 6 次:带插件 3 次 + 不带插件 3 次,输出 WITH / W/OUT / Δ 三列——Δ 才是插件真正的贡献
  • 6 种 grader:regex / tool_used / tool_order / file_exists(纯本地,不花钱)+ llm / baseline(调裁判模型,计入成本)
  • 最常见的首次发现是 Δ≈0 且 tool_used: Skill grader 失败——Claude 在自然措辞下根本没选中你的 skill,修法是改 skill 的 description 而不是改逻辑

⚠️ 版本号以官方为准:本轮检索中有第三方把 claude plugin eval 写成 “shipped in v2.1.271(September 14)“,官方 changelog 明确是 v2.1.269(September 11)。这本书此前已经反复遇到”第三方版本号滞后一整轮”,这次是错号而非滞后——同一类问题,但更隐蔽。另:v2.1.283 起该命令要求 git 2.31 或更高(装了 git 的话),低版本会被拒绝并报出版本号。

两条后续演进把这条质量工程线再推一步(2026-10-17):

  • v2.1.290 —— hook 失败会不会放行,变成可检查项。 claude plugin validate 现在列出 mod 在每个 gating site 注册的 hook 及其有没有 .catch(--json 下字段名为 gatingHooks)。这与 v2.1.295 的 onFailure: "block" 是一对:前者能检查,后者能声明。放在一起看,官方给的是一套完整的”钩子自身失败”工程闭环——先能声明期望行为,再能静态检查有没有声明。
  • v2.1.299 —— Δ 更干净。 claude plugin eval 新增 --disallow-tools 与 case 字段 disallowed_tools,可把 Agent 等内置工具排除在 eval 之外。官方 changelog 的说明是 “keep specific built-in tools, such as Agent, out of eval runs”——排除子代理兜底之后测出来的,才是插件自身的贡献。这也把 Δ 三列机制的一个隐含前提摆到了台面上:Δ 干净与否取决于对照组里排除了什么,而”排除什么”此前是不可配置的。

命令层实现了 70+ 内置 Slash 命令,按功能分为:

分类主要命令
基础命令/help、/config、/model、/version、/login、/logout
Git 操作/commit、/diff、/status、/issue、/pr_comments
UI 交互/theme、/color、/keybindings、/vim
系统管理/doctor、/memory、/tasks、/skills
集成扩展/mcp、/plugins、/oauth-refresh

源码引用:commands.ts 通过 Feature Flags 实现命令的动态加载,部分命令根据 Flag 条件导入。 参见:commands.ts

工具层(Tools)

目录规模说明
tools/184 个文件,50,863 行42+ 工具实现
Tool.ts枢纽文件工具契约中心——定义 Tool Schema、权限上下文、执行上下文
tools.ts枢纽文件工具注册中心——工具列表装配与环境裁剪

工具层是 Agent 的”手脚”。42+ 内置工具横跨文件操作、代码搜索、命令执行、任务管理、MCP 集成、多代理协作等 9 大类(完整分类见第 5 章)。

工具清单会收缩,收缩路径是”先合并、再弃用、再移除”。 本章给的是一个静态快照,而工具层是五层里 churn 最快的一层。TaskOutput 工具的完整生命周期就是现成的标本:

版本动作官方 changelog 原文要点
v2.0.64合并AgentOutputTool 与 BashOutputTool 下线,合并为统一的 TaskOutputTool
v2.1.83弃用改为用 Read 读后台任务的输出文件路径
v2.1.277移除工具本体删除;taskOutputMaxChars 设置与 TASK_MAX_OUTPUT_LENGTH 环境变量一并失效

📌 这也是”42+“这个写法值得保留的原因:写死成”42 个工具”的话,v2.1.277 之后这一行就是错的。模糊上限比精确数字更耐久——对逆向研究类写作来说,这是一条通用的表述策略。

2026-09 ~ 10 出现了第四条收缩路径:改形(reshape)。 工具既不被合并也不被移除,而是改变它的输入 / 输出形态:

版本工具改了什么
v2.1.285WebFetchCLAUDE_CODE_DISABLE_WEB_FETCH 环境变量可把该工具直接关掉(官方 changelog 逐字 “turn off the WebFetch tool”)
v2.1.296Read新增 allow_large 选项,需要全文且上下文放得下时,可一次读完超过常规体积限制的文本文件
v2.1.299@ 文件提及CLAUDE_CODE_DISABLE_FILE_MENTIONS:Claude 只拿到 @ 提及文件的路径去用自己的文件工具读,而不是文件内容

把它与入口层的 --restricted 对照着看,粒度变化最清楚:--restricted 是启动期、整层、减法(移除命令执行类工具与 WebFetch);这三条是运行期、单工具、改形(关掉一个工具 / 放开一次读取上限 / 把内容换成路径)。工具层的裁剪粒度从”整层”下沉到了”单个工具的输入输出”,而且裁剪动作不再是单向的减法——allow_large 是加法。所以”工具清单会收缩”这句话要改成:工具清单会收缩,也会变形。

工具产出不是无限写入的。 v2.1.265(2026-09-08)给单次工具结果落盘加了显式配额,官方原文:

Added a 1 GB cap on tool results saved to disk; the in-conversation preview says when a saved file was truncated

注意后半句:会话内预览会明确告诉你文件被截断过。工具层第一次有了”我给你的结果不完整”的自述通道。

每个工具通过 Tool 接口定义,包含关键属性:

// Tool.ts 中的工具定义接口(简化)
interface Tool {
  name: string;
  description: string;      // 工具描述(给模型看的)
  inputSchema: ZodSchema;   // Zod Schema 运行时验证
  call(input): Promise<ToolResult>;  // 执行逻辑

  // 行为标记
  isConcurrencySafe: boolean;  // 是否并发安全(默认 false)
  isReadOnly: boolean;         // 是否只读(默认 false)
  isDestructive: boolean;      // 是否破坏性操作
  shouldDefer: boolean;        // 是否延迟加载
  alwaysLoad: boolean;         // 是否始终加载

  // 权限与安全
  checkPermissions(input): PermissionResult;
  toAutoClassifierInput(): string;  // 给 AI 分类器的输入
}

设计亮点:buildTool 函数采用 fail-closed 策略填充默认值——isConcurrencySafe 默认 false(假设不安全),isReadOnly 默认 false(假设会写入)。这意味着忘记设置某个标记时,系统会选择更安全的行为。

参见:Tool.ts

服务层(Services)

目录规模说明
services/130 个文件,53,683 行18+ 服务模块

服务层是业务逻辑的核心,包括:

  • API 服务:与 Anthropic API(以及 Bedrock/Azure/Vertex 后端)的通信
  • MCP 服务:MCP 客户端管理、配置解析、传输层(stdio/SSE/HTTP/WebSocket)、描述长度配额——⚠️ 自 v2.1.295 起这个配额不再是一个全局默认值,而是按加载路径分叉的四条轨道(详见 2.7「体积三面」表后的四轨表):会话级总开关 CLAUDE_CODE_MAX_MCP_DESCRIPTION_LENGTH(v2.1.280,原默认 2,048 字符/server)、经 tool search 加载的工具描述 16,384(v2.1.295)、sent up front 的工具描述与 server instructions 4,096(v2.1.296)、Anthropic 第一方 server(api.anthropic.com)不截断(v2.1.299)
  • 权限服务:权限规则解析、决策引擎、AI 分类器集成
  • 遥测服务:使用量统计、性能监控、错误上报
  • LSP 服务:语言服务器协议集成
  • OAuth 服务:认证流程管理
  • 策略服务:速率限制、Token 预算、安全策略
  • 工具执行服务:toolExecution.ts——工具调用的完整生命周期管理,包括权限验证、流式执行、错误分类。“错误分类”在 v2.1.265 之后多了一类:结果过大被截断(详见工具层小节)——它既不是权限拒绝也不是执行失败,而是”执行成功但产出被裁剪”

组件层(Components + UI)

目录规模说明
components/389 个文件,81,892 行React 终端 UI 组件
ink/96 个文件,19,859 行Ink 框架定制实现
hooks/104 个文件,19,232 行React Hook 与交互逻辑
screens/3 个文件,5,980 行全屏界面(REPL、Doctor、Resume)

Claude Code 使用 React + Ink 构建终端 UI。Ink 是一个将 React 组件渲染到终端的框架。但 Claude Code 并不是简单地使用了 Ink——src/ink/ 目录有近 2 万行定制代码,说明它对 Ink 做了大量内部改造。

screens/REPL.tsx 是交互式主界面,一个 5,980 行的组件(分布在 3 个文件中),集成了会话管理、权限控制、远程连接等核心逻辑。

2026-06 新增:展示层(Artifacts):2026-06-18 上线的 Artifacts(Team/Enterprise Beta)引入了一个新的输出维度——将终端会话转化为交互式 HTML 网页(私有 claude.ai URL),实时更新。Artifacts 不严格属于五层架构中的任何一层:它既不是入口(不接收用户输入),也不是终端组件(输出目标是浏览器)。从架构视角,它代表了一个平行的’展示层’——将 Claude Code 的会话产出从终端文本扩展为 web 可访问的可视化产物。16 MiB 渲染上限,严格 CSP 禁止外部请求,仅限 Org 内访问。

2.3 十个枢纽文件

在 1,903 个文件中,有 10 个文件的地位特殊——它们是整个系统的关节。理解了它们,就理解了 80% 的架构。

文件角色重要性
main.tsx主入口编排器CLI 参数解析、初始化、模式分流
screens/REPL.tsx交互式主界面REPL 主 UI,包含大量会话/权限/远程逻辑
cli/print.tsHeadless 入口非交互式运行、SDK/结构化输出
QueryEngine.ts会话引擎核心中的核心——主对话循环、工具调用、消息状态推进
query.tsQuery 管线工具/消息流转、停机点与上下文处理
Tool.ts工具契约中心Tool Schema、权限上下文、执行上下文
commands.ts命令注册中心Slash 命令聚合与 Feature Flag 装配
tools.ts工具注册中心Tool 列表装配与环境裁剪(⚠️ 2026-10-17 补:列表顺序本身也会变,见下方注记)

⚠️ 工具列表的顺序不只”排了没有”,还取决于”按什么规则排”,而规则本身会变。 v2.1.293 官方 changelog 逐字:

Changed the order of agent lists and of MCP servers announced to the model: names with non-ASCII characters now sort after ASCII names

这一条的直接后果是升级 v2.1.293 后的第一批会话,工具列表顺序与上一版不同。把它与第 5 章 5.4 节”排序后的工具列表在 System Prompt 中顺序稳定 → 提升 Prompt Caching 命中率”放在一起读,结论要补一格:缓存稳定性依赖的是”排序规则不变”,不只是”排序这件事存在”。一次排序规则变更就是一次全量缓存前缀失效事件——它不会报错,只会在账单上体现。⚠️ 此处”前缀失效”是本书推断(规则变 → 顺序变 → 前缀重写),官方 changelog 只描述了顺序变更,未提缓存影响,引用时须标为推断。 | entrypoints/init.ts | 启动初始化 | 配置、代理、遥测、清理、Scratchpad | | setup.ts | 会话准备 | cwd、worktree、tmux、hooks、终端恢复 |

源码引用:以上枢纽文件列表来自源码分析知识库 01-源码结构与技术栈分析.md,基于导入深度、被引用次数和功能关键性综合评定。

其中 QueryEngine.ts 是整个系统的心脏——所有运行模式最终都进入这个会话引擎。它管理主对话循环:接收用户消息 → 构建提示 → 调用模型 → 解析响应 → 执行工具 → 循环。我们会在第 4 章详细拆解它。

2.4 横切基础设施:utils 的 18 万行

src/utils 是代码量最大的目录(564 个文件,180,487 行),但它不是一般意义上的”工具函数集合”。把它拆开看:

子模块功能
utils/permissions/权限规则解析、决策引擎、六层规则来源合并
utils/config/配置文件读写(含 CLAUDE.md / AGENTS.md 的加载与模式选择,见下)、Feature Flag 管理
utils/git/Git 操作封装(status、diff、commit)
utils/telemetry/遥测与使用量统计
utils/session/会话管理、历史记录
utils/ripgrep/ripgrep 封装(代码搜索引擎)
utils/sandbox/沙箱隔离机制(v2.1.271 起支持 per-command allowed_domains:Bash / PowerShell / Monitor 在 auto mode + 沙箱下,所需域名随该命令一并审查,只对该条命令开放,其余域名一律拒绝)
utils/swarm/多代理团队协作(teamHelpers.ts)
utils/api.tsAPI 调用辅助(工具模式转换、系统提示处理、缓存控制)
utils/hooks.ts钩子系统(pre/post hook 执行、匹配逻辑、超时控制)

这实际上是 Claude Code 的”操作系统层”——配置管理、权限引擎、Git 集成、遥测、沙箱,这些功能在其他项目中可能各自是独立的包。Anthropic 选择将它们全部放在 utils 下,这可能是快速迭代的产物,但也确保了模块间的低延迟调用。

项目指令文件的第二种可能:AGENTS.md(v2.1.277,2026-09-18)

utils/config/ 这一行里”配置文件”这个词,在 v2.1.277 之前是单数——项目指令只可能来自 CLAUDE.md。官方 changelog 原文:

Added AGENTS.md support: in a project with no CLAUDE.md, Claude Code reads AGENTS.md instead; change it under “Project instructions” in /config

/config 的 Project instructions 有四种取值(官方文档 memory.md):

取值行为
claude-md-or-agents-md(默认)读 CLAUDE.md;工作目录及其父目录都没有 CLAUDE.md / CLAUDE.local.md 时,改读 AGENTS.md
claude-md-and-agents-md两者都读,每个目录先 CLAUDE.md 后 AGENTS.md;已加载过的 AGENTS.md 不重复读
claude-md只读 CLAUDE.md
managed-only启动时只加载企业托管 CLAUDE.md 与自动记忆;项目/本地/用户级 CLAUDE.md、.claude/rules/ 与所有 AGENTS.md 全部排除(子目录的 CLAUDE.md 与 .claude/rules/ 仍在读取该目录文件时加载)

⚠️ 三条必须一起记住的边界(官方文档,不是社区猜测):

  1. CLAUDE.local.md 也算”存在 CLAUDE.md”。它会与 CLAUDE.md、.claude/CLAUDE.md 一起参与判定,一旦出现在工作目录或任一父目录,就静默抑制整条路径上的 AGENTS.md 回退。官方给的修法是改用 claude-md-and-agents-md。不计入判定的只有 ~/.claude/CLAUDE.md、企业托管 CLAUDE.md 与 .claude/rules/。
  2. 通过 Project instructions 读入的 AGENTS.md 不触发 InstructionsLoaded hook——但被 CLAUDE.md 用 @AGENTS.md import 或 symlink 引入时会正常触发。同理,--add-dir 加进来的目录(在 CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD 开启时)其 AGENTS.md 不加载。
  3. 后端覆盖是分阶段的:v2.1.277 引入时,部分会话(例如 Amazon Bedrock、以及关闭遥测的会话)只读 CLAUDE.md;v2.1.281 起已扩展到 Amazon Bedrock、Google Vertex AI、Microsoft Foundry、LLM 网关与关闭遥测的会话。另有两条”看起来坏了其实不是”的场景:低于 v2.1.277;在 /plugin 里禁用了内置 agents-md 插件;以及从 v2.1.276 或更早升级后的第一次会话(下一次会话起生效)。

📌 架构上最值得注意的一点:AGENTS.md 支持是以内建插件 agents-md@builtin 的形式实现的——可以在 /plugin 里禁用,也可以在 ~/.claude/settings.json 的 pluginConfigs 里配置:

{
  "pluginConfigs": {
    "agents-md@builtin": { "options": { "instructionFiles": "claude-md-and-agents-md" } }
  }
}

这与 2.2 节入口层那条 --plugin-dir 是同一件事的两面:连”读哪个指令文件”都被下沉成了插件层的一个可配置、可禁用项。对逆向研究而言,这意味着”配置层”的边界比源码目录结构暗示的更宽。

治理因果链:AGENTS.md 由 OpenAI 于 2025-08 发布,2025-12-09 捐给 Linux Foundation,现由 Agentic AI Foundation(AAIF) 托管——它是 AAIF 三个创始捐赠项目之一(另两个是 Anthropic 的 MCP 与 Block 的 goose),官方称已被 60,000+ 开源项目与 Agent 框架采用。这条链解释了本章此前无法解释的一件事:Anthropic 为什么会去支持一个竞争对手发起的指令文件格式——当这个格式已被 6 万个项目采用、且由中立基金会持有时,不支持它的成本高于支持它。(第 1 章 1.4 节从”为什么值得逆向研究”的角度写了同一条链的另一个侧面。)

2.5 技术栈选择

技术用途评价
TypeScript + TSX主体语言(1,332 + 552 个文件)全面强类型,贯穿全栈
React + Ink终端 UI组件化终端渲染,支持状态管理和虚拟 DOM
Zod运行时数据验证50+ Schema 定义,确保工具输入/配置的类型安全
Bun构建打包快速打包(也是导致泄露的原因——默认生成 source map)
OAuth 2.0 + PKCE认证安全的第三方登录流程
Jest测试单元测试和集成测试

源码引用:技术栈总结来自源码分析知识库”项目概述 - 技术栈总览”。

打包体积演进:2026-08 之后的四个数据点

上表 “Bun / 构建打包” 一行的评价停留在 2026-04 的泄露事件(默认生成 source map)。2026-08 之后,打包工程是持续投入的方向,且给出了可引用的具体数字:

版本日期改动官方数据
v2.1.2432026-08-25原生安装与自动更新下载改为 zstd 压缩Linux x64 约 75 MB 而非 340 MB
v2.1.2432026-08-25更紧凑地存储捆绑技能与提示文本原生二进制小约 2 MB
v2.1.2432026-08-25代码按需加载,不再常驻整个 bundle每会话内存少约 40–70 MB
v2.1.2512026-08-28移除 1c、gml、isbl、mathematica、maxima、sqf 六种极少使用语言的语法高亮二进制小 2.5 MB
v2.1.2512026-08-28安装体积优化原生二进制小约 5 MB

同一版本的 v2.1.243 还改了启动路径:沙箱与 MCP 的拉起不再阻塞第一帧,裸启动跳过子命令注册,workflow 发现、设置与 trust-store 的开销降低。

这些数据合起来指向一个结论:捆绑内容——技能、提示词、语法高亮、图像模块——的体积是原生安装的一等公民成本。这与第 6 章讨论的上下文体积是同一个问题的两面:一边压缩的是运行时塞进模型上下文的 token,另一边压缩的是分发到本地磁盘与内存的字节。

2026-09 的两个版本把”两面”补成了三面——体积不只是分发时和推理时要压缩,单次工具产出也有自己的配额:

体积的哪一面压缩的是什么证据
分发体积磁盘与内存字节v2.1.243 zstd(Linux x64 约 75 MB 而非 340 MB)、每会话省 40–70 MB;v2.1.251 二进制小 5 MB / 2.5 MB
上下文体积塞进模型上下文的 token第 6 章展开;MCP 工具描述与 server 指令:v2.1.295 起按加载路径分成四条轨道(见下表),不再是单一的 2,048
产出体积单次工具结果落盘v2.1.265 起上限 1 GB,超出即截断,且会话内预览会明示截断

三面各自的”超了会怎样”也不一样:分发体积超标是安装慢、内存高;上下文体积超标是模型看不见(或被裁剪);产出体积超标是执行成功但结果不完整——只有第三种会明确告诉你。

MCP 描述配额的四条轨道(2026-10-17):

轨道上限版本官方 changelog 原文要点
会话级总开关 CLAUDE_CODE_MAX_MCP_DESCRIPTION_LENGTH可调(原默认 2,048)v2.1.280对该会话所有 MCP server 统一生效
经 tool search 加载的工具描述16,384(原 2,048)v2.1.295”descriptions the model loads through tool search”
sent up front 的工具描述 + server instructions4,096(原 2,048)v2.1.296”the default limit on MCP tool descriptions sent up front and on MCP server instructions”
Anthropic 第一方 server(api.anthropic.com)不截断v2.1.299”to reach Claude in full instead of being cut at 4,096 characters”

方法论一句:同一个”上限”在 11 天内被拆成四条轨道,说明“上下文体积”不是一个标量,而是按加载路径分叉的一组量。这同时修正了一个容易犯的错——把 v2.1.295 记成”MCP 描述上限默认值改为 16,384”是不完整的,16,384 只适用于 tool search 那一条轨道;up-front 轨道的默认值在次日(v2.1.296)变成了 4,096,两者相差 4 倍。

四条轨道的”超了会怎样”也不同:up-front 超限是描述被裁短(模型看到的信息变少);tool search 超限是搜到的工具描述不完整(搜索命中但内容残缺);第一方不截断这条轨道压根没有上限。只有第三种会明确告诉你发生了什么——“有上限”这件事本身也是一条轨道的属性。

几个值得注意的技术选择:

  1. React 用于终端 UI:这是一个大胆的选择。大多数 CLI 工具使用 readline 或 blessed,Claude Code 选择了 React + Ink,获得了组件复用和声明式渲染的好处,但也引入了额外的复杂度(96 个文件的 Ink 定制代码就是证据)。

  2. Zod 做运行时验证:TypeScript 的类型系统只在编译时有效。Zod 补上了运行时验证——当模型返回的工具调用参数不符合 Schema 时,可以在运行时捕获并给出有意义的错误信息。

  3. 不使用任何 AI 框架:没有 LangChain、没有 LlamaIndex、没有 AutoGen。Claude Code 从零构建了自己的 Agent Loop、工具系统、权限系统。这是有意为之——生产级系统需要对每个环节的精确控制,通用框架的抽象层反而是障碍。这种”零框架自研”的选择在 2026 年被社区广泛讨论为 Harness Engineering 的典型实践:模型周围的一切基础设施(工具编排、权限、上下文管理、错误恢复)构成 Agent 的”Harness”,对其每一层的精确控制比框架便利性更重要。

2.6 模块化设计原则

在逐条列举设计原则之前,值得先退一步审视更高层的问题:这些原则服务于什么样的设计目标?

arXiv 论文 2604.14228(Dive into Claude Code: The Design Space of Today’s and Future AI Agent Systems,VILA-Lab,2026-04)对 Claude Code 的设计空间做了系统化分析,提出五大设计动机——即架构层面”为什么这么做”的价值观根基:

动机含义对应的工程选择
Human Decision Authority人类保留最终决策权六层权限规则 + AI 分类器(第 7 章)
Safety & Security安全是不可协商的前提Fail-Closed 默认值、Docker 沙箱、破坏性操作拦截、供应链加固、输入净化(后两项为 2026-09 新增)
Reliable Execution在长时间运行中保持可靠五层上下文压缩、错误分类与重试、熔断器模式
Capability Amplification持续扩展能力边界MCP 协议、插件系统、技能系统、子代理委派
Contextual Adaptability适应不同用户和场景Feature Flags、动态 System Prompt、配置层级(含项目指令文件 CLAUDE.md / AGENTS.md 的多格式回退与模式选择)

论文将 Claude Code 与 OpenClaw 做了对比分析,展示同一组设计动机在不同部署场景(本地终端 vs 云端容器)下产生的不同实现选择。这些动机不是源码里写着的——它们是从架构模式中反推出的驱动力,帮助理解下面 6 条工程原则的”为什么”。

Safety & Security 动机的 2026-09 ~ 10 六条新证据

泄露代码是 2026-03-31 的快照,而”安全是不可协商的前提”这条动机在此后持续产生新的工程选择。2026-09 一个月内就有四条,2026-10 又添两条,且形态各异——不是同一招用了六遍:

版本形态官方 changelog 要点
v2.1.275供应链npm 来源的插件改用 npm pack --ignore-scripts 获取并做完整性校验,包的 install scripts 不再执行
v2.1.277输入净化(可见化)提示中的不可见 Unicode 格式化与标签字符被移除,且清理后的提示会在发送前展示给你复核
v2.1.271最小权限粒度下沉per-command allowed_domains:Bash / PowerShell / Monitor 在 auto mode + 沙箱下,所需域名随该命令一并审查,只对该条命令开放,其余域名一律拒绝
v2.1.271指令作用域裁剪(per-agent)omitClaudeMd 加入 agent frontmatter 与 --agents JSON,让自定义与插件子代理不加载用户/项目/本地 CLAUDE.md(托管策略文件仍加载)
v2.1.286供应链(来源形态收窄)插件安装拒绝 git 仓库或文件夹形式的 npm 源,插件依赖只能从 registry 包安装(官方 changelog 逐字)
v2.1.289工具描述完整性修掉”用户安装的插件可以改写组织托管 MCP server 的登录工具描述”(官方 changelog 逐字)

第二条值得单独说一句:它和本章前面 buildTool 那类 fail-closed 处理不是同一招。fail-closed 是”拿不准就拒绝,你不必然知道发生了什么”;这条是“我改了你的输入,并且改了什么摆给你看”——同一个动机长出了两种相反的表达方式。安全工程里这两招都合理,但把它们当成一回事会误判 Anthropic 的设计取向。

第三条把最小权限的粒度从”会话级 / 工具级”下沉到了单条命令:域名不是你配一份白名单全局生效,而是随那条命令一起被审查、只对那条命令开放。

第四条与 2.4 节的 AGENTS.md 是一对,构成”指令作用域”的两个控制层次:

  • 全局层(/config → Project instructions):决定这个仓库读不读 AGENTS.md、以及和 CLAUDE.md 怎么组合
  • 单代理层(agent frontmatter 的 omitClaudeMd):决定某个具体子代理读不读用户/项目/本地 CLAUDE.md

前者管”有哪些指令文件进入会话”,后者管”这些文件对谁生效”。把这两层分开,是”子代理应该有自己独立作用域”这个判断落到配置层的证据——第 8 章讲多 Agent 协作时会再遇到它。

第五条与第一条要放在一起读:它们是同一族,但收紧点前移了。 v2.1.275 是”拿到了不执行脚本”(npm pack --ignore-scripts + 完整性校验),v2.1.286 是”根本不允许从 git 仓库或文件夹拿”(依赖只能来自 registry 包)。同一类威胁的两道闸门从执行期退到了获取期——供应链防线的位置在往前移,这与本书第 5 章讲的”防线越靠前,需要信任的东西越少”是同一条。

第六条是一条全新形态,也是六条里唯一一条”官方修复实例”。 前四条防的是”工具做了坏事”或”指令被污染”,这一条防的是可信方之间的描述互相覆盖:用户侧安装的插件顶替了组织托管 MCP server 的登录工具描述,等于托管信任等级被用户侧内容覆盖。这正是第 5 章 CSA「Poisoned Foundations」所述 tool poisoning 的形态——区别在于这一条有官方修复,比研究报告更硬:研究报告只能证明攻击可行,官方 changelog 的一条 Fixed 证明它真的发生过、且已被修。

从源码中可以提炼出 Claude Code 遵循的几条设计原则:

原则实现方式
分层架构入口层 → 命令层 → 工具层 → 服务层 → 组件层,依赖方向单向向下
模块化35 个顶层目录,每个目录职责单一
按需加载Feature Flags 实现动态加载,支持 Tree Shaking 减少启动时间
依赖注入React Context 实现组件间的依赖注入
类型安全TypeScript 编译时 + Zod 运行时,双层类型保障
Fail-Closed安全相关的默认值选择更保守的选项。2026-09 的两条加固给这条原则补了两个新样本:npm 插件改用 npm pack --ignore-scripts 并做完整性校验(v2.1.275)与per-command allowed_domains 默认只开该命令所需的域名(v2.1.271)

源码引用:设计原则总结自源码分析知识库”工程结构 - 模块化设计原则”,引用 main.tsx、commands.ts、Tool.ts。

2.7 与其他 AI 编程工具的架构对比

在跨产品对比之前,先处理一个容易让读者困惑的问题:同一份源码存在不止一种拆解方式。

本章采用的”五层架构”(入口 / 命令 / 工具 / 服务 / 组件)按依赖方向划分,层间单向向下。社区还流传着另一种划分——把源码拆成 25 个子系统、再归纳为 7 个功能域(入口层、核心引擎、模型交互层、工具系统、安全与权限、输出与展示、扩展系统),按的是功能关注点。两者的关键差异在于后者的”模型交互”与”扩展系统”被提升为独立域,而在五层模型里它们分别被折叠进服务层和工具层。

两种划分不冲突,只是切法不同:前者适合追踪一次调用从上到下的穿透路径,后者适合按职责定位代码。读者在对照社区资料时会同时遇到这两种,这里先做预告。

📌 待核实:25 子系统 / 7 功能域的具体清单来自中文技术社区的拆解文章,非官方来源,也未经过同行评审。上述差异描述基于对该划分的概要转述,引用时建议回到原始拆解资料核对子系统清单。

为了更好地理解 Claude Code 的架构选择,把它和同类产品做个简要对比:

维度Claude CodeCursorAiderOpenHandsClaw Code
运行环境终端(React + Ink)VS Code 扩展终端(纯 Python)浏览器 + Docker终端(Rust 92.9% + Python 7.1%)
代码规模~51 万行 TS非公开~3 万行 Python~10 万行 PythonRust 核心 + Python 测试框架
Agent Loop自研 QueryEngine非公开LiteLLM 调度自研 EventStream自研(Rust 核心,Claude Code 架构复刻)
工具系统42+ 内置 + MCP非公开~10 个内置~20 个30+ 内置 + MCP
多代理6 种内置代理非公开无有有(多代理编排)
权限模型六层规则 + AI 分类器IDE 权限用户确认Docker 沙箱用户确认 + 沙箱
框架依赖零框架,全部自研非公开LiteLLM部分自研零框架(Clean-room 重写)

Claw Code(claw-code.codes,150k+ GitHub stars)是 Claude Code 架构的 Rust clean-room 复刻。它已完成从”Python 为主 + Rust 为辅”到”Rust 92.9% + Python 7.1%“的架构迁移——核心 CLI/运行时/插件系统/内存管理全部由 Rust 实现,构建产出单文件二进制(213MB ELF),性能远超原 TypeScript 实现。它的存在本身是对 Claude Code 架构可移植性和影响力的有力证明——核心设计模式(Agent Loop + 工具系统 + MCP 集成)被证明可以跨语言栈复现。

社区学习资源:shareAI-lab/learn-claude-code(原 analysis_claude_code)是一个 65.7k stars 的系统课程,提供中/英/日三语 20 节课程,从 agent loop 讲到 MCP 扩展,是目前对中文开发者最友好的 Claude Code 深入学习资料。