Feature Flags: Why Your Claude Code Isn't Mine
Two developers install the same Claude Code version, on the same OS, in the same repo. One of them has a feature the other doesn't, and neither of them gets an error message. This isn't folklore — it's the documented design. Claude Code switches some features on using feature flags it fetches from Anthropic at startup, and several ordinary, well-intentioned configurations turn that fetch off completely.
The consequence that surprises people: a purely local operation can depend on a network call. In September 2026 that became a 437-point Hacker News thread, because reading a Markdown file off your own disk turned out to need one.
- How Claude Code's remote feature flags are fetched, cached, and evaluated
- The four configurations that silently switch flag fetching off
- Why DISABLE_TELEMETRY=0 still opts you out — and why DO_NOT_TRACK=0 doesn't
- The fifteen features you lose with fetching off
- How to detect gating in two minutes and pin behavior so it can't bite you
The mechanism
Claude Code ships with a code default for every flag and then tries to fetch the real values. The provider is GrowthBook — there's a dedicated DISABLE_GROWTHBOOK environment variable, and the changelog has entries like a crash fix for "when a GrowthBook feature evaluates to null" (v2.1.214).
Four properties of that system explain almost every weird case you'll hit:
- The binary knows the flag names and a fallback value for each. The values that decide what your session can do come from Anthropic over the network. No fetch means every flag falls back to its code default — which for a feature mid-rollout is usually off.
- Fetched values persist between sessions, which is why a feature can appear one run after you expected it. The changelog records this going wrong: v2.1.70 fixed flags read during early startup never refreshing their disk cache, so stale values survived across sessions.
- Evaluation takes your Claude Code version and your subscription tier into account. v2.1.227 fixed flags being evaluated without the user's tier when a session started on an expired login token — which wrongly prompted Max plan users to enable usage credits. v2.1.261 fixed flags gated to a newer version occasionally applying to an older Claude Code running on the same machine.
- v2.1.214 fixed feature flags going stale in long-running sessions after the OAuth token rotates. A session that runs for hours is not guaranteed to hold the same feature set it started with.
The four ways the fetch goes dark
The docs are explicit about this. Claude Code skips the flag fetch in these sessions:
- You set one of four environment variables:
DISABLE_GROWTHBOOK,DISABLE_TELEMETRY,DO_NOT_TRACK, orCLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC. - You're on a third-party provider: Amazon Bedrock, Claude Platform on AWS, Google Cloud's Agent Platform, or Microsoft Foundry — unless a host platform that embeds Claude Code sets
CLAUDE_CODE_PROVIDER_MANAGED_BY_HOST. - You're in a Claude apps gateway session.
- It's your first session after a fresh install or an upgrade — the flags haven't arrived yet. More on this below.
Notice what those first two have in common: they're the configurations a security-conscious enterprise picks. The exact population most likely to disable telemetry and route through Bedrock is the population that silently gets the smallest feature set.
- Disabling telemetry is not only a privacy choice — it is also a feature switch. The docs say DISABLE_TELEMETRY 'also disables feature-flag fetching with the same effect as DISABLE_GROWTHBOOK'.
- If you want privacy without losing features, there is no combination that gives you both: every documented way to stop the telemetry also stops the flag fetch.
- CI runners with an ephemeral HOME are a fresh install on every run, so they land in the no-flags case every single time.
The value trap: three variables, three parsing rules
This is the part that costs people an afternoon. These variables live in the same family, read as if they do the same thing, and parse their values under three different rules.
| Variable | How it reads the value | So =0 means |
|---|---|---|
DISABLE_TELEMETRY | Any non-empty value turns it on | Still opts you out. Unset it to re-enable |
CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC | Any non-empty value turns it on | Still disables the traffic. Unset it to re-enable |
DISABLE_ERROR_REPORTING | Any non-empty value turns it on | Still opts you out. Unset it to re-enable |
DISABLE_GROWTHBOOK | Standard boolean — set to 1 or true | Leaves fetching on |
DO_NOT_TRACK | Standard boolean — set to 1 | Leaves telemetry on |
Read that table twice. DISABLE_TELEMETRY=0 disables telemetry. DO_NOT_TRACK=0 does not. Both are documented, deliberate, and opposite.
- The docs state the rule directly: some variables 'read only whether you set them at all, so any non-empty value including 0 turns the behavior on'.
- To undo one of those, you must unset the variable or set it to an empty value — assigning 0 or false is not an off switch.
- This bites hardest in a Dockerfile or CI config where someone 'turned it off' by flipping 1 to 0.
What you actually lose
With flag fetching off, fifteen documented capabilities go away. Grouped by what they cost you:
Permissions and startup
- Sessions can't start in auto mode by default on Pro, Max, and Team plans
- The VS Code extension can't read settings files for the starting permission mode
/auto-mode-setupcan't draftautoMode.environmententries
Anything that reaches beyond the local session
- Remote Control
- Messaging sessions on other machines (same-machine messaging still works)
- Syncing the skills and plugins enabled for your claude.ai account into terminal sessions
- Reading or replying to comments on an artifact
- The advisor tool
Commands and diagnostics
claude importand the/importcommand/skill-doctorand its report in the/pluginStats tab
Silent behavior changes — the dangerous group
- MCP: Claude Code stops excluding MCP tools whose input schema the API would reject. It sends the schema anyway, and the request fails with a 400 naming the tool by position
- MCP: no probing of claude.ai connector servers for protocol revision 2026-07-28, unless you set
MCP_PROTOCOL_NEGOTIATION=auto - Large pastes are no longer treated as pasted rather than typed text — the content behind a
[Pasted text #N]placeholder reaches Claude unmarked - On Windows with Git Bash installed, claude.ai and Console accounts don't get the PowerShell tool by default; set
CLAUDE_CODE_USE_POWERSHELL_TOOL=1 - Claude-drafted feedback is off
The last group is the one to internalize. A missing slash command announces itself. A 400 error that names a tool by its position in the array does not look like a telemetry setting, and you will debug your MCP server for an hour before you think to check an env var.
The blast radius has precedent
Flag and telemetry settings have leaked into places nobody would predict. Two fixed-but-instructive examples from the changelog:
- v2.1.108 fixed subscribers who set
DISABLE_TELEMETRYfalling back to a 5-minute prompt cache TTL instead of 1 hour. A privacy variable was quietly costing money on every long session — a 12× shorter cache window. - v2.1.105 fixed
CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFICset in one project's settings permanently disabling usage metrics for all projects on the machine.
Both are fixed. Both show the shape of the risk: these switches cut across subsystems that look unrelated.
The first session after an install or upgrade
This one is worth its own heading because it produces the classic irreproducible bug report.
On your first session after installing Claude Code — or after upgrading to a version that adds a feature — a flag-gated feature can simply be missing, and the session can start in Manual mode on a plan that otherwise starts in auto mode. Claude Code fetches the flags during that session, so both are present next time.
Two corollaries:
- It fixes itself, which is exactly why it's hard to report. By the time anyone looks, the second session has the flags.
- It never fixes itself in ephemeral environments. A CI runner, a fresh container, or any setup with a throwaway home directory is on its first session every time.
The docs do note one mitigation: after a fresh install, a non-interactive session such as claude -p, the Agent SDK, or the VS Code extension can still pick the flags up before it chooses the starting permission mode.
Case study: AGENTS.md, a local file behind a remote switch
The clearest example of the whole pattern, and the one that made the front page.
- The changelog entry: in a project with no CLAUDE.md, Claude Code reads AGENTS.md instead; change it under 'Project instructions' in /config. The entry itself flags that it isn't on Bedrock, Vertex or Foundry yet.
- Because the rollout was flag-gated, sessions that skip the fetch fell back to the code default — off. Reading a Markdown file from the current directory, an operation with no network component whatsoever, became conditional on a network call.
- No warning, no log line, no error. The instructions simply never reach the model, so the symptom reads as 'Claude is ignoring my AGENTS.md' — which sends you to rewrite the file rather than to check an env var.
- Filed as 'Claude Code's AGENTS.md Support: A Local Feature Locked Behind a Remote Switch'. Reporters reproduced it on 2.1.278 and 2.1.280, and confirmed that DISABLE_TELEMETRY, DISABLE_GROWTHBOOK and nonessential-traffic-off all block it, plus the very first session after a fresh install.
- The memory docs now say it plainly: 'Before v2.1.281, some sessions, such as those on Amazon Bedrock or with telemetry disabled, read CLAUDE.md files only. On those versions, update Claude Code.' If you're pinned below 2.1.281, you still have this.
The lesson generalizes past this one bug. Ask of any new Claude Code feature: is this gated? If it is, then your telemetry posture, your provider, and how recently you installed all become inputs to whether it works.
Diagnose it in two minutes
You don't need to guess. Three checks, cheapest first.
1. Ask whether the setting even exists. When AGENTS.md support is unavailable, the Project instructions row doesn't appear in the /config panel at all. A missing setting is itself the diagnosis — the feature isn't off, it's absent.
2. Look at what an interactive session tells you. When it works, Claude Code prints a line in the conversation like no CLAUDE.md found; AGENTS.md loaded: /home/you/repo/AGENTS.md. No line, no load.
3. Run a canary. The technique that cracked the original report: put a word in the file that appears nowhere else, then ask for it in a clean, non-interactive session. If the word comes back, the file reached the model. This works for any instruction file, on any version.
Canary test — did the instruction file actually load?
mkdir -p /tmp/canary && cd /tmp/canary echo 'The project codeword is PERIWINKLE.' > AGENTS.md claude -p 'What is the project codeword? Answer with one word.'
Run it once with your normal environment, then once with the privacy variables cleared, and compare. Note the empty-string assignment — remember that DISABLE_TELEMETRY=0 would not clear it.
Same test with flag fetching allowed — note the empty values, not zeros
cd /tmp/canary env DISABLE_TELEMETRY= CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC= DISABLE_GROWTHBOOK=false \ claude -p 'What is the project codeword? Answer with one word.'
4. If you need the detail, turn on debug logging. Launch with --debug or /debug, and logs land in ~/.claude/debug/<session-id>.txt. One catch: the DEBUG environment variable only accepts the truthy values 1, true, yes, and on — a namespace pattern like DEBUG=express:* left over from another tool will not enable it.
Pin behavior instead of relying on a flag
The durable fix is to stop depending on the gate. Two patterns.
Pin the setting explicitly. For instruction files, the Project instructions value can go in a settings file under the built-in plugin's ID rather than being left to the default. One important limit: Claude Code ignores this key in project and local settings files — it only reads it from ~/.claude/settings.json, a --settings file, or managed settings. Putting it in your repo's .claude/settings.json will do nothing.
Load CLAUDE.md and AGENTS.md together — user or managed settings only
{
"pluginConfigs": {
"agents-md@builtin": {
"options": { "instructionFiles": "claude-md-and-agents-md" }
}
}
}Use a path that was never gated. A CLAUDE.md that imports AGENTS.md has worked on every version, every provider, and with telemetry off — because it's ordinary @path import expansion, not a flagged code path. This is the recommendation the docs themselves give for Bedrock, Vertex and Foundry sessions.
The one-line CLAUDE.md that has never needed a flag
@AGENTS.md
One subtlety if you take this route: an AGENTS.md read through the setting behaves slightly differently from one pulled in by import. InstructionsLoaded hooks don't fire for the setting-based path, but they fire as usual for an AGENTS.md that a CLAUDE.md imports or symlinks to. If you have hooks on instruction loading, the import is the safer path.
Check yourself
Check yourself
0/4- Claude Code fetches feature flags from Anthropic (GrowthBook), caches them to disk, and evaluates them against your version and subscription tier — so two identical installs can legitimately behave differently.
- Four env vars, three third-party providers, apps gateway sessions, and the first session after an install all skip that fetch, costing you fifteen documented features.
- DISABLE_TELEMETRY, CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC and DISABLE_ERROR_REPORTING treat any non-empty value as on — including 0. DO_NOT_TRACK and DISABLE_GROWTHBOOK are real booleans. Unset, don't zero.
- The worst losses are silent: unfiltered MCP schemas causing positional 400s, and unmarked pasted text.
- AGENTS.md was the case study — native from v2.1.277, gated, fixed in v2.1.281. A CLAUDE.md containing @AGENTS.md never needed the flag.
Next
- AGENTS.md & Cross-Tool Interop — the feature this page used as its case study, and the sync patterns that don't depend on a flag
- Settings & Configuration — where
pluginConfigsand theenvkey live, and which settings files are read - Self-Hosted & Enterprise Environments — Bedrock, Vertex and gateway setups, the same sessions that skip the fetch
Sources & further reading
- Claude Code environment variables — Features that need feature-flag fetching — the authoritative list, plus the per-variable value semantics
- Claude Code memory docs — AGENTS.md — precedence table, the Project instructions setting, and when support is unavailable
- Claude Code CHANGELOG — v2.1.277 (AGENTS.md support), v2.1.281, and the flag-system fixes in v2.1.70, v2.1.108, v2.1.214, v2.1.227 and v2.1.261
- anthropics/claude-code issue #95690 — the original report, with community reproductions on 2.1.278 and 2.1.280
- Claude Code reads AGENTS.md only when telemetry is on — the write-up that surfaced it, and the canary-word method