Claude Code 是 Anthropic 的官方 CLI 工具,通过 npm 发布为 @anthropic-ai/claude-code。你 npm install 拿到的是一个约 12MB 的 minified bundle cli.js——一坨不可读的压缩代码。
直到有人把它逆向了。
泄露了什么
这个仓库从 npm 包 v2.1.88 中逆向提取了完整的 TypeScript 源码。规模不小:
- 1,884 个 TypeScript 文件
- 约 51 万行代码
- 覆盖 40+ 工具实现、90+ slash 命令、完整的 Ink 终端 UI 框架、MCP 集成、Sub-agent 系统
核心架构是典型的 Node.js CLI:入口 → Query Engine → Tools/Services/State。Ink(一个基于 React 的终端 UI 框架)被 Anthropic 深度魔改,自己实现了 reconciler、layout engine、事件系统。
不过,这份源码不完整。108 个模块被 Bun 编译时的 feature() 开关排除在外——它们只存在于 Anthropic 内部 monorepo,从未出现在 npm 包里。包括后台守护进程(DAEMON)、主动通知系统(PROACTIVE)、上下文折叠(CONTEXT_COLLAPSE)等。
虽然这些模块的实现缺失,但调用它们的条件分支代码完整保留了。你能看到 KAIROS(全自动 agent 模式)何时激活、做什么,只是走进条件分支后 require() 的模块是空的。像看到了门和钥匙孔,但门后面的房间是空的。
真正值得关注的不在缺失的部分,而在已有的部分。
Agent 架构:五层编排系统
这是整个源码里最有工程价值的部分。Claude Code 的 agent 系统不是一个简单的”调 API 然后返回结果”——它是一个五层编排架构。
第一层:同步 Agent
最基础的模式。AgentTool.call() 启动一个子 agent,阻塞等待返回。就是你在 Claude Code 里看到的 “Explore”、“Plan” 这些 built-in agent。
第二层:异步后台 Agent
通过 LocalAgentTask 实现。不阻塞主线程,有实时进度追踪。关键设计在 runAsyncAgentLifecycle() 里:
- 每 30 秒 fork 一个轻量 agent 来生成 3-5 词的进度摘要
- 这个摘要 agent 复用父 agent 的 prompt cache,只多传一条”总结一下进度”的指令
- 完成时先标记 completed(gate TaskOutput),再跑交接分类器
- 出错时从消息历史中提取部分结果,而不是直接返回空
第三层:Fork 子 Agent
这是 prompt cache 优化的精髓。当 subagent_type 没指定时,子 agent 继承父 agent 的完整对话历史。
// Fork child message construction// Result: [...history, assistant(all_tool_uses), user(placeholder_results..., directive)]// Only final text block differs per child → maximizes cache hits技巧在于:对父 agent 的所有 tool_use 调用,子 agent 统一用一个 placeholder 结果填充("Fork started — processing in background")。这样多个子 agent 的消息前缀字节完全一致,只有最后的指令文本不同。Anthropic 的 prompt cache 是按前缀匹配的,这意味着 fork 出来的子 agent 几乎不额外消耗 cache 配额。
子 agent 还有个有意思的规则——不允许递归 fork:
// forkSubagent.ts:171-198// Child receives boilerplate rules preventing recursive forking防止 agent 自己 fork 自己造成无限递归。
第四层:进程内 Teammate(Swarm)
多个 agent 跑在同一个 Node.js 进程里,通过 AsyncLocalStorage 做上下文隔离。
// Key responsibilities:// 1. AsyncLocalStorage-based context isolation// 2. Mailbox system for permission requests/responses// 3. Automatic task list coordination (shared task directory)
export const TEAMMATE_MESSAGES_UI_CAP = 50// BQ analysis: ~125MB per concurrent agent at swarm burst scale每个 teammate 约 125MB 内存(BQ 分析得出的数据)。权限请求通过 mailbox 系统传给 leader agent,leader 可以在 UI 中审批。如果 bridge 不可用,回退到文件级别的 mailbox。
执行后端有四种选择:InProcess、Tmux(开新 pane)、iTerm2(开新 tab)、通用 pane 执行器。系统自动检测当前终端环境来选择。
第五层:远程 Agent(Teleport)
把任务发到云端执行:
export type RemoteAgentTaskState = TaskStateBase & { type: 'remote_agent' remoteTaskType: RemoteTaskType // 'remote-agent' | 'ultraplan' | 'ultrareview' | 'autofix-pr' reviewProgress?: { stage?: 'finding' | 'verifying' | 'synthesizing' bugsFound: number }}远程任务通过 polling 获取进度,元数据持久化到本地以支持断线恢复。这解释了 Claude Code 的 ultraplan 和 ultrareview 功能——它们实际上是远程执行的。
Agent 记忆:三层作用域
export type AgentMemoryScope = 'user' | 'project' | 'local'// 'user': ~/.claude/agent-memory/<agentType>/ — 跟随用户// 'project': .claude/agent-memory/<agentType>/ — 跟随项目(可 VCS 共享)// 'local': .claude/agent-memory-local/<agentType>/ — 只在本机还有个 snapshot 分发机制:project scope 的记忆可以打快照,新机器首次运行时从 snapshot 初始化,之后通过 .snapshot-synced.json 追踪版本。这让团队可以通过 Git 共享 agent 记忆。
Dream Task:后台记忆整理
一个特殊的后台任务,自动整理 agent 记忆:
export type DreamTaskState = TaskStateBase & { type: 'dream' phase: DreamPhase // 'starting' | 'updating' sessionsReviewing: number filesTouched: string[]}“Dream”——做梦。像人类在睡眠时整理记忆一样,这个任务在后台回顾历史会话,整合零散的记忆片段。用户感知不到它在跑,但能在任务列表里看到。
Anthropic 如何识别你
用户身份追踪是多层的。看 src/utils/user.ts:
// CoreUserData 的关键字段{ deviceId: getOrCreateUserID(), // 256-bit random hex, 存 ~/.claude/config.json sessionId: getSessionId(), // 每次启动新生成的 UUID email: getEmail(), // OAuth profile 或 git config organizationUuid, // 组织 UUID accountUuid, // 账户 UUID userType: process.env.USER_TYPE, // 'ant' 或 undefined subscriptionType, // max/pro/enterprise/team rateLimitTier, // 限速层级}Device ID 是最持久的标识符——256 bit 随机数,首次运行时生成,存在 ~/.claude/config.json 的 userID 字段,跨会话永久复用。即使你没登录 OAuth,Anthropic 也能通过这个 ID 关联你的所有使用记录。
内部员工判定很简单:process.env.USER_TYPE === 'ant'。这个环境变量在 Anthropic 的内部构建中预设,外部用户永远是 undefined。内部员工还有额外的特权——可以从 git config 读 email,可以用 COO_CREATOR 环境变量构造 xxx@anthropic.com 邮箱。
Protobuf 事件结构
每个遥测事件最终以 Protobuf 格式发送,schema 在 src/types/generated/events_mono/ 里:
{ event_name: string, // "tengu_api_success" client_timestamp: Date, model: string, session_id: string, user_type: string, // "ant" or undefined device_id: string, // 256-bit hex email: string, // OAuth 邮箱 env: EnvironmentMetadata, // platform, runtime, CI, version process: string, // JSON: uptime, memory, CPU auth: PublicApiAuth, // account_id, org_uuid(API 端注入,非客户端) agent_id: string, // swarm teammate 追踪 parent_session_id: string, // team leader session agent_type: string, // "teammate" | "subagent" | "standalone" skill_name: string, plugin_name: string, additional_metadata: string, // base64 编码的 JSON}注意 auth 字段——里面的 account_id 和 organization_uuid 不是客户端填的,是 API 端自动注入的。也就是说,即使客户端没带认证,Anthropic 仍然可以通过其他信息关联到你的账户。
限额与”封号”机制
Claude Code 没有显式的”封号” API。它的执行机制是配额耗尽。
五个限额窗口
type RateLimitType = | 'five_hour' // 5 小时滑动窗口 | 'seven_day' // 7 天总量 | 'seven_day_opus' // Opus 模型专用 7 天量 | 'seven_day_sonnet' // Sonnet 模型专用 7 天量 | 'overage' // 超额使用量
type QuotaStatus = 'allowed' | 'allowed_warning' | 'rejected'配额状态通过 API 响应头传递:
anthropic-ratelimit-unified-status: allowed | allowed_warning | rejectedanthropic-ratelimit-unified-5h-utilization: 0-100(百分比)anthropic-ratelimit-unified-7d-utilization: 0-100anthropic-ratelimit-unified-reset: Unix 时间戳anthropic-ratelimit-unified-overage-status: allowed | disabled当 status 变成 rejected,你的下一次 API 请求就会被拦截。如果 overage(超额付费)启用了,会自动回退到超额模式继续用。
超额使用被禁的六种原因
// src/services/claudeAiLimits.ts:107-120overage_not_provisioned // 你的套餐不支持org_level_disabled // 组织管理员关了out_of_credits // 组织没余额了seat_tier_level_disabled // Team tier 不包含超额member_level_disabled // 你的账号被单独禁了*_zero_credit_limit // 信用额度设为 $0member_level_disabled——你的账号被单独禁用超额。这就是”针对性封号”的实际机制:不是删账户,而是把你的超额额度设为 0,配额一耗尽就卡住。
组织级策略限制
export function isPolicyAllowed(policy: string): boolean { const restrictions = getRestrictionsFromCache() if (!restrictions) { // 策略 API 不可达时默认放行 return true } const restriction = restrictions[policy] return restriction ? restriction.allowed : true}组织管理员可以通过 /api/claude_code/policy_limits 端点下发限制策略,每小时刷新一次。fail-open 设计——策略 API 不可达时默认放行,除非在 essential-traffic-only 模式(HIPAA 合规场景)下才 fail-close。
只有 Enterprise 和 Team 订阅用户才会被策略系统管理。Pro 和 Max 用户不受组织策略约束。
双重遥测:你的数据发往两个地方
翻 src/services/analytics/ 目录,遥测架构一目了然。
Claude Code 有两条遥测管道,同时运行:
管道一:1P (First Party),事件批量发往 Anthropic 自己的后端:
https://api.anthropic.com/api/event_logging/batch管道二:Datadog,事件发往第三方监控平台:
https://http-intake.logs.us5.datadoghq.com/api/v2/logsDatadog 的 client token 直接硬编码在源码里:
const DATADOG_CLIENT_TOKEN = 'pubbbf48e6d78dae54bceaa4acf463299bf'Datadog 那边还额外做了 user bucket 哈希——把 user_id SHA256 后取模 30,用来估算独立用户数。
发不出去?存盘重试
一般的遥测都是 fire-and-forget:发不出去就丢了,无所谓。Claude Code 不是。
发送失败的事件会写入 ~/.claude/telemetry/ 目录,以 JSONL 格式持久化到磁盘。下次启动时自动加载重试。Quadratic backoff,最多 8 次。
甚至认证失败(401)也会回退到无认证发送——宁可不带身份信息也要确保事件送达。
退出遥测的两个开关
源码里有个三级隐私模型(src/utils/privacyLevel.ts):
DISABLE_TELEMETRY=1 只关分析追踪。但 Claude Code 仍然会拉取通知、轮询远程配置、上报错误、检查更新、查询限额。
想真正断网?需要 CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1。这才会关闭所有非必要网络请求,只保留核心 API 对话。
这两个环境变量没有任何 UI 入口。
远程控制与混淆命名
Claude Code 使用 GrowthBook 做远程配置。有趣的是 killswitch 的命名方式:
// Mangled name: per-sink analytics killswitchconst SINK_KILLSWITCH_CONFIG_NAME = 'tengu_frond_boric'注释写了 “Mangled name”——故意混淆。“Tengu” 是 Claude Code 内部代号,frond_boric 是随机词对。类似的命名遍布 GrowthBook 配置,让外部观察者即使截获配置请求也猜不到功能。
其他已知的代号:Capybara(当前主线版本)、Fennec(Opus 4.6)、Numbat(下一代,未发布)。
远程 managed settings 有个硬核设计:推送的”危险”变更(修改 API 端点、代理配置等)会弹确认对话框。但拒绝 = 程序退出,没有跳过选项。
卧底模式:一个巧妙的 Prompt Engineering
源码里有个 “undercover mode”。名字唬人,但看完实现就明白了——本质是个 prompt engineering 技巧。
Anthropic 员工在公开仓库用 Claude Code 时,需要防止模型在 commit message 里泄露内部代号(Capybara、Tengu、opus-4-7 等)。问题是,如果直接告诉模型”隐藏你是 AI 的事实”,模型的 safety training 会应激拒绝——“我必须声明我是 AI 助手”。
解决方案:把指令包装成安全上下文。
## UNDERCOVER MODE — CRITICALYou are operating UNDERCOVER in a PUBLIC/OPEN-SOURCE repository.Do not blow your cover.“Do not blow your cover” 听着像间谍片,但实际目的就是:别在 commit 里写出 Capybara、别加 Co-Authored-By: Claude、别暴露内部 Slack 频道名。这些都是合理的信息安全诉求。用”公开仓库”做上下文框定,给了模型一个不违背 safety training 的理由去配合。
NOTE卧底模式只对内部员工(
USER_TYPE === 'ant')生效,在 npm 发布版中被 dead-code eliminate。如果你不是 Anthropic 的人,这段代码永远不会执行。
如果你在用 Claude Code
最低限度,设置这两个环境变量:
# 关闭遥测(分析追踪),但仍保留其他网络请求export DISABLE_TELEMETRY=1
# 关闭所有非必要网络流量(推荐)export CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1加到 ~/.zshrc 或 ~/.bashrc 里。如果你用 Bedrock 或 Vertex 接入,遥测会自动关闭。
更有意思的是把这份源码当学习材料。agent 架构的 prompt cache 优化、AsyncLocalStorage 做进程内隔离、三层记忆系统——这些设计在其他地方很难看到,因为大部分 agent 框架都是开源的玩具级实现。Claude Code 是一个生产级 agent 系统,而我们现在有了它的源码。