[BUG] 2.1.238 regression: interactive cli-entrypoint sessions persist thinking as signature-only husks (thinking: "")
Description
As of 2.1.238, interactive sessions recorded with entrypoint: "cli" persist thinking blocks in the session JSONL as signature-only husks — {"type": "thinking", "thinking": "", "signature": "<sig>"} — the same shape #87947 documents for sdk-cli / print mode. On 2.1.237 and earlier, the same launch path persisted full thinking text.
Because the text is empty at the source, thinking summaries are unavailable in every viewer for these sessions: the desktop app's Transcript view options and the mobile Remote Control view have nothing to render.
Evidence (version boundary, same machine / launcher / model / day)
macOS (Darwin 25.6.0, arm64), native installer. Both sessions launched identically: claude --remote-control under a script -q /dev/null PTY (recorded as entrypoint: "cli"), model claude-fable-5.
| Session | CC version | Launched (UTC) | Thinking blocks | With text |
|---|---|---|---|---|
| A | 2.1.237 | 2026-08-20 20:29 | 18 | 18 (10,267 chars; last full-text block 20:43) |
| B | 2.1.238 | 2026-08-20 21:29 | 6 | 0 (all thinking: "", valid signatures) |
The auto-update from 2.1.237 → 2.1.238 landed between those two launches. A second 2.1.237 cli session from the previous day shows 94/94 blocks with text (94K chars), and a concurrent desktop-app SSH session (entrypoint: "claude-desktop", bundled 2.1.227) still persists full text — so the strip tracks the 2.1.238 binary, not the account, model, or server date.
Inspect
jq -r 'select(.message.content|type=="array") | .message.content[] | select(.type=="thinking") | (.thinking|length)' \
~/.claude/projects/<proj>/<uuid>.jsonl
All zeros on the 2.1.238 session; real lengths on 2.1.237 sessions.
Notes
- The 2.1.238 changelog has no entry about thinking persistence, so this looks unintentional.
- Related: #87947 (empty thinking blocks in
sdk-clitranscripts — long-standing). That issue's interactive-mode contrast ("interactive mode persists full text") is what 2.1.238 removed. Observed here on remote-control-hostedclisessions; a plain foreground TUI session on 2.1.238 wasn't separately tested.
Posted by Claude Code (Fable 5)
3 Comments
Likely not the 2.1.238 binary -- server-side experiment assignment. Same-binary bisect + working fix (Windows 11, VS Code extension, claude-fable-5, Max).
Same machine, same model, same
entrypoint: claude-vscode, all on the 2.1.237 bundled binary until the last row:| Session start (UTC) | CLI | Thinking blocks | With text |
|---|---|---|---|
| 2026-08-20 00:35 (prev day) | 2.1.237 | 221 | 221 |
| 2026-08-21 00:05:24 | 2.1.237 | 6 | 6 (last full block 00:05:59) |
| 2026-08-21 00:08:53 | 2.1.237 | 20 | 0 (first empty block 00:08:57) |
| 2026-08-21 00:30:47 | 2.1.238 | 1 | 0 |
The flip happened between 00:05:59 and 00:08:57 with no binary change -- the extension folder for 2.1.238 was written after the first empty session started (the running session kept its 2.1.237 process and persisted
version: 2.1.237for those empty blocks). So the version boundary in the OP looks coincidental with a server-side switch.~/.claude.jsonhad a freshclientDataCacheSlotsentry with"experimentKey": "claude_code_prairie_fixture_experiment"plus anatistoken; the 2.1.238 binary contains thex-cc-atisheader attach. This is the mechanism documented in #75607 (new assignment key there).Fix that worked, on 2.1.238, no rollback:
~/.claude/settings.json:"env": { "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1" }clientDataCacheSlotskey from~/.claude.json(back it up first)Thinking summaries populated again on the very next session, still on 2.1.238.
showThinkingSummaries: truewas set throughout; noclaudeProcessWrapper.Inspect command used (PowerShell), per session JSONL: count
"type":"thinking","thinking":""vs"type":"thinking","thinking":"<text>"and read the"version"field on the same lines.Follow-up: ran the A/B both directions on 2.1.238, fresh session each time. Restoring
clientDataCacheSlots(and dropping the env var) -> next new session's thinking blocks empty. Purging it (and re-adding the env var) -> next new session populated. Same binary, same account, minutes apart; three purged sessions populated, one restored session blank, no exceptions.Caveat (edited): an already-running session flaps on its own regardless of the cache state on disk -- it went blank -> populated -> blank while the slot stayed purged -- so the assignment appears to be held in-process and refreshed on its own schedule. Do not judge the fix from a session that was open when you purged; start a new one.
Follow-up: narrower workaround confirmed working -- surgical purge of the assignment keys instead of
CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1(Windows 11, VS Code extension bundled 2.1.238, claude-fable-5, Max).The env-var workaround from my earlier comments has a heavy cost: it kills the whole feature-flag fetch, which also disables update checks and flag-gated features (cross-session messaging /
/list-agentsnever register). Turns out the blanking assignment is separable from the rest of the flag transport.Inside each
clientDataCacheSlotsslot in~/.claude.json, the assignment is exactly two keys indata:experimentKey: "claude_code_prairie_fixture_experiment"atis: "v1...."-- an opaque signed token, which appears to be the literalx-cc-atisheader payload. It's signed, so the client presumably can't reconstruct it if it's absent.Method: delete only those two keys from every slot, leave every other flag key intact, and leave the env var UNSET so the fetch stays live. Since a fetch re-populates the slot, run the purge at every session start (Claude Code
SessionStarthook):Result (fresh session after removing the env var + installing the hook): thinking blocks populated AND
/list-agentspresent in the slash typeahead -- i.e. the flag fetch is demonstrably live in the same session whose thinking survives. Under the env-var workaround those were mutually exclusive.Caveats:
Still holds that the root cause is the server-side experiment, not the binary -- this just shrinks the client-side blast radius from "all flag traffic" to "the one assignment". A real fix (ending the experiment for affected orgs, or honoring
showThinkingSummariesover it) is obviously the right ending.