Claude Code 架构全解

51.2 万行 TypeScript · 1,902 个文件 · 单系统深潜 · 不做任何对比

这篇文章的定位

这一篇只讲 Claude Code 一个系统。不和任何其他项目对比,不讨论「别人怎么做」,只回答一个问题:这个系统是怎么造出来的?

从进程启动的第一行代码,到最后一条消息落盘,逐层拆开每一个子系统 —— 包括那些在对照式文章里通常被跳过的部分:终端界面层怎么渲染、会话怎么恢复、埋点体系怎么组织、单文件可执行程序怎么构建出来。

阅读门槛:不需要人工智能背景。所有概念在首次出现时都会解释。如果你完全没接触过大语言模型,建议先读《合刊》那一篇的第 1 章(零基础前置知识),大约 20 分钟,之后再回来。

0 · 项目全景与代码地图

0.1 这个软件是什么

Claude Code 是一个在终端里运行的编程助手。你在命令行里敲 claude,进入一个可以持续对话的界面,然后用自然语言让它帮你读代码、改代码、跑测试、提交 git。

它和普通聊天机器人的区别是:它会真的动手操作你的电脑 —— 读文件、写文件、执行 shell 命令。这个能力也正是它全部工程复杂度的来源。

属性
开发方Anthropic
编程语言TypeScript
运行环境Bun —— 一个比 Node.js 更快的 JavaScript 运行时,而且能把整个程序打包成单个可执行文件
界面框架React + Ink —— Ink 是「用 React 写终端界面」的框架,把 React 组件渲染成终端里的文字
代码规模1,902 个 .ts / .tsx 文件,51.2 万行
源码来源2026 年 3 月 31 日因 npm 包附带的 source map(源码映射文件)配置失误而泄露。它不是开源项目。

为什么文件后缀有 .ts.tsx 两种?.tsx 是包含 JSX 语法(也就是在代码里直接写 HTML 式标签)的 TypeScript 文件,用于写界面组件。.ts 是纯逻辑文件。

0.2 源码目录逐个解释

下面是 src/ 目录下的全部内容。括号里是文件数量,可以直观看出各部分的体量分布:

src/ │ ├── main.tsx (804 KB) 程序主入口。命令行参数解析(用 Commander.js 库) │ 光是 --xxx 选项就定义了 60 多个 ├── QueryEngine.ts (46 KB) 会话层。一场对话一个实例 → 第 2 章 ├── query.ts (68 KB) ★ 智能体主循环。整个系统的心脏 → 第 3 章 ├── Tool.ts (29 KB) 工具接口契约定义 → 第 4 章 ├── tools.ts (17 KB) 工具注册表与装配逻辑 → 第 4 章 ├── commands.ts (25 KB) 斜杠命令注册表 ├── context.ts (6 KB) 系统提示词的上下文收集 ├── cost-tracker.ts(10 KB) 花费统计 │ ├── tools/ (40 个) ★ 模型可以调用的工具 → 第 4、5 章 ├── commands/ (100 个) 用户敲的斜杠命令(模型看不到) ├── components/ (146 个) 终端界面组件 → 第 10 章 ├── hooks/ (87 个) React 状态管理单元 → 第 10 章 ├── screens/ (3 个) 整屏界面:REPL 主界面 / 诊断 / 恢复选择器 ├── ink/ (50 个) Ink 框架的定制版(他们自己 fork 了一份) │ ├── services/ (38 个) 对外服务层 │ ├── api/ 调用模型接口、重试、缓存标记 → 第 3 章 │ ├── compact/ 上下文压缩的五级实现 → 第 6 章 │ ├── mcp/ MCP 外部工具协议客户端 → 第 9 章 │ ├── tools/ 工具执行编排 → 第 5 章 │ └── analytics/ 埋点上报 → 第 12 章 │ ├── utils/ (331 个) ★ 最大的目录,所有共享逻辑 │ ├── permissions/ 权限判定(21 个文件) → 第 7 章 │ ├── bash/ shell 命令的语法解析器 │ ├── plugins/ 插件加载与市场 → 第 9 章 │ ├── hooks/ 用户钩子的执行引擎 → 第 9 章 │ ├── shell/ 只读命令判定、沙箱 │ └── messages.ts (189 KB) 消息的构造、规范化、序列化 │ ├── entrypoints/ (6 个) 四种启动形态的入口 → 第 1 章 ├── state/ (7 个) 全局应用状态容器 ├── types/ (10 个) TypeScript 类型定义 ├── constants/ (23 个) 常量 ├── bootstrap/ (3 个) 进程启动引导 ├── skills/ (4 个) 技能系统 → 第 9 章 ├── plugins/ (4 个) 插件系统 → 第 9 章 ├── coordinator/ (1 个) 协调者模式 ├── tasks/ (11 个) 后台任务的几种形态 ├── bridge/ (33 个) 编程软件(VS Code / JetBrains)对接 ├── remote/ (6 个) 远程会话 ├── server/ (5 个) 内嵌 HTTP 服务 ├── memdir/ (10 个) 长期记忆目录 ├── migrations/ (13 个) 配置文件版本迁移 ├── keybindings/ (16 个) 快捷键配置 ├── vim/ (7 个) Vim 编辑模式 ├── voice/ (1 个) 语音输入 └── native-ts/ (5 个) 原生模块绑定

0.3 从这张地图能读出的三件事

第一:核心极小,外围极大

核心逻辑(刻意保持很小)外围模块(放任臃肿)
query.ts 主循环 —— 1,730 行
Tool.ts 工具契约 —— 793 行
toolOrchestration.ts —— 189 行
tools.ts 注册表 —— 390 行
screens/REPL.tsx —— 875 KB
main.tsx —— 804 KB
components/PromptInput.tsx —— 347 KB
utils/messages.ts —— 189 KB

这不是疏忽,是有意识的取舍:核心抽象要小到能被一个人完整读懂并测试;边缘代码可以脏,因为它们改动频繁、逻辑分支多、而且出错的后果有限。

第二:utils/ 有 331 个文件,说明什么

utils(工具函数)目录通常是一个项目的「杂物间」。331 个文件是个惊人的数字 —— 但翻开看会发现它并不是真的杂乱,里面有清晰的二级分组:

  • utils/permissions/ —— 21 个文件,是完整的权限子系统
  • utils/bash/ —— shell 命令的词法分析器和抽象语法树bashParser.ts 128 KB + ast.ts 109 KB)
  • utils/plugins/ —— 插件加载器 107 KB + 市场管理 91 KB

这些本可以是独立的顶级目录。它们被塞进 utils/,更可能是历史原因(先写成小工具函数,后来长大了但没搬家)。这是一个真实项目的正常样貌 —— 值得注意的是它们内部依然是分组清晰的。

第三:tools/commands/ 是最关键的一条切分线

tools/(40 个)commands/(约 100 个)
谁能触发模型。模型输出一个「工具调用」请求,程序执行它只有人。用户在终端敲 /compact/resume 这样的命令
进不进上下文进。每个工具的说明文字都要放进系统提示词,每一轮都要重新发给模型、重新付费不进。模型完全不知道这些命令的存在
走不走权限判定走。每次调用都要过一条 10 步的判定链不走。用户自己敲的,视为已授权
典型例子Read(读文件)、Bash(执行命令)、Edit(改文件)/model 换模型、/cost 看花费、/doctor 诊断

这条线解释了「技能」(Skill)这个功能存在的意义:技能是一座把命令变成工具的桥。

有些能力,用户希望模型能自己判断何时使用(所以应该是工具),但内容又像命令一样是「一段固定的操作流程」。技能系统让这类内容以工具的形式暴露给模型 —— 第 9 章会详细讲。

0.4 一次完整请求的旅程(全文导航)

Claude Code 分层架构总览
Claude Code 分层架构总览 — 从终端入口向下穿过会话层、主循环、工具模型与执行、上下文治理、权限级联,最终抵达模型接口。左侧标注的是每一层对应的章节点击放大

下面这条路径把 14 章串起来。建议先扫一遍,建立整体印象,再逐章深入。

用户在终端敲下一句话,按回车 │ ▼ 【第 1 章】入口层 main.tsx 解析命令行 → 判断是交互模式还是无头模式 → 加载配置、插件、技能、MCP 服务 → 启动 React Ink 渲染循环 │ ▼ 【第 10 章】界面层接收输入 PromptInput 组件 → 处理 @文件提及、图片粘贴、斜杠命令补全 │ ▼ 【第 2 章】会话层 QueryEngine.submitMessage() 被调用 → 组装系统提示词、附件、用户上下文 → 把用户消息先落盘(防止进程被杀掉后丢失) │ ▼ 【第 3 章】主循环开始 ← ★ 整个系统的心脏 │ ├─【第 6 章】上下文治理五级流水线 │ 落盘超大结果 → 删僵尸消息 → 微压缩 → 折叠 → 摘要 │ ├─ 调用模型接口(流式返回) │ └─【第 5 章】流式工具执行器:便条一到手就开始执行 │ ├─【第 4 章】解析模型返回的工具调用 │ ├─【第 5 章】工具执行编排 │ 并发分区 → 【第 7 章】权限判定 → 实际执行 → 【第 9 章】钩子 │ └─【第 8 章】如果调用的是 Agent 工具 → 创建子智能体 │ ├─【第 3 章】错误恢复状态机 │ 上下文超长?输出被截断?模型过载?用户中断? │ └─ 有工具调用 → 回到循环开头 没有工具调用 → 结束 │ ▼ 【第 11 章】持久化 对话记录写成 JSONL 文件 → 支持 --resume 恢复 │ ▼ 【第 12 章】埋点上报(贯穿全程,几乎每条决策分支都有) 【第 13 章】这一切被 Bun 打包成一个 300 MB 的单文件可执行程序

0.5 全文章节索引

标题核心内容
1入口层与启动流程四种启动形态、60 多个命令行选项、启动时序、--bare 极简模式
2会话层:QueryEngine一场对话的完整生命周期、状态所有权、消息落盘时机
3智能体主循环★ 状态机、7 条恢复路径、错误扣留、中断处理、模型降级
4工具模型Tool 接口的七组能力、失败保守默认值、工具清单装配与缓存
5工具执行并发分区、流式执行器、两级中止作用域、单次执行的完整流程
6上下文治理★ 五级阶梯、缓存编辑、时间触发、摘要提示词工程
7权限系统10 步判定链、bypass 免疫层、自动模式分类器、权限规则语法、沙箱
8子智能体三种形态、分叉的字节级缓存复用、工具限制、后台任务
9扩展体系技能、插件、MCP 客户端、15 类钩子事件
10终端界面层React Ink 架构、146 个组件、虚拟消息列表、输入框的复杂度
11持久化与恢复JSONL 对话记录、写入队列、--resume、文件历史与回滚
12可观测体系埋点密度、事件命名、缓存断裂检测、性能剖析检查点
13构建与分发Bun 单文件打包、编译期特性开关、死代码消除、版本管理

Claude Code Architecture, in Full

512,000 lines of TypeScript · 1,902 files · a single-system deep dive · no comparisons

What this piece is

This piece covers one system only: Claude Code. No comparisons with other projects, no discussion of “how others do it.” It answers a single question: how was this system built?

From the first line of code that runs when the process starts to the last message written to disk, it takes every subsystem apart layer by layer — including the parts that comparison-style write-ups usually skip: how the terminal UI renders, how a session gets resumed, how the telemetry is organized, how the single-file executable is built.

Who this is for: no AI background required. Every concept is explained the first time it appears. If you have never touched a large language model, read Chapter 1 of the Companion volume first (the from-zero primer) — about 20 minutes — then come back.

0 · The Project at a Glance, and a Map of the Code

0.1 What this software is

Claude Code is a coding assistant that runs in your terminal. You type claude at the command line, land in an interface where you can hold an ongoing conversation, and then ask it in plain language to read code, change code, run tests, and commit to git for you.

What sets it apart from an ordinary chatbot: it actually operates your computer — reading files, writing files, running shell commands. That ability is also the source of every bit of its engineering complexity.

AttributeValue
DeveloperAnthropic
LanguageTypeScript
RuntimeBun — a JavaScript runtime that is faster than Node.js and can bundle the whole program into a single executable
UI frameworkReact + Ink — Ink is a framework for “writing terminal UIs in React”; it renders React components as text in the terminal
Code size1,902 .ts / .tsx files, 512,000 lines
Where the source came fromLeaked on March 31, 2026, when a misconfigured npm package shipped with its source maps. It is not an open-source project.

Why are there two file extensions, .ts and .tsx? A .tsx file is TypeScript that contains JSX syntax (HTML-style tags written directly in code) and is used for UI components. A .ts file is pure logic.

0.2 The source tree, directory by directory

Below is everything under src/. File counts are in parentheses, so you can see at a glance how the bulk is distributed:

src/ │ ├── main.tsx (804 KB) Main entry point. Command-line parsing (via the Commander.js library) │ The --xxx options alone number more than 60 ├── QueryEngine.ts (46 KB) Session layer. One instance per conversation → Chapter 2 ├── query.ts (68 KB) ★ The agent main loop. The heart of the system → Chapter 3 ├── Tool.ts (29 KB) The tool interface contract → Chapter 4 ├── tools.ts (17 KB) Tool registry and assembly logic → Chapter 4 ├── commands.ts (25 KB) Slash command registry ├── context.ts (6 KB) Context gathering for the system prompt ├── cost-tracker.ts(10 KB) Spend accounting │ ├── tools/ (40) ★ Tools the model can call → Chapters 4, 5 ├── commands/ (100) Slash commands the user types (invisible to the model) ├── components/ (146) Terminal UI components → Chapter 10 ├── hooks/ (87) React state-management units → Chapter 10 ├── screens/ (3) Full-screen views: REPL main screen / diagnostics / resume picker ├── ink/ (50) A customized version of Ink (they forked their own copy) │ ├── services/ (38) Outward-facing service layer │ ├── api/ Model API calls, retries, cache markers → Chapter 3 │ ├── compact/ The five-tier context compaction implementation → Chapter 6 │ ├── mcp/ MCP client for external tools → Chapter 9 │ ├── tools/ Tool execution orchestration → Chapter 5 │ └── analytics/ Telemetry reporting → Chapter 12 │ ├── utils/ (331) ★ The largest directory; all shared logic │ ├── permissions/ Permission decisions (21 files) → Chapter 7 │ ├── bash/ Syntax parser for shell commands │ ├── plugins/ Plugin loading and marketplace → Chapter 9 │ ├── hooks/ Execution engine for user hooks → Chapter 9 │ ├── shell/ Read-only command detection, sandbox │ └── messages.ts (189 KB) Message construction, normalization, serialization │ ├── entrypoints/ (6) Entry points for the four launch modes → Chapter 1 ├── state/ (7) Global application state container ├── types/ (10) TypeScript type definitions ├── constants/ (23) Constants ├── bootstrap/ (3) Process startup bootstrap ├── skills/ (4) The skill system → Chapter 9 ├── plugins/ (4) The plugin system → Chapter 9 ├── coordinator/ (1) Coordinator mode ├── tasks/ (11) The several forms of background task ├── bridge/ (33) IDE integration (VS Code / JetBrains) ├── remote/ (6) Remote sessions ├── server/ (5) Embedded HTTP server ├── memdir/ (10) Long-term memory directory ├── migrations/ (13) Config file version migrations ├── keybindings/ (16) Keyboard shortcut configuration ├── vim/ (7) Vim editing mode ├── voice/ (1) Voice input └── native-ts/ (5) Native module bindings

0.3 Three things you can read off this map

First: the core is tiny, the periphery is huge

Core logic (deliberately kept small)Peripheral modules (allowed to sprawl)
query.ts main loop — 1,730 lines
Tool.ts tool contract — 793 lines
toolOrchestration.ts189 lines
tools.ts registry — 390 lines
screens/REPL.tsx875 KB
main.tsx804 KB
components/PromptInput.tsx347 KB
utils/messages.ts189 KB

This is not an oversight; it is a conscious trade-off: the core abstractions must be small enough for one person to read and test in full; the code at the edges is allowed to be messy, because it changes often, branches heavily, and the cost of a mistake there is bounded.

Second: what 331 files in utils/ tells you

A utils (utility functions) directory is usually a project’s junk drawer. 331 files is a startling number — but open it up and you find it is not actually a mess; there is clear second-level grouping inside:

  • utils/permissions/ — 21 files, a complete permission subsystem
  • utils/bash/ — a lexer and abstract syntax tree for shell commands (bashParser.ts 128 KB + ast.ts 109 KB)
  • utils/plugins/ — a 107 KB plugin loader + 91 KB marketplace management

These could have been standalone top-level directories. That they ended up inside utils/ is most likely historical (they started as small helper functions, grew up, and never moved out). This is what a real project looks like — and what is worth noting is that internally they remain clearly grouped.

Third: tools/ versus commands/ is the most important dividing line

tools/ (40)commands/ (about 100)
Who can trigger itThe model. The model emits a “tool call” request, and the program executes itOnly a human. The user types a command like /compact or /resume in the terminal
Does it enter the contextYes. Every tool’s description goes into the system prompt, re-sent to the model and paid for again on every turnNo. The model has no idea these commands exist
Does it go through permission checksYes. Every call passes through a 10-step decision chainNo. The user typed it, so it counts as authorized
Typical examplesRead (read a file), Bash (run a command), Edit (modify a file)/model to switch models, /cost to see spend, /doctor to run diagnostics

This line explains why the “skill” feature exists: a skill is a bridge that turns a command into a tool.

Some capabilities are things you want the model to decide on its own when to use (so they should be tools), yet their content is command-like — “a fixed sequence of steps.” The skill system exposes that kind of content to the model in the form of a tool — Chapter 9 covers it in detail.

0.4 The journey of one complete request (a map of the whole book)

Claude Code layered architecture overview
Claude Code layered architecture overview — from the terminal entry point down through the session layer, main loop, tool model and execution, context management, and the permission cascade, ending at the model API. The labels on the left mark the chapter for each layerClick to enlarge

The path below strings all 14 chapters together. Skim it once to build an overall picture, then dig into the chapters one at a time.

The user types a line in the terminal and presses Enter │ ▼ [Chapter 1] Entry layer main.tsx parses the command line → decides interactive vs. headless mode → loads config, plugins, skills, MCP servers → starts the React Ink render loop │ ▼ [Chapter 10] UI layer receives the input PromptInput component → handles @file mentions, pasted images, slash command completion │ ▼ [Chapter 2] Session layer QueryEngine.submitMessage() is called → assembles the system prompt, attachments, user context → writes the user message to disk first (so it survives if the process is killed) │ ▼ [Chapter 3] Main loop begins ← ★ the heart of the system │ ├─[Chapter 6] Five-tier context management pipeline │ spill huge results to disk → drop zombie messages → micro-compaction → collapse → summarize │ ├─ Call the model API (streaming response) │ └─[Chapter 5] Streaming tool executor: starts running as soon as a tool call arrives │ ├─[Chapter 4] Parse the tool calls the model returned │ ├─[Chapter 5] Tool execution orchestration │ concurrency partitioning → [Chapter 7] permission decision → actual execution → [Chapter 9] hooks │ └─[Chapter 8] If the call is to the Agent tool → spawn a subagent │ ├─[Chapter 3] Error recovery state machine │ Context too long? Output truncated? Model overloaded? User interrupted? │ └─ Tool calls present → back to the top of the loop No tool calls → done │ ▼ [Chapter 11] Persistence Conversation written as a JSONL file → supports --resume │ ▼ [Chapter 12] Telemetry (runs throughout; nearly every decision branch reports) [Chapter 13] All of it bundled by Bun into a single 300 MB executable

0.5 Chapter index

Ch.TitleCore content
1The entry layer and startupFour launch modes, 60-plus command-line options, startup sequence, --bare minimal mode
2The session layer: QueryEngineThe full lifecycle of one conversation, state ownership, when messages hit disk
3The agent main loop★ State machine, 7 recovery paths, error withholding, interrupt handling, model fallback
4The tool modelThe seven capability groups of the Tool interface, fail-safe defaults, tool list assembly and caching
5Tool executionConcurrency partitioning, streaming executor, two-level abort scopes, the full flow of a single execution
6Context management★ The five-tier ladder, cache edits, time-based triggers, summary prompt engineering
7The permission system10-step decision chain, bypass-immune layer, auto-mode classifier, permission rule syntax, sandbox
8SubagentsThree forms, byte-level cache reuse on fork, tool restrictions, background tasks
9ExtensionsSkills, plugins, MCP client, 15 kinds of hook events
10The terminal UIReact Ink architecture, 146 components, virtualized message list, the complexity of the input box
11Persistence and recoveryJSONL conversation records, write queue, --resume, file history and rollback
12ObservabilityTelemetry density, event naming, cache-break detection, performance profiling checkpoints
13Build and distributionBun single-file bundling, compile-time feature flags, dead code elimination, version management