一文了解Claude Code源码:为啥它就是好用?无为堂记

4/1/2026

2026年3月31日,安全研究者 Chaofan Shou 发现 Anthropic 发布到 npm 的 Claude Code 包中,source map 文件没有被剥离。

这意味着:Claude Code 的完整 TypeScript 源码,51.2万行,1903个文件,就这样暴露在了公网上。

我当然不可能在短短数小时内看完这么多代码,因此,我带着三个问题去读这份源码:

Claude Code 和其他 AI 编程工具到底有什么本质区别?

为什么它写代码的"手感"就是比别人好?

51万行代码里,到底藏着什么?

读完之后,我的第一反应是:这不是一个 AI 编程助手,这是一个操作系统。

一、先讲一个故事:如果你要雇一个远程程序员

想象你雇了一个远程程序员,给他你电脑的远程访问权限。

你会怎么做?

如果你是 Cursor 的做法:你让他坐在你旁边,每次他要敲命令之前你看一眼,点个"允许"。简单粗暴,但你得一直盯着。

如果你是 GitHub Copilot Agent 的做法:你给他一台全新的虚拟机,让他在里面随便折腾。搞完了把代码提交上来,你审核后再合并。安全,但他看不到你本地的环境。

如果你是 Claude Code 的做法:

你让他直接用你的电脑——但你给他配了一套极其精密的安检系统。他能做什么、不能做什么、哪些操作需要你点头、哪些可以自己来、甚至他想用 rm -rf 都要经过9层审查才能执行。

这就是三种完全不同的安全哲学:

为什么 Anthropic 选了最难的那条路?

因为只有这样,AI 才能用你的终端、你的环境、你的配置来干活——这才是"真正帮你写代码",而不是"在一个干净房间里给你写一段代码然后复制过来"。

但代价是什么?他们为此写了 51 万行代码。

二、你以为的 Claude Code vs 实际的 Claude Code

大多数人以为 AI 编程工具是这样的:

plaintext

用户输入 → 调用 LLM API → 返回结果 → 显示给用户

Claude Code 实际是这样的:

plaintext

→ 动态组装 7 层系统提示词

→ 注入 Git 状态、项目约定、历史记忆

→ 42 个工具各自附带使用手册

→ LLM 决定使用哪个工具

→ 9 层安全审查(AST 解析、ML 分类器、沙箱检查...)

→ 权限竞争解析(本地键盘 / IDE / Hook / AI 分类器 同时竞争)

→ 200ms 防误触延迟

→ 执行工具

→ 结果流式返回

→ 上下文接近极限?→ 三层压缩(微压缩 → 自动压缩 → 完全压缩)

→ 需要并行?→ 生成子 Agent 蜂群

→ 循环直到任务完成

相信大家都很好奇上面的是什么,不着急,让我们逐个拆开看。

三、第一个秘密:提示词不是写出来的,是"拼装"出来的

打开 src/constants/prompts.ts,你会看到这个函数:

typescript

export async function getSystemPrompt(

tools: Tools,

model: string,

additionalWorkingDirectories?: string[],

mcpClients?: MCPServerConnection[],

): Promise

return [

// --- 静态内容(可缓存)---

getSimpleIntroSection(outputStyleConfig),

getSimpleSystemSection(),

getSimpleDoingTasksSection(),

getActionsSection(),

getUsingYourToolsSection(enabledTools),

getSimpleToneAndStyleSection(),

getOutputEfficiencySection(),

// === 缓存边界 ===

...(shouldUseGlobalCacheScope() ? [SYSTEM_PROMPT_DYNAMIC_BOUNDARY] : []),

// --- 动态内容(每次不同)---

...resolvedDynamicSections,

].filter(s =>

s !== null)

注意到那个 SYSTEM_PROMPT_DYNAMIC_BOUNDARY 了吗?

这是一个缓存分界线。分界线上面的内容是静态的,Claude API 可以缓存它们,节省 token 费用。分界线下面的内容是动态的——你当前的 Git 分支、你的 CLAUDE.md 项目配置、你之前告诉它的偏好记忆……每次对话都不一样。

这意味着什么?

Anthropic 把提示词当成了编译器的输出来优化。静态部分是"编译后的二进制",动态部分是"运行时参数"。这样做的好处是:

省钱:静态部分走缓存,不重复计费

快:缓存命中直接跳过这些 token 的处理

灵活:动态部分让每次对话都能感知当前环境

⛏️每个工具都有独立的"使用手册"

更让我震惊的是:每个工具目录下都有一个 prompt.ts 文件——这是专门写给 LLM 看的使用手册。

看看 BashTool 的(src/tools/BashTool/prompt.ts,约 370 行):

plaintext

Git Safety Protocol:

- NEVER update the git config

- NEVER run destructive git commands (push --force, reset --hard,

checkout .) unless the user explicitly requests

- NEVER skip hooks (--no-verify) unless the user explicitly requests

- CRITICAL: Always create NEW commits rather than amending

这不是写给人看的文档,这是写给 AI 看的行为准则。每次 Claude Code 启动时,这些规则都会被注入到系统提示词中。

这就是为什么 Claude Code 从不会擅自 git push --force,而某些工具会——不是模型更聪明,是提示词里已经把规矩讲清楚了。

而且 Anthropic 内部版本和你用的不一样

代码里大量出现这样的分支:

typescript

const minimalUniquenessHint =

process.env.USER_TYPE === 'ant'

? '\n- Use the smallest old_string that\'s clearly unique'

ant 就是 Anthropic 内部员工。他们的版本有更详细的代码风格指引("不写注释除非 WHY 不明显")、更激进的输出策略("倒金字塔写作法"),以及一些仍在 A/B 测试的实验功能(Verification Agent、Explore & Plan Agent)。

这说明 Anthropic 自己就是 Claude Code 最大的用户。他们在用自己的产品来开发自己的产品。

四、第二个秘密:42个工具,但你只看到了冰山一角

打开 src/tools.ts,会看到工具注册中心:

typescript

export function getAllBaseTools(): Tools {

return [

AgentTool,

BashTool,

FileReadTool, FileEditTool, FileWriteTool,

GlobTool, GrepTool,

WebFetchTool, WebSearchTool,

TodoWriteTool, NotebookEditTool,

// ... 大量条件加载的工具 ...

...(isToolSearchEnabledOptimistic() ? [ToolSearchTool] : []),

42 个工具,但大部分你从未直接看到过。因为很多工具是延迟加载的——只有当 LLM 需要时,才通过 ToolSearchTool 按需注入。

为什么这样做呢?

因为每多一个工具,系统提示词就要多一段描述,token 就要多花一份钱。 如果你只是想让 Claude Code 帮你改一行代码,它不需要加载"定时任务调度器"和"团队协作管理器"。

还有一个更聪明的设计:

typescript

if (isEnvTruthy(process.env.CLAUDE_CODE_SIMPLE)) {

const simpleTools: Tool[] = [BashTool, FileReadTool, FileEditTool]

return filterToolsByDenyRules(simpleTools, permissionContext)

Scroll for more