Feature Flags (Build-Time)
- Entity ID:
ent-20260410-4e2d6754780c - Type:
concept - Scope:
shared - Status:
active
Description
Claude Code uses build-time feature flags to gate entire subsystems, tools, commands, and code paths. The mechanism centers on a feature(name) function imported from the bun:bundle module. In production Bun builds, feature() calls resolve to compile-time boolean constants, and Bun's bundler performs dead-code elimination (DCE): code inside inactive if (feature('FLAG')) branches is stripped entirely from the output, including any string literals, require() calls, and GrowthBook flag references those branches contain. This prevents Anthropic-internal feature names from leaking into external builds.
In development, the bun:bundle import is intercepted by a Bun preload plugin (scripts/bun-plugin-shims.ts) that resolves it to src/shims/bun-bundle.ts. This shim maintains a FEATURE_FLAGS map where each flag reads from an environment variable (e.g., CLAUDE_CODE_PROACTIVE) via the envBool() helper, defaulting to false. For the esbuild-based production build (scripts/build-bundle.ts), bun:bundle is aliased to the same shim file.
The codebase contains approximately 91 distinct feature flags referenced via feature() calls. Flags gate behavior at multiple levels: CLI entrypoint routing, slash-command registration, tool availability, system prompt composition, keybinding registration, UI component rendering, and module-level conditional require() imports.
Two-layer gating pattern
Many features use a two-layer gating pattern: a build-time feature() check (eliminates dead code) wrapping a runtime GrowthBook/Statsig check (controls rollout and kill-switch). The code comments refer to a "positive ternary pattern" where the feature check is written as return feature('X') ? runtimeCheck() : false rather than if (!feature('X')) return; ..., because the negative pattern fails to eliminate inline string literals from external builds.
Flag categories
Always-on subsystem flags (registered in the shim with env-var fallbacks):
| Flag | Env var | What it gates |
|---|---|---|
PROACTIVE |
CLAUDE_CODE_PROACTIVE |
Proactive agent mode: SleepTool, proactive prompts, auto-mode notifications |
KAIROS |
CLAUDE_CODE_KAIROS |
Always-on assistant mode: daily-log prompts, session resume, assistant module, BriefTool, SendUserFileTool, PushNotificationTool, channel notifications |
KAIROS_BRIEF |
CLAUDE_CODE_KAIROS_BRIEF |
Brief-mode subset of Kairos: BriefTool visibility, brief-only rendering, keybindings |
KAIROS_GITHUB_WEBHOOKS |
CLAUDE_CODE_KAIROS_GITHUB_WEBHOOKS |
GitHub PR subscription via SubscribePRTool |
BRIDGE_MODE |
CLAUDE_CODE_BRIDGE_MODE |
IDE bridge / Remote Control: bridge commands, REPL bridge, entitlement checks (requires claude.ai subscription + GrowthBook gate tengu_ccr_bridge) |
DAEMON |
CLAUDE_CODE_DAEMON |
Background daemon worker: --daemon-worker CLI path, remote-control server command |
VOICE_MODE |
CLAUDE_CODE_VOICE_MODE |
Voice I/O: voice commands, push-to-talk keybinding, STT streaming, VoiceIndicator, voice integration hooks (requires Anthropic OAuth) |
AGENT_TRIGGERS |
CLAUDE_CODE_AGENT_TRIGGERS |
Scheduled/triggered actions: CronCreateTool, CronDeleteTool, CronListTool, cron scheduler, cron jitter config |
MONITOR_TOOL |
CLAUDE_CODE_MONITOR_TOOL |
MonitorTool for streaming background process events |
COORDINATOR_MODE |
CLAUDE_CODE_COORDINATOR_MODE |
Multi-agent coordinator: coordinator module, in-process teammate tools, session mode matching (also requires CLAUDE_CODE_COORDINATOR_MODE env var at runtime) |
ABLATION_BASELINE |
hardcoded false |
Harness-science ablation: sets env vars to disable thinking, compaction, auto-memory, background tasks. Always off in external builds. |
DUMP_SYSTEM_PROMPT |
CLAUDE_CODE_DUMP_SYSTEM_PROMPT |
--dump-system-prompt CLI flag for prompt sensitivity evals |
BG_SESSIONS |
CLAUDE_CODE_BG_SESSIONS |
Background sessions: ps, logs, attach, kill, --bg/--background CLI commands |
HISTORY_SNIP |
CLAUDE_CODE_HISTORY_SNIP |
SnipTool, /force-snip command, history snipping in message rendering |
WORKFLOW_SCRIPTS |
CLAUDE_CODE_WORKFLOW_SCRIPTS |
WorkflowTool, /workflows command, bundled workflow initialization |
CCR_REMOTE_SETUP |
CLAUDE_CODE_CCR_REMOTE_SETUP |
/web remote-setup command |
EXPERIMENTAL_SKILL_SEARCH |
CLAUDE_CODE_EXPERIMENTAL_SKILL_SEARCH |
Skill search in system prompt, skill index cache clearing, attachment skill search |
ULTRAPLAN |
CLAUDE_CODE_ULTRAPLAN |
/ultraplan command |
TORCH |
CLAUDE_CODE_TORCH |
/torch command |
UDS_INBOX |
CLAUDE_CODE_UDS_INBOX |
Unix domain socket inbox, ListPeersTool, /peers command |
FORK_SUBAGENT |
CLAUDE_CODE_FORK_SUBAGENT |
/fork command (replaces fork as alias for /branch) |
BUDDY |
CLAUDE_CODE_BUDDY |
CompanionSprite UI, buddy notifications, buddy prompt injection |
MCP_SKILLS |
CLAUDE_CODE_MCP_SKILLS |
MCP skill fetching, skill-based resource discovery |
REACTIVE_COMPACT |
CLAUDE_CODE_REACTIVE_COMPACT |
Reactive compaction in auto-compact and /compact |
Additional flags found only via feature() calls in source (not in the shim -- likely defined in internal Bun build configs or added after the shim snapshot):
AGENT_MEMORY_SNAPSHOT, AGENT_TRIGGERS_REMOTE, ALLOW_TEST_VERSIONS, ANTI_DISTILLATION_CC, AUTO_THEME, AWAY_SUMMARY, BASH_CLASSIFIER, BREAK_CACHE_COMMAND, BUILDING_CLAUDE_APPS, BUILTIN_EXPLORE_PLAN_AGENTS, BYOC_ENVIRONMENT_RUNNER, CACHED_MICROCOMPACT, CCR_AUTO_CONNECT, CCR_MIRROR, CHICAGO_MCP, COMMIT_ATTRIBUTION, COMPACTION_REMINDERS, CONNECTOR_TEXT, CONTEXT_COLLAPSE, COWORKER_TYPE_TELEMETRY, DIRECT_CONNECT, DOWNLOAD_USER_SETTINGS, ENHANCED_TELEMETRY_BETA, EXTRACT_MEMORIES, FILE_PERSISTENCE, HARD_FAIL, HISTORY_PICKER, HOOK_PROMPTS, IS_LIBC_GLIBC, IS_LIBC_MUSL, KAIROS_CHANNELS, KAIROS_DREAM, KAIROS_PUSH_NOTIFICATION, LODESTONE, MCP_RICH_OUTPUT, MEMORY_SHAPE_TELEMETRY, MESSAGE_ACTIONS, NATIVE_CLIENT_ATTESTATION, NATIVE_CLIPBOARD_IMAGE, NEW_INIT, OVERFLOW_TEST_TOOL, PERFETTO_TRACING, POWERSHELL_AUTO_MODE, PROMPT_CACHE_BREAK_DETECTION, QUICK_SEARCH, REVIEW_ARTIFACT, RUN_SKILL_GENERATOR, SELF_HOSTED_RUNNER, SHOT_STATS, SKILL_IMPROVEMENT, SLOW_OPERATION_LOGGING, SSH_REMOTE, STREAMLINED_OUTPUT, TEAMMEM, TEMPLATES, TERMINAL_PANEL, TOKEN_BUDGET, TRANSCRIPT_CLASSIFIER, TREE_SITTER_BASH, TREE_SITTER_BASH_SHADOW, ULTRATHINK, UNATTENDED_RETRY, UPLOAD_USER_SETTINGS, VERIFICATION_AGENT, WEB_BROWSER_TOOL
How flags gate code
Flags control behavior at several architectural layers:
-
CLI entrypoint routing (
src/entrypoints/cli.tsx): Flags likeDAEMON,BRIDGE_MODE,BG_SESSIONS, andDUMP_SYSTEM_PROMPTgate entire CLI subcommands before the main application loads. -
Slash-command registration (
src/commands.ts): Each flag-gated command uses a conditionalrequire()that resolves tonullwhen the flag is off. The command array filters out nulls. -
Tool availability (
src/tools.ts,src/constants/tools.ts): Tools likeMonitorTool,WorkflowTool,SnipTool,ListPeersTool,CronCreateTool,SendUserFileTool,WebBrowserTool, andTerminalCaptureToolare conditionallyrequire()'d and included in tool lists only when their flag is active. -
System prompt composition (
src/constants/prompts.ts): Prompt sections for proactive behavior, brief mode, and skill search are conditionally included based on flag state. -
Keybinding registration (
src/keybindings/defaultBindings.ts): Push-to-talk (VOICE_MODE), brief-mode shortcuts (KAIROS/KAIROS_BRIEF), and terminal toggle (TERMINAL_PANEL) are conditionally added. -
Module-level conditional require (throughout): The dominant pattern is
const Foo = feature('FLAG') ? require('./Foo.js').Foo : null, which ensures the entire module subtree is eliminated by DCE when the flag is off. -
UI component rendering (
src/components/): Components likeCompanionSprite(BUDDY),ChannelsNotice(KAIROS_CHANNELS),WebBrowserPanel(WEB_BROWSER_TOOL), andVoiceIndicator(VOICE_MODE) are conditionally rendered or entirely skipped.
Relationship to process.env.USER_TYPE
A parallel gating mechanism uses process.env.USER_TYPE (set to "external" via define in the build config). This gates Anthropic-internal ("ant") tools and packages (e.g., REPLTool, SuggestBackgroundPRTool, @ant/* packages) and is handled by esbuild's define replacements rather than the bun:bundle feature system. Both mechanisms achieve DCE but serve different purposes: USER_TYPE separates internal vs. external builds, while feature flags control incremental feature rollout.
Key claims
- The
feature()function frombun:bundlereturns a compile-time boolean in production Bun builds; inactive branches and all their contents (string literals, require calls, GrowthBook flag names) are stripped by dead-code elimination. - In development,
bun:bundleis shimmed via a Bun preload plugin tosrc/shims/bun-bundle.ts, which reads each flag from an environment variable (pattern:CLAUDE_CODE_<FLAG_NAME>) withfalseas default. - The esbuild production build (
scripts/build-bundle.ts) aliasesbun:bundleto the same shim and usesdefinereplacements forMACRO.*constants andprocess.env.USER_TYPE. - Approximately 91 distinct feature flags are referenced across the codebase, with 24 registered in the dev shim and the remainder defined in internal build configurations.
- The "positive ternary pattern" (
return feature('X') ? check() : false) is required instead of early-return guards to ensure string literal elimination in external builds. - Many flags use two-layer gating: build-time
feature()for DCE, plus a runtime GrowthBook/Statsig gate for gradual rollout and kill-switches. ABLATION_BASELINEis hardcoded tofalsein external builds and is never env-configurable, serving as a harness-science mechanism for internal experimentation.COORDINATOR_MODErequires both the build-time feature flag AND theCLAUDE_CODE_COORDINATOR_MODEruntime env var to be truthy.
Relations
- depends-on
bun:bundlemodule (Bun's bundler compile-time constant system) - depends-on
src/shims/bun-bundle.ts(dev/esbuild shim providing runtime flag resolution) - depends-on
scripts/bun-plugin-shims.ts(Bun preload plugin interceptingbun:bundleimports) - depends-on
scripts/build-bundle.ts(esbuild production build config with alias and define) - interacts-with GrowthBook / Statsig (runtime feature gates used inside build-time flag guards)
- interacts-with
process.env.USER_TYPEgating (parallel DCE mechanism for internal vs. external builds)
Sources
src/shims/bun-bundle.ts-- dev shim defining 24 feature flags with env-var resolution and thefeature()exportsrc/types/bun-bundle.d.ts-- TypeScript declaration for thebun:bundlemodule'sfeature()functionscripts/bun-plugin-shims.ts-- Bun preload plugin that interceptsbun:bundleimportsscripts/build-bundle.ts-- esbuild production build script withbun:bundlealias anddefinereplacementsbunfig.toml-- Bun config referencing the preload pluginsrc/entrypoints/cli.tsx-- CLI entrypoint with feature-gated subcommand routingsrc/commands.ts-- slash-command registration with conditional requires per flagsrc/tools.ts-- tool registration with conditional requires per flagsrc/constants/tools.ts-- tool-list construction gated byWORKFLOW_SCRIPTSandAGENT_TRIGGERSsrc/constants/prompts.ts-- system prompt composition gated byPROACTIVE,KAIROS,EXPERIMENTAL_SKILL_SEARCHsrc/bridge/bridgeEnabled.ts-- two-layer gating example:feature('BRIDGE_MODE')+ GrowthBooktengu_ccr_bridgesrc/voice/voiceModeEnabled.ts-- two-layer gating example:feature('VOICE_MODE')+ GrowthBook kill-switchsrc/coordinator/coordinatorMode.ts-- two-layer gating:feature('COORDINATOR_MODE')+ runtime env var