What this is: On 2026-03-31, the npm package of Claude Code accidentally included sourcemaps (the "map" for restoring source code), and the complete TypeScript source code (approximately 1884 files / 510,000 lines, version v2.1.88) was extracted. This article is a teardown of that batch of source code at the architecture layer — how it is built internally.
Notes: ① Leaked/decompiled source code is in a legal gray area, for understanding only, do not use commercially ② Some details are inferred from code by third parties, not official documentation, and may contain errors ③ The complete source code bundle is stored locally:
~/projects/开源项目/collection-claude-code-source-code, go check it directly if you want to verify implementations.Insider-type findings (what data it collects about you / model codenames / remote switches / roadmap) can be found in Claude Code Insider Findings (Telemetry/Codenames/Undercover Features/Remote Switches/Roadmap). For how to use CC workflows, see Claude Code Workflows (Cross-Author Topic Synthesis).
One-sentence skeleton: one loop + 12 layers of hardening
The most core part of the entire Claude Code is small enough to draw on a napkin:
用户 → messages[] → 调 Claude API → 看返回
│
返回里有 "要用工具" 吗?
╱ 有 ╲ 没有
执行工具 返回文本,结束
把结果塞回 messages[]
↑——————— 回到"调 API"循环 ———————┘
Analogy: this is like a kitchen apprentice. You give him a recipe (prompt), he takes a look, finds "I need to chop the onion first" (needs to use a tool), goes to chop it, brings the chopped onion back and puts it on the table (tool_result), then looks at the next step of the recipe… until no more actions are needed, and serves the finished product (text). This loop of "take a look → do the action → look back" is the minimal kernel of all AI agents. The code is in
query.ts(785KB, the largest single file in the entire repository).
Key insight: this loop itself can be written in 50 lines. Of the 510,000 lines of Claude Code,99% is not this loop, but the "production hardening" wrapped around it — how to prevent it from going off the rails, how to save tokens, how to parallelize, how to not lose progress. The following 12 layers are all the secrets that turn a "toy loop" into a "shippable product".
12 Layers of Progressive Hardening (Harness Mechanisms)
This is the most valuable table in the entire source code batch — it essentially answers "what parts are missing to build a production-grade agent besides the basic loop":
| # | Mechanism | One-sentence principle | What problem it solves |
|---|---|---|---|
| s01 | Core loop | "One loop + Bash is enough" | The starting point of the agent: call the API, check stop_reason, execute tools, feed results back |
| s02 | Tool dispatch | "Adding a tool = adding a handler" | The loop stays unchanged; adding new capabilities only requires registering a handler to the dispatch table |
| s03 | Planning | "An agent without a plan gets lost" | List steps first (TodoWrite / Plan Mode) then execute, doubling completion rate |
| s04 | Sub-agents | "Split big tasks, each clears its own context" | Dispatch clones to do work; each clone gets a brand new conversation, so the main thread is not polluted by noise |
| s05 | On-demand knowledge | "Load only when needed" | Skill / CLAUDE.md are injected via tool results, without bloating the system prompt |
| s06 | Context compression | "When it's full, make space" | Three sets of strategies to compress old conversations, see below |
| s07 | Persistent tasks | "Big goals → small tasks → written to disk" | Task graph is stored on disk, with states/dependencies, can resume after crashes |
| s08 | Background tasks | "Throw slow work to the background, let the agent keep thinking" | Daemon threads run commands, notify the agent when done |
| s09 | Agent teams | "Can't carry it alone → send teammates" | Persistent teammates with asynchronous inboxes |
| s10 | Team protocol | "Shared communication rules" | Use a request-response protocol (SendMessage) to drive negotiation between agents |
| s11 | Autonomous agents | "Teammates scan tasks and claim them on their own" | Idle loop + automatic claiming, no need for the leader to assign every task |
| s12 | Worktree isolation | "Everyone works in their own directory" | One independent git worktree per task, parallel file edits don't conflict |
Why this table matters: if you, as a PM, ever need to evaluate "whether we should build our own agent / which layer to reach", these 12 layers are the ceiling reference for the feature roadmap — from s01 being able to run, to s06 saving costs, to s09-s12 enabling multi-agent collaboration. Difficulty and value both climb stepwise.
Tool system: every tool is a "standard slot"
CC has 40+ built-in tools (read/write files, Bash, search, network, sub-agents, MCP, skills…). They are not implemented ad-hoc; instead, they all plug into a unified template(buildTool() factory), and every tool must fill in these fields:
一个工具 = 填满下面这张表:
├─ 生命周期
│ ├ validateInput() → 参数不对?最早一关就拒,别浪费后面
│ ├ checkPermissions() → 这个操作准不准做?(工具自己的授权逻辑)
│ └ call() → 真正干活,返回结果
├─ 能力标签(给调度器看的"说明书")
│ ├ isConcurrencySafe() → 能不能和别的工具同时跑?
│ ├ isReadOnly() → 有没有副作用?(只读的可放心并行)
│ └ isDestructive() → 是不是不可逆操作?(删文件等,要慎重)
├─ 渲染(终端 UI 怎么显示这个工具的输入/输出/进度)
└─ 面向 AI
└ prompt() / description() → 给模型看的"这个工具是干嘛的"
Why this design: this is the implementation of the s02 line "adding a tool = adding a handler".The loop code never needs to be modified; to add a new capability to CC, you only need to fill in a new tool according to this table and register it.
isConcurrencySafe/isReadOnlyThese tags are critical — the scheduler uses them to decide "which tools can run in parallel in one go, which must queue up", which is the underlying reason CC feels "fast".
Rough tool categories: file operations (Read/Edit/Write/Notebook), search (Glob/Grep/ToolSearch), execution (Bash/PowerShell), network (WebFetch/WebSearch), agents and tasks (Agent/SendMessage/Team/Task), skill extensions (Skill/LSP), planning workflows (EnterPlanMode/Worktree/TodoWrite), interaction (AskUserQuestion), system (Config/Schedule/Sleep).
Permission system: a "layered security check" funnel
When the model wants to use a tool, it is not allowed through directly; instead, it passes through a security check funnel, and any layer can block it:
工具调用请求
↓
① validateInput() 参数非法?直接退回
↓
② PreToolUse Hooks 你在 settings.json 写的自定义 shell 钩子
│ 能:批准 / 拒绝 / 改写输入
↓
③ 权限规则 alwaysAllow / alwaysDeny / alwaysAsk 三张名单匹配
│ (来自设置、CLI 参数、本次会话的决定)
↓ 没有规则命中?
④ 交互式弹窗 给你看工具名+参数,选 允许一次 / 总是允许 / 拒绝
↓
⑤ checkPermissions() 工具自己的逻辑(如路径沙盒检查)
↓
通过 → 真正执行 tool.call()
Why it matters: this explains why you sometimes get pop-up prompts and sometimes get automatic approval — it depends on the three lists at layer ③. It also explains why hooks (layer ②) are so powerful: they run before the rules, and can directly rewrite or veto any tool call.Rejection = insert an "operation denied" result into the conversation, and the loop continues(the model will know this path doesn't work and try another approach), instead of crashing the program.
Sub-agents and multi-agents: 4 ways to "dispatch clones"
The main agent can dispatch clones to do work, with 4 levels of isolation strength:
| Mode | How it is isolated | Analogy |
|---|---|---|
| default | Same process, shared conversation | You switch to another topic and keep thinking yourself |
| fork | Subprocess, brand new messages[], shared file cache | Send an assistant, give him a clean brain but let him see the same set of files |
| worktree | Independent git working directory + fork | The assistant modifies a copy of the same project in his own room, then merges it back after finishing |
| remote | Connected to a remote container via bridge, fully isolated | Sent to a remote office, completely independent |
Multiple agents collaborate via SendMessage (sending messages to each other),TaskCreate/Update (shared task board),TeamCreate/Delete (team lifecycle).Swarm mode: one leader + multiple teammates, sharing a task board and inbox, but each has isolated conversations, file caches, and working directories — teammates go to the board to claim tasks on their own (corresponding to s11 autonomous agents).
Context compression: what to do when the conversation is full
The model's "memory" (context window) has an upper limit. Long conversations will eventually fill up, and CC has three strategies to free up space:
| Strategy | What it does | Analogy |
|---|---|---|
| autoCompact | When tokens exceed the threshold, old messages are summarized summarize old messages into a summary (a separate API call) | Condense the first half of meeting minutes into a "previously on…" recap |
| snipCompact | Delete "zombie messages" and outdated markers | Tear off the crossed-out invalid parts on scratch paper |
| contextCollapse | Restructure context to improve efficiency | Re-categorize scattered notes |
Structure after compression:[旧消息的压缩摘要] + [compact_boundary 分界标记] + [最近消息(完整保真)].
Why: this is the moment you see "compacting conversation" after using CC for a long time. Understanding this helps you judge when to actively run /clear — no matter how good the summary is, it loses details; for critical tasks, it's best not to let it span multiple automatic compressions.
Session persistence: why --resume works
Every conversation is append-only written to a JSONL log (~/.claude/projects/<hash>/sessions/<id>.jsonl), one message per line.
--continue → 当前目录的上一次会话
--resume <id> → 指定某次会话
--fork-session → 新 ID,复制历史(从某个节点分叉)
The disk write strategy is very deliberate:User messages block until write completes (to prevent losing your input on crash),assistant messages are fire-and-forget (order-preserving queue, does not block streaming).
Other key subsystems
▸ MCP integration — MCP is the standard protocol for "plugging external tools into an agent". CC supports 5 connection methods (stdio subprocess / SSE / streaming HTTP / WebSocket / in-process), tool naming convention mcp__<服务器>__<工具>, and supports OAuth 2.0 authorization.
▸ Bridge layer — allows Claude Desktop / Web to remotely control your local CLI to run jobs. Uses JWT authentication + working key exchange, session lifecycle create/run/stop, with backoff reconnection. (Corresponds to the official prototype of that lark-channel-bridge / multi-window-bridge in your memory.)
▸ Feature Flag + Dead Code Elimination (DCE) — at compile time,feature('X') features set to false are directly deleted from the package (not turned off at runtime, they physically do not exist). This is why the leaked source code shows a bunch of features that are not present in the regular user version at all (voice, browser tools, coordinator mode, etc.). For the specific hidden features see Claude Code Insider Findings (Telemetry/Codenames/Undercover Features/Remote Switches/Roadmap).
Quick reference to key design patterns
A few engineering patterns worth noting (PM perspective: these are the engineering answers to "why CC is fast and stable"):
| Pattern | What it does |
|---|---|
| AsyncGenerator full-pipeline streaming | Streams tokens all the way from the API to the screen, without waiting for full generation |
| Builder + factory (buildTool) | Gives tool definitions safe defaults, making new tools less error-prone |
| Feature Flag + DCE | Deletes disabled features at compile time, making the package smaller and preventing secrets from leaking |
| Fire-and-forget writes | Order-preserving queue non-blocking disk writes, streaming does not stutter |
| Snapshot state (FileHistory) | File operations can be undone/redone |
| Context isolation (AsyncLocalStorage) | Each agent in the same process has independent context |
| Ring buffer | Error logs use bounded memory, long sessions do not run out of memory |
Directory structure (map for when you go dig through the source code)
Local source code is at ~/projects/开源项目/collection-claude-code-source-code. Core entry points:
query.ts— main agent loop (785KB, largest file, start here for core logic)Tool.ts+tools.ts— tool interfaces and registrationQueryEngine.ts— SDK/headless query lifecycletools/— one directory per tool for 40+ toolsservices/— API client / telemetry / compression / MCP / tool executorbridge/— desktop/remote bridgetasks/— task types such as LocalShell / LocalAgent / RemoteAgent / Dreamutils/permissions/— permission rule engineutils/swarm/— multi-agent swarm
Runtime: compiled by Bun into a Node.js ≥18 bundle. Approximately 192 npm dependencies.