claude-code/docs/agentic-design/06-feature-gating.md
Claude 808d5a61b3
docs: Add comprehensive agentic design documentation (2.5-hour learning session)
新增 docs/agentic-design/ 教育文档,全中文+英文技术术语,覆盖:

- README.md: 总索引,整体架构图,阅读指南
- 00-codebase-tour.md: 代码库全景,递归覆盖所有重要目录
- 01-agent-loop.md: Query loop 状态机,token budget,compaction
- 02-tool-system.md: Tool interface,权限检查,并发执行,sibling abort
- 03-multi-agent-coordination.md: Agent 类型,coordinator 4 阶段,XML 通信
- 04-permission-system.md: Permission mode,rule system,YOLO 分类器,denial tracking
- 05-context-and-memory.md: System prompt 分层,compaction,auto-dream 后台巩固
- 06-feature-gating.md: Compile-time feature,runtime flags,Bun dead-code elimination

总计 ~2.5 小时阅读,每篇含 Design Decision 专栏和常见误解纠正

https://claude.ai/code/session_017Vdqo9B8eTXiEDcqnv9DxM
2026-03-31 16:07:29 +00:00

9.8 KiB
Raw Blame History

Feature Gating内部功能和公开功能的隔离

为什么需要 Feature Gating?

Claude Code 是一个复杂系统,有很多功能:

  • 一些已发布、稳定、所有用户可用
  • 一些还在测试、只给内部用户("ant" 用户)
  • 一些只给特定高级用户Max/Pro)
  • 一些通过实验 A/B 测试

如果不做隔离,代码会变得一团糟:

// 不好的做法
if (user.isInternal) {
  // KAIROS 模式逻辑
} else if (user.isMax) {
  // 高级功能
} else if (featureFlags.has('experimental_search')) {
  // A/B 测试
} else {
  // 默认行为
}
// ... 这样嵌套太深,难以维护

Claude Code 的解决方案:编译期和运行期双层 gating


编译期 GatingBun 的 feature() API

BunJavaScript 运行时)提供了一个编译期特性检测 API

if (feature("KAIROS")) {
  // 这段代码只在 KAIROS 构建中出现
  // 其他构建完全不包含这代码
} else {
  // 默认行为
}

工作原理

源代码:
  if (feature("KAIROS")) {
    launchKAIROS()
  } else {
    launchDefault()
  }
      ↓ Bun 编译(--feature KAIROS
  if (true) {
    launchKAIROS()  // 只保留这段
  } else {
    // 被 dead code elimination 删除
  }
      ↓ 输出的二进制
  launchKAIROS()  // 这是最终的可执行代码

优势

  1. 二进制体积小:内部功能完全不包含在公开二进制中
  2. 安全:用户不能"解锁"内部功能(不存在于二进制)
  3. 性能:不需要运行时检查这些条件

相关代码散布在整个 codebase 中,比如 entrypoints/cli.tsx, bootstrap/state.ts


Compile-Time Feature 列表

Claude Code 在构建时支持这些 feature flag

Flag 启用时 作用
KAIROS 启动 KAIROS modealways-on Claude 全天候 assistant
PROACTIVE 同上(别名) 同上
BRIDGE_MODE 启用 claude.ai 远程控制 在 Web UI 中控制 CLI
VOICE_MODE 启用语音输入 用话筒说指令
DAEMON 启用 daemon 模式 后台运行的 Claude
COORDINATOR_MODE 启用 coordinator 多 agent 复杂任务分解
BUDDY 启用 Tamagotchi 伴侣系统 养一个宠物 AI
WORKFLOW_SCRIPTS 启用工作流脚本 自动化重复任务
NATIVE_CLIENT_ATTESTATION 启用本地证明 设备信任
TRANSCRIPT_CLASSIFIER 启用 AFK 自动模式 离开电脑时自动工作
HISTORY_SNIP 启用历史压缩优化 Context 更高效
EXPERIMENTAL_SKILL_SEARCH 启用技能搜索(实验) 发现新 skill 命令
ABLATION_BASELINE 科学研究 baseline 论文用

默认只编译:KAIROS=0, BRIDGE_MODE=0, ...(全是 0最小二进制

内部构建时:编译脚本设置 --feature KAIROS=1 --feature BRIDGE_MODE=1 ...

相关文件:构建脚本(如 scripts/build.sh,如果存在),或 bunfig.toml


运行期 GatingGrowthBook Feature Flags

编译期 feature 决定"可能性",运行期 flags 决定"激活"。

系统启动时,从 GrowthBook特性管理平台获取动态配置

// 启动时
const flags = await growthbook.getFeatures({
  userId: currentUser.id,
  organization: currentUser.org
})

// 现在可以做运行期决策
if (flags.has('tengu_scratch')) {
  // 启用共享 scratchpadcoordinator 模式)
  enableScratchpad()
}

if (flags.has('tengu_amber_flint')) {
  // 启用 in-process teammate swarms
  enableTeammates()
}

if (flags.has('tengu_penguins_off')) {
  // 禁用某个实验
  disableExperiment()
}

Flag 命名约定

Runtime flags 以 tengu_ 开头("tengu" 是 Claude Code 的内部代号):

tengu_scratch              # 共享 scratchpad为 coordinator
tengu_amber_flint          # In-process teammate
tengu_onyx_plover          # 某个实验
tengu_penguins_off         # 禁用什么功能
...

这样容易区分:

  • KAIROS编译期vs tengu_kairos_v2(运行期)

相关文件:bootstrap/state.ts(初始化),services/analytics/GrowthBook 集成)


两层系统的协作

场景 1Compile-Time Only最常见

新功能 KAIROSalways-on Claude
  ↓ 编译
  ├─ 构建 ant内部--feature KAIROS=1
  │   → KAIROS 代码被编译进去
  │
  └─ 构建 public公开--feature KAIROS=0
      → KAIROS 代码被 dead-code-elimination 删除
      → 二进制不含任何痕迹

场景 2Compile-Time + Runtime用于 A/B 测试)

新的 memory 系统(已编译进去)
  ↓ 运行时
  ├─ 用户在 tengu_new_memory=true 组50%
  │   → 使用新系统
  │
  └─ 用户在 tengu_new_memory=false 组50%
      → 使用旧系统
      → 收集对比数据

场景 3运行期特定用户

高级功能(编译期编译进去)
  ↓ 运行时
  ├─ Max 订阅用户 → 启用计算机使用
  ├─ Pro 订阅用户 → 启用高级 memory
  └─ 免费用户 → 基础功能

相关文件:services/policyLimits/(根据订阅级别应用 policy


对 System Prompt 的影响

Feature gating 会改变 system prompt 的内容:

const systemPrompt = [
  BASE_PROMPT,

  // 只有在编译时启用 BRIDGE_MODE 时才包含
  feature("BRIDGE_MODE") ? BRIDGE_MODE_INSTRUCTIONS : "",

  // 运行时检查:如果用户有 tengu_coordinator flag
  flags.get("tengu_coordinator") ? COORDINATOR_INSTRUCTIONS : "",

  // 运行时 API beta 特性
  BETAS_NEGOTIATED_WITH_API,  // 如 "interleaved_thinking"
]

这也影响 prompt cache

缓存键 = MD5(system_prompt_prefix)

如果 flag 变化cache key 变化,旧 cache 失效

所以,高频变化的 runtime flag 应该放在 cache boundary 之后(动态部分),而不是之前(静态部分)。


Betas 协商

Claude API 定期发布新特性betaClaude Code 需要:

  1. 请求启用这些 beta
  2. 如果启用,在 system prompt 中告诉 Claude这个 API 支持什么新功能)

例子:

// constants/betas.ts
const BETAS_REQUESTED = [
  "interleaved-thinking",        // 支持在回复中穿插思考
  "structured-outputs",           // 支持返回结构化 JSON
  "context-1m",                   // 100 万 token context
  "web-search",                   // 网络搜索能力
]

// API 返回确认
const BETAS_ENABLED = [
  "interleaved-thinking",         // ✓ 已启用
  // "structured-outputs",        // ✗ 暂无权限
  "context-1m",                   // ✓ 已启用
  "web-search",                   // ✓ 已启用
]

// System prompt 中加入这些信息
You have access to the following beta features:
  - Interleaved thinking: You can output <thinking> blocks
  - Context 1M: You can use up to 1,000,000 tokens
  - Web search: You can call the WebSearchTool

相关文件:constants/betas.ts


Design Decision 专栏

为什么同时用编译期和运行期?

只用编译期:

缺点:无法做快速的 A/B 测试(需要重新编译)
      无法根据用户身份动态启用功能

只用运行期:

缺点:内部功能可能被反编译/逆向工程
      内部代码暴露在公开二进制中
      启动时需要网络请求拿 flags

两者结合:

编译期决定"可能性"(物理隔离内部代码)
运行期决定"激活"(灵活的 A/B 测试)
最安全、最灵活

为什么 Bun 的 feature() 而不是其他工具?

Bun 的 feature() 是编译期指令,会进行 dead code elimination

其他工具(如 rollup 的条件编译):
  需要额外的 webpack 插件
  编译配置复杂

Bun:
  原生支持
  编译快Bun 本身就快)
  输出体积最小

常见误解

误解 1"Runtime flag 可以改变编译期行为?"

实际不能。Runtime flag 只能在编译期已包含的代码中做选择。如果代码在编译时被 dead-code-elimination 删除了,运行时再想启用也没办法。

// 如果编译时 --feature KAIROS=0这段代码被删除
if (feature("KAIROS")) {
  launchKAIROS()
}

// 运行时即使 growthbook.flags.get("enable_kairos") == true也没用
// 代码不存在于二进制中

误解 2"Feature flag 对性能有开销?"

实际:编译期 feature flag 没有开销(代码级别选择)。运行期 flag 有极小开销map lookup可忽略不计。

误解 3"所有用户都能看到内部代码?"

实际:不能。公开二进制中编译时被删除的代码,用户看不到。只有 ant内部用户的二进制才包含这些代码。


关键要点

  1. 编译期 featureBun 的 feature() APIdead code elimination对二进制体积和安全性的保障
  2. 运行期 flagsGrowthBook动态启用特性支持 A/B 测试
  3. 两层协作:编译决定可能性,运行时决定激活
  4. System prompt 影响:不同 flag 组合 → 不同 system prompt → 不同 cache key
  5. API Beta:协商启用新的 Claude API 特性,在 system prompt 中告诉 Claude

深入阅读

  • bootstrap/state.ts:运行时 flag 初始化56 KB
  • constants/betas.tsBeta feature 列表
  • constants/system.tsconstants/systemPromptSections.tsSystem prompt 组装
  • entrypoints/cli.tsx:编译期条件编译示例

后记

这 6 篇文档覆盖了 Claude Code 最核心的 agentic 设计决策。还有很多其他话题Bridge 模式、Voice 输入、Plugin 系统等),但这些是最重要的基础。

如果你想进一步了解,建议:

  1. 读完这 6 篇
  2. 打开 query.tsTool.ts,对照源代码
  3. 运行 Claude Code--verbose flag 看内部日志
  4. 探索 tools/AgentTool/ 的源代码

祝学习愉快!