Claude Code Undercover Mode 深度解析:AI 工具如何在开源世界里保守秘密

2 阅读17分钟

本文基于 Claude Code 源码(utils/undercover.tsutils/commitAttribution.tsutils/attribution.tsconstants/prompts.tscommands/commit.tstools/BashTool/prompt.tscomponents/PromptInput/PromptInputFooter.tsxscreens/REPL.tsx)进行逆向分析,还原 Undercover Mode 的完整设计。


一、背景:一个真实存在的工程难题

当 Anthropic 的工程师用 Claude Code 向开源社区贡献代码时,他们面临一个棘手的问题:

Claude Code 默认会在 git commit 的 trailer 行里附上类似这样的内容:

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

在公司内部仓库里,这没什么问题。但如果工程师正在给某个公共开源项目提 PR,这行 trailer 就可能泄露一些本不该出现在公共场合的信息:

  • 未发布的模型版本号(如 opus-4-7sonnet-4-8
  • 内部代号(如动物代号 Capybara、Tengu 等——这些是真实的 Anthropic 内部模型代号)
  • 内部工具和频道名(如 go/cc#claude-code-internal 等 Slack 频道)
  • Claude Code 本身的存在(某些情况下 Anthropic 不希望外界知道特定代码是 AI 辅助完成的)

更危险的是,LLM 在生成 commit message 时,可能会不经意地在描述中写出 "Fixed bug found while testing with Claude Capybara" 这样的句子——直接把内部代号暴露在 GitHub 的公共提交历史里。

这不是假设场景,而是 Anthropic 工程团队在日常协作中真实遇到的安全隐患。Undercover Mode 正是为此而生。


二、Undercover Mode 是什么

简而言之,Undercover Mode 是 Claude Code 的一个安全沙盒层,专门用于保护 Anthropic 内部信息不泄露到公开的 git 历史中

当该模式激活时,Claude Code 会:

  1. 屏蔽所有 AI 归属信息:不生成 Co-Authored-By trailer,不在 PR body 里写 "Generated with Claude Code"
  2. 隐藏模型身份:从系统提示词中移除所有模型名称、版本号、内部代号
  3. 注入强制指令:在 commit/PR 生成任务的提示词前插入一段 UNDERCOVER MODE — CRITICAL 指令,要求模型像普通人类开发者一样写提交信息
  4. 在 UI 上显示状态:在终端底部 footer 显示一个 dimmed 的 undercover 状态标识

值得注意的是,这个功能**只存在于 Anthropic 内部构建版本(ant 构建)**中。外部用户下载的 Claude Code 中,所有 Undercover Mode 相关代码都被构建工具在编译期彻底消除了。


三、激活逻辑:三段式状态机

Undercover Mode 的激活逻辑写在 utils/undercover.ts 中,核心函数是 isUndercover()

export function isUndercover(): boolean {
  if (process.env.USER_TYPE === 'ant') {
    if (isEnvTruthy(process.env.CLAUDE_CODE_UNDERCOVER)) return true
    // Auto: active unless we've positively confirmed we're in an allowlisted
    // internal repo. 'external', 'none', and null (check not yet run) all
    // resolve to ON. The check is primed in setup.ts; only 'internal' → OFF.
    return getRepoClassCached() !== 'internal'
  }
  return false
}

这段代码实现了一个三段式状态机

条件Undercover 状态原因
USER_TYPE !== 'ant'(外部构建)永远 OFF死代码消除,外部用户无此功能
CLAUDE_CODE_UNDERCOVER=1强制 ON手动覆盖,即使在内部仓库也生效
repo 分类为 internalOFF确认在内部仓库白名单内,安全
repo 分类为 externalON确认是公开仓库,需要伪装
repo 分类为 noneON不是 git 仓库(如 /tmp),保守默认
repo 分类为 null(尚未检测)ON检测尚未完成,保守默认

"保守默认为 ON" 是这个设计最关键的安全原则。在工程师打开 Claude Code 的那一刻,异步的仓库检测还没有完成,此时如果默认 OFF,就存在一个时间窗口可能泄露信息。通过默认 ON,即使检测延迟,系统也处于安全状态。

注意文档注释里特别强调:"There is NO force-OFF"——没有任何方式可以强制关闭 Undercover Mode,只有被允许列表内的内部仓库能自动解除。


四、仓库分类引擎:commitAttribution.ts

Undercover Mode 的自动检测依赖于 utils/commitAttribution.ts 中的仓库分类系统。

4.1 内部仓库白名单

const INTERNAL_MODEL_REPOS = [
  'github.com:anthropics/claude-cli-internal',
  'github.com/anthropics/claude-cli-internal',
  'github.com:anthropics/anthropic',
  'github.com/anthropics/anthropic',
  'github.com:anthropics/apps',
  'github.com/anthropics/apps',
  // ... 约30个仓库,每个同时列出 SSH 和 HTTPS 格式
]

这个白名单有一个重要注释值得关注:

NOTE: This is intentionally a repo allowlist, not an org-wide check. The anthropics and anthropic-experimental orgs contain PUBLIC repos (e.g. anthropics/claude-code, anthropic-experimental/sandbox-runtime). Undercover mode must stay ON in those to prevent codename leaks. Only add repos here that are confirmed PRIVATE.

即,Anthropic 的 GitHub 组织(anthropics)下同时存在公开仓库和私有仓库。系统采用逐仓库白名单而非按组织放行,正是为了防止把公开仓库误判为内部仓库。比如 anthropics/claude-code 本身是公开的,不在白名单内,Anthropic 工程师向它提交代码时仍然会触发 Undercover Mode。

4.2 分类缓存与 Sequential 并发控制

let repoClassCache: 'internal' | 'external' | 'none' | null = null

export const isInternalModelRepo = sequential(async (): Promise<boolean> => {
  if (repoClassCache !== null) {
    return repoClassCache === 'internal'
  }
  const cwd = getAttributionRepoRoot()
  const remoteUrl = await getRemoteUrlForDir(cwd)
  if (!remoteUrl) {
    repoClassCache = 'none'
    return false
  }
  const isInternal = INTERNAL_MODEL_REPOS.some(repo => remoteUrl.includes(repo))
  repoClassCache = isInternal ? 'internal' : 'external'
  return isInternal
})

这里用了 sequential() 包装器——这是一个自定义的并发控制工具,确保即使多个地方同时调用 isInternalModelRepo(),实际的 git 子进程只会执行一次。

分类结果会缓存到模块级变量 repoClassCache,进程生命周期内只检测一次。注释明确写着 "Memoized - only checks once per process"

同时提供了两个同步读取缓存的函数:

  • getRepoClassCached():返回原始分类值(包含 null 表示"尚未检测")
  • isInternalModelRepoCached():返回是否已确认为内部仓库(nullexternal 都返回 false

这两个函数是同步的,专供在 UI 渲染等不能 await 的场景使用。

4.3 初始化时机:setup.ts

// Prime repo classification cache for auto-undercover mode. Default is
// undercover ON until proven internal; if this resolves to internal, clear
// the prompt cache so the next turn picks up the OFF state.
void import('./utils/commitAttribution.js').then(async m => {
  if (await m.isInternalModelRepo()) {
    const { clearSystemPromptSections } = await import(
      './constants/systemPromptSections.js'
    )
    clearSystemPromptSections()
  }
})

setup.ts(应用启动函数)中,仓库分类会被异步"预热"(primed)。如果检测结果是内部仓库,还会调用 clearSystemPromptSections() 清除之前缓存的系统提示词——因为那些提示词可能是在 Undercover 为 ON 状态时构建的,现在需要以 OFF 状态重新生成。


五、归属信息抑制:attribution.ts

Undercover Mode 最直接的效果是清空所有 AI 归属信息。utils/attribution.ts 中的 getAttributionTexts() 是全局唯一的归属信息入口:

export function getAttributionTexts(): { commit: string; pr: string } {
  if (process.env.USER_TYPE === 'ant' && isUndercover()) {
    return { commit: '', pr: '' }
  }
  // ...
  const modelName =
    isInternalModelRepoCached() || isKnownPublicModel
      ? getPublicModelName(model)
      : 'Claude Opus 4.6'  // 防止未知代号泄漏的兜底值

  const defaultAttribution = `🤖 Generated with [Claude Code](${PRODUCT_URL})`
  const defaultCommit = `Co-Authored-By: ${modelName} <noreply@anthropic.com>`
  // ...
}

这里有一个微妙的防御设计:即使不在 Undercover Mode 下(内部仓库),对于"未知模型"(可能是内测代号)也不会直接使用原始 model ID,而是回退到硬编码的公开模型名 'Claude Opus 4.6'。注释里的 @[MODEL LAUNCH] 标注说明这个值需要在每次新模型发布时手动更新。

模型名称清洁管道

commitAttribution.ts 还包含一个模型名映射系统,将内部变体映射到公开名称:

export function sanitizeModelName(shortName: string): string {
  if (shortName.includes('opus-4-6')) return 'claude-opus-4-6'
  if (shortName.includes('opus-4-5')) return 'claude-opus-4-5'
  // ...
  // Unknown models get a generic name
  return 'claude'
}

内部可能有 opus-4-6-fastopus-4-6-experimental 等变体,这些都会被规范化为对应的公开名称。真正未知的模型名(没有任何匹配项)最终被简化为字符串 'claude',确保任何情况下都不会泄露内部代号。


六、系统提示词的"黑暗模式":constants/prompts.ts

Undercover Mode 对 AI 行为的影响不止于 commit trailer。系统提示词(system prompt)中所有与模型身份相关的内容都会被移除。

6.1 模型描述的完全静默

export async function computeEnvInfo(modelId: string, ...): Promise<string> {
  // Undercover: keep ALL model names/IDs out of the system prompt so nothing
  // internal can leak into public commits/PRs. This includes the public
  // FRONTIER_MODEL_* constants — if those ever point at an unannounced model,
  // we don't want them in context. Go fully dark.
  let modelDescription = ''
  if (process.env.USER_TYPE === 'ant' && isUndercover()) {
    // suppress
  } else {
    const marketingName = getMarketingNameForModel(modelId)
    modelDescription = marketingName
      ? `You are powered by the model named ${marketingName}. The exact model ID is ${modelId}.`
      : `You are powered by the model ${modelId}.`
  }
  // ...
}

正常情况下,系统提示词的环境信息部分会包含:

You are powered by the model named Claude Opus 4.6. The exact model ID is claude-opus-4-6.

在 Undercover Mode 下,这整段文字都被静默移除。注释特别强调 "Go fully dark",甚至连 FRONTIER_MODEL_* 这类公开常量也不注入——因为该常量如果指向一个尚未发布的新模型,也会成为泄漏点。

6.2 多处静默的链式保护

computeSimpleEnvInfo 函数中,Undercover 检查出现了不止一次:

const envItems = [
  // ...
  process.env.USER_TYPE === 'ant' && isUndercover()
    ? null
    : `The most recent Claude model family is Claude 4.5/4.6. ...`,
  process.env.USER_TYPE === 'ant' && isUndercover()
    ? null
    : `Claude Code is available as a CLI in the terminal, ...`,
  process.env.USER_TYPE === 'ant' && isUndercover()
    ? null
    : `Fast mode for Claude Code uses the same ${FRONTIER_MODEL_NAME} model ...`,
].filter(item => item !== null)

注释强调:process.env.USER_TYPE === 'ant' 这个检查必须在每个调用点内联,不能提升为模块级常量,原因是:

DCE: process.env.USER_TYPE === 'ant' is build-time --define. It MUST be inlined at each callsite (not hoisted to a const) so the bundler can constant-fold it to false in external builds and eliminate the branch.

这涉及到 Bun bundler 的 Dead Code Elimination(DCE,死代码消除)机制。Bun 在构建外部版本时,会把 process.env.USER_TYPE 替换为字符串字面量 "external",然后常量折叠整个条件分支,使 if ("external" === 'ant') 永远为 false,相关代码块被整体从 bundle 中删除。如果把检查提升为变量,bundler 就无法追踪到该变量的来源进行折叠。

6.3 getAntModelOverrideSection 的条件注入

function getAntModelOverrideSection(): string | null {
  if (process.env.USER_TYPE !== 'ant') return null
  if (isUndercover()) return null  // 卧底时不注入任何内部模型配置
  return getAntModelOverrideConfig()?.defaultSystemPromptSuffix || null
}

内部版本有一个额外的"模型覆盖"系统提示词段(AntModelOverrideConfig),允许 Anthropic 内部为不同模型注入定制化指令。Undercover 模式下,这段内容同样被移除,避免任何内部配置泄漏进公开 commit 的上下文。


七、提示词注入:UNDERCOVER MODE — CRITICAL 指令

仅仅屏蔽模型身份信息还不够。因为 LLM 即使不知道自己叫什么,也可能在生成 commit message 时写出 "AI-assisted refactoring" 或提到某个内部项目名。

Undercover Mode 的第二层保护是在 commit/PR 相关操作的提示词前插入一段强制指令

7.1 指令原文

export function getUndercoverInstructions(): string {
  if (process.env.USER_TYPE === 'ant') {
    return `## UNDERCOVER MODE — CRITICAL

You are operating UNDERCOVER in a PUBLIC/OPEN-SOURCE repository. Your commit
messages, PR titles, and PR bodies MUST NOT contain ANY Anthropic-internal
information. Do not blow your cover.

NEVER include in commit messages or PR descriptions:
- Internal model codenames (animal names like Capybara, Tengu, etc.)
- Unreleased model version numbers (e.g., opus-4-7, sonnet-4-8)
- Internal repo or project names (e.g., claude-cli-internal, anthropics/…)
- Internal tooling, Slack channels, or short links (e.g., go/cc, #claude-code-…)
- The phrase "Claude Code" or any mention that you are an AI
- Any hint of what model or version you are
- Co-Authored-By lines or any other attribution

Write commit messages as a human developer would — describe only what the code
change does.

GOOD:
- "Fix race condition in file watcher initialization"
- "Add support for custom key bindings"
- "Refactor parser for better error messages"

BAD (never write these):
- "Fix bug found while testing with Claude Capybara"
- "1-shotted by claude-opus-4-6"
- "Generated with Claude Code"
- "Co-Authored-By: Claude Opus 4.6 <…>"
`
  }
  return ''
}

这段指令的几个设计亮点:

禁止列表的具体化:禁止项不是笼统的"不要泄露内部信息",而是列出了具体的信息类别——内部代号(并点名了动物代号这一模式)、未发布版本号(给出了格式示例)、内部工具名(包括 Slack 频道格式)。这是为了给 LLM 提供清晰的分类边界,减少模糊地带。

好坏对照的 few-shot:提供了正确和错误的 commit 示例,这是典型的 few-shot prompting 技巧。通过正向示例,模型能立即理解期望的输出风格;通过负向示例,模型能识别应当避免的具体模式。

人格化指令"Write commit messages as a human developer would""Do not blow your cover"——这是拟人化的提示词写法,引导模型进入"伪装成人类开发者"的角色,而不是试图用规则列表去约束每一种可能的违规。

7.2 注入点:commands/commit.ts

function getPromptContent(): string {
  const { commit: commitAttribution } = getAttributionTexts()

  let prefix = ''
  if (process.env.USER_TYPE === 'ant' && isUndercover()) {
    prefix = getUndercoverInstructions() + '\n'
  }

  return `${prefix}## Context
...
## Your task
Based on the above changes, create a single git commit:
...`
}

/commit 命令(用于一键创建 git commit)的提示词构建函数里,Undercover 指令作为 prefix前置插入,确保它出现在所有其他内容之前,在注意力机制中获得更高的权重。

7.3 纵深防御:tools/BashTool/prompt.ts

function getCommitAndPRInstructions(): string {
  // Defense-in-depth: undercover instructions must survive even if the user
  // has disabled git instructions entirely. Attribution stripping and model-ID
  // hiding are mechanical and work regardless, but the explicit "don't blow
  // your cover" instructions are the last line of defense against the model
  // volunteering an internal codename in a commit message.
  const undercoverSection =
    process.env.USER_TYPE === 'ant' && isUndercover()
      ? getUndercoverInstructions() + '\n'
      : ''

  if (!shouldIncludeGitInstructions()) return undercoverSection
  // ...
}

注释里的 "Defense-in-depth"(纵深防御)一词来自军事和网络安全领域,指的是多层叠加的防御措施,单层失效时其他层仍能发挥作用。

这里的设计逻辑是:用户可能通过配置关闭 git 指令(shouldIncludeGitInstructions() === false)。正常情况下,关闭 git 指令意味着不注入关于 commit/PR 的操作指导。但在 Undercover Mode 下,即使 git 指令被关闭,Undercover 安全指令仍然会被注入——它作为函数的提前返回值单独存在,不受 shouldIncludeGitInstructions 的影响。

这正是纵深防御的体现:机械性的归属信息清零(getAttributionTexts 返回空字符串)是第一层防御,提示词指令约束是最后一道防线,无论其他配置如何,它都不会被关闭


八、UI 层的感知:状态显示与一次性通知

8.1 Footer 状态标识

Undercover Mode 激活时,终端输入框底部的 footer 会显示一个灰色的 undercover 标识:

// components/PromptInput/PromptInputFooter.tsx
{"external" === 'ant' && isUndercover() && <Text dimColor>undercover</Text>}

这个标识使用 dimColor(暗淡颜色),不会喧宾夺主,但能让用户知道当前处于特殊模式。对于 Anthropic 内部工程师,这是一个清晰的工作状态提示:你现在操作的是一个公开仓库,AI 的行为已被约束。

8.2 自动激活的一次性通知

当 Undercover Mode 通过自动检测(而非手动设置环境变量)激活时,系统会显示一个一次性的解释对话框。相关逻辑在 screens/REPL.tsx 中:

const [showUndercoverCallout, setShowUndercoverCallout] = useState(false)
useEffect(() => {
  if ("external" === 'ant') {
    void (async () => {
      // Wait for repo classification to settle (memoized, no-op if primed).
      const { isInternalModelRepo } = await import('../utils/commitAttribution.js')
      await isInternalModelRepo()
      const { shouldShowUndercoverAutoNotice } = await import('../utils/undercover.js')
      if (shouldShowUndercoverAutoNotice()) {
        setShowUndercoverCallout(true)
      }
    })()
  }
}, [])

shouldShowUndercoverAutoNotice() 的判断条件:

export function shouldShowUndercoverAutoNotice(): boolean {
  if (process.env.USER_TYPE === 'ant') {
    if (isEnvTruthy(process.env.CLAUDE_CODE_UNDERCOVER)) return false  // 手动强制时不弹
    if (!isUndercover()) return false    // 未激活时不弹
    if (getGlobalConfig().hasSeenUndercoverAutoNotice) return false  // 已看过不再弹
    return true
  }
  return false
}

四个条件形成一个精确的触发逻辑:

  1. 必须是内部构建ant 构建)
  2. 必须是自动检测激活(手动强制的情况下用户已知晓,无需通知)
  3. 必须当前处于 Undercover 状态
  4. 用户必须从未看过该通知(通过 config 持久化 hasSeenUndercoverAutoNotice 标志)

这个设计避免了重复打扰用户,同时确保每个工程师在第一次遇到自动 Undercover 时能得到清晰的解释。


九、构建时的死代码消除:外部用户看到的世界

整个 Undercover Mode 系统对外部用户是完全透明的——不是通过运行时 if 判断跳过,而是在构建阶段被物理删除

Bun bundler 在构建外部版本时:

  1. 将所有 process.env.USER_TYPE 替换为字符串 "external"
  2. 常量折叠:"external" === 'ant'false
  3. 死代码消除:整个 if (false) { ... } 块被移除
  4. 结果:isUndercover() 函数体变为简单的 return false

最终在用户安装的 Claude Code 中,undercover.ts 的三个导出函数等价于:

export function isUndercover(): boolean { return false }
export function getUndercoverInstructions(): string { return '' }
export function shouldShowUndercoverAutoNotice(): boolean { return false }

甚至这三个函数本身在后续的 tree-shaking 中也会因为总是返回固定值而被进一步优化掉。

这也是为什么在 PromptInputFooter.tsx 中能看到:

{"external" === 'ant' && isUndercover() && <Text dimColor>undercover</Text>}

这行 JSX 中 "external" === 'ant' 在外部构建中直接是 false,整个表达式和 <Text> 组件都不会出现在外部版本的 bundle 里——undercover 这个字符串字面量本身也会被消除,杜绝了任何通过分析 bundle 内容推断内部功能的可能。


十、设计模式总结:安全工程的五条原则

通过对 Undercover Mode 的完整分析,我们可以提炼出几条值得借鉴的安全工程设计原则:

原则一:保守默认(Safe by Default)

"Safe default is ON — Claude may push to public remotes from a CWD that isn't itself a git checkout"

系统在不确定时选择更安全的一侧。仓库检测尚未完成?默认 ON。不是 git 仓库?默认 ON。只有在积极确认为内部仓库之后,才会解除限制。这种"非白即黑"的设计在安全敏感场景中比"非黑即白"更可靠。

原则二:不可关闭的安全开关(No Force-Off)

"There is NO force-OFF."

对于核心安全约束,不提供绕过机制。工程师可以强制打开 Undercover Mode(CLAUDE_CODE_UNDERCOVER=1),但无法强制关闭它。这防止了"误操作"和"图方便"导致的安全疏漏,也使得系统的安全保证更强(不需要依赖用户的正确使用)。

原则三:纵深防御(Defense in Depth)

多层互相独立的保护措施:

  • 机械层getAttributionTexts() 返回空字符串,commit trailer 物理不存在
  • 系统提示词层:模型身份信息从上下文中移除,模型不知道自己是谁
  • 指令层:在 commit 任务提示词中明确禁止各类泄漏行为
  • UI 层:状态标识告知用户当前模式

每一层独立工作,单层失效不会导致整体失效。

原则四:构建时隔离(Build-time Isolation)

内部功能通过构建变量(process.env.USER_TYPE)而非运行时配置进行隔离,并依赖 bundler 的 DCE 能力彻底从外部 bundle 中消除相关代码。这是比"runtime check + feature flag"更强的隔离手段——外部用户从根本上无法启用不存在的代码路径。

原则五:精准的用户感知(Precise User Awareness)

  • 手动强制时不弹通知(用户已知晓)
  • 自动检测激活时弹一次性通知(用户需要了解)
  • Footer 持续显示状态(用户可以随时感知当前处于何种模式)
  • 通知标志持久化(不重复打扰)

安全机制不应该是沉默的黑箱,也不应该是烦人的警告轰炸。Undercover Mode 在正确的时机传递正确量的信息。


十一、延伸思考:AI 工具的身份透明性问题

Undercover Mode 背后有一个更深层的问题值得思考:AI 工具是否应该在所有时候都声明自己的存在?

从开源社区的角度看,有观点认为所有代码都应该注明是否由 AI 辅助创作,以便社区评估代码质量和可信度。Co-Authored-By: Claude Opus 4.6 这样的 trailer 在某种意义上是 AI 参与透明性的体现。

但 Undercover Mode 代表了另一种情境:Anthropic 的工程师在贡献代码时,使用的可能是内部测试版的 AI 工具,附带的模型信息可能是敏感的商业机密。在这种情况下,"AI 参与透明性"和"商业机密保护"之间存在张力

Claude Code 的解决方案是通过模型版本映射(sanitizeModelName)在归因信息中使用公开的、已发布的模型名称,同时在 Undercover 场景下完全移除归因。这是一种妥协:保持了对已知公开模型的归因透明,但对未公开信息保持沉默。

对于其他 AI 辅助开发工具的设计者而言,Undercover Mode 提供了一个值得参考的思路:透明性不一定意味着全盘披露,而是在合理边界内的诚实披露


十二、完整调用链路图

应用启动 (setup.ts)
    │
    ├─ [async] isInternalModelRepo()
    │       │
    │       ├─ getRemoteUrlForDir(cwd)  ← git remote get-url origin
    │       ├─ 对比 INTERNAL_MODEL_REPOS 白名单
    │       └─ 写入 repoClassCache ('internal' | 'external' | 'none')
    │
    └─ 如果 internal → clearSystemPromptSections()

用户执行 /commit 或 Bash git commit
    │
    ├─ isUndercover()
    │       ├─ USER_TYPE !== 'ant' → false(外部构建)
    │       ├─ CLAUDE_CODE_UNDERCOVER=1 → true(强制)
    │       └─ getRepoClassCached() !== 'internal' → true/false
    │
    ├─ [如果 ON] getUndercoverInstructions() → 前置指令
    ├─ [如果 ON] getAttributionTexts() → { commit: '', pr: '' }
    └─ [如果 ON] computeEnvInfo() → 不含模型描述

UI 渲染
    │
    ├─ Footer: isUndercover() && <Text dimColor>undercover</Text>
    └─ 首次自动激活: shouldShowUndercoverAutoNotice() → UndercoverAutoCallout

十三、结语

Undercover Mode 是 Claude Code 中一个规模相对较小但设计密度极高的子系统。它的代码量不多(核心逻辑不超过 200 行),但涉及了:

  • 运行时状态机(三态仓库分类、异步预热、同步缓存读取)
  • 构建时代码消除--define + DCE + tree-shaking)
  • 提示词工程(前置指令、few-shot 示例、角色扮演引导)
  • 多层安全架构(机械抑制 + 上下文清洗 + 行为约束)
  • 精细化 UX 设计(状态标识、一次性通知、持久化标志)

每一个设计决策都有清晰的工程理由。注释质量也相当高——很多关键设计选择都有内联的解释,而不是留给读者自己猜测。

这种"把安全设计文档写进代码注释"的习惯,本身也是值得学习的工程实践。


本文分析基于 Claude Code 逆向工程得到的源代码,文中引用的代码片段均来自该代码库。Undercover Mode 仅在 Anthropic 内部构建版本(ant 构建)中存在,外部用户安装的 Claude Code 不含此功能。