提示词

Layer 1: Prompt Assembly Architecture

Claude Code 源码深度拆解 -- prompts.ts 编排器及其卫星模块的完整逆向工程分析

状态
已收录
语言
中文
来源
Projects/claude-code-deep-dive/layer1-prompt-assembly.html
重复副本
0

提取结果

提示词片段

headlessProfilerCheckpoint('before_getSystemPrompt')
headlessProfilerCheckpoint('after_getSystemPrompt')
buildSystemPromptBlocks()
enhanceSystemPromptWithEnvDetails()
export async function getSystemPrompt( tools: Tools, // 当前会话启用的全部工具列表 model: string, // 模型标识符,如 'claude-opus-4-6' additionalWorkingDirectories?: string[], // 额外工作目录(worktree 等) mcpClients?: MCPServerConnection[], // MCP 服务器连接状态 ): Promise<string[]>Copy
return [ `\nYou are an autonomous agent. Use the available tools to do useful work.\n\n${CYBER_RISK_INSTRUCTION}`, getSystemRemindersSection(), await loadMemoryPrompt(), envInfo, getLanguageSection(settings.language), isMcpInstructionsDeltaEnabled() ? null : getMcpInstructionsSection(mcpClients), getScratchpadInstructions(), getFunctionResultClearingSection(model), SUMMARIZE_TOOL_RESULTS_SECTION, getProactiveSection(), ].filter(s => s !== null)Copy
const dynamicSections = [ systemPromptSection('session_guidance', () => ...), // 缓存 systemPromptSection('memory', () => ...), // 缓存 systemPromptSection('ant_model_override', () => ...), // 缓存 systemPromptSection('env_info_simple', () => ...), // 缓存 systemPromptSection('language', () => ...), // 缓存 systemPromptSection('output_style', () => ...), // 缓存 DANGEROUS_uncachedSystemPromptSection( // 不缓存! 'mcp_instructions', () => ..., 'MCP servers connect/disconnect between turns' ), systemPromptSection('scratchpad', () => ...), // 缓存 systemPromptSection('frc', () => ...), // 缓存 systemPromptSection('summarize_tool_results', ...), // 缓存 // + 条件追加: numeric_length_anchors, token_budget, brief ]Copy
const resolvedDynamicSections = await resolveSystemPromptSections(dynamicSections) return [ // --- 静态内容(可缓存) --- getSimpleIntroSection(outputStyleConfig), // 1. 身份定义 getSimpleSystemSection(), // 2. 系统行为规则 outputStyleConfig === null || keepCoding // 3. 做任务指南(条件) ? getSimpleDoingTasksSection() : null, getActionsSection(), // 4. 执行操作准则 getUsingYourToolsSection(enabledTools), // 5. 工具使用指南 getSimpleToneAndStyleSection(), // 6. 语气与格式 getOutputEfficiencySection(), // 7. 输出效率 // === 边界标记 === ...(shouldUseGlobalCacheScope() ? [SYSTEM_PROMPT_DYNAMIC_BOUNDARY] : []), // --- 动态内容(注册管理) --- ...resolvedDynamicSections, ].filter(s => s !== null)Copy

正文

清洗后的原始内容

Layer 1: Prompt Assembly Architecture

Claude Code 源码深度拆解 -- prompts.ts 编排器及其卫星模块的完整逆向工程分析

1架构概述

1.1 prompts.ts 的角色定位:编排器而非模板

prompts.ts(914 行)是 Claude Code 系统 prompt 的核心编排器。它不是一个静态模板文件——不存在一个预写好的长文本在运行时被填入变量。相反,它是一个运行时决策引擎,根据当前会话的上下文(模型类型、工具集合、feature flags、用户配置、MCP 服务器状态等)动态组装出一个 string[] 数组,每个元素代表系统 prompt 的一个语义分节。

这种设计的核心优势在于:

  • Prompt Cache 友好:静态分节与动态分节通过边界标记分离,静态部分可以跨组织级别缓存(cacheScope: 'global'),大幅降低 API 成本
  • 条件组装:每个分节函数独立决定是否返回内容(null 表示跳过),避免了"if-else 嵌套地狱"
  • 分节级 Memoization:通过 systemPromptSections.ts 的缓存层,避免跨 turn 重复计算
  • 三路运行模式:同一入口函数 getSystemPrompt() 支持 SIMPLE、PROACTIVE、标准三种完全不同的 prompt 拓扑

1.2 调用关系:谁调用 getSystemPrompt(),返回值如何被消费

调用链路 QueryEngine.ts SessionMemory.ts | | v v getSystemPrompt(tools, model) getSystemPrompt(tools, mainLoopModel) | | v v string[] // 系统 prompt 分节数组 | +───────────────────────────────────────> buildSystemPromptBlocks() | (services/api/claude.ts) v splitSysPromptPrefix() // utils/api.ts | v SystemPromptBlock[] // { text, cacheScope } | v TextBlockParam[] // Anthropic API system[] 字段

QueryEngine.ts:284 是主入口调用点。它在 headlessProfilerCheckpoint('before_getSystemPrompt')headlessProfilerCheckpoint('after_getSystemPrompt') 之间调用此函数,获取到 string[] 后与 getUserContext()getSystemContext() 的结果合并,最终传递给 buildSystemPromptBlocks()

SessionMemory.ts:413 是第二个调用点,用于会话恢复场景。它使用三路并行 Promise.all 同时获取系统 prompt、用户上下文和系统上下文。

另一个重要的卫星函数是 enhanceSystemPromptWithEnvDetails()(行 760-791),用于子 agent(subagent)场景。它不重新调用 getSystemPrompt(),而是在已有的 prompt 基础上追加环境信息和技能发现引导。

2getSystemPrompt() 完整拆解

2.1 函数签名与参数

export async function getSystemPrompt(
  tools: Tools,                              // 当前会话启用的全部工具列表
  model: string,                             // 模型标识符,如 'claude-opus-4-6'
  additionalWorkingDirectories?: string[], // 额外工作目录(worktree 等)
  mcpClients?: MCPServerConnection[],       // MCP 服务器连接状态
): Promise<string[]>Copy

返回类型是 Promise<string[]>,不是单个字符串。每个数组元素代表一个独立的语义分节,在 API 层面被拼接为 \n\n 分隔的文本块,或者被拆分到不同的 TextBlockParam 中以获得不同的缓存策略。

2.2 SIMPLE 模式(极简路径)

当环境变量 CLAUDE_CODE_SIMPLE=1 时,函数直接返回一个单元素数组,跳过所有复杂逻辑:

if (isEnvTruthy(process.env.CLAUDE_CODE_SIMPLE)) {
  return [
    `You are Claude Code, Anthropic's official CLI for Claude.\n\nCWD: ${getCwd()}\nDate: ${getSessionStartDate()}`,
  ]
}Copy

这个模式用于测试和极端轻量场景。注意 getSessionStartDate()memoize(getLocalISODate),在会话启动时冻结日期值,避免跨午夜的 prompt cache 失效。

2.3 PROACTIVE 模式(自主代理路径)

feature('PROACTIVE') || feature('KAIROS')proactiveModule.isProactiveActive() 为真时,进入自主代理路径。此路径完全跳过标准模式的分节框架,直接构建一个面向自主工作的精简 prompt:

return [
  `\nYou are an autonomous agent. Use the available tools to do useful work.\n\n${CYBER_RISK_INSTRUCTION}`,
  getSystemRemindersSection(),
  await loadMemoryPrompt(),
  envInfo,
  getLanguageSection(settings.language),
  isMcpInstructionsDeltaEnabled() ? null : getMcpInstructionsSection(mcpClients),
  getScratchpadInstructions(),
  getFunctionResultClearingSection(model),
  SUMMARIZE_TOOL_RESULTS_SECTION,
  getProactiveSection(),
].filter(s => s !== null)Copy

关键差异:没有 "Doing tasks" 部分、没有 "Actions" 部分、没有缓存边界标记,且身份定义从 "CLI tool" 变为 "autonomous agent"。自主代理有自己独特的指令(详见 getProactiveSection()),包括 tick 处理、睡眠控制、终端焦点感知等。

2.4 标准模式:完整组装流程

标准模式是最复杂也最核心的路径,分为三个阶段:

阶段 1:三路并行数据预获取

const [skillToolCommands, outputStyleConfig, envInfo] = await Promise.all([
  getSkillToolCommands(cwd),         // 扫描可用的 Skill 命令
  getOutputStyleConfig(),             // 解析输出样式配置
  computeSimpleEnvInfo(model, dirs),  // 计算环境信息
])Copy

这三个异步操作完全独立,可并行执行。getSkillToolCommands 扫描 .claude/commands/ 目录;getOutputStyleConfig 读取样式配置并处理插件强制样式;computeSimpleEnvInfo 获取 git 状态、操作系统信息和模型元数据。

阶段 2:动态分节数组构建

构建一个 SystemPromptSection[] 数组,每个元素包含名称、计算函数和缓存策略。在此阶段不执行任何计算——只是注册:

const dynamicSections = [
  systemPromptSection('session_guidance', () => ...),  // 缓存
  systemPromptSection('memory', () => ...),             // 缓存
  systemPromptSection('ant_model_override', () => ...), // 缓存
  systemPromptSection('env_info_simple', () => ...),   // 缓存
  systemPromptSection('language', () => ...),           // 缓存
  systemPromptSection('output_style', () => ...),      // 缓存
  DANGEROUS_uncachedSystemPromptSection(                // 不缓存!
    'mcp_instructions', () => ...,
    'MCP servers connect/disconnect between turns'
  ),
  systemPromptSection('scratchpad', () => ...),        // 缓存
  systemPromptSection('frc', () => ...),               // 缓存
  systemPromptSection('summarize_tool_results', ...),  // 缓存
  // + 条件追加: numeric_length_anchors, token_budget, brief
]Copy

阶段 3:解析 + 组装最终数组

const resolvedDynamicSections = await resolveSystemPromptSections(dynamicSections)

return [
  // --- 静态内容(可缓存) ---
  getSimpleIntroSection(outputStyleConfig),      // 1. 身份定义
  getSimpleSystemSection(),                      // 2. 系统行为规则
  outputStyleConfig === null || keepCoding       // 3. 做任务指南(条件)
    ? getSimpleDoingTasksSection() : null,
  getActionsSection(),                            // 4. 执行操作准则
  getUsingYourToolsSection(enabledTools),        // 5. 工具使用指南
  getSimpleToneAndStyleSection(),                // 6. 语气与格式
  getOutputEfficiencySection(),                  // 7. 输出效率
  // === 边界标记 ===
  ...(shouldUseGlobalCacheScope() ? [SYSTEM_PROMPT_DYNAMIC_BOUNDARY] : []),
  // --- 动态内容(注册管理) ---
  ...resolvedDynamicSections,
].filter(s => s !== null)Copy

3全部分节构建函数逐个拆解

3.1 身份与系统基础

getSimpleIntroSection(outputStyleConfig) -- 行 175-184

属性
位置静态前缀 #1
返回类型string(始终返回)
缓存标记Static

这是整个系统 prompt 的开篇。根据 outputStyleConfig 是否为 null 决定身份描述:

  • 有自定义输出样式"helps users according to your 'Output Style' below"
  • 无自定义样式"helps users with software engineering tasks"

同时注入 CYBER_RISK_INSTRUCTION(网络安全行为边界,由 Safeguards 团队维护,不可随意修改)和 URL 生成禁令。

getSimpleSystemSection() -- 行 186-197

属性
位置静态前缀 #2
返回类型string(始终返回)
标题# System

包含 6 条系统级行为规则:

  1. 输出文本使用 GitHub-flavored Markdown(CommonMark 渲染)
  2. 工具权限模式说明——用户拒绝工具时不要重试相同调用
  3. <system-reminder> 标签说明——与工具结果/用户消息无关的系统注入信息
  4. 外部来源注入检测——疑似 prompt injection 时向用户报警
  5. Hooks 机制说明(调用 getHooksSection()
  6. 自动压缩说明——对话不受上下文窗口限制

getSimpleDoingTasksSection() -- 行 199-253

属性
位置静态前缀 #3(条件包含)
条件outputStyleConfig === null || keepCodingInstructions === true
标题# Doing tasks
ant 差异4 条额外子项(注释风格、完成验证、bug 报告、false-claims 缓解)

这是最长的分节之一,包含软件工程任务的核心行为指南。关键内容包括:

  • 不要自作主张添加功能、重构或"改进"
  • 不要为不可能发生的场景添加错误处理
  • 不要为一次性操作创建帮助函数/工具类
  • 修改前先读代码,尽量编辑而非新建文件
  • 注意安全漏洞(OWASP Top 10)
  • codeStyleSubitems 中有 4 条 ant-only 规则(注释极简主义、完成前验证、如实报告结果、false-claims 缓解)
ant-only 注释规则(行 206-213)

标记为 @[MODEL LAUNCH]: Update comment writing for Capybara,是针对 Capybara 模型过度注释倾向的对冲。包括"默认不写注释"、"不要解释代码做什么"、"不要删除已有注释除非删除对应代码"三条。这些规则仅在 USER_TYPE === 'ant' 时注入。

3.2 操作与工具

getActionsSection() -- 行 255-267

属性
位置静态前缀 #4
标题# Executing actions with care
分支无条件分支

这是一个篇幅较长的纯文本分节,定义了 Claude Code 对"高风险操作"的行为框架。核心思想是"可逆性与影响范围评估":

  • 自由执行:本地可逆操作(编辑文件、运行测试)
  • 需要确认:不可逆操作(删除文件/分支、force push、修改 CI/CD)、可见于他人的操作(push、创建 PR/issue、发送消息)、上传到第三方工具
  • 障碍处理原则:不要用破坏性操作走捷径(如 --no-verify),调查根因而非绕过检查

getUsingYourToolsSection(enabledTools) -- 行 269-314

属性
位置静态前缀 #5
标题# Using your tools
输入enabledTools: Set<string>
依赖hasEmbeddedSearchTools()isReplModeEnabled()

根据运行模式有两个完全不同的分支:

REPL 模式(行 277-285):Read/Write/Edit/Glob/Grep/Bash/Agent 被隐藏,只保留 TaskTool 相关引导。

标准模式(行 289-313):核心是"专用工具优先于 Bash"的强制规则——用 FileReadTool 而非 cat,用 FileEditTool 而非 sed,用 GlobTool 而非 find(除非 ant 内置搜索工具启用时跳过 Glob/Grep 引导)。还包括并行工具调用指南和 TaskTool 使用引导。

getAgentToolSection() -- 行 316-320

根据 isForkSubagentEnabled() 返回不同的 AgentTool 使用说明:

  • Fork 模式:Agent 在后台运行,保持工具输出脱离主上下文。如果自己就是 fork,直接执行不要再委托。
  • 标准模式:用于并行化独立查询或保护主上下文窗口,但不要过度使用,不要重复 subagent 已在做的工作。

getDiscoverSkillsGuidance() -- 行 333-341

仅在 feature('EXPERIMENTAL_SKILL_SEARCH') 开启时返回。告知模型技能会自动浮现("Skills relevant to your task:" 提醒),但在中途转向、不寻常工作流或多步计划时应主动调用 DiscoverSkillsTool

3.3 语气与效率

getSimpleToneAndStyleSection() -- 行 430-442

属性
位置静态前缀 #6
标题# Tone and style
ant 差异ant 时不包含"responses should be short and concise"

5 条格式规则:不用 emoji(除非用户明确要求)、引用代码时用 file_path:line_number、GitHub issue 用 owner/repo#123 格式、工具调用前不用冒号。ant 用户跳过"简短回复"规则(因为 ant 版有自己更详细的输出效率指令)。

getOutputEfficiencySection() -- 行 402-428

属性
位置静态前缀 #7
ant 差异完全不同的内容

这个分节在 ant 和非 ant 之间有完全不同的内容:

ant 版(标题:# Communicating with the user):长篇叙事式指导,强调"为人写作而非记录日志"。核心规则包括:工具调用前简要说明意图、关键时刻给简短更新、假设用户离开后失去了线索、用流畅散文而非片段、倒金字塔结构、不要过分强调琐碎的过程。标记为 @[MODEL LAUNCH]: Remove this section when we launch numbat

外部版(标题:# Output efficiency):精简指令——开门见山、先行动后解释、聚焦于需要用户输入的决策和关键里程碑更新。

3.4 SessionSpecificGuidanceSection -- 条件最密集的分节

getSessionSpecificGuidanceSection(enabledTools, skillToolCommands) -- 行 352-400

属性
位置动态后缀 #1
缓存systemPromptSection
标题# Session-specific guidance
依赖enabledTools, skillToolCommands, 多个 feature flags
为什么此分节在边界之后

注释明确说明(行 343-351):此分节的每一个条件判断都是运行时 bit,如果放在 SYSTEM_PROMPT_DYNAMIC_BOUNDARY 之前,会导致 Blake2b 前缀哈希出现 2^N 个变体,彻底摧毁全局缓存命中率。这正是 PR #24490 和 #24171 中出现的 bug 类型。

此分节最多包含以下条目(全部条件判断):

  1. AskUserQuestionTool 存在时:提示用户被拒绝的工具调用可以用此工具追问原因
  2. 非 non-interactive 会话时:告知用户可以用 ! <command> 前缀在 prompt 中运行 shell 命令
  3. AgentTool 存在时:注入 getAgentToolSection() 内容(fork 或标准模式)
  4. ExploreAgent 启用 + 非 fork 模式:搜索工具直接 vs Agent 探索的使用分界
  5. SkillTool 存在且有技能时:/skill-name 快捷方式说明
  6. DiscoverSkillsTool 存在时:技能自动浮现引导
  7. VERIFICATION_AGENT feature + tengu_hive_evidence GrowthBook flag:验证代理规则——非平凡实现必须经过独立对抗验证

当所有条件都为 false 时,函数返回 null,整个分节被跳过。

3.5 环境信息

computeSimpleEnvInfo(modelId, additionalWorkingDirectories) -- 行 651-710

属性
位置动态后缀 #4
缓存systemPromptSection
标题# Environment

使用 Promise.all([getIsGit(), getUnameSR()]) 并行获取 git 状态和操作系统信息,然后组装 <env> 标签块。包含的信息:

  • 主工作目录和 worktree 标识
  • 是否为 git 仓库
  • 额外工作目录列表
  • 平台、Shell、OS 版本
  • 模型名称和 ID(undercover 模式下隐藏)
  • 知识截止日期(从 getKnowledgeCutoff()
  • 最新 Claude 模型家族信息(Opus 4.6、Sonnet 4.6、Haiku 4.5)
  • Claude Code 可用平台说明
  • Fast mode 说明(使用相同模型,仅更快输出)

getKnowledgeCutoff(modelId) -- 行 713-730

基于模型 canonical name 的简单模式匹配返回知识截止日期:

模型截止日期
claude-sonnet-4-6August 2025
claude-opus-4-6May 2025
claude-opus-4-5May 2025
claude-haiku-4February 2025
claude-opus-4 / claude-sonnet-4January 2025
其他null(不显示)

getShellInfoLine() -- 行 732-743

process.env.SHELL 提取 shell 名称。Windows 平台额外添加 "(use Unix shell syntax, not Windows)" 提示。

3.6 语言、样式与 MCP

getLanguageSection(languagePreference) -- 行 142-149

属性
位置动态后缀 #5
缓存systemPromptSection
条件仅当 settings.language 非空时返回

注入 # Language 标题,指令模型用指定语言回复,但技术术语和代码标识符保持原形式。

getOutputStyleSection(outputStyleConfig) -- 行 151-158

属性
位置动态后缀 #6
缓存systemPromptSection
条件仅当 outputStyleConfig !== null 时返回

简单包装:# Output Style: {name}\n{prompt}。输出样式的复杂逻辑在 outputStyles.ts(详见第 6 章)。

getMcpInstructionsSection(mcpClients) -- 行 160-165

属性
位置动态后缀 #7
缓存DANGEROUS_uncached
原因MCP 服务器在 turn 之间可能连接/断开

调用 getMcpInstructions()(行 579-603),过滤已连接且有 instructions 的 MCP 客户端,为每个生成 ## {serverName}\n{instructions} 块,用 # MCP Server Instructions 标题包装。当启用 isMcpInstructionsDeltaEnabled() 时,此分节返回 null——MCP 指令改由 attachments 注入。

3.7 辅助功能分节

getScratchpadInstructions() -- 行 797-818

属性
位置动态后缀 #8
缓存systemPromptSection
条件isScratchpadEnabled()

当启用 scratchpad 时,注入 # Scratchpad Directory,指示模型使用会话特定的临时目录而非 /tmp。用途包括中间结果存储、临时脚本、分析处理中的工作文件等。

getFunctionResultClearingSection(model) -- 行 821-839

属性
位置动态后缀 #9
缓存systemPromptSection
条件feature('CACHED_MICROCOMPACT') + 模型支持 + 配置启用

当 micro-compact(自动上下文压缩)启用时,告知模型旧的工具结果会被自动清除以释放空间,最近 N 条结果始终保留。这与 SUMMARIZE_TOOL_RESULTS_SECTION 配合,提醒模型在回复中写下可能后续需要的重要信息。

getBriefSection() -- 行 843-858

属性
位置动态后缀(条件追加)
条件feature('KAIROS') || feature('KAIROS_BRIEF'),且 Brief 工具启用,且非 PROACTIVE 活跃

当 Brief 模式启用但 PROACTIVE 未激活时,注入 BRIEF_PROACTIVE_SECTION。如果 PROACTIVE 激活,此内容已由 getProactiveSection() 内联包含,因此这里跳过以避免重复。

getProactiveSection() -- 行 860-913

属性
位置PROACTIVE 路径专属
条件feature('PROACTIVE') || feature('KAIROS') + isProactiveActive()
标题# Autonomous work

最长的单分节之一,定义了 Claude Code 作为自主代理时的完整行为框架。结构包括:

  • Tick 处理<tick> 是保活机制,处理最新一条即可
  • Pacing:用 SleepTool 控制动作间隔,无事可做时必须调用 Sleep
  • 首次唤醒:简短问候并等待方向,不要擅自探索代码库
  • 后续唤醒:主动寻找有用的工作,不要重复提问
  • 响应性:用户活跃时保持紧密反馈循环
  • 偏向行动:用最佳判断行动而非请求确认
  • 终端焦点:根据 terminalFocus 调整自主程度

3.8 系统级辅助分节

getHooksSection() -- 行 127-129

单行指令,解释 hooks 是用户配置的 shell 命令(响应工具调用等事件),<user-prompt-submit-hook> 来自用户端。被 hook 阻塞时应尝试调整方法或请用户检查 hooks 配置。被 getSimpleSystemSection() 内部调用。

getSystemRemindersSection() -- 行 131-134

两条规则:<system-reminder> 标签是系统自动添加的有用信息(与具体工具结果或用户消息无关);对话通过自动摘要拥有无限上下文。仅在 PROACTIVE 路径直接使用。

getAntModelOverrideSection() -- 行 136-140

属性
位置动态后缀 #3
缓存systemPromptSection
条件USER_TYPE === 'ant' 且非 undercover

getAntModelOverrideConfig() 获取 ant 内部模型覆盖配置的 defaultSystemPromptSuffix。返回 null 当:非 ant 用户、undercover 模式、或无覆盖配置。

4SYSTEM_PROMPT_DYNAMIC_BOUNDARY 深度解析

4.1 边界标记的定义与语义

export const SYSTEM_PROMPT_DYNAMIC_BOUNDARY =
  '__SYSTEM_PROMPT_DYNAMIC_BOUNDARY__'Copy

这个字符串常量是 Claude Code prompt 缓存架构的核心枢纽。它将 getSystemPrompt() 返回的数组分为两个区域:

区域内容cacheScope特征
静态前缀7 个分节(Intro → OutputEfficiency)'global'跨用户/跨组织可缓存,内容与会话状态无关
动态后缀10+ 分节(SessionGuidance → Brief)null每个会话可能不同,含用户配置/模型/工具集依赖

静态前缀(7 个分节)的顺序

  1. getSimpleIntroSection() -- 身份定义 + 安全指令
  2. getSimpleSystemSection() -- 系统行为规则
  3. getSimpleDoingTasksSection() -- 任务执行指南(条件包含)
  4. getActionsSection() -- 操作风险评估
  5. getUsingYourToolsSection() -- 工具使用偏好
  6. getSimpleToneAndStyleSection() -- 语气与格式
  7. getOutputEfficiencySection() -- 输出效率

动态后缀(10+ 分节)的顺序

  1. session_guidance -- 会话特定引导
  2. memory -- Memory prompt
  3. ant_model_override -- ant 模型覆盖
  4. env_info_simple -- 环境信息
  5. language -- 语言偏好
  6. output_style -- 输出样式
  7. mcp_instructions -- MCP 服务器指令 uncached
  8. scratchpad -- Scratchpad 目录
  9. frc -- Function Result Clearing
  10. summarize_tool_results -- 工具结果摘要提醒
  11. numeric_length_anchors -- 数值长度锚点 ant-only
  12. token_budget -- Token 预算 TOKEN_BUDGET
  13. brief -- Brief 模式 KAIROS

shouldUseGlobalCacheScope() 的条件

export function shouldUseGlobalCacheScope(): boolean {
  return (
    getAPIProvider() === 'firstParty' &&
    !isEnvTruthy(process.env.CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS)
  )
}Copy

仅当 API Provider 是 Anthropic 第一方(非 Bedrock/Vertex/Foundry)且未禁用实验性 beta 时,才启用全局缓存范围。Foundry 被显式排除——GrowthBook 从未将 Foundry 用户纳入 rollout 实验。

4.2 splitSysPromptPrefix 的处理逻辑

splitSysPromptPrefix()utils/api.ts:321)是消费边界标记的关键函数,有三个处理路径:

路径 1:MCP 工具存在(skipGlobalCache=true)

过滤掉边界标记,返回最多 3 个块,全部用 cacheScope: 'org'(不使用全局缓存,因为 MCP 工具是用户特定的):

  • Attribution header(cacheScope: null
  • CLI 系统 prompt 前缀(cacheScope: 'org'
  • 其余拼接(cacheScope: 'org'

路径 2:全局缓存模式 + 边界标记存在

这是最优路径。返回最多 4 个块:

  • Attribution header(cacheScope: null
  • CLI 系统 prompt 前缀(cacheScope: null
  • 边界前静态内容拼接(cacheScope: 'global')-- 跨所有用户共享
  • 边界后动态内容拼接(cacheScope: null)-- 每次重新处理

路径 3:默认模式

3P 提供商或边界缺失时的回退。返回最多 3 个块,全部 org 级缓存。

4.3 为什么不能随意移动分节(PR 教训)

PR #24490 和 #24171 的教训

源码注释(行 343-351)明确警告:getSessionSpecificGuidanceSection 中的每个条件判断都是一个运行时 bit。如果将它放在边界标记之前(静态区域),每个 bit 组合(如 hasAskUserQuestionTool x hasSkillTool x hasAgentTool x ...)都会产生不同的 Blake2b 哈希前缀,导致 2^N 个缓存变体,全局缓存命中率暴跌。

同样的道理,outputStyleConfig 被特意保留在静态区域(虽然它有条件判断),因为"身份定义的开场位置"的 eval 影响更大。但 isForkSubagentEnabled() 因为读取 getIsNonInteractiveSession() 而必须在边界后。

CLI 系统 prompt 前缀(CLI_SYSPROMPT_PREFIXES)也通过内容匹配(而非位置)来识别,定义在 constants/system.ts

const CLI_SYSPROMPT_PREFIX_VALUES = [
  `You are Claude Code, Anthropic's official CLI for Claude.`,
  `You are Claude Code, Anthropic's official CLI for Claude, running within the Claude Agent SDK.`,
  `You are a Claude agent, built on Anthropic's Claude Agent SDK.`,
] as constCopy

三种前缀对应不同的入口场景:默认交互、Agent SDK 中的 CC 预设、纯 Agent SDK 场景。

5systemPromptSections.ts 缓存机制

5.1 缓存 API

SystemPromptSection 类型

type SystemPromptSection = {
  name: string        // 缓存键
  compute: ComputeFn  // () => string | null | Promise<string | null>
  cacheBreak: boolean // true = 每个 turn 重新计算
}

type ComputeFn = () => string | null | Promise<string | null>Copy

systemPromptSection(name, compute) -- 缓存版

返回 { name, compute, cacheBreak: false }。计算一次后缓存到 /clear/compact 触发 clearSystemPromptSections()

DANGEROUS_uncachedSystemPromptSection(name, compute, _reason) -- 非缓存版

返回 { name, compute, cacheBreak: true }。每个 turn 重新计算。_reason 参数是文档用途——强制调用者解释为什么需要打破缓存。

5.2 resolveSystemPromptSections 并行解析

export async function resolveSystemPromptSections(
  sections: SystemPromptSection[],
): Promise<(string | null)[]> {
  const cache = getSystemPromptSectionCache()   // Map<string, string | null>

  return Promise.all(
    sections.map(async s => {
      if (!s.cacheBreak && cache.has(s.name)) {
        return cache.get(s.name) ?? null       // 缓存命中
      }
      const value = await s.compute()             // 计算
      setSystemPromptSectionCacheEntry(s.name, value) // 写入缓存
      return value
    }),
  )
}Copy

所有分节的计算通过 Promise.all 并行执行。缓存存储在 STATE.systemPromptSectionCachebootstrap/state.ts:1641),是一个简单的 Map<string, string | null>

clearSystemPromptSections() -- 缓存清除

export function clearSystemPromptSections(): void {
  clearSystemPromptSectionState()  // Map.clear()
  clearBetaHeaderLatches()         // 重置 beta 头锁存
}Copy

/clear/compact 时调用,确保新对话获得最新的评估结果。同时重置 beta header latches,让 AFK/fast-mode/cache-editing 头在新对话中重新评估。

5.3 分节缓存类型矩阵

分节名称缓存策略说明
session_guidancecached工具集/技能在会话内不变
memorycachedMemory prompt 在会话内稳定
ant_model_overridecached模型覆盖在会话内不变
env_info_simplecached环境信息在会话内不变
languagecached语言设置在会话内不变
output_stylecached样式在会话内不变
mcp_instructionsDANGEROUS_uncachedMCP 服务器在 turn 间连接/断开
scratchpadcachedScratchpad 路径在会话内固定
frccachedMicro-compact 配置在会话内稳定
summarize_tool_resultscached静态文本
numeric_length_anchorscached静态文本(ant-only)
token_budgetcached曾用 DANGEROUS_uncached,改为 cached 以避免 ~20K token/次的缓存失效
briefcachedBrief 状态在会话内稳定
token_budget 的演变

注释明确记录:此分节曾经是 DANGEROUS_uncached(根据 getCurrentTurnTokenBudget() 切换),会在每次预算切换时破坏约 20K token 的 prompt cache。改为 cached + "When the user specifies..." 的条件措辞后,即使无预算时该文本也是无害的 no-op,同时消除了缓存失效。

6输出样式系统

6.1 OutputStyleConfig 类型定义

export type OutputStyleConfig = {
  name: string                       // 样式名称
  description: string                // 用户可见描述
  prompt: string                     // 注入系统 prompt 的指令文本
  source: SettingSource | 'built-in' | 'plugin'
  keepCodingInstructions?: boolean  // true = 保留 "Doing tasks" 分节
  forceForPlugin?: boolean         // true = 插件强制启用此样式
}Copy

keepCodingInstructions 是一个关键字段:当自定义输出样式完全改变了 Claude 的身份定位(如"你是一个诗人")时,保留"Doing tasks"分节中的编程指南是无意义的。设为 false 或未设置时,getSimpleDoingTasksSection() 将被跳过。

6.2 三种内置样式

default(null)

OUTPUT_STYLE_CONFIG['default'] 返回 null——表示不注入任何特殊输出样式 prompt。这是最常见的路径。

Explanatory(教学模式)

keepCodingInstructions: true。在正常编程辅助基础上,添加"Insights"教育性解释板块——代码前后提供 2-3 个与当前代码库相关的教育要点,使用特殊的星标格式渲染。

Learning(学习模式)

keepCodingInstructions: true。最复杂的内置样式。核心机制是"Learn by Doing"——当生成 20+ 行涉及设计决策、业务逻辑或关键算法的代码时,要求用户自己写 2-10 行。包含完整的请求格式模板、TodoList 集成指南、三个示例(整函数、部分函数、调试)和贡献后洞察分享规则。

6.3 自定义样式加载

getOutputStyleDirStyles(cwd) -- loadOutputStylesDir.ts

.claude/output-styles/*.md 目录(项目级和用户级)加载 Markdown 文件,解析 frontmatter 获取 name/description/keepCodingInstructions,文件内容作为 prompt。使用 memoize 缓存结果。

getAllOutputStyles(cwd) -- outputStyles.ts:137

合并所有来源的样式,优先级从低到高:

  1. 内置样式(built-in)
  2. 插件样式(plugin)
  3. 用户设置样式(userSettings)
  4. 项目设置样式(projectSettings)
  5. 托管设置样式(policySettings)-- 最高优先级

6.4 getOutputStyleConfig() 选择逻辑

export async function getOutputStyleConfig(): Promise<OutputStyleConfig | null> {
  const allStyles = await getAllOutputStyles(getCwd())

  // 1. 检查插件强制样式
  const forcedStyles = Object.values(allStyles).filter(
    style => style?.source === 'plugin' && style.forceForPlugin === true
  )
  if (forcedStyles[0]) return forcedStyles[0]  // 多个时用第一个,log warn

  // 2. 读取用户设置
  const outputStyle = settings?.outputStyle || 'default'
  return allStyles[outputStyle] ?? null
}Copy

优先级链:插件强制样式 > 用户/项目设置 > default(null)。多个插件有强制样式时仅使用第一个并记录警告。

7上下文注入 (context.ts)

7.1 getSystemContext()

export const getSystemContext = memoize(
  async (): Promise<{ [k: string]: string }> => {
    // 跳过 git status: CCR 模式或 git 指令被禁用时
    const gitStatus = isRemote || !shouldIncludeGitInstructions()
      ? null : await getGitStatus()

    // 系统 prompt 注入(ant-only,用于缓存打破)
    const injection = feature('BREAK_CACHE_COMMAND')
      ? getSystemPromptInjection() : null

    return {
      ...(gitStatus && { gitStatus }),
      ...(injection ? { cacheBreaker: `[CACHE_BREAKER: ${injection}]` } : {}),
    }
  },
)Copy

getGitStatus()(同文件 :36-111)通过 5 路 Promise.all 并行执行 git 命令:branchdefaultBranchstatus --shortlog --oneline -n 5config user.name。状态超过 2000 字符时截断并附加提示。整个结果被 memoize 缓存,会话期间只执行一次。

缓存失效机制

setSystemPromptInjection(value) 同时清除 getUserContext.cachegetSystemContext.cache,确保注入变更时上下文立即刷新。

7.2 getUserContext()

export const getUserContext = memoize(
  async (): Promise<{ [k: string]: string }> => {
    // CLAUDE_CODE_DISABLE_CLAUDE_MDS: 硬关闭
    // --bare: 跳过自动发现,但尊重 --add-dir
    const shouldDisable = isEnvTruthy(process.env.CLAUDE_CODE_DISABLE_CLAUDE_MDS)
      || (isBareMode() && getAdditionalDirectoriesForClaudeMd().length === 0)

    const claudeMd = shouldDisable
      ? null
      : getClaudeMds(filterInjectedMemoryFiles(await getMemoryFiles()))

    setCachedClaudeMdContent(claudeMd || null)  // 供 yoloClassifier 使用

    return {
      ...(claudeMd && { claudeMd }),
      currentDate: `Today's date is ${getLocalISODate()}.`,
    }
  },
)Copy

关键设计决策:

  • CLAUDE.md 加载:通过 getMemoryFiles() 发现所有 CLAUDE.md 文件(全局、项目、用户级),经 filterInjectedMemoryFiles() 过滤掉已通过 Memory 系统注入的文件,最终由 getClaudeMds() 格式化为上下文文本
  • currentDate 注入:使用 getLocalISODate()(非 memoized 版本),每次调用获取实时日期。但由于 getUserContext 本身被 memoize,日期实际上在首次调用时冻结
  • --bare 模式语义:"跳过我没要求的东西",不是"忽略我要求的东西"——--add-dir 指定的目录仍然被尊重
  • 缓存副作用setCachedClaudeMdContent() 将 CLAUDE.md 内容缓存到全局状态,供 yoloClassifier.ts 读取(避免循环依赖:permissions/filesystem -> permissions -> yoloClassifier)

8Memory Prompt 构建 (memdir/memdir.ts)

8.1 MEMORY.md 截断规则

export const MAX_ENTRYPOINT_LINES = 200
export const MAX_ENTRYPOINT_BYTES = 25_000  // ~125 chars/line at 200 linesCopy

truncateEntrypointContent(raw) 实现双重截断:

  1. 先行截断:如果超过 200 行,取前 200 行
  2. 后字节截断:如果截断后仍超过 25000 字节,在最后一个换行符处切断(避免行中截断)

截断时附加警告信息,说明触发原因(行数超限、字节超限、或两者皆超)。设计目标:捕获那些单行很长、虽在 200 行内但已达 197KB 的极端索引文件(p100 观测值)。

8.2 buildMemoryLines() 完整结构

buildMemoryLines(displayName, memoryDir, extraGuidelines, skipIndex) 构建行为指令(不含 MEMORY.md 内容),返回 string[]。完整结构如下:

  1. # {displayName} 标题 + 目录路径 + DIR_EXISTS_GUIDANCE("目录已存在,直接写入")
  2. 总体描述:建立记忆系统的目的
  3. 显式记忆保存/遗忘指令
  4. ## Types of memoryTYPES_SECTION_INDIVIDUAL)-- 四类记忆的 XML 结构化定义
  5. ## What NOT to save in memoryWHAT_NOT_TO_SAVE_SECTION
  6. ## How to save memories -- 两步流程(写文件 + 更新 MEMORY.md 索引),或单步流程(skipIndex=true
  7. ## When to access memoriesWHEN_TO_ACCESS_SECTION
  8. ## Before recommending from memoryTRUSTING_RECALL_SECTION)-- 记忆验证规则
  9. ## Memory and other forms of persistence -- 记忆 vs 计划 vs 任务的区分
  10. 可选:extraGuidelines(如 Cowork 注入的额外策略)
  11. 可选:## Searching past contexttengu_coral_fern feature flag)

ensureMemoryDirExists(memoryDir)

幂等目录创建。fs.mkdir 递归创建(内部已处理 EEXIST)。由 loadMemoryPrompt() 调用(通过 systemPromptSection 缓存,每会话只执行一次)。确保模型可以直接写入而无需检查目录存在。

8.3 内存类型定义

类型描述何时保存
user用户角色、目标、职责、知识水平了解到用户详情时
feedback用户对工作方式的修正和确认纠正("不要这样")或确认("对,就是这样")时
project进行中的工作、目标、事件、bug(非代码可推导)了解谁在做什么、为什么、截止日期时
reference外部系统信息指针(Linear、Slack、Grafana 等)了解到外部资源位置时

WHAT_NOT_TO_SAVE_SECTION 核心内容

  • 代码模式、架构、文件路径——可从项目当前状态推导
  • Git 历史——git log / git blame 是权威来源
  • 调试解决方案——修复在代码中,上下文在 commit message 中
  • CLAUDE.md 中已记录的内容
  • 临时任务细节
  • 即使用户明确要求也适用——如果用户要求保存 PR 列表,应追问"什么是令人惊讶或不显而易见的"

TRUSTING_RECALL_SECTION(记忆验证规则)

eval 验证的关键洞察(memory-prompt-iteration case 3, 0/2 -> 3/3):

  • 记忆中命名的文件路径——使用前检查文件是否存在
  • 记忆中命名的函数或 flag——使用前 grep 确认
  • "记忆说 X 存在"不等于"X 现在存在"
  • 仓库状态摘要是时间冻结的快照——询问"最近"或"当前"状态时,优先用 git log 或读代码

loadMemoryPrompt() 的调度逻辑

根据启用的内存系统选择不同的构建路径:

  1. KAIROS + autobuildAssistantDailyLogPrompt()——追加式日志模式,写入 logs/YYYY/MM/YYYY-MM-DD.md
  2. TEAMMEM + auto + teambuildCombinedMemoryPrompt()——私有 + 团队双目录
  3. auto onlybuildMemoryLines()——单目录个人记忆
  4. 全部禁用:返回 null,记录遥测

9特性门控清单

9.1 Feature Flags 列表(从代码提取)

Feature Flag控制的分节/行为类型
CACHED_MICROCOMPACTgetFunctionResultClearingSection + getCachedMCConfig 条件导入bun:bundle DCE
PROACTIVEproactiveModule 条件导入 + 整个 PROACTIVE 路径bun:bundle DCE
KAIROSproactiveModule 导入 + PROACTIVE 路径 + Brief 分节 + 日志模式记忆bun:bundle DCE
KAIROS_BRIEFBRIEF_PROACTIVE_SECTION 导入 + Brief 分节bun:bundle DCE
EXPERIMENTAL_SKILL_SEARCHDiscoverSkillsTool 导入 + getDiscoverSkillsGuidance()bun:bundle DCE
VERIFICATION_AGENT验证代理规则注入(session_guidance 内)bun:bundle DCE
TOKEN_BUDGETtoken_budget 分节bun:bundle DCE
BREAK_CACHE_COMMANDsystemPromptInjection 缓存打破(context.ts)bun:bundle DCE
TEAMMEMteamMemPaths/teamMemPrompts 条件导入(memdir.ts)bun:bundle DCE
NATIVE_CLIENT_ATTESTATIONAttribution header 中的 cch 占位符bun:bundle DCE

GrowthBook Flags(运行时)

Flag控制
tengu_hive_evidence验证代理是否启用(ant-only A/B)
tengu_coral_fern"Searching past context" 分节
tengu_moth_copseskipIndex(记忆不维护 MEMORY.md 索引)
tengu_herring_clock团队记忆 cohort 遥测
tengu_attribution_headerAttribution header 启用/禁用

环境变量 Flags

环境变量效果
CLAUDE_CODE_SIMPLE极简模式,跳过所有复杂逻辑
CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS禁用全局缓存范围
CLAUDE_CODE_DISABLE_CLAUDE_MDS禁用 CLAUDE.md 加载
CLAUDE_CODE_DISABLE_AUTO_MEMORY禁用自动记忆
CLAUDE_CODE_OVERRIDE_DATE覆盖日期(ant-only 测试)
CLAUDE_CODE_REMOTE远程模式,跳过 git status
CLAUDE_COWORK_MEMORY_EXTRA_GUIDELINESCowork 注入的额外记忆策略
USER_TYPE'ant' = Anthropic 内部用户

9.2 ant vs 非 ant 差异矩阵

分节/行为ant外部
注释风格(DoingTasks)4 条极简规则:默认不写注释、不解释 WHAT、不删已有注释、完成前验证无额外规则
OutputEfficiency"Communicating with the user"——长篇叙事式指导"Output efficiency"——简洁指令
ToneAndStyle不含"be short and concise"含"be short and concise"
False-claims 缓解如实报告规则(不隐瞒失败、不虚称通过)
主动性提示"你是协作者不只是执行者"
Bug 报告引导/issue 或 /share 建议 + Slack 频道发送
numeric_length_anchors工具调用间文本 ≤25 词,最终回复 ≤100 词
AntModelOverride可能注入模型覆盖 prompt 后缀
Undercover 模式隐藏所有模型名称/IDN/A

10与 AI-Fleet 的对照分析

10.1 对比矩阵

维度Claude Code (prompts.ts)AI-Fleet (CLAUDE.md + .claude/rules/)
架构模式 运行时编排器——TypeScript 函数动态组装 string[],每个分节独立计算 静态声明式——Markdown 文件由 CLI harness 全文加载到 T0/T1 层
缓存机制 三层:全局缓存(SYSTEM_PROMPT_DYNAMIC_BOUNDARY)+ 分节 memoization(systemPromptSections.ts)+ 函数 memoize(context.ts) 无显式缓存层;依赖 Claude 的 KV-cache 隐式复用(规则:静态常量放前面,动态变量放后面)
条件组装 每个分节函数独立返回 string | null,feature flags + 运行时条件驱动 粗粒度条件——rules-on-demand 按任务类型整体加载(04/07/10/11),无分节级开关
身份多态 三路模式(SIMPLE / PROACTIVE / 标准),outputStyle 可完全改变身份 单一身份("业财税合规产品经理助手"),通过 Skill 切换行为而非身份
内存系统 四类型记忆(user/feedback/project/reference)+ MEMORY.md 索引 + 截断规则 + 日志模式 MEMORY.md + memory/*.md 文件(T2 按需加载),无类型分类,无截断机制
上下文管理 编译时 DCE(bun:bundle feature())+ 运行时 GrowthBook flags + env vars 手动分层(T0 Auto-mount / T1 Index-mount / T2 Query-mount / T3 Immutable)+ context_monitor.py 阈值监控
工具引导 根据 enabledTools Set 动态生成工具偏好规则,REPL 模式有独立路径 TOOLBOX.md 静态描述 + Skill 路由器(semantic_skill_router.py)

10.2 可借鉴的改进方向

方向 1:分节级缓存标记

CC 的 systemPromptSection() / DANGEROUS_uncachedSystemPromptSection() 模式值得借鉴。AI-Fleet 的 .claude/rules/ 文件全部在 T0 层始终加载(约 19K token / ~10%),但其中有些内容(如 04-frontend-validation.md)只在前端任务时需要。引入类似的缓存/按需标记机制,可以将 T0 负载降低 30-40%。

方向 2:动态边界协议

CC 的 SYSTEM_PROMPT_DYNAMIC_BOUNDARY 将静态指令和会话特定内容物理分离,使得 API 层可以对静态部分使用全局缓存。AI-Fleet 虽然在 06-context-engineering.md 中提到"静态常量在 prompt 开头,动态变量在末尾"的 KV-Cache 保护规则,但缺少显式的边界标记和自动化的缓存分区。可以在 CLAUDE.md 中引入类似的 boundary marker,配合 API wrapper 自动分区。

方向 3:记忆类型分类

CC 的四类记忆(user/feedback/project/reference)+ "什么不应该保存" + "推荐前验证"三层约束系统,比 AI-Fleet 当前的自由形式 memory/*.md 更加结构化。特别是 TRUSTING_RECALL_SECTION("记忆说文件存在不等于文件现在存在")的验证规则,直接解决了记忆漂移问题。AI-Fleet 的 context_monitor.py 监控上下文利用率,但缺少记忆内容的质量约束。

方向 4:条件组装替代全文加载

AI-Fleet 的 .claude/rules/01-11 是"始终加载 + 按需加载"二分法。CC 的模式更细粒度——同一文件内的不同段落根据 feature flag 和运行时条件动态包含/排除。这种模式在 Skill 系统中特别有价值:一个 Skill 的不同章节可以根据当前上下文选择性注入,而非整个 SKILL.md 要么全加载要么全不加载。

方向 5:DANGEROUS_ 前缀命名规范

CC 用 DANGEROUS_uncachedSystemPromptSection 这个刻意恐吓的名字来阻止开发者随意打破缓存,且强制提供 _reason 参数。这种"通过命名制造摩擦"的设计模式值得在 AI-Fleet 的 Harness 层采用——比如 DANGEROUS_forceCompact(reason: string) 替代 forceCompact()

Layer 1: Prompt Assembly Architecture -- Claude Code 源码深度拆解

Maurice | maurice_wen@proton.me

Generated 2026-03-31 | Source: claude-code-rev/src/constants/prompts.ts (914 lines) + satellite modules