Claude Code 源码全曝光:51万行代码,10大架构设计拆个底朝天

摘要

Claude Code 源码意外曝光,1884 个 TypeScript 文件、9.8 万行核心代码、42 个工具模块、189 个斜杠命令。本文带你逐一拆解 10 大架构设计亮点,从启动优化到权限系统,从 MCP 深度融合到多 Agent 编排,看看 Anthropic 的工程团队究竟在 CLI 里藏了多少"黑科技"。


就在今天,Claude Code 的完整源码被逆向还原并在 GitHub 上公开,全网开发者集体炸锅。

1884 个 TypeScript 文件、src/ 目录 9.8 万行代码、389 个终端 UI 组件、42 种工具、189 个斜杠命令。 这不是一个简单的 CLI 工具——这是一个完整的 AI 操作系统。

我花了大半天时间把源码翻了个底朝天。坦率说,看完之后只有一个感受:这是我见过的工程质量最高的 AI 工具项目,没有之一。

下面,我挑出 10 个最值得聊的架构设计,逐一拆解。


一、启动魔法:import 空隙里省出 65ms

Claude Code 打开速度很快,你以为这是理所当然?不,这背后有精心的工程优化。

main.tsx 的前 20 行:

profileCheckpoint('main_tsx_entry')
startMdmRawRead()       // 立刻启动 MDM 子进程
startKeychainPrefetch()  // 立刻启动 Keychain 预读

还没等其他模块加载完,这三行就已经跑起来了。

为什么放在最前面?因为 Bun 在 import 其他模块时会有一段"评估时间"(module evaluation),这段时间 JavaScript 主线程是空闲的,但事件循环的 I/O 通道是通的。

Anthropic 的工程师利用了这个空隙:

  • startMdmRawRead() 在 macOS 上并行读取多个 plist 文件(通过 plutil 子进程),在 Windows 上并行查询两个注册表路径(HKLMHKCU
  • startKeychainPrefetch() 同时启动 OAuth Token 和 Legacy API Key 两个 Keychain 查询
// keychainPrefetch.ts
export function startKeychainPrefetch(): void {
  if (process.platform !== 'darwin' || prefetchPromise || isBareMode()) return
  
  const oauthSpawn = spawnSecurity(
    getMacOsKeychainStorageServiceName(CREDENTIALS_SERVICE_SUFFIX),
  )
  const legacySpawn = spawnSecurity(getMacOsKeychainStorageServiceName())
  
  prefetchPromise = Promise.all([oauthSpawn, legacySpawn]).then(
    ([oauth, legacy]) => {
      if (!oauth.timedOut) primeKeychainCacheFromPrefetch(oauth.stdout)
      if (!legacy.timedOut) legacyApiKeyPrefetch = { stdout: legacy.stdout }
    },
  )
}

原来这两个 Keychain 读取是在后面 applySafeConfigEnvironmentVariables()串行执行的,加起来大约 65ms。现在提前并行化后,这段延迟几乎归零。

启动 Profiling 也很有意思:100% 内部用户采样、0.5% 外部用户采样,持续监控每个启动阶段的耗时。这种"对自己产品的性能永远保持敬畏"的态度,值得学习。


二、三元权限决策:Hook、Classifier、User 的级联竞争

Claude Code 的权限系统不是简单的"允许/拒绝"二选一,而是一个三路竞争的异步决策架构

当 AI 要执行一个工具时,三条决策路径同时启动

  1. Hook 路径:检查用户配置的自动化规则
  2. Classifier 路径:用 AI 分类器判断命令是否安全
  3. User 路径:弹出交互确认框

谁先返回结果,谁就赢。

但问题来了:三个异步回调可能在几毫秒内先后返回,如果不做保护,可能同时触发两个 resolve(),导致权限被批准两次。

这就是 ResolveOnce 的用武之地:

function createResolveOnce<T>(resolve: (value: T) => void): ResolveOnce<T> {
  let claimed = false
  let delivered = false
  return {
    resolve(value: T) {
      if (delivered) return
      delivered = true
      claimed = true
      resolve(value)
    },
    claim() {
      if (claimed) return false
      claimed = true
      return true  // 返回 true 表示"我赢了"
    },
  }
}

claim() 实现了一个原子的 Check-and-Mark 操作。三条路径竞争时,只有第一个调用 claim() 并返回 true 的赢家才能最终决定权限。

这是一种非常优雅的异步竞态解决方案,比传统的 mutex/lock 轻量得多。


三、Bash 工具的 2600 行权限检查

42 个工具里,BashTool 的权限逻辑最复杂,单独的 bashPermissions.ts 就有近 2600 行。

权限检查分三层:

第一层:精确匹配(最高优先级)

const exactMatchResult = bashToolCheckExactMatchPermission(input, context)
if (exactMatchResult.behavior === 'deny' || exactMatchResult.behavior === 'ask') {
  return exactMatchResult  // 精确拒绝/询问直接生效
}

第二层:前缀规则(拒绝 > 询问 > 允许)

const { matchingDenyRules, matchingAskRules, matchingAllowRules } =
  matchingRulesForInput(input, context, 'prefix', {
    skipCompoundCheck: astCommand !== undefined,
  })

第三层:通行证(兜底,要求用户确认)

还有一个特别巧妙的设计——安全包装器剥离

const SAFE_WRAPPER_PATTERNS = [
  /^\s*time\s+/,
  /^\s*nohup\s+(?:--\s+)?/,
  /^\s*timeout\s+(?:[^\s]+\s+)*(?:\d+(?:\.\d+)?[smhd])?\s+/,
  /^\s*nice\s+(?:-n\s*-?\d+\s+(?:--\s+)?)?/,
]

如果有人试图用 time nice -n 10 sudo rm -rf / 绕过检查怎么办?系统会循环剥离这些安全包装器,直到露出真实命令,然后才做权限判断。

命令前缀提取也是一道安全防线:

export function getSimpleCommandPrefix(command: string): string | null {
  // NODE_ENV=prod npm run build → 'npm run'(安全变量可跳过)
  // MY_VAR=val npm run build → null(不安全变量,回退精确匹配)
  // chmod 755 file → null(数字不是 subcommand)
}

这套设计的核心理念很清晰:安全默认、纵深防御、宁可误拦不可漏放。


四、Classifier 的投机执行

权限系统还有一个性能优化:投机执行(Speculative Execution)

当权限对话框弹出等用户确认时,Classifier 已经在后台默默跑起来了:

export function startSpeculativeClassifierCheck(
  command: string,
  toolPermissionContext: ToolPermissionContext,
  signal: AbortSignal,
): boolean {
  const promise = classifyBashCommand(command, cwd, allowDescriptions, ...)
  promise.catch(() => {})  // 防止未处理的 rejection
  speculativeChecks.set(command, promise)
  return true
}

如果 Classifier 判定"高置信度允许",对话框会自动关闭,用户甚至不需要手动确认。如果 Classifier 还没返回,用户手动确认了,投机结果就被丢弃。

这是 CPU 分支预测思想在 AI 权限系统中的应用——预测大概率结果,提前执行,失败了再回退。


五、42 个工具的极致模块化

Claude Code 的工具系统用 TypeScript 泛型定义了一套统一接口:

export type Tool<Input, Output> = {
  name: string
  call(args: Input, context: ToolUseContext, ...): Promise<ToolResult<Output>>
  description(input: Input, options: ...): Promise<string>
  inputSchema: Input
  isConcurrencySafe(input: Input): boolean  // 是否可并行
  isReadOnly(input: Input): boolean          // 是否只读
  isDestructive?(input: Input): boolean      // 是否有破坏性
  checkPermissions(input): Promise<PermissionResult>
}

每个工具都是一个独立目录:index.ts(主逻辑)、prompt.ts(AI 提示词)、constants.ts(名称常量)。

buildTool() 函数会自动填充安全默认值:

const TOOL_DEFAULTS = {
  isConcurrencySafe: () => false,  // 默认不可并行
  isReadOnly: () => false,          // 默认可写
  isDestructive: () => false,       // 默认无破坏性
}

失败关闭(Fail-Closed) 原则贯穿始终:新工具如果忘了声明并发安全,就默认串行执行,宁可慢一点也不出错。


六、MCP 深度融合:12 万行让外部服务"透明化"

MCP(Model Context Protocol)客户端是整个项目中最大的单文件——3348 行、12 万字符。

MCP 工具和原生工具共享同一个 Tool<Input, Output> 接口。融合的关键代码:

const fullyQualifiedName = buildMcpToolName(client.name, tool.name)
// 如 mcp__github__create_issue

return {
  ...MCPTool,           // 继承基础 MCPTool 模板
  name: fullyQualifiedName,
  description: async () => serverDescription,
  call: async (args, context) => {
    const mcpResult = await callMCPTool({ ... })
    return { data: mcpResult }
  },
}

用户完全感知不到 MCP 工具和原生工具的区别。 在 AI 的视角里,BashFileReadmcp__github__create_issue 都只是"工具",调用方式完全一致。

传输层支持五种协议:SSE、WebSocket、Stdio、SDK Control、In-Process。其中 InProcessTransport 最有意思——用 queueMicrotask() 在两个对等端之间传递消息,零网络开销:

async send(message: JSONRPCMessage): Promise<void> {
  queueMicrotask(() => {
    this.peer?.onmessage?.(message)
  })
}

OAuth 动态刷新也做得非常完善:令牌到期前 5 分钟主动刷新,并发刷新请求会复用同一个 Promise,还专门处理了 Slack 等非标准 OAuth 实现的兼容问题。


七、多 Agent 编排:Swarm 架构的三种隔离

Claude Code 支持三种 Agent 隔离模式:

模式 隔离级别 适用场景
同进程 共享内存,AsyncLocalStorage 隔离 快速子任务
Worktree 独立 Git 分支,文件系统隔离 代码修改
远程 CCR 完全隔离的远程环境 高风险操作

Agent 着色系统用 8 种颜色区分不同 Agent 的输出:

export const AGENT_COLORS: readonly AgentColorName[] = [
  'red', 'blue', 'green', 'yellow',
  'purple', 'orange', 'pink', 'cyan',
]

记忆快照系统让 Agent 可以跨会话保留经验。记忆分三个作用域:

  • user~/.claude/agent-memory/(跨项目)
  • project<cwd>/.claude/agent-memory/(项目级)
  • local<cwd>/.claude/agent-memory-local/(本地临时)

Worktree 隔离模式还会把 node_modules 等大目录做符号链接,避免磁盘膨胀:

async function symlinkDirectories(repoRootPath, worktreePath, dirs) {
  for (const dir of dirs) {
    if (containsPathTraversal(dir)) continue  // 防路径遍历
    await symlink(sourcePath, destPath, 'dir')
  }
}

八、自动 Compact:AI 驱动的上下文压缩

当对话快要撑爆上下文窗口时,Claude Code 不是简单地截断,而是用 AI 重新摘要早期对话。

export const AUTOCOMPACT_BUFFER_TOKENS = 13_000
export const WARNING_THRESHOLD_BUFFER_TOKENS = 20_000
const MAX_CONSECUTIVE_AUTOCOMPACT_FAILURES = 3

关键设计:断路器模式。代码注释里写着一行令人印象深刻的数据:

BQ 2026-03-10: 1,279 sessions had 50+ consecutive failures wasting ~250K API calls/day globally.

于是他们加了断路器——连续失败 3 次就停止重试。这条注释本身就是工程文化的缩影:数据驱动决策,注释记录决策背景。

四级阈值逐步升级:Warning(20k) → Error(20k) → AutoCompact(13k) → Blocking(3k)。


九、终端渲染:为什么 Claude Code 比其他 CLI 流畅得多

答案藏在 src/ink/ 目录的 96 个文件里。

核心优化:DECSTBM 硬件滚动

普通终端应用滚动时,需要重新绘制整个可视区域。Claude Code 利用了 VT100 的 DECSTBM(Set Top and Bottom Margins)指令,让终端硬件自己处理滚动:

if (altScreen && next.scrollHint && decstbmSafe) {
  const { top, bottom, delta } = next.scrollHint
  shiftRows(prev.screen, top, bottom, delta)
  scrollPatch = [{
    type: 'stdout',
    content:
      setScrollRegion(top + 1, bottom + 1) +  // CSI top;bot r
      (delta > 0 ? csiScrollUp(delta) : csiScrollDown(-delta)) +
      RESET_SCROLL_REGION + CURSOR_HOME,
  }]
}

比例排水算法处理大量输出时的滚动:每帧消化 3/4 的待滚动行数,用 log₄ 帧数收敛到目标位置——既快速赶上又平滑减速。

还有一个 CharPool 字符驻留池

export class CharPool {
  private ascii: Int32Array = initCharAscii()
  
  intern(char: string): number {
    if (char.length === 1) {
      const code = char.charCodeAt(0)
      if (code < 128) {
        const cached = this.ascii[code]!
        if (cached !== -1) return cached  // ASCII 直接数组查找
      }
    }
    // 非 ASCII 走 Map
  }
}

ASCII 字符直接用数组索引查找(O(1)),不走 Map 的哈希路径。跨帧复用字符 ID,屏幕 diff 时只比较整数,比字符串比较快一个数量级。


十、Bun 特性开关:编译时消除死代码

Claude Code 用 Bun 的 feature() 做编译时特性开关:

import { feature } from 'bun:bundle'

const getCoordinatorUserContext = feature('COORDINATOR_MODE')
  ? require('./coordinator/coordinatorMode.js').getCoordinatorUserContext
  : () => ({})

如果 COORDINATOR_MODE 在当前构建中未启用,整个 coordinatorMode.js 模块不会被打包——彻底的死代码消除,不是运行时 if,是编译时直接砍掉。

已知的特性开关包括:

标志 功能
COORDINATOR_MODE 多 Agent 协调器
BASH_CLASSIFIER Bash 命令 AI 分类
CONTEXT_COLLAPSE 上下文折叠
VOICE_MODE 语音输入
EXTRACT_MEMORIES 记忆提取
REACTIVE_COMPACT 被动压缩

这种方式的好处:外部构建的二进制体积更小,而且不会泄露内部功能的名称和实现。


快速推理的冷却管理

快速推理模式(Fast Mode)遇到速率限制时,不是简单报错,而是进入冷却状态

export type FastModeRuntimeState =
  | { status: 'active' }
  | { status: 'cooldown'; resetAt: number; reason: CooldownReason }

resetAt 是一个时间戳,到期后自动恢复,无需后台轮询。每次查询状态时检查一下时间就行:

export function getFastModeRuntimeState(): FastModeRuntimeState {
  if (runtimeState.status === 'cooldown' && Date.now() >= runtimeState.resetAt) {
    runtimeState = { status: 'active' }
  }
  return runtimeState
}

用户偏好和运行时状态分离——你设置了"我要快速模式",但系统可能因为限流临时切回普通模式,限流解除后自动恢复,全程无感。


写在最后

拆完这 10 个模块,我最大的感受不是某个单点有多炫,而是整体工程哲学的一致性

  1. 安全默认:权限三元竞争、工具失败关闭、命令包装器剥离
  2. 性能敬畏:启动 65ms 优化、投机执行、DECSTBM 硬件滚动、CharPool 字符驻留
  3. 数据驱动:断路器阈值来自真实生产数据(250K 浪费调用)、采样率精确到 0.5%
  4. 透明抽象:MCP 工具与原生工具无缝统一、Agent 隔离对用户透明

这不是一个"先跑起来再优化"的项目。每一行代码都能看出经过反复打磨和生产验证的痕迹。

对于开发者来说,这份源码的价值不仅仅是"看看 Anthropic 怎么写代码",更是一本关于"如何构建生产级 AI 工具"的教科书。


觉得有用?转发给你身边写代码的朋友。有什么想深入讨论的架构细节,评论区见。

Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐