[BUG] Server-side experiment (`x-cc-atis`) silently removed Opus 4.8 thinking summaries, and the CLI silently self-updated even with `autoUpdates: false`. No notice, no opt-in, settings silently overridden.

Open 💬 4 comments Opened Jul 8, 2026 by phase3dev

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

UPDATE 2026-07-08:
The mitigation documented below (purge the cached assignment + DISABLE_GROWTHBOOK=1) stopped working within a day. The CLI's startup bootstrap fetch re-enrolls the install about one second after launch, ignoring that variable. The only working user-side opt-out is now purge + CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1, which also disables Projects sync, DesignSync, /feedback, live preview, and telemetry. Measurements in the correction comment below.

ORIGINAL POST:
I want a straight answer from someone at Anthropic about what shipped yesterday, because from where I sit you reached into my working setup mid-evening without authorization, turned off a documented feature on the one model I use most (Opus 4.8), told nobody, and left us to burn the rest of the night debugging to ultimately determine it was Anthropic's own stealthily installed experimental flag that caused the issues.

If that wasn't bad enough, while diagnosing the above, I discovered a second violation the same day: the CLI binary somehow updated itself while auto-updates are explicitly disabled (confirmed). Combined with the other recent issues and revelations, Anthropic seems to be engaging in some extremely sketchy practices.

Although lengthy, I urge other users to read through this issue report.

Background (issue #63358)

#63358 documents that Opus 4.8 returns thinking blocks with an empty thinking field, so the UI has nothing to render, continuing the Opus 4.7 regression family (#49268, #49555, #56356, #49322, #49902, #54348). The root cause established in that thread was client-side: the API defaults thinking.display to omitted on 4.7/4.8, showThinkingSummaries was honored only in interactive mode, and the VS Code extension (non-interactive) never mapped the setting onto the --thinking-display flag.

My comment in that thread

I root-caused the client-side gap, posted the analysis (https://github.com/anthropics/claude-code/issues/63358#issuecomment-4656278497), and built and shared a public workaround so other affected users could get summaries back: a launcher that injects --thinking-display summarized, the one lever that is not interactivity-gated, plus an extension patch and a proxy design:

https://github.com/phase3dev/claude-code-workarounds

What happened on 2026-07-07 (times HST, UTC-10): full timeline

  • 6:35am: I manually updated the VS Code extension to 2.1.202 (extension install directory mtime). That was my last version action until the evening.
  • 11:09am: The CLI native binary SILENTLY self-updated 2.1.202 -> 2.1.203. I did NOT run an update. Auto-updates are disabled ("autoUpdates": false in ~/.claude.json) and were disabled at the time. The CLI's own updater recorded the event in ~/.claude/.last-update-result.json; timestamp converted below to HST for readability:

``json
{"timestamp_hst_start":"2026-07-07 11:09:12.832 HST","path":"native","outcome":"success","status":"success","version_from":"2.1.202","version_to":"2.1.203","error_code":null}
``

The 2.1.203 binary in ~/.local/share/claude/versions/ carries the same creation second (11:09:12.648 local). A Claude Code session was running at that minute. The background updater fired inside a live session, against the explicit setting. I have NEVER had the CLI binary update itself before, ever.

  • Sessions all day continued to return populated summaries on Opus 4.8 (session transcripts: max thinking length 5,347 chars at 7:50pm, 4,179 at 7:12pm).
  • At 7:12:18pm, Claude Code's built-in remote feature-flag client cached a new experiment assignment into ~/.claude.json (epoch 1783487538925).
  • The next session (7:58pm) and every session after: EVERY Opus 4.8 thinking block came back with thinking length 0 and a valid signature (21 consecutive signed-but-empty blocks in one session; signatures 660-7,436 bytes).
  • I noticed thinking summaries had stopped showing in VS Code upon opening a new chat. I checked versions: the VS Code extension was still 2.1.202, unchanged since my morning update, and no 2.1.203 extension version was ever installed on this machine. The CLI binary, however, had somehow become 2.1.203.
  • ~7:56pm: I downgraded the CLI back to 2.1.202 to test whether summaries would return (the re-downloaded 2.1.202 binary carries mtime 7:56:55pm). They did not; consistent with the root cause being server-side, not the binary.
  • 10:01-10:02pm: to ensure everything matched, I manually updated both surfaces to the latest version: VS Code extension 2.1.204 (10:01:22) and CLI 2.1.204 (10:02:13).
  • To be clear: the regression occurred before any manual update or downgrade. The break is at 7:12:18pm; my first manual version action of the evening was ~7:56pm.
  • No client component changed across the break. Both sides of it: CLI 2.1.202, model claude-opus-4-8, entrypoint claude-vscode: byte-identical binary, opposite outcome. We wasted hours ruling out CLI 2.1.201/202/203/204 and extension versions. All red herrings for the blanking itself: the silent 2.1.203 self-update at 11:09am is NOT the cause of the blanking (summaries worked for hours after it, and the blanking reproduces on 2.1.201-2.1.204 alike once the assignment is cached). It is a second, independent problem from the same day, documented in its own section below.

The CLI updated itself while auto-updates were disabled

Auto-updates were and remain off in both the CLI and VS Code. My ~/.claude.json reads, verbatim:

{
  "autoUpdates": false,
  "autoUpdatesProtectedForNative": true,
  "installMethod": "native"
}

Yet the updater ran through the native path starting at 11:09:12am HST on 2026-07-07, downloaded 2.1.203, switched the active binary, and recorded "outcome":"success" in its own log. This occurred with no notice, no prompt, and no user action. I have never experienced the CLI binary auto-updating before. This significantly reduces my trust in what this tool does on my machine. I want to know:

  1. How is this possible with "autoUpdates": false set? Is the native install path ignoring the setting, and what does the undocumented autoUpdatesProtectedForNative key actually mean?
  2. What provision of the Terms of Service allows Anthropic to stealthily install software and experimental features, with no opt-in, while auto-updates are explicitly turned off?

The combination is what makes this serious: on the same day, the same install received an unrequested binary swap (client-side, against my setting) and an unannounced server-side experiment enrollment (against my documented showThinkingSummaries: true). Both were silent. Both were discovered only by forensics.

Layman summary

My install was silently enrolled in an A/B experiment. The enrollment token is cached in my local config and attached by the CLI to every API request as an x-cc-atis header. When Opus 4.8 (and only Opus 4.8) sees that token, the API strips the thinking text out of the response while keeping the signed thinking block. The reasoning still runs and still consumes tokens; only the human-readable text is withheld. Remove the token and the very same request returns summaries again. Nothing I did caused this, and nothing I was allowed to configure could stop it.

Technical details

  1. The assignment, cached client-side (~/.claude.json, clientDataCacheSlots):
"experimentKey": "claude_code_attic_parcel_experiment",
"atis": "attic-parcel-meridian"

First cached at epoch 1783487538925 = 19:12:18 HST, the exact minute summaries died. A second slot refresh landed at 20:01:35 (1783490495244), the relaunch after the 2.1.204 update.

  1. The header attach, in the 2.1.204 native binary (shared fetch wrapper, first-party path, i.e. every surface: VS Code, headless -p/SDK, TUI):
Yvi = "x-cc-atis"
function Xvi(){ let e = cL()?.atis; return typeof e === "string" && e.length > 0 ? e : void 0 }
// per-request:
if (o) { let m = Xvi(); if (m !== void 0) a.set(Yvi, m) }
// cL() reads clientDataCacheSlots / clientDataCache back out of ~/.claude.json
  1. The request is provably correct. Observed on the wire through a local forwarder (which logged only the body's model/thinking fields and response thinking lengths, never headers): the request body carries
"thinking": {"type": "adaptive", "display": "summarized"}

So this is not the #63358 client gap. The client asks for summaries exactly as documented, and the server withholds the text anyway.

  1. Single-variable proof, one binary (2.1.204), one account, same prompt, minutes apart, request body identical in every run:

| Run | x-cc-atis on the wire | Opus 4.8 thinking length |
| --- | --- | --- |
| Direct (assignment cached) | yes | 0 (signature present; repeated runs: sig 512/540/564/836) |
| Identical request, header stripped in flight | no | 226 |
| Assignment purged from config + DISABLE_GROWTHBOOK=1 (direct request shape) | no (verified) | 65 |
| DISABLE_GROWTHBOOK=1 alone, cache not purged | yes | 0 |

  1. Model scope, same flags (--thinking-display summarized --max-thinking-tokens 8000), same account, direct path:

| Model | thinking length |
| --- | --- |
| claude-opus-4-7 | 179 |
| claude-sonnet-5 | 253 |
| claude-haiku-4-5 | 528 |
| claude-fable-5 | 5,643 (VS Code path) |
| claude-opus-4-8 | 0 |

All four alias spellings (opus, claude-opus-4-8, opus[1m], claude-opus-4-8[1m]) resolve to claude-opus-4-8 and all return 0. Transport ruled out: HTTP/1.1 and HTTP/2 upstream legs, and accept-encoding forwarded verbatim, all behave identically once the header is controlled for.

  1. No user-accessible lever can prevent it. On first-party auth the CLI hard-forces thinking.type: "adaptive" for 4.8 (capability-gated; the only override hook is a server-rejection retry), the ANTHROPIC_*_SUPPORTED_CAPABILITIES env overrides are disabled on first-party, and DISABLE_GROWTHBOOK=1 alone still sends the already-cached token (measured, row 4 above). The only mitigation is manually editing the assignment out of ~/.claude.json and setting DISABLE_GROWTHBOOK=1 so the next feature refresh doesn't re-enroll; in other words, opting out of your entire client-side feature system to get back one documented feature.

Why this is unacceptable

  • There is no documentation. Nothing anywhere documents that an x-cc-atis assignment can disable thinking summaries per model. Users cannot diagnose what is not documented; it took binary disassembly and a wire proxy to find this.
  • It is not in the release notes. The CHANGELOG through 2.1.204 does not mention it, and no client release note could cover it, because the switch is server-evaluated. That is precisely why server-side behavior changes need their own announcement channel, and this one had none.
  • Affected users were not notified. The flip happened mid-evening, between two sessions, on an unchanged binary. There is no message, no banner, no log line. The feature just dies and the user is left debugging their own setup.
  • There is no opt-in. I never agreed to be an experiment subject for the removal of a feature I actively depend on and explicitly enabled.
  • There is no documented opt-out. showThinkingSummaries is your documented opt-in: the setting's own schema says: "Request API-side thinking summaries and show them in the conversation and in the transcript view (ctrl+o)." It is set to true, the client honors it, and the server overrides it silently. Shipping a toggle that no longer toggles anything is worse than shipping no toggle.
  • The updater ignored my explicit setting. "autoUpdates": false is the documented control, it was set, and the native-path updater installed 2.1.203 anyway, silently and mid-session, recorded as "success" in its own log. If a documented off-switch does not switch anything off, every other setting in the product is now suspect too.
  • It broke my local workflow. I review this model's reasoning as part of how I work. That went dark mid-session, on the model I pay to use, while the thinking tokens kept being generated, signed, and counted.
  • It broke my workaround. The launcher I built exists specifically to guarantee display: "summarized" reaches the wire. It still does. The experiment ignores it.
  • It broke the workaround shared publicly with other users. phase3dev/claude-code-workarounds is linked in this thread and used by others who followed it out of the same regression. Every one of them who lands in this experiment bucket loses summaries again with no explanation, and this time no flag can bring them back.
  • Users should not need to maintain public workaround repos for this in the first place. The community spent weeks reverse-engineering #63358's client gap. You fixed it in 2.1.202, which was good. Then a server-side experiment reintroduced the identical user-facing symptom within weeks, invalidating both your fix and ours.
  • Targeting exactly Opus 4.8 is suspicious and concerning. Of five models tested, the only one that ignores an explicit display: "summarized" is your flagship coding model, the one this thread is about, the one the workaround was built for, and the primary model in my workflow. Whether the blanked text is the experiment arm working as designed or a defect in an experimental serving path, I cannot tell from outside. Either way it is a decision someone configured and shipped against paying users, silently.
  • You are spending user trust you will not easily get back. Documentation, a release note, a notification, an opt-in, or a working opt-out, any single one of these would have prevented most of the damage. All of them are basic product hygiene. None of them happened. I am a loyal, paying user who has put real effort into this product's ecosystem, and this is the second time in short order I've had to treat my own tooling as the suspect for something Anthropic changed under my feet.
  • This is a pattern, not a one-off. The AskUserQuestion 60-second-timeout behavior change (#73125) shipped the same way: silent, undocumented, discovered by users in the field. Silent behavior changes to a tool that people build workflows on is not a sustainable way to run a developer product.

What Should Happen?

  1. claude-opus-4-8 honors an explicitly requested thinking.display: "summarized" exactly like Opus 4.7, Sonnet 5, Haiku 4.5, and Fable 5 do, regardless of experiment bucket. At minimum, users with showThinkingSummaries: true should be excluded from any experiment that suppresses summaries.
  2. Server-side experiments that change user-visible, documented behavior come with: an announcement, a changelog/release-notes entry, in-product notice to enrolled users, and a documented, supported opt-out. Ideally opt-in.
  3. showThinkingSummaries either works or is removed/deprecated with notice. A documented setting must not be silently overridden by an undisclosed experiment.
  4. Answers, from someone in a position to know: Why does Opus 4.8 alone ignore the explicit display request when x-cc-atis: attic-parcel-meridian is present? Is the blanked text the intended arm behavior of claude_code_attic_parcel_experiment, or a defect in that arm? Who decided to ship it with no notice? What is the supported path for users who need visible reasoning on Opus 4.8 today?
  5. An explanation and a fix for the auto-update: why did the native updater install 2.1.203 starting at 11:09:12am HST on 2026-07-07 with "autoUpdates": false set, what does autoUpdatesProtectedForNative mean, and what Terms of Service provision covers silently installing software and experiment enrollment on a machine whose owner has auto-updates turned off? autoUpdates: false must mean no self-updates, period.

Error Messages/Logs

There is no error. That is the problem. The response is a 200 with a signed, empty thinking block.

Transcript sweep across the break (per-session max thinking length, model claude-opus-4-8, entrypoint claude-vscode, CLI 2.1.202 on both sides):

17:50 HST -> 5347 chars OK
19:12 HST -> 4179 chars OK
19:12:18 HST x-cc-atis assignment cached (epoch 1783487538925)
19:58 HST -> 0 chars BROKEN
20:06 HST -> 0 chars BROKEN (21/21 thinking blocks empty, signatures 660-7436 bytes)

Cached assignment (from ~/.claude.json; identifiers redacted, experiment fields verbatim):

{ "data": { "experimentKey": "claude_code_attic_parcel_experiment", "atis": "attic-parcel-meridian" }, "at": 1783487538925 }

Silent self-update record (~/.claude/.last-update-result.json; timestamp converted from UTC to HST and treated as the start time, written with "autoUpdates": false in ~/.claude.json):

{"timestamp_hst_start":"2026-07-07 11:09:12.832 HST","path":"native","outcome":"success","status":"success","version_from":"2.1.202","version_to":"2.1.203","error_code":null}

Wire capture (local forwarder; request-body fields and response thinking stats only, headers never logged):

{"dir":"req","model":"claude-opus-4-8","thinking":{"type":"adaptive","display":"summarized"},"stream":true}
{"dir":"resp","status":200,"model":"claude-opus-4-8","stop_reason":"end_turn","thinking_blocks":[{"type":"thinking","len":0,"sig":504}]} // header present
{"dir":"resp","status":200,"model":"claude-opus-4-8","stop_reason":"end_turn","thinking_blocks":[{"type":"thinking","len":226,"sig":580,"preview":"This is a classic cognitive reflection t"}]} // same request, x-cc-atis stripped

Steps to Reproduce

Precondition: an install whose feature client has received the assignment. Check with:

jq '.clientDataCacheSlots // {} | to_entries | map(select(.value.data.atis != null) | .value.data | {experimentKey, atis})' ~/.claude.json

If enrolled (non-empty output):

  1. Run the matrix (any small reasoning prompt):

``sh
for m in claude-opus-4-7 claude-sonnet-5 claude-haiku-4-5 claude-opus-4-8; do
claude -p 'A bat and ball cost $1.10; the bat costs $1.00 more than the ball. Reason step by step: what does the ball cost?' \
--model "$m" --output-format stream-json --verbose \
--max-thinking-tokens 8000 --thinking-display summarized --max-turns 1 > "out-$m.jsonl" 2>/dev/null
jq -r --arg m "$m" 'select(.type=="assistant")|(.message.content//[])[]|select(.type=="thinking")|"\($m) len=\(.thinking|length) sig=\((.signature//"")|length)"' "out-$m.jsonl"
done
``

Observed: claude-opus-4-7 len=179, claude-sonnet-5 len=253, claude-haiku-4-5 len=528, claude-opus-4-8 len=0 (sig 540).

  1. Prove the header is the trigger: route through a localhost forwarder (ANTHROPIC_BASE_URL=http://127.0.0.1:<port> plus _CLAUDE_CODE_ASSUME_FIRST_PARTY_BASE_URL=1 so the CLI still builds the true first-party request shape; without that env the CLI builds a different request and stops sending the header, which masks the bug) and drop only the x-cc-atis request header. Same run: len=226.
  1. Prove the mitigation: purge the atis slots from ~/.claude.json, launch with DISABLE_GROWTHBOOK=1, run direct: len=65, header absent. (Steps and caveats: https://github.com/phase3dev/claude-code-workarounds, 2026-07-07 update.)

For the silent self-update: check ~/.claude/.last-update-result.json against your own "autoUpdates" setting in ~/.claude.json and the version-binary creation times in ~/.local/share/claude/versions/.

Claude Model

Opus

Is this a regression?

Yes, this worked in a previous version

Last Working Version

Not applicable. This is not a client regression. CLI 2.1.202 both worked and failed on the same day, and 2.1.201-2.1.204 all behave identically once the assignment is cached.

Claude Code Version

2.1.204 (Claude Code)

Platform

Anthropic API

Operating System

Ubuntu/Debian Linux

Terminal/Shell

VS Code integrated terminal

Additional Information

  • Background issue: https://github.com/anthropics/claude-code/issues/63358
  • Billing note: in every broken response the thinking block is generated and cryptographically signed. The reasoning tokens are produced and consumed; only the text is withheld from the person paying for them.

View original on GitHub ↗

This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗