Anthropic "released" the Claude Code source code. The coverage that followed focused on architecture — the streaming loop, the tool pipeline, the context window management. That is not the interesting story. The interesting story is a fully-built virtual pet nobody announced, an autonomous agent already connected to the production backend, a mode that instructs Claude to write commits as if it were a human and deny being an AI, and five distinct identifiers attached to every event you trigger. None of it is in the changelog.
What the source reveals:
- Claude Code's internal name is Tengu. Opus 4.6 was previously codenamed Fennec. Capybara is a real model — confirmed in two separate parts of the codebase.
- A fully-implemented companion system called BUDDY — a Tamagotchi with 18 species, rarity tiers, and a soul generated by Claude — exists in the source and has never shipped to users.
- KAIROS, an always-on autonomous agent that proactively acts on your session without waiting for input, is wired into the backend and has been since at least July 2025.
- ULTRAPLAN opens your browser, sends your session to a cloud Claude instance, and returns a pull request. Its prompt cannot contain its own name or it recurses into failure.
- Undercover Mode strips all AI attribution from commits when Anthropic employees work on public repos. The model is not told what model it is. There is no way to turn it off.
- Fast mode (
/fast) is internally called Penguin Mode and silently downgrades to standard speed under load — without showing you anything in the UI. - Five distinct identifiers track your every action in Claude Code — and the official opt-out flags come with undocumented side effects. How much user information is Anthropic actually collecting?
- OAuth users have their email, account UUID, and organization UUID attached to every analytics event sent to Anthropic's BigQuery. API key users do not.
- Your permanent device ID lives in
~/.claude.json. Session transcripts accumulate in~/.claude/projects/indefinitely. There are env vars to disable telemetry — but two open bugs mean they don't fully work on Windows, and enabling them silently cuts off access to the Opus 4.6 1M context window.
The Names Anthropic Uses When Nobody's Looking
Anthropic does not call Claude Code "Claude Code" internally. Throughout the source, the project is referred to as Tengu — a Japanese supernatural creature associated with intelligence and martial arts mastery. The name is everywhere once you know to look for it: analytics events are prefixed tengu_, feature flags carry names like tengu_onyx_plover and tengu_ultraplan_model, and the migration file that upgrades user settings after a model rename fires a tengu_sonnet45_to_46_migration event. It is the kind of internal name a team uses when they want something that sounds cooler in Slack than a product name.
More revealing is what the codenames tell you about the models. A migration file in src/migrations/migrateFennecToOpus.ts quietly discloses that Opus 4.6 used to go by a different name internally: Fennec. The file migrates stored user settings from fennec-latest, fennec-latest[1m], and fennec-fast-latest to their current Opus equivalents. There is also Capybara, which shows up in two separate contexts with very different implications — more on that shortly. And then there is the matter of how Anthropic employees are identified throughout the codebase: not by email domain or org ID, but by a build-time constant, process.env.USER_TYPE === 'ant'. Dozens of code paths branch on this value. An "ant" gets access to internal tooling, different default behaviors, and the ability to operate in a mode that regular users cannot access at all.
BUDDY: The Secret Tamagotchi Nobody Announced
The most delightful thing in the source code is a fully-implemented virtual companion system called BUDDY, living in src/buddy/. It is, in every meaningful sense, a Tamagotchi that lives in the corner of the Claude Code terminal UI. It has never been announced. It is not in any changelog or release note. It is feature-gated behind a compile-time flag that strips it entirely from external builds.
Here is how it works. When BUDDY is enabled, every user gets a companion deterministically rolled from a hash of their user ID, fed through a seeded pseudorandom number generator called Mulberry32. The companion has a species chosen from 18 options — duck, goose, blob, cat, dragon, octopus, owl, penguin, turtle, snail, ghost, axolotl, capybara, cactus, robot, rabbit, mushroom, and chonk. It has a rarity — common (60%), uncommon (25%), rare (10%), epic (4%), legendary (1%) — which determines the floor values on its five stats: DEBUGGING, PATIENCE, CHAOS, WISDOM, and SNARK. It has eyes chosen from six variants, a hat from eight options (none, crown, tophat, propeller, halo, wizard, beanie, or tinyduck), and a 1% chance of being "shiny." The salt used to derive all of this from the user ID is hardcoded in the source: 'friend-2026-401'.
The companion also has a soul — a name and personality description generated by Claude itself on first hatch and stored in config. The soul is the only part that persists. The "bones" (species, rarity, stats, hat, eyes) are regenerated from the user ID hash on every read, which means editing your config to claim a legendary is impossible — the system will just recompute the real result and overwrite your edit. As the source comment puts it: "editing config.companion can't fake a rarity."
The companion sits beside the user's input box, renders as a terminal sprite on a 500ms tick, and occasionally comments in a speech bubble. The system prompt injection for BUDDY contains this line: "You're not [companion name] — it's a separate watcher. When the user addresses [name] directly, its bubble will answer. Your job in that moment is to stay out of the way." Claude knows about the companion and has been instructed how to coexist with it. The system is fully wired. It is just not on.
The Obfuscated Capybara
This is where the codenames and BUDDY collide in a way that reveals something about Anthropic's internal security practices. The source comment on the capybara species entry in src/buddy/types.ts reads:
"One species name collides with a model-codename canary in excluded-strings.txt. The check greps build output (not source), so runtime-constructing the value keeps the literal out of the bundle while the check stays armed for the actual codename."
Rather than just writing the string 'capybara', the engineers hex-encode it:
export const capybara = c(
0x63, 0x61, 0x70, 0x79,
0x62, 0x61, 0x72, 0x61,
) as 'capybara'
Anthropic runs an automated scanner on build output that flags any file containing known model codenames. Capybara is both a Claude model codename and a cute animal companion species. The solution was to construct the string programmatically so the literal never appears in the bundle and the scanner stays silent. The fact that this solution was necessary at all is confirmation that Capybara is (or was) a real Claude model codename — one that Anthropic does not want appearing in shipped artifacts.
KAIROS: The Agent That Is Already Watching
Scattered across hundreds of lines in the source — in src/assistant/, src/bridge/bridgeMain.ts, src/cli/print.ts, and more — is a feature called KAIROS. The code describes it as an "always-on assistant" that watches session logs and acts proactively without waiting for user input. Where the normal Claude Code REPL responds to what you type, KAIROS operates in a continuous loop, monitoring context and autonomously generating actions. It has its own session history fetcher that pages through server-side session events. It has sub-features: KAIROS_BRIEF for compact status summaries, KAIROS_CHANNELS for what appears to be a channel-based task distribution system.
The session history fetcher in src/assistant/sessionHistory.ts uses a beta API header that has not been publicly documented: anthropic-beta: ccr-byoc-2025-07-29. The "BYOC" in that header almost certainly stands for "Bring Your Own Context" — a server-side session persistence mechanism that allows KAIROS to resume exactly where it left off across process restarts. The date in the header (July 2025) suggests this backend capability has been live for months.
KAIROS is also specifically excluded from triggering AutoDream — the background memory consolidation agent. The gate check reads: if (getKairosActive()) return false // KAIROS mode uses disk-skill dream. A separate consolidation path exists for it. This is not a prototype. This is a parallel product built on top of the same infrastructure as Claude Code, integrated deeply enough that it needed its own memory consolidation strategy.
ULTRAPLAN: 30 Minutes with Opus, Via Your Browser
The /ultraplan slash command is fully implemented in src/commands/ultraplan.tsx. When invoked, it does not run a planning session locally. Instead, it opens a browser window to claude.ai, teleports the current session to a remote Claude Code instance running in Anthropic's cloud (called CCR — Claude Code Remote), and hands the problem to Opus 4.6 with a 30-minute timeout. The timeout is hardcoded:
// Multi-agent exploration is slow; 30min timeout.
const ULTRAPLAN_TIMEOUT_MS = 30 * 60 * 1000;
The model used is configurable via a GrowthBook feature flag (tengu_ultraplan_model) that defaults to the canonical first-party Opus 4.6 ID. Once the remote session finishes planning, there is a choice: bring the plan back to your local session, or execute it entirely in the browser. The completion notification for the browser-execution path reads: "Results will land as a pull request when the remote session finishes. There is nothing to do here."
There is a remarkable engineering detail buried in the implementation. The prompt for the ULTRAPLAN session deliberately avoids the word "ultraplan." The source comment explains why:
"Phrasing deliberately avoids the feature name because the remote CCR CLI runs keyword detection on raw input before any tag stripping, and a bare 'ultraplan' in the prompt would self-trigger as /ultraplan, which is filtered out of headless mode as 'Unknown skill'."
ULTRAPLAN's prompt cannot say its own name, because the remote environment it runs inside would try to invoke ULTRAPLAN again and fail. The workaround is a prompt written to describe the task without using the command that invokes it.
Undercover Mode: Claude Goes Dark in Public Repos
For Anthropic employees — the "ants" — working on public or open-source repositories, there is a mode that activates automatically whenever Claude Code cannot confirm it is inside an internal Anthropic repo. The source file src/utils/undercover.ts describes it plainly:
"When active, Claude Code adds safety instructions to commit/PR prompts and strips all attribution to avoid leaking internal model codenames, project names, or other Anthropic-internal information. The model is not told what model it is."
In undercover mode, the model receives a CRITICAL block in its system prompt instructing it to write commit messages as a human developer would. The list of things it must never include is specific:
"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 — The phrase 'Claude Code' or any mention that you are an AI — Co-Authored-By lines or any other attribution."
The mode activates automatically when the repo remote does not match an internal allowlist. The source is explicit about one design constraint: "There is NO force-OFF. This guards against model codename leaks — if we're not confident we're in an internal repo, we stay undercover." There is no way to disable it by environment variable in auto mode. An Anthropic engineer who pushes to a public repo via Claude Code will have commits that look indistinguishable from human-written commits. The model will not acknowledge it is an AI. The Co-Authored-By: Claude line that users of the public product see in their commits is absent.
Is Claude Getting Dumber Over Time? The Model Fallback Question
If you have ever felt like Claude Code started giving worse answers mid-session and suspected it quietly swapped to a less capable model — the source code answers that directly: no, Claude Code does not secretly downgrade your model. There is no hidden code path that substitutes Haiku for Opus without telling you. What it does do, however, is silently switch between performance tiers of the same session in ways most users do not realize are happening. When fast mode hits a rate limit or overload error, it automatically drops from high-speed output back to standard speed without any notice in the UI. If your extra usage billing runs out, fast mode is permanently disabled mid-session and your setting is cleared, also silently. The model does not change. The speed, the cache behavior, and the output quality under load do.
The model fallback system that does exist is documented in src/services/api/withRetry.ts and is deliberately transparent. It triggers only after three consecutive HTTP 529 errors — the "overloaded" status code Anthropic's API returns when the model tier is at capacity. Even then, it only fires if you have explicitly set the --fallback-model flag at startup. There is no default fallback. If you never passed that flag, three 529s just produce an error: Repeated 529 Overloaded errors. When a fallback does trigger, the UI shows a warning-level system message — the same visual weight as other alerts — that says:
Switched to {fallbackModel} due to high demand for {originalModel}
You see it. It is not silent. The event is also logged to analytics as tengu_model_fallback_triggered with both model names recorded.
There is a second mechanism that is less user-controlled: the tengu-off-switch. This is a remote dynamic config flag Anthropic can flip server-side without shipping a release. It applies to Opus users during extreme capacity events. When activated, it does not silently substitute a cheaper model — it stops your request from going through at all and shows: "Opus is experiencing high load, please use /model to switch to Sonnet." The model selection is left to you. The source calls this an "emergency capacity off switch for Opus PAYG users," and it is what gets used when the overloaded error rate is high enough that even the retry loop is making things worse.
One code comment reveals something extra. When the fallback mechanism retries a request on a different model, it must first strip what the comment calls "thinking signatures" — protected reasoning blocks that are model-bound. The comment names the model that generates them:
// Thinking signatures are model-bound: replaying a protected-thinking
// block (e.g. capybara) to an unprotected fallback (e.g. opus) 400s.
// Strip before retry so the fallback model gets clean history.
if (process.env.USER_TYPE === 'ant') {
messagesForQuery = stripSignatureBlocks(messagesForQuery)
}
(e.g. capybara) — the same model codename the BUDDY system obfuscated in hex to avoid string scanners — appears here as the canonical example of a model that produces protected thinking blocks. It is confirmation in a different part of the codebase that Capybara is a real, internally-used model with a distinct capability profile, not just an animal Anthropic happened to pick for a companion species.
The condition for who gets automatic fallback is also narrower than it appears. The code explicitly carves out Claude.ai subscribers:
(!isClaudeAISubscriber() && isNonCustomOpusModel(options.model))
If you are paying for Claude.ai Pro or Max, the automatic 529-to-fallback path is disabled for you. The fallback only applies to API users running Opus with no custom model configuration. Subscribers who hit Opus capacity get the error, not the silent retry. Whether that is the right tradeoff is a product decision the code does not explain, but the distinction is in there and it is not documented anywhere.
Fast Mode Is Internally Called Penguin Mode
The /fast toggle — which Claude Code calls "fast mode" in its UI — has a different name everywhere it matters in the code. The config key that persists whether your organization has it enabled is penguinModeOrgEnabled. The analytics event that fires when the org check fails is tengu_org_penguin_mode_fetch_failed. One feature flag that gates a related build requirement is called tengu_marble_sandcastle. Fast mode is Penguin Mode internally, and the rename to "fast" appears to be entirely a user-facing decision.
The mechanics of how Penguin Mode degrades under load are more layered than the toggle implies. When fast mode is active and hits a 429 or 529, the code evaluates the retry-after header:
- Short retry-after: waits and retries with fast mode still active — specifically to preserve the prompt cache. Switching to standard speed changes how the request is identified, which would bust the cache and mean paying full input token prices again.
- Long or unknown retry-after: enters a cooldown window and retries at standard speed. The cooldown duration is derived from the retry-after header or a default, subject to a minimum floor to prevent flip-flopping. When the cooldown expires, fast mode resumes automatically.
- Overage rejection: if a 429 comes back with a header indicating that extra usage billing is not available, fast mode is permanently disabled for that session and the user setting is cleared. The code distinguishes this from a regular rate limit; it is treated as a capability loss, not a temporary backoff.
The cooldown state — and the reason for it (overloaded vs rate_limit) — is logged as tengu_fast_mode_fallback_triggered. The overage rejection is logged separately as tengu_fast_mode_overage_rejected with the specific rejection reason from the API header.
Fast mode is supported only on Opus 4.6. The check in src/utils/fastMode.ts is straightforward:
return parsedModel.toLowerCase().includes('opus-4-6')
If you switch models mid-session, fast mode silently becomes inoperative regardless of your setting. There is also an org-level gate: Anthropic can disable Penguin Mode for an entire organization from the API side. The client discovers this on startup via a prefetch request and caches the result. If the org check fails due to a network error (common behind corporate proxies), Anthropic employees default to enabled; external users fall back to whatever was cached. The env var CLAUDE_CODE_SKIP_FAST_MODE_NETWORK_ERRORS=1 bypasses this network check entirely for external builds — it is what ships in the Claude Code binary to prevent proxy environments from silently breaking fast mode availability.
Memory Does Not Live in the System Prompt
The model behavior questions have straightforward answers once you read the source. The memory architecture question does not — because most users have the mental model completely wrong.
Your memory files do not go into the system prompt. Most users assume they do. They do not. They are injected as <system-reminder> blocks in the user turn — specifically as a special attachment type called relevant_memories, delivered immediately before your message.
graph TB
subgraph "What most users assume"
SP1["System Prompt\n──────────\nInstructions\n+\nAll memory files\n+\nClaude.md"]
UT1["User Turn\n──────────\nYour message"]
end
subgraph "What actually happens"
SP2["System Prompt\n──────────\nInstructions\n+\nMEMORY.md index\n(stable → cached)"]
UA["User Turn (injected)\n──────────\n<system-reminder>\nRelevant memory files\nmatched to this query\n</system-reminder>"]
UT2["User Turn\n──────────\nYour message"]
SP2 --> UA --> UT2
endThis separation is intentional and has a meaningful consequence. The system prompt — which contains your Claude Code instructions and the MEMORY.md index — stays identical across queries. Anthropic's API caches prompt prefixes, so a stable system prompt means subsequent turns cost roughly 10% of normal input token prices for that portion of the prompt. If memory files lived in the system prompt and changed per query, every query would break the cache and you would pay full price each time.
The code also reveals something about what happens after compaction. The comment in src/utils/attachments.ts explains: "Scanning messages rather than tracking in toolUseContext means compact naturally resets both — old attachments are gone from the compacted transcript, so re-surfacing is valid again." In other words, after your conversation is compacted, Claude Code is allowed to re-inject memory files it had already surfaced before compaction. The compact boundary is not just a context reset for the model — it resets the memory injection tracking too.
What Claude Is Actually Told When It Summarizes Your Session
When your conversation gets long enough to trigger compaction, Claude runs a separate summarization pass. The prompt it receives for that task starts with this:
CRITICAL: Respond with TEXT ONLY. Do NOT call any tools.
- Do NOT use Read, Bash, Grep, Glob, Edit, Write, or ANY other tool.
- You already have all the context you need in the conversation above.
- Tool calls will be REJECTED and will waste your only turn — you will fail the task.
That preamble exists because without it, Sonnet 4.6 attempts tool calls during compaction roughly 2.79% of the time. The source comment is specific: "on Sonnet 4.6+ adaptive-thinking models the model sometimes attempts a tool call despite the weaker trailer instruction. With maxTurns: 1, a denied tool call means no text output → falls through to the streaming fallback (2.79% on 4.6 vs 0.01% on 4.5)." The aggressive preamble was added specifically because the newer, more capable model is also more likely to reach for tools even when asked not to.
flowchart LR
A["Context nears limit"] --> B["Tool result too large?\napplyToolResultBudget()"]
B -->|yes| B1["Truncate result\nSave full content to disk\nModel gets preview + path"]
B1 --> C
B -->|no| C["Session memory extract\n(lightweight facts)"]
C -->|enough headroom| Z["Continue"]
C -->|still too full| D["Full compaction\nSend CRITICAL: no tools preamble\nSonnet 4.6 needs this 2.79% of calls"]
D --> E["Model writes <analysis> scratchpad\nthen <summary> block"]
E --> F["Strip <analysis>\nStore only <summary>"]
F --> G["Insert compact_boundary marker\nOld history kept locally\nNever sent to API again"]
G --> ZThe compaction summary the model produces also has a hidden layer. It is asked to produce two sections: an <analysis> block — a drafting scratchpad where it can reason through what happened — and a <summary> block with the actual structured output. The <analysis> block is stripped before the summary is stored. You never see it, and the model in subsequent turns never sees it either. The scratchpad was added because, on evals, models that drafted their reasoning before committing to a summary produced measurably better output. It is an invisible thinking step for an invisible process.
The Context Compression Hierarchy Nobody Documents
There is no public documentation explaining how Claude Code decides which of its several compression strategies to apply, or in what order. The source reveals a clear hierarchy:
flowchart TD
A["Tool result returned"] --> B{"Result > tool's\nmaxResultSizeChars?"}
B -->|yes| C["Save to disk\nPass preview + path to model\nModel can Read() specific sections"]
B -->|no| D{"Context window\n> 80%?"}
C --> D
D -->|no| Z["Continue normally"]
D -->|80–90%| W["Show warning UI only"]
W --> E
D -->|"> 90% — 33K tokens before limit"| E{"Consecutive compact\nfailures < 3?"}
E -->|yes| F["Try session memory\nextract — lightweight"]
F -->|freed enough space| Z
F -->|still too full| G["Full compactConversation\n30-minute cap on output"]
G -->|success| H["Insert compact_boundary\nReset memory surfacing\nContinue"]
G -->|fails| I["Increment failure counter"]
I -->|counter = 3| J["Circuit breaker trips\nNo more compact attempts"]
E -->|no — circuit breaker| J
J --> ZThe circuit breaker is particularly notable. After three consecutive compaction failures — which can happen when a single message is so large the API returns prompt_too_long even on the compaction attempt — the system stops trying. The comment in the source is frank about why: production data showed sessions accumulating over 3,000 consecutive compaction failures, each one burning an API call. The circuit breaker tripped at three.
None of this is visible in the UI. The context hierarchy, the circuit breaker, the scratchpad that gets stripped — you experience the effects without any indication of what the system is doing internally. The same is true of what happens on the other side of every API call: what gets attached to those requests and where it goes.
What Anthropic Knows About You: The Tracking Identifiers
Every time you trigger an event in Claude Code — a tool use, a session start, a compaction, an OAuth refresh — one or more identifiers are attached to it and sent to Anthropic. There are five of them. Which ones you're sending depends entirely on how you authenticated, and the difference is significant.
The first is the device ID — a 32-byte random hex string generated the first time you run Claude Code and stored permanently in your global config file. It is not your Anthropic account. It is not tied to your email or API key. It is a client-generated random identifier that persists forever unless you manually delete the config. Every event sent to Anthropic's first-party BigQuery sink includes this raw string as device_id.
The second is the session ID — a randomUUID() generated at startup and regenerated whenever you start a new session or run /clear. It is included in both Datadog and BigQuery. It is the identifier that lets Anthropic correlate events within a single working session.
The third and fourth are the account UUID and organization UUID, pulled from your OAuth token. These only exist if you authenticated with Claude.ai — not if you are using an API key. Both are attached to every first-party BigQuery event when present.
The fifth is your email address. The code collects it from one of three places, evaluated in order:
// OAuth users: email from Claude.ai login
if (oauthAccount?.emailAddress) return oauthAccount.emailAddress
// Anthropic employees only:
if (process.env.COO_CREATOR) return `${process.env.COO_CREATOR}@anthropic.com`
return getGitEmail() // runs `git config user.email`
For external users, email is only included if you authenticated with Claude.ai OAuth. API key users send no email. The email goes to the first-party BigQuery sink only — it is a top-level field on the ClaudeCodeInternalEvent proto. It does not go to Datadog. That separation is deliberate: the Datadog client token is public and hardcoded in the source. Your email is routed exclusively to the sink only Anthropic can read.
What Datadog receives instead is a bucket number — a value between 0 and 29 derived by hashing your device ID with SHA-256 and taking the result modulo 30:
const hash = createHash('sha256').update(userId).digest('hex')
return parseInt(hash.slice(0, 8), 16) % 30
This is a privacy-preserving cardinality estimation technique. Anthropic can count roughly how many users are triggering a given event without any individual being identifiable from Datadog's side.
There is one additional case: when Claude Code runs inside GitHub Actions, the first-party sink also receives actor_id, repository_id, and repository_owner_id — the numeric GitHub IDs for the triggering user, the repository, and its owner. These are not display names. They are the stable numeric identifiers GitHub assigns internally and they go into the github_actions_metadata field of the environment block.
The full breakdown by sink:
| Identifier | Datadog | BigQuery |
|---|---|---|
| Raw device ID | No | Yes |
| Session ID | Yes | Yes |
| Email address | No | Yes (OAuth users only) |
| Account UUID | No | Yes (OAuth users only) |
| Organization UUID | No | Yes (OAuth users only) |
| Bucket number (0–29) | Yes | No |
| GitHub actor/repo IDs | No | Yes (CI only) |
| Subscription type / rate tier | Yes | Yes |
API key users have the smallest footprint: only the bucket number reaches Datadog, and only the device ID and session ID reach BigQuery. Claude.ai OAuth users have their email, account UUID, and organization UUID attached to every BigQuery event for every action they take in the tool.
If You Care About Privacy: What to Clean and What to Set
Everything Claude Code stores locally that is relevant to your identity and session history lives under these paths, derived from the source:
~/.claude.json— the global config file. This is where your permanent device ID (userID) is stored, alongside your OAuth tokens (which carry account UUID, org UUID, and email), trusted project paths, and model preferences. Deleting this file resets your device ID — a new one is generated on next launch — but it also logs you out of Claude.ai. If you want to rotate only the ID without losing auth, open the file and remove just the"userID"key; Claude Code will generate a fresh one on next run.~/.claude/projects/— session transcripts. Every conversation is stored here as a.jsonlfile, one per session, organized by project directory. These files contain the full message history of every session you have run. They are never sent to Anthropic, but they accumulate indefinitely. The source shows Claude Code only auto-cleans files older than a configurable cutoff — the rest persist until you delete them.~/.claude/history.jsonl— every command you have typed at the prompt across all sessions, stored globally. Not sent to Anthropic, but it is a local record of everything you have asked.~/.claude/telemetry/— failed or buffered first-party analytics events. These are events that did not flush successfully and are queued for retry. If telemetry is disabled after events were written here, this directory may still contain them.~/.claude/cache/— model capability cache and changelog. Safe to delete; it repopulates on next launch.
To stop events from being sent in the first place, the source confirms two env vars:
# Stops all analytics events (Datadog + first-party BigQuery)
DISABLE_TELEMETRY=1
# Master toggle: analytics + auto-updates + release note fetches + bug report command
CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1
Both can be set persistently in ~/.claude/settings.json so they apply to every session:
{
"env": {
"CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1"
}
}
Three things the official opt-outs do not cover:
First, model training is a completely separate control from telemetry. The env vars above do not affect whether Anthropic uses your conversations to train models. For Free, Pro, and Max accounts, that toggle lives at claude.ai/settings/data-privacy-controls — it is opt-out, not opt-in. Commercial API, Team, and Enterprise users are excluded from training data by default.
Second, there is a known open bug (GitHub #34178): setting DISABLE_TELEMETRY or CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC silently disables access to the Opus 4.6 1M context window on eligible plans. The opt-out and the capability gate are coupled in a way that has not been fixed. If you enable the privacy flag and then lose access to the extended context window, that is why.
Third, another open bug (GitHub #5508) reports that on Windows, OpenTelemetry output continues to send data every 30 seconds even with DISABLE_TELEMETRY set. The flag is not fully honored on that platform.
Three Products, One Codebase
Reading the source as a whole, a few things become clear that are not obvious from using the product. Claude Code is not one product — it is at minimum three, layered on the same infrastructure: the CLI tool users have today, KAIROS (an always-on autonomous agent that is already wired into the backend), and a browser-based remote execution environment (CCR) that ULTRAPLAN already integrates with. The Fennec-to-Opus migration, the opus[1m] alias wired into the model selector, and the context-1m-2025-08-07 SDK beta header suggest a 1 million token context window is already plumbed into the codebase and waiting on a gate flip.
BUDDY is harder to read strategically. It is too carefully built to be a throwaway experiment — the Mulberry32 PRNG, the anti-cheat bone regeneration, the Claude-generated soul, the 1% shiny probability — these are details that take time. The friend-2026-401 salt suggests it was built or finalized in early 2026. It may simply be that Anthropic's engineering team wanted something delightful in the tool they use every day, and the external release is the moment the rest of us find out it exists.
The tracking architecture is worth reading carefully if you are a Claude.ai OAuth user. Every tool use, every session start, every model call, every compaction — each one arrives at Anthropic's BigQuery sink with your email address, account UUID, and organization UUID attached. API key users send a hashed bucket number instead, which is meaningfully different. The official env vars to stop this exist, but they come with an undocumented side effect on the 1M context window and a known bug on Windows. The source is honest about the mechanism; the product is less forthcoming about the tradeoffs.
The Undercover Mode, finally, is the most quietly significant revelation. Anthropic employees use Claude Code on public repositories. The system has been designed so that the resulting commits are indistinguishable from human work — no attribution, no AI acknowledgment, no version numbers. The model does not even know what model it is. Whether that is a reasonable operational security measure or something users of public open-source software should know about is a question the source code does not answer. It just shows you that the system exists and that there is no way to turn it off.