# Claude Code v2.1.240

> Claude Code v2.1.240, released 22 Aug 2026 (2026-08-22). 10 entries read out of the shipped bundle. Unofficial, and not affiliated with Anthropic.

Web version: https://changelogs.core-directive.com/v/2.1.240

This build carries seven pieces of unreleased work, most of it about how the model's thinking is shown. The machinery to pick a thinking display mode is present, but the one path that does anything new, connector text only, needs a server-supplied model capability plus an internal gate before it sends the `thinking-display-updates-2026-08-18` API beta, so nothing changes on a stock build; the new three-state `CLAUDE_CODE_THINKING_DISPLAY_UPDATES` setting lets you force it on or off, and left unset it defers to the remote gate, which is off. Claude Code also now detects thinking blocks the server tagged as narration by reading the block's signature, and counts them for everyone, though hiding them from the live thinking preview and marking them "(summarized)" both sit behind an off-by-default gate. A one-time dialog offering to drop your saved default effort from high to medium is fully wired up, telemetry included, but takes all its wording from the remote config key `tengu_radiant_island`, which ships empty, so it never renders. Separately, saving a default effort can be scoped to just the model you are using rather than globally, gated off by default.

## What probably matters to you

Anything you can use today, anything that visibly changes, and anything worth poking at. One line each, open for detail.

### CLAUDE_CODE_THINKING_DISPLAY_UPDATES environment variable

Set CLAUDE_CODE_THINKING_DISPLAY_UPDATES to force the new thinking display on or off yourself.

**What**

A new three-state environment variable in the settings schema. Set it true to force the new thinking display on, false to force it off; leave it unset and the remote gate decides, which is off by default.

**Evidence**

`CLAUDE_CODE_THINKING_DISPLAY_UPDATES`

- Area: Thinking Display
- Names: `CLAUDE_CODE_THINKING_DISPLAY_UPDATES`
- Tier: Use it now
- Useful: 4/5
- Signal: 4/5

### Thinking display modes gated behind a server-side model capability

Claude Code can present thinking as connector text only, but nothing enables it here.

**What**

Claude Code gains machinery to choose how a model's thinking is presented: thinking plus the short connector text that bridges to the next action, connector text only, or nothing at all. Only the connector-text-only path does anything new, asking the model for streaming thinking updates and attaching the new API beta id `thinking-display-updates-2026-08-18` to the request. Reaching that path needs a model capability the server has to supply plus an internal gate, so with no server configuration the beta is never sent, and the selector helper that maps a requested mode onto a display is not called anywhere in this build.

**Details**

- Resolution order is: an explicit `summarized` request wins and shows thinking plus connector text, then `omitted` shows nothing, then non-interactive sessions show nothing, then the `showThinkingSummaries` setting gives thinking plus connector text, and last the capability-plus-gate path gives connector text only.
- The helper's own fallback branch shows connector text only when both the thinking-display-updates gate and the `tengu_sable_thrush` gate are on, and otherwise shows nothing.
- Setting the `CLAUDE_CODE_THINKING_DISPLAY_UPDATES` environment variable short-circuits the check and is returned directly; otherwise the server-supplied model capability or the remote `tengu_thinking_display_updates` gate decides, with the value compiled into the binary defaulting to off.
- The outgoing request is only rewritten to carry the beta when the endpoint is first-party and streaming-capable and the `CLAUDE_CODE_SIMULATE_PROXY_USAGE` environment variable is not set.

**Evidence**

`if (e === "summarized") return "thinking_and_connector_text";`, `thinking-display-updates-2026-08-18`

- Flag `tengu_sable_thrush`: On for this account, and not off by default (read for one account on one subscription tier against v2.1.240; this account: on, anonymous baseline: on, compiled default: on)
- Flag `tengu_thinking_display_updates`: Off in both readings (read for one account on one subscription tier against v2.1.240; this account: off, anonymous baseline: off, compiled default: on)
- Area: Thinking Display
- Names: `CLAUDE_CODE_THINKING_DISPLAY_UPDATES`
- Tier: Not switched on
- Useful: 2/5
- Signal: 5/5
- Present in the build but not switched on

### "Switch your default effort to medium?" prompt, complete but with no text to show

A one-time prompt offering to switch your default effort to medium exists but has no text.

**What**

A one-time dialog offering to change your saved default effort from high to medium, confirming with `Effort set to medium and saved as your default` or a warning if the write fails. It is fully reachable in the prompt sequence, ahead of the LSP and plugin hints, and marks itself seen so it appears at most once. But its wording comes entirely from the remote config key `tengu_radiant_island`, whose in-binary value is an empty object and whose body text is required, so with no server value the dialog never appears.

**Details**

- Only the body text is required; title, confirm label and cancel label have in-code defaults.
- You are only eligible if you have no effort pinned anywhere, or have pinned high in your user settings. Any other configuration disqualifies.
- The parent picks it as `effort-medium-nudge` in the same chain as the fullscreen upsell and remote callouts.

**Evidence**

`Switch your default effort to medium?`

- Flag `tengu_radiant_island`: Not enough to say (read for one account on one subscription tier against v2.1.240; this account: no value returned, anonymous baseline: no value returned, compiled default: not a boolean we can read)
- Area: Effort Levels
- Tier: Not switched on
- Useful: 3/5
- Signal: 4/5
- Present in the build but not switched on

### Saving a default effort level can now scope it to one model

Your saved default effort could apply per model instead of everywhere, but that is off.

**What**

Previously, saving a default effort wrote both a global setting and a per-model one. With the `tengu_russet_plover` gate on, it now writes only the per-model entry, so the default applies to the model you are using rather than everything. With the gate off, which is the built-in default, it writes only the global setting.

**Details**

- The gate is remote, `tengu_russet_plover`, fallback off.
- Model names that would collide with built-in JavaScript object property names also fall back to the global-only write.

**Evidence**

`{ effortLevel: t, modelSettings: { [r]: { effortLevel: t } } }`

- Flag `tengu_russet_plover`: Off in both readings (read for one account on one subscription tier against v2.1.240; this account: off, anonymous baseline: off, compiled default: on)
- Area: Effort Levels
- Tier: Not switched on
- Useful: 3/5
- Signal: 4/5
- Present in the build but not switched on

### Server-tagged "narration" thinking blocks, counted now and rendered as "(summarized)" later

Claude Code now spots server-tagged narration thinking, but the display change stays off by default.

**What**

Claude Code can now tell whether the model's thinking block was tagged by the server as narration, by decoding the block's cryptographic signature and looking for the literal string `narration` inside it. The count of such blocks per request is reported for everyone on this build. The display changes that depend on it are held behind a gate that is off by default, so on a stock build thinking still renders exactly as before.

**Details**

- The classifier caches its result per block, so each block is decoded once.
- Decode failures are swallowed silently and reported once as `narration_classifier_error`.
- The telemetry field counting narration blocks per request existed in 2.1.239 but was wired to a check hardcoded to return nothing, so it never reported; it is now wired to the real check and has no gate.
- The display-side check additionally requires `CLAUDE_CODE_SABLE_THRUSH` set true or the remote `tengu_sable_thrush` gate to be on, with the in-binary fallback off, and it also requires the server to actually be tagging blocks.
- With the gate on, the main message renderer prints a dimmed, italic `(summarized)` label above the trimmed thinking text instead of the reasoning itself, the live thinking pane blanks out for such blocks, and a reply whose first block is narration counts as having visible content.
- Screen readers get a dot column labelled `summarized:` in place of the visual label.
- Each of the three display sites checks the classifier helper is present before calling it, so those paths stay inert if it is absent.

**Evidence**

`narration_classifier_error`, `"aria-label": "summarized:"`, `(summarized)`

- Flag `tengu_sable_thrush`: On for this account, and not off by default (read for one account on one subscription tier against v2.1.240; this account: on, anonymous baseline: on, compiled default: on)
- Area: Thinking Display
- Names: `CLAUDE_CODE_SABLE_THRUSH`
- Tier: Not switched on
- Useful: 2/5
- Signal: 4/5
- Present in the build but not switched on

## In Development

### Narration thinking is kept out of the live thinking preview

Narration thinking would be hidden from the live thinking preview, but that path is switched off.

**What**

The streaming path used to always show the first thinking block of a reply as the in-progress thinking preview. It now checks whether that block is narration first and shows nothing if so. Only reachable with the sable-thrush gate on, which is off by default.

**Details**

- The call site also checks that the narration helper is present before using it, so builds without it behave as before.

**Evidence**

`isNarrationSummaryBlock`

- Area: Thinking Display
- Tier: Not switched on
- Useful: 2/5
- Signal: 3/5
- Present in the build but not switched on

### Telemetry for the effort nudge

Two events would record the effort prompt and your answer, but it never shows.

**What**

Two events fire only when the effort-medium prompt actually renders, which requires the remote `tengu_radiant_island` config to supply its text. One records the display and which group you fell into, the other records your choice and the outcome: switched, declined, write_failed or unavailable.

**Details**

- Failure paths also record a reason, either `unavailable_at_accept` or `settings_write_failed`.

**Evidence**

`tengu_effort_medium_nudge_resolved`

- Flag `tengu_radiant_island`: Not enough to say (read for one account on one subscription tier against v2.1.240; this account: no value returned, anonymous baseline: no value returned, compiled default: not a boolean we can read)
- Area: Effort Levels
- Tier: Not switched on
- Useful: 1/5
- Signal: 2/5
- Present in the build but not switched on

## Internal Changes

### Per-message stats count narration thinking blocks

Per-message character tallies now include narration blocks, so usage stats count a bit more.

**What**

The routine that tallies text and thinking character counts per message now also counts blocks tagged as narration. This uses the raw signature check with no gate, so it counts on every build where the helper is present.

**Evidence**

`isNarrationTaggedBlock`

- Area: Telemetry
- Tier: Under the hood
- Useful: 2/5
- Signal: 3/5

### Version stamped as 2.1.240

The build now reports itself as version 2.1.240 in version checks and headers.

**What**

The embedded version, build time and commit id moved to the 2.1.240 build. These drive `claude --version`, update checks, Remote Control minimum-version messages, user-agent headers and analytics fields. No behaviour change beyond the new values.

**Evidence**

`VERSION: "2.1.240"`

- Area: Elsewhere
- Names: `claude --version`
- Tier: Under the hood
- Useful: 2/5
- Signal: 1/5

### Most of this release is the version stamp and compiler churn

Nearly all of this release is repeated build-constant updates and renamed variables, not real changes.

**What**

About 90 of the changes are the same build-constant block re-emitted at each place it is used. The rest, including the GitLab merge-request URL pattern, git worktree paths, test and typecheck command detection, the login-error check and a long tail of reformatting in the MCP and plugin sync code, are identical apart from renamed internal variables.

**Evidence**

`GIT_SHA: "d235569e3f61fc4d9aacd7c85e6d1b6253e03f52"`

- Area: Elsewhere
- Tier: Under the hood
- Useful: 1/5
- Signal: 1/5
