# Claude Code v2.1.261

> Claude Code v2.1.261, released 4 Sep 2026 (2026-09-04). 189 entries read out of the shipped bundle. Unofficial, and not affiliated with Anthropic.

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

This build carries 17 dormant additions, most switched off behind hardcoded flags. Real-time PR webhook updates exist but are hardcoded off, so PR monitoring still polls every 30 minutes, and a new "thinking-binding-controls" beta header is compiled in but never sent. A Poll/Wait tool "evals" mode has nothing in this bundle that triggers it, and three placeholder tool entries are now always listed internally yet forced permanently off and hidden. Also inert: subagent output-truncation accounting behind the tengu_swift_whistle gate, a prefix-lock-rejection warning whose message text is always empty, an overage-included-models display with an empty-by-default model list, a "grant refused" safeguards error path whose trigger always returns false, a message-history folding pass held off by default behind tengu_chair_sermon, and MCP task-sidecar restore in --print mode, which is hard-gated off.

Of 80 shipped changes, several add configuration you can use right away. New settings bashOutputMaxChars and taskOutputMaxChars let you control how much Bash and Task output Claude sees inline before it spills to a file, and CLAUDE_STREAM_FIRST_BYTE_TIMEOUT_MS lets you tune how long Claude Code waits for the first byte of a streamed response. Cloud sessions running /mcp can now also list MCP servers attached to your local machine, and plugin marketplace add --claudeai lets you add a marketplace hosted on your claude.ai account. Other additions include an SDK --await-initialize flag to wait for plugin config over stdin, a CLAUDE_CODE_NONBLOCKING_STDOUT env var so slow output pipes can't hang the terminal, --append-subagent-system-prompt-file for the CLI, a configurable AWS Bedrock credential-resolution timeout, and an auto-mode dangerous-tool-use classifier, now expanded, that runs server-side and blocks unreachable checks for safety.

Among 35 fixes, failed background wake deliveries to agents now retry with backoff instead of dropping, and a cloud gateway 403 rejecting your org's settings no longer logs you out, showing a contact-admin message instead. Saving large tool results to disk is hardened against symlink and hardlink tampering, and the tool permission cache is now correctly keyed on GitHub repo and workspace-restriction state instead of serving stale results. Policy-limit data from before an account switch can no longer leak into the new account's session, and a newly org-approved synced plugin no longer stays silently disabled by a leftover local override. Separately, the keybindingFlavor setting is deprecated and classic word-editing keybindings are removed, so the prompt now always uses Bash-style word navigation.

## 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.

### New `<claude-code-hint>` tag lets tool/command output suggest a plugin to install

Tool and command output can now embed a hidden tag that suggests installing a specific plugin.

Tool and command output can now embed a `<claude-code-hint type="plugin" value="name@marketplace" v=1/>` tag to suggest installing a plugin. The tag is stripped from displayed output, and on the main thread the referenced plugin is surfaced as a pending install hint. Seen hints are deduplicated via new `seenHintPluginIds` session state (capped at 64) and logged through `tengu_plugin_hint_seen` with a hashed plugin id; only this telemetry/tracking step is skipped in restricted environments, while stripping always happens.

- Area: Plugin Marketplace
- Tier: Nothing to try yet
- Useful: 5/5
- Signal: 4/5
- Present in the build but not switched on

### Bulk per-tool token counting path gated behind two flags, both defaulting off

A bulk per-tool token counting path exists but is gated behind two flags, both off by default.

A new `countEach` helper can batch-count all tool definitions in a single model call instead of issuing one call per tool, for `contextType === "full"` contexts. This requires both the `tengu_peppy_zephyr` and `tengu_context_usage_bulk_counts` flags to be enabled, and both default to off, so the existing per-tool counting path remains in effect for now.

- Flag `tengu_peppy_zephyr`: Off by default, switched on for this account (read for one account on one subscription tier against v2.1.261; this account: on, anonymous baseline: on, compiled default: off) These values were read against a different version of Claude Code, so treat them as the nearest reading available instead of one taken on this release.
- Flag `tengu_context_usage_bulk_counts`: Not enough to say (read for one account on one subscription tier against v2.1.261; this account: no value returned, anonymous baseline: no value returned, compiled default: off) These values were read against a different version of Claude Code, so treat them as the nearest reading available instead of one taken on this release.
- Area: Context Management
- Names: `tengu_peppy_zephyr`, `tengu_context_usage_bulk_counts`
- Tier: Nothing to try yet
- Useful: 4/5
- Signal: 4/5
- Present in the build but not switched on

### Bridge (Remote Control) session creation can use a new v1alpha2 API surface

Remote Control session creation can use a new v1alpha2 API surface behind a flag.

Creating a bridge (Remote Control) session now checks a feature flag, `isCcrV2BridgeCreateEnabled`; when enabled, session creation builds the request and response through a new code path and sends `v1alpha2` as the create endpoint instead of the previous fixed `/v1/sessions` request shape.

- Area: Remote Control
- Names: `isCcrV2BridgeCreateEnabled`, `v1alpha2`
- Tier: Nothing to try yet
- Useful: 4/5
- Signal: 3/5
- Present in the build but not switched on

### New claude.ai-hosted marketplace source type

Plugin marketplaces gain a new claude.ai-hosted source type with its own caching and refresh logic.

Plugin marketplaces can now be sourced directly from claude.ai, alongside the existing git/github/url/local source kinds. This new `claudeai` source has its own cache-only/if-missing fetch logic and dedicated refresh and list-refresh code paths, and bulk refresh, `autoUpdate` toggling, and cache lookups all branch to handle it.

- Area: Plugin Marketplace
- Tier: Under the hood
- Useful: 4/5
- Signal: 3/5

### `--claudeai` flag lets you add a claude.ai-hosted plugin marketplace

You can now add a claude.ai-hosted plugin marketplace with a new --claudeai flag.

`plugin marketplace add` gains a `--claudeai <name>` option for adding a marketplace hosted on claude.ai for the user's account rather than declared in local settings files. A new `claudeai` source kind is now accepted throughout install, eligibility, and host-pattern checks alongside `github`, `git`, and `url`, and catalog files for it are stored under a `.marketplace-<id>.json` naming scheme. Adding a marketplace whose name starts with the reserved claude.ai prefix without `--claudeai` is now explicitly refused, and `--claudeai` itself rejects `--sparse`/`--scope` since these marketplaces aren't declared locally. On success the command prints an install hint (`claude plugin install <plugin>@<name>`); on failure it distinguishes tier-unavailable, ambiguous-name, policy-blocked, and not-listed cases with specific error messages.

Plugins installed from this source record new `claudeaiPluginId` and `archiveSha256` fields. Both the install-time capability check and the update path now verify that an installed plugin's `claudeaiPluginId` still matches what the marketplace lists; if the marketplace now points the same name at a different claude.ai plugin, a different source type, or the identity was lost, the plugin is refused or the update is blocked, with a message telling the user to uninstall and reinstall to re-pin it.

- Area: Plugin Marketplace
- Names: `--claudeai`, `--sparse`, `--scope`
- Tier: Use it now
- Useful: 5/5
- Signal: 2/5

### Background claude.ai plugin catalog refresh, off by default

A background refresh for claude.ai plugin catalogs exists but is off by default.

A new background routine refreshes claude.ai marketplace catalogs for plugins currently in use and emits a `claudeai_catalog_background_refresh` telemetry event when it runs. It only runs when account plugin sync is enabled, and that session flag defaults to false.

- Area: Plugin Marketplace
- Names: `claudeai_catalog_background_refresh`
- Tier: Nothing to try yet
- Useful: 3/5
- Signal: 3/5
- Present in the build but not switched on

### Detailed prompt-cache-break diagnostics (message0 shape/section diffing) sampled off by default

Detailed prompt-cache-break diffing telemetry exists but is sampled at zero by default.

New telemetry can capture a detailed structural snapshot of the first request message, including block kinds, lengths, hashes, named sections like `preamble`, `claudeMd`, and `workerToolsContext`, and worker tool/MCP-server counts, diffing it on a cache break to report changed, added, and removed sections and blocks. This collection is sampled via the gate `tengu_iridescent_gem`, which defaults to a sample rate of 0, so none of this data is captured unless that rate is raised remotely.

- Area: Prompt Caching
- Names: `tengu_iridescent_gem`
- Tier: Nothing to try yet
- Useful: 3/5
- Signal: 3/5
- Present in the build but not switched on

### New CCR v2 bridge CLI flag added, default off

A new CCR v2 bridge CLI is gated behind a flag that currently defaults off.

A new helper function gates creation of a "ccr v2 bridge cli" behind the `tengu_ccr_v2_bridge_create_cli` flag, which currently falls back to disabled.

- Flag `tengu_ccr_v2_bridge_create_cli`: Off in both readings (read for one account on one subscription tier against v2.1.261; this account: off, anonymous baseline: off, compiled default: off) These values were read against a different version of Claude Code, so treat them as the nearest reading available instead of one taken on this release.
- Area: Remote Control
- Names: `tengu_ccr_v2_bridge_create_cli`
- Tier: Nothing to try yet
- Useful: 3/5
- Signal: 3/5
- Present in the build but not switched on

### Overage-included-models usage display is data-driven from an empty-by-default allowlist

A display for overage-included models exists but has an empty allowlist until set remotely.

A new usage-limit display can show which models are included under overage ("weekly_scoped"), refreshing its list from GrowthBook once the data source moves off fallback/disk. The underlying allowlist, gate `tengu_usage_overage_included_models`, defaults to an empty array, so this new display currently has nothing to show until a remote value is set.

- Flag `tengu_usage_overage_included_models`: Not enough to say (read for one account on one subscription tier against v2.1.261; this account: no value returned, anonymous baseline: no value returned, compiled default: no gate table built for this version) These values were read against a different version of Claude Code, so treat them as the nearest reading available instead of one taken on this release.
- Area: Usage & Limits
- Names: `tengu_usage_overage_included_models`
- Tier: Nothing to try yet
- Useful: 3/5
- Signal: 3/5
- Present in the build but not switched on

### Sandbox can inject a Java proxy agent jar for JVM network isolation

The sandbox can now inject a Java proxy agent so JVM processes get network isolation too.

The sandbox wrapper can now optionally pass a `javaAgentJarPath` to the macOS and Linux sandbox builders, pointing JVMs started inside the sandbox at the proxy via a Java agent built from a vendored java-proxy-agent jar. This enables network isolation for JVM processes running under the sandbox.

- Area: Sandbox
- Tier: Nothing to try yet
- Useful: 3/5
- Signal: 3/5

### New SDK launch flag: --await-initialize

A new SDK CLI flag makes the process wait for an initialize request over stdin before starting.

The Claude Agent SDK CLI has a new `--await-initialize` flag that makes the process block at startup and read the first stdin line as an `initialize` control request, applying its launch-scoped fields (currently `plugins`) the same way `--plugin-dir`/`--plugin-dir-no-mcp` would. It requires `--input-format=stream-json`, cannot be combined with `--sdk-url`, and only applies when stdin isn't a TTY. Startup fails with a descriptive error if the first line isn't valid JSON, isn't an initialize request, or never arrives before the wait times out.

- Area: SDK
- Names: `--plugin-dir`
- Tier: Use it now
- Useful: 4/5
- Signal: 2/5

### New settings for inline Bash/Task output truncation limits

New settings let you control how much Bash and Task output Claude sees before it gets truncated to a file.

Two new `settings.json` fields control how much command output Claude sees inline: `bashOutputMaxChars` (default 30000, clamped 4000-128000) for Bash/PowerShell, and `taskOutputMaxChars` (default 32000, clamped 4000-128000) for the `TaskOutput` tool. Output beyond the limit is saved to a file with a preview and path shown instead. Setting these also replaces the older `BASH_MAX_OUTPUT_LENGTH` and `TASK_MAX_OUTPUT_LENGTH` env vars for this purpose.

- Area: Output Limits
- Names: `bashOutputMaxChars`, `taskOutputMaxChars`
- Tier: Use it now
- Useful: 4/5
- Signal: 2/5

### SDK plugin delivery via `initialize` request

SDK plugins can now be sent via an initialize request instead of the command line, with a fallback warning if not applied.

The SDK can now deliver plugins through the `initialize` control request by setting `pluginDelivery: 'initialize'`, as an alternative to passing them via argv or `--plugin-dir` at launch. On the client side, `Query.initialize()` checks the server's `plugins_applied` response field, and if plugins sent this way were not applied, it logs a warning noting that the process runs with whatever it was launched with.

- Area: SDK
- Names: `pluginDelivery: 'initialize'`, `plugins_applied`
- Tier: Use it now
- Useful: 4/5
- Signal: 2/5

### Two new SDK control-protocol request types: get_usage and reload_output_styles

SDK gains get_usage and reload_output_styles requests for pulling usage data and refreshing styles mid-session.

The SDK/agent control protocol gains two new request subtypes. `get_usage` returns the structured `/usage` data — session cost/usage totals plus claude.ai plan rate-limit utilization — and accepts an optional `skip_behaviors` flag to skip the 7-day transcript scan that produces the `behaviors` section; it requires an `onGetUsage` callback to be registered, or it errors. `reload_output_styles` re-reads output-style directories from disk mid-session (a style file written mid-session was previously invisible until the next session), returns the refreshed style names, and also drops the shared markdown-file scan cache used by agents, skills, and routines; it's exposed via a corresponding `sdk_reload_output_styles` wrapper.

- Area: SDK
- Names: `get_usage`, `reload_output_styles`, `skip_behaviors`, `onGetUsage`
- Tier: Use it now
- Useful: 4/5
- Signal: 2/5

### claude.ai-hosted plugin marketplaces

Plugin marketplaces can now be hosted on claude.ai itself, with full catalog fetching, caching and install support.

Plugin marketplaces can now be hosted directly on claude.ai instead of backed by a git repo or local marketplace.json, sourced from an organization library, personal uploads, or a claude.ai account. This adds a full pipeline: fetching a paginated plugin catalog from claude.ai's API, caching it to disk (`known_marketplaces_claudeai.json` plus a per-marketplace catalog cache with etag/If-None-Match support), handling gone/denied/policy-blocked/offline states, collision-safe slugging of claude.ai display names into CLI marketplace names, and downloading and installing plugin archives with sha256 verification and zip-safety checks. Errors surface through new `ClaudeAiMarketplaceError`/`ClaudeAiPluginInstallError` types with specific codes such as `not_installable`, `no_identity`, `policy_blocked`, and `extract_refused`.

Marketplaces backed by a claude.ai source must be added with `claude plugin marketplace add --claudeai <name>`; names starting with the reserved prefix can no longer be added manually. `claude marketplace remove` now rejects `--scope` for these marketplaces, since they aren't declared in any settings scope, and instead removes them through a dedicated hosted-marketplace removal path. New plugin/marketplace fields (`claudeaiPluginId`, `archiveSha256`, `attributedMarketplaceName`) support installs sourced this way.

List and JSON output now include claude.ai-hosted marketplaces for the account alongside local ones, with status/scope info and an `Add: claude plugin marketplace add --claudeai <name>` hint. The `/plugin marketplace` UI gains a third "hosted" category distinct from the existing browse-only claude.ai listings, with its own confirmation screen before adding and update-availability notes per plugin; when an installed plugin's version doesn't match the marketplace's published version, the marketplace details view shows a note like "N plugin updates available · update the marketplace to apply."

- Area: Plugin Marketplace
- Tier: Use it now
- Useful: 4/5
- Signal: 2/5

### `--resume` can now adopt/accept custom (non-UUID) session IDs when used with SDK URL sessions

--resume can now accept custom, non-UUID session IDs for SDK URL sessions.

A new helper decides whether a resumed session ID is adopted and whether the resume is effectively a fork. `--resume` now accepts custom, non-UUID session IDs specifically when `d.sdkUrl` is set, for SDK URL sessions. The returned message bundle now also reports `resumedAsFork`.

- Area: Sessions
- Names: `--resume`
- Tier: Use it now
- Useful: 3/5
- Signal: 2/5

### SDK session init accepts a `plugins` field over stdin

The SDK's initialize request can now carry plugin paths over stdin instead of one flag per plugin.

The SDK's initialize control-request schema now accepts a `plugins` field, mirroring the SDK's `plugins` launch option, so callers can pass plugin-dir entries over stdin instead of adding one `--plugin-dir` flag per plugin. It only takes effect on a CLI launched with `--await-initialize`, where it's read during startup before plugin work happens; a repeated `initialize` call or a remote session transport ignores it. The response's `plugins_applied` field reports whether it actually took effect.

- Area: SDK
- Names: `plugins_applied`
- Tier: Use it now
- Useful: 3/5
- Signal: 2/5

### Escalated retry windows for the first-byte stream timeout

Retrying a stalled API request now waits longer on the retry than on the first attempt.

The first-byte stream timeout logic, which aborts an API request if no response headers arrive in time, now tracks per-request retry state via `streamFirstByteArmedRequestIds`. On a retry of the same request it computes an escalated (larger) retry window instead of reusing the original first-attempt window. The request timeout/retry budget calculator now returns an object with `escalated`, `firstWindowMs`, and `retryWindowMs` instead of a single number, and these values are surfaced in a new `noResponse` field on the shaped API error, reporting how long the client waited before giving up.

- Area: Internals
- Tier: You'll notice
- Useful: 3/5
- Signal: 2/5

### Sandboxed Java processes get proxy-aware java agent injection

Sandboxed Java processes now automatically route through the sandbox's proxy via an injected agent jar.

Network-sandboxed commands now look for a bundled `srt-proxy-agent.jar` and inject it into Java processes via `-javaagent`, merged into `JAVA_TOOL_OPTIONS`, so JVM subprocesses route through the sandbox's HTTP/SOCKS proxy. This applies on both the Linux (bwrap) and macOS (sandbox-exec) sandbox code paths; if the jar isn't found, a warning is logged and the process continues without it.

- Area: Sandbox
- Tier: You'll notice
- Useful: 3/5
- Signal: 2/5

### Worker-restart continuity for excludeDynamicSections, with a kill switch

A session setting for excluding dynamic sections now survives a worker restart in headless mode.

In headless/`-p` mode, worker-restart handling now restores `sessionState`'s `excludeDynamicSections` flag from the prior worker epoch's internal metadata (`internal.exclude_dynamic_sections`), so the setting survives a worker restart. A kill switch can still disable this restoration.

- Flag `tengu_ccr_exclude_dynamic_restore_killswitch`: Not enough to say (read for one account on one subscription tier against v2.1.261; this account: no value returned, anonymous baseline: no value returned, compiled default: off) These values were read against a different version of Claude Code, so treat them as the nearest reading available instead of one taken on this release.
- Area: Elsewhere
- Names: `excludeDynamicSections`
- Tier: Under the hood
- Useful: 2/5
- Signal: 2/5

### More detailed stream-timeout error message with tunable env vars

Stream-timeout errors now suggest raising API_TIMEOUT_MS or CLAUDE_STREAM_FIRST_BYTE_TIMEOUT_MS.

When a request fails with a `StreamNoResponseError` (no first byte received in time), the error message now reports how long Claude Code waited, including whether it escalated to a retry window, and suggests raising `API_TIMEOUT_MS` or `CLAUDE_STREAM_FIRST_BYTE_TIMEOUT_MS` if a proxy or gateway is holding responses.

- Area: Internals
- Names: `API_TIMEOUT_MS`, `CLAUDE_STREAM_FIRST_BYTE_TIMEOUT_MS`
- Tier: Use it now
- Useful: 3/5
- Signal: 1/5

### New CLAUDE_CODE_NONBLOCKING_STDOUT env var for Ink renderer

A new env var stops Claude Code from hanging when stdout is slow, like when piped somewhere.

A new `CLAUDE_CODE_NONBLOCKING_STDOUT` environment variable makes the terminal renderer install a non-blocking stdout writer with backpressure handling instead of writing directly. This can prevent the process from hanging when stdout is slow or blocked, such as when piped to a slow consumer.

- Area: Terminal Renderer
- Names: `CLAUDE_CODE_NONBLOCKING_STDOUT`
- Tier: Use it now
- Useful: 3/5
- Signal: 1/5

### New CLI flag --append-subagent-system-prompt-file

A new flag lets you supply a subagent system-prompt append from a file instead of typing it inline.

A new `--append-subagent-system-prompt-file <file>` flag lets a subagent system-prompt append be supplied from a file instead of inline. It's mutually exclusive with the existing `--append-subagent-system-prompt` flag.

- Area: CLI
- Tier: Use it now
- Useful: 3/5
- Signal: 1/5

### New SDK `reloadOutputStyles()` method

The SDK can now reload output styles mid-session with a new method.

The SDK gains a `reloadOutputStyles()` query method, mirroring the existing `reloadPlugins`/`reloadSkills` pattern. It sends a `reload_output_styles` control-request subtype, which is validated in the request schema and handled by the runtime's control-request switch.

- Area: SDK
- Names: `reloadOutputStyles`
- Tier: Use it now
- Useful: 3/5
- Signal: 1/5

### New distinct UI for 'no response from API' retry state, separate from rate-limit retries

A 'no response from API' retry message now appears separately from rate-limit retries, with a tunable timeout hint.

The chat's retry-status UI now special-cases requests where the API gave no response at all, distinct from rate-limit retries. It shows 'No response from the API after {duration}' with either 'retrying once, waiting up to {t}' on the final attempt or 'retrying, waiting up to {t} · attempt X/Y' otherwise, plus a hint that a buffering proxy or gateway can cause this and that `CLAUDE_STREAM_FIRST_BYTE_TIMEOUT_MS` controls the wait.

- Area: Internals
- Names: `CLAUDE_STREAM_FIRST_BYTE_TIMEOUT_MS`
- Tier: You'll notice
- Useful: 3/5
- Signal: 1/5

### New env var CLAUDE_STREAM_FIRST_BYTE_TIMEOUT_MS

A new env var controls how long Claude Code waits for the first byte of a streamed response.

A new environment variable, `CLAUDE_STREAM_FIRST_BYTE_TIMEOUT_MS`, controls the timeout for receiving the first byte of a streamed API response. The CLI's allowed-env-var list now recognizes and passes it through, and the stream-start timeout logic was simplified to read it directly.

- Area: Internals
- Names: `CLAUDE_STREAM_FIRST_BYTE_TIMEOUT_MS`
- Tier: Use it now
- Useful: 2/5
- Signal: 1/5

### SDK's experimental `usage()` call gains a `skip_behaviors` opt-out

The experimental usage() SDK call can now skip the 7-day behaviors scan for a faster response.

The still-experimental `usage_EXPERIMENTAL_MAY_CHANGE_DO_NOT_RELY_ON_THIS_API_YET` SDK method now takes an options object. Passing `skipBehaviors: true` sends `skip_behaviors: true` on the wire, and the CLI-side handler now conditions `includeBehaviors` on that flag being absent.

- Area: SDK
- Names: `skipBehaviors`
- Tier: Use it now
- Useful: 2/5
- Signal: 1/5

### get_usage remote command can skip behaviors

The get_usage command can now omit behavior data via a skip_behaviors flag.

The `get_usage` remote command now honors a new request field, `skip_behaviors`. When set to `true`, usage stats omit behavior data even outside headless/agent sessions.

- Area: SDK
- Names: `skip_behaviors`
- Tier: Use it now
- Useful: 2/5
- Signal: 1/5

### GCP credential check becomes tri-state and honors ANTHROPIC_GOOGLE_CLOUD_PROJECT

GCP credential checks now distinguish timeout from failure and honor a new project env var fallback.

The GCP credentials pre-check used before running the configured `gcpAuthRefresh` command now returns one of `valid`, `timeout`, or `invalid` instead of a plain boolean, with distinct log messages for a timeout versus an outright failure. It also honors a new `ANTHROPIC_GOOGLE_CLOUD_PROJECT` fallback (alongside `GCLOUD_PROJECT` and friends) for the `projectId` passed into the GoogleAuth client.

- Area: Cloud Auth
- Names: `ANTHROPIC_GOOGLE_CLOUD_PROJECT`
- Tier: You'll notice
- Useful: 2/5
- Signal: 1/5

### New AWS Bedrock timeout with configurable override

AWS credential lookups now time out with a clearer error, and you can raise the timeout via an env var.

AWS credential-chain resolution — covering STS `GetCallerIdentity`, `ListInferenceProfiles`, and profile/SSO credential fetches — is now wrapped with a request timeout. On timeout, the error message tells users to raise `CLAUDE_CODE_AWS_CHAIN_RESOLVE_TIMEOUT_MS`, and a separate generic message covers other AWS timeouts.

- Area: Elsewhere
- Names: `CLAUDE_CODE_AWS_CHAIN_RESOLVE_TIMEOUT_MS`
- Tier: You'll notice
- Useful: 2/5
- Signal: 1/5

### GrowthBook env var feature overrides disabled

The CLAUDE_INTERNAL_FC_OVERRIDES env var no longer overrides feature flags.

The `CLAUDE_INTERNAL_FC_OVERRIDES` environment variable no longer has any effect. `getEnvironmentOverrides()` previously read and JSON-parsed this variable to override GrowthBook features, but it now unconditionally returns `null`, so any feature overrides set through this variable are silently ignored.

- Area: Internals
- Names: `CLAUDE_INTERNAL_FC_OVERRIDES`
- Tier: Under the hood
- Useful: 2/5
- Signal: 1/5

### New settings keys: bashOutputMaxChars / taskOutputMaxChars

The new Bash and Task output limit settings are now formally recognized and propagated internally.

Two new settings keys, `bashOutputMaxChars` and `taskOutputMaxChars`, were added to the list of recognized and propagated settings, alongside existing keys like `autoCompactWindow`. These suggest new user-configurable output truncation limits for the Bash and Task tools.

- Area: Output Limits
- Names: `bashOutputMaxChars`, `taskOutputMaxChars`
- Tier: Use it now
- Useful: 1/5
- Signal: 1/5

## New Features

### New "gateway required by host policy" cloud-provider mode

Hosts can now force gateway auth and routing through a policy check, independent of your env vars.

Provider detection now also treats the session as a Cloud gateway provider when a new host policy reader, `gatewayRequiredByHostPolicy`, returns true, in addition to the existing gateway-server-process checks. This gives hosts a way to force gateway auth and provider routing independent of the `CLAUDE_CODE_USE_*` environment variables.

- Area: Cloud Gateway
- Tier: Under the hood
- Useful: 3/5
- Signal: 3/5

### New notification kind: claudeai_identity_changed

A new notice can appear if your claude.ai account identity changes mid-session.

A new notification key `claudeai_identity_changed` was added to the mood-mapping table, mapped to "sad". This suggests a new UI notice can fire when the user's claude.ai account identity changes mid-session.

- Area: Terminal UI
- Names: `claudeai_identity_changed`
- Tier: You'll notice
- Useful: 2/5
- Signal: 2/5

## Improvements

### Two new Anthropic API beta headers added

Two new API beta headers, for dangerous tool use checks and thinking binding controls, are now sent by default.

Two new Anthropic API beta feature flags are now sent as headers: `dangerous_tool_use` (`dangerous-tool-use-2026-09-03`) and `thinking_binding_controls` (`thinking-binding-controls-2026-08-01`). Both are included in the same outgoing beta-headers list as established betas like `interleaved_thinking`, so they are sent whenever not explicitly nulled out.

- Area: API Headers
- Names: `dangerous-tool-use-2026-09-03`, `thinking-binding-controls-2026-08-01`
- Tier: You'll notice
- Useful: 3/5
- Signal: 3/5

### Server-side auto-mode dangerous-tool-use classifier

Auto mode's dangerous-action classifier now runs server-side and blocks actions it flags or can't reach.

Auto mode's server-side dangerous-tool-use classifier is expanded: API requests now carry a `safeguards: [{ type: "dangerous_tool_use", context }]` field, riding on a new `anthropic-beta` header entry, and the response's streaming deltas are parsed for matching `safeguard_results` against a schema of per-tool-call outcomes (flagged, not_flagged, skipped, unavailable). When flagged, the action is blocked with reason 'The server-side auto mode classifier judged this action dangerous'; if the server call is unavailable or times out, it blocks for safety with 'Classifier unavailable - blocking for safety'. The auto-mode fast-path check can now await a server classifier result and fall back to asking the user if the classification changed while queued (`mode_changed_while_queued`), recording telemetry fields `classifierSource: server` and `serverClassifierNoVerdict`, and a `tengu_auto_mode_fallback_to_ask` event.

- Area: Auto Mode Safety
- Tier: You'll notice
- Useful: 3/5
- Signal: 3/5

### New diagnostics for org-managed hook restrictions on synced plugins

New diagnostics explain when org-managed hook restrictions or disabled settings are suppressing a synced plugin.

Two new plugin-issue diagnostics help explain org-managed hook behavior on synced plugins. `managed-hooks-restricted` reports when a plugin loads because it matches an org-mandated plugin by sync attribution, but its hooks are suppressed because `allowManagedHooksOnly` only runs hooks from the exact managed plugin@marketplace id. `managed-plugin-disabled-by-settings` reports when a locally-disabled copy of a plugin shadows what the org's managed settings expect to be running. Both include remediation text.

- Area: Plugin Management
- Tier: You'll notice
- Useful: 3/5
- Signal: 2/5

### Cloud sessions can now list remote MCP servers attached to the local machine

Running /mcp in a cloud session now also lists MCP servers attached to your local machine.

Running `/mcp` with no arguments in a cloud/remote session (`CLAUDE_CODE_REMOTE`) now also queries MCP servers attached to the local machine and lists them in a new section, showing each server's host name, status (connected, unreachable, or unreachable due to version mismatch), transport, and tool count. Locally-disabled or failed servers won't appear in this remote listing.

- Area: MCP
- Names: `/mcp`
- Tier: You'll notice
- Useful: 3/5
- Signal: 2/5

### Plugin content-hash verification against claude.ai archives

Plugins from claude.ai now get their downloaded archive verified against the install-time hash.

When loading a plugin sourced from claude.ai at a pinned version, the client now compares the downloaded archive's content hash against the digest recorded at install time. On a mismatch, it deletes the staged download and refuses to load the plugin, telling the user to uninstall and reinstall to accept the new content.

- Area: Plugin Marketplace
- Tier: You'll notice
- Useful: 3/5
- Signal: 2/5

### New API error code for version-too-old rejections

A new error clearly tells you to update Claude Code when your build is too old for a request.

The API error schema gains a new `claude_code_version_too_old` error code, sent when the API refuses a request because the Claude Code build is below a required minimum, whether a model-specific floor or an org-policy floor. The error's message text carries the details, and the remedy is updating Claude Code.

- Area: API Errors
- Names: `claude_code_version_too_old`
- Tier: You'll notice
- Useful: 3/5
- Signal: 2/5

### claude.ai marketplace sync separates hosted, browse-only, and policy-blocked entries

claude.ai marketplace sync now separates installed, browse-only, and policy-blocked plugins.

Marketplace sync/cache logic for claude.ai-sourced marketplaces now classifies entries into three buckets instead of a single browse-only list: ones the org has actually installed (hosted), ones visible only for browsing, and ones blocked by policy. Each entry's scope is re-derived on every sync, with a warning logged if that re-derivation fails, and a new info log is emitted when browse-only marketplaces are present.

- Area: Plugin Marketplace
- Tier: You'll notice
- Useful: 3/5
- Signal: 2/5

### claude.ai-hosted marketplaces gain a registry fallback when local cache is missing

claude.ai marketplace lookups now fall back to a synced registry when the local cache misses.

Marketplace and plugin lookups for claude.ai-hosted marketplaces now fall back to a locally-synced "claude.ai marketplace registry" whenever the usual `known_marketplaces.json`-derived cache lookup misses or the cache file can't be read. Previously a cache miss simply returned null; now these lookups resolve against the registry and can synthesize a `claudeai`-sourced plugin entry from account plugin data.

- Area: Plugin Marketplace
- Tier: You'll notice
- Useful: 3/5
- Signal: 2/5

### Usage overage-included-models allowlist can be refreshed mid-session from GrowthBook

The list of models included in overage usage can now refresh mid-session from remote config.

When seven-day overage usage data is seeded from HTTP response headers, the code now waits for GrowthBook config to settle before finalizing the 'overage included models' allowlist, so it reflects remote config rather than the disk/fallback cache. A change in source is logged when this happens.

- Area: Usage & Limits
- Tier: You'll notice
- Useful: 2/5
- Signal: 2/5

### SDK warns when launch-time plugins aren't applied

The SDK now warns if plugins sent via initialize weren't actually applied by the server.

After `Query.initialize()`, if plugins were supplied via the `initialize` delivery path but the server doesn't report `plugins_applied`, the SDK now logs a warning that the process is running with only the plugins it was launched with.

- Area: SDK
- Names: `plugins_applied`
- Tier: You'll notice
- Useful: 2/5
- Signal: 2/5

### Artifact `copy_from` action now honors deny/ask permission rules

Copying assets between artifacts now respects deny/ask permission rules, not just prior consent.

Copying assets between artifacts via `action: "copy_from"` now consults the permission-rule engine for deny and ask rules before proceeding, instead of only checking consent/session state as before. A matching deny rule blocks the copy with a message naming the rule's tool and pattern, and a matching ask rule forces a confirmation prompt even if the destination or source was already consented.

Reading an artifact's structured page data (`read_page_data`) is now also checked against this permission-rule engine before fetching. Previously a session-wide "Read artifacts' structured page data for the rest of this session" grant auto-allowed all such reads; now a matching ask rule shows a one-shot confirmation instead, and a matching deny rule refuses the read entirely.

- Area: Permissions
- Names: `copy_from`
- Tier: You'll notice
- Useful: 3/5
- Signal: 1/5

### Per-URL ask/deny rules for artifact reads, page-data reads, diagnostics, and database reads

Artifact reads, diagnostics, and database reads now check per-URL deny/ask rules before falling back to session consent.

Artifact tool permission checks gain a new rule-matching step that checks configured deny/ask rules against the specific artifact URL before falling back to session-wide consent. This covers the `read_page_data`, `verify` (diagnostics), `read`, and `read_db` actions, and permission messages now surface which rule matched, for example when Claude wants to read the structured page data of an artifact.

- Area: Permissions
- Tier: You'll notice
- Useful: 3/5
- Signal: 1/5

### Auto-mode permission checks get finer-grained unavailable reasons

Auto-mode's 'action pending' message now explains the specific reason instead of a generic unavailable notice.

The message shown for auto-mode actions awaiting an async server verdict now distinguishes many more reasons the verdict didn't arrive: server-side skip, unsupported request, stream-ended, input-too-long, disabled, and "not requested," each with its own tailored guidance text instead of a single generic "temporarily unavailable" message.

- Area: Auto Mode
- Tier: You'll notice
- Useful: 3/5
- Signal: 1/5

### `/doctor` output now waits for organization policy limits to load before reporting them

/doctor now waits for org policy limits to load and shows an updating status line for them.

`/doctor` now waits for organization policy limits to finish loading, via `waitForPolicyLimitsToLoad` bounded by `POLICY_LIMITS_FIRST_ATTEMPT_WAIT_MS`, before reporting them. The output gains an 'Organization policy: …' status line that updates once the check resolves, instead of doctor only surfacing settings and env-var issues immediately.

- Area: Diagnostics
- Names: `/doctor`
- Tier: You'll notice
- Useful: 3/5
- Signal: 1/5

### New 'not fetched'/'no response' diagnostics for organization policy retrieval

Diagnostics now explain in detail why org policy couldn't be fetched, with specific failure reasons.

Diagnostics gain a new status entry explaining why organization policy couldn't be fetched, covering cases such as a third-party provider, a custom base URL, no auth, a missing OAuth inference scope, or a Pro/Max account. It also reports why a fetch attempt failed, distinguishing `auth_failed` (including HTTP 403 with proxy guidance), timeout, `network_error`, `parse_failed`, `spurious_304`, and `request_failed` (with specific guidance for HTTP 404, 304, and 407), and notes that the fetch is 'Retried hourly while Claude Code runs; restart to retry now.'

- Area: Org Policy
- Tier: You'll notice
- Useful: 3/5
- Signal: 1/5

### Managed-policy enforcement of Cloud gateway sign-in

Claude Code now fails fast with a clear /login message if admin policy requires gateway sign-in.

API client construction now throws early with "Administrator policy requires a Cloud gateway sign-in on this machine - run /login." if administrator policy requires a Cloud gateway login and the user hasn't signed in via gateway, before any provider-specific auth logic runs.

- Area: Cloud Gateway
- Names: `/login`
- Tier: You'll notice
- Useful: 3/5
- Signal: 1/5

### GCP credentials check now reports why it failed

GCP credential checks now report why they failed instead of just pass/fail.

The GCP Application Default Credentials probe used for Vertex/cloud auth now reports why a check failed instead of a plain true/false, returning one of 'valid', 'timeout', or 'invalid' with a distinct warning message logged for each case. It can also pass an explicit `projectId`, sourced from `ANTHROPIC_GOOGLE_CLOUD_PROJECT` or a new helper, to `GoogleAuth`.

- Area: Cloud Auth
- Names: `ANTHROPIC_GOOGLE_CLOUD_PROJECT`
- Tier: You'll notice
- Useful: 2/5
- Signal: 1/5

### Custom 1M-context model labels

Custom Sonnet/Opus model picker labels now note when a model has a 1M-token context window.

A new helper builds picker labels and descriptions for custom Sonnet and Opus models, appending a "(1M context)" note when the model qualifies for the 1M-context window.

- Area: Elsewhere
- Tier: You'll notice
- Useful: 2/5
- Signal: 1/5

### Frozen artifact types: publish path now enforces a type lock

Type-locked artifacts now block changing their contract or language when publishing.

Artifact publish and read logic now checks `frozenArtifactTypes?.typesOn` together with a per-artifact `typeLock` to determine when re-reading capabilities is required, and to deny changing the contract or language on a type-locked artifact, for example blocking publishing a non-page file to an Artifact created from an Artifact type.

- Area: Artifacts
- Tier: You'll notice
- Useful: 2/5
- Signal: 1/5

### Artifact design-system default now framed as a standing instruction

A default design system now applies to every slide deck or visual design by default, with clear precedence rules.

The artifact-types system prompt now treats a default design system set by the user or org as the user's own standing instruction, expected to apply to every slide deck or visual design "however brief the request." Precedence for choosing typeface and palette is now spelled out explicitly: named design system, then declined, then default, then none.

- Area: Artifacts
- Tier: You'll notice
- Useful: 2/5
- Signal: 1/5

### Usage display distinguishes partial vs fully-unavailable rate-limited data

The usage panel now distinguishes partial rate-limited data from fully unavailable data.

When usage stats are rate-limited, the settings usage panel now checks whether any per-model limit entries are `weekly_scoped`-style objects. If so, it shows "Partial usage data (rate limited — try again in a moment)" instead of the previous blanket "Per-model breakdown unavailable" message.

- Area: Usage & Limits
- Tier: You'll notice
- Useful: 2/5
- Signal: 1/5

### Artifacts listing now nudges Claude to use the marked default without asking

Claude now uses your marked default artifact automatically instead of asking, unless you said otherwise.

The Artifacts-listing tool response text now tells the model that a row marked as the user's or org's default "is the user's standing choice," and instructs it to use that artifact without asking. This nudge only yields, per the new wording, when the user named a different artifact or declined one earlier in the current conversation.

- Area: Artifacts
- Tier: You'll notice
- Useful: 2/5
- Signal: 1/5

### Artifact egress-blocked message distinguishes remote sessions

Blocked artifact network requests now explain clearly when the restriction is due to running remotely.

When a network allowlist blocks fetching an artifact's frame content, the error message now checks `CLAUDE_CODE_REMOTE`. On a remote session it tells the user that this is a restriction of where the session runs and that retrying locally won't help, instead of suggesting they add the domain to the environment's allowed domains.

- Area: Artifacts
- Names: `CLAUDE_CODE_REMOTE`
- Tier: You'll notice
- Useful: 2/5
- Signal: 1/5

### initialize control request can now report whether requested plugins loaded

The initialize request now reports whether plugins you asked for actually loaded.

The `initialize` control request's response now includes a `plugins_applied` telemetry field, reporting whether every plugin named in the request is among those actually loaded at launch via the `plugins` field under `--await-initialize` or via `--plugin-dir`. The `plugins` field itself never loads anything after launch.

- Area: SDK
- Names: `plugins_applied`
- Tier: You'll notice
- Useful: 2/5
- Signal: 1/5

### skill-doctor availability text now explains rollout mechanics

The skill-doctor unavailable message now explains exactly why it's off instead of just saying early access.

The offline reference text shown when `/skill-doctor` is unavailable now explains why in detail instead of just labeling it "(early access)." It's on by default in current releases, but a session may lack it on an older release, or when the client hasn't received feature settings yet — naming Bedrock, Vertex, Foundry, telemetry or non-essential traffic disabled, or a first launch that hasn't fetched settings — or when an administrator hasn't switched it on.

- Area: Elsewhere
- Names: `/skill-doctor`
- Tier: You'll notice
- Useful: 2/5
- Signal: 1/5

### Bedrock count_tokens fallback no longer uses Haiku probe

Bedrock token counting fallback now uses your own model instead of a Haiku probe.

When a Bedrock-style proxy returns 501 for `count_tokens`, the client no longer falls back to a Haiku `max_tokens:1` probe. It instead counts tokens with a one-token request using the session's own model, unless `ANTHROPIC_SMALL_FAST_MODEL` or `ANTHROPIC_DEFAULT_HAIKU_MODEL` is set.

- Area: Elsewhere
- Names: `ANTHROPIC_SMALL_FAST_MODEL`, `ANTHROPIC_DEFAULT_HAIKU_MODEL`
- Tier: You'll notice
- Useful: 2/5
- Signal: 1/5

### Trusted-proxy client IP resolution now reports bad hops

Client IP resolution now reports the specific bad hop instead of silently falling back.

The function that resolves the real client IP from `X-Forwarded-For` against a trusted proxy list now returns a structured result including a `badHop` field (truncated to 100 characters) when a hop in the chain can't be parsed as an IP, rather than silently falling back to the untrusted original address.

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

### Policy-limits 404 error message rewritten

The 404 policy-endpoint error now names the request path and points you to claude doctor.

The error shown when an org's policy endpoint returns 404 was rewritten to be more actionable: it now names the specific request path and points to `claude doctor` (or `/status` in a session) to see which host was asked, so users can direct their network admin accordingly.

- Area: Org Policy
- Names: `claude doctor`, `/status`
- Tier: You'll notice
- Useful: 2/5
- Signal: 1/5

### New HTTP 403 message for gateway-disabled orgs

A blocked gateway now shows a specific 'contact your admin' message instead of a generic login error.

When a custom gateway or proxy rejects a request with HTTP 403, Claude Code now shows a specific message noting that Claude Code may not be enabled for the user's organization and to contact an administrator, instead of reusing the generic 401 "credential not accepted" text.

- Area: Cloud Gateway
- Tier: You'll notice
- Useful: 2/5
- Signal: 1/5

### New 'org policy not loaded' Remote Control status line

Remote Control diagnostics now show a distinct 'org policy not loaded' state.

Remote Control status/diagnostics now report a distinct "Org policy not loaded" state when the org policy simply hasn't loaded yet, as opposed to being unavailable or denied, and points the user to the Organization policy line above for `allow_remote_control`.

- Area: Remote Control
- Tier: You'll notice
- Useful: 2/5
- Signal: 1/5

### Offline cloud/bridge sessions now flagged distinctly

Disconnected bridge sessions now clearly show as 'offline' instead of a raw status string.

Session listings for remote-control/bridge sessions now carry an explicit `offline` flag when the bridge connection is disconnected. In the CLI, sessions in this state display as 'offline' instead of showing the underlying worker status string.

- Area: Remote Control
- Tier: You'll notice
- Useful: 2/5
- Signal: 1/5

### Offline machine messaging for remote/bridge delivery

You'll now see a clear message when a target machine is offline and delivery is queued.

A new user-facing message explains that a target machine "is offline right now" and that delivery will be queued until that machine reconnects. This pairs with a new `offline` flag now propagated onto device/session records, such as in remote-control machine listings.

- Area: Remote Control
- Tier: You'll notice
- Useful: 2/5
- Signal: 1/5

### Plugin cache-miss errors can now be enriched with install-record context

Plugin cache-miss errors can now include more specific install-record context.

When a plugin fails to load from cache, the loader now checks a recorded install (including archive sha256 and claude.ai plugin id) via a new helper before falling back to the generic 'plugin-cache-miss' error. This produces a more specific error message when install-record context is available.

- Area: Plugin Management
- Tier: You'll notice
- Useful: 2/5
- Signal: 1/5

### 'Organization policy' line added to settings-source status list

Diagnostics now show an 'Organization policy' status line alongside managed settings status.

The function that builds the settings-source list shown in diagnostics now appends an 'Organization policy' entry describing the fetch and apply state of remote org policy, alongside the existing 'Managed settings (remote)' entry.

- Area: Diagnostics
- Tier: You'll notice
- Useful: 2/5
- Signal: 1/5

### Clearer managed-settings error when org requires Cloud gateway sign-in

A clearer error now tells you exactly how to fix a mismatched credential under gateway-mode org policy.

When managed settings require first-party login but a non-OAuth credential is configured under an org policy specifically set to "gateway" mode, the validation error message is now more specific. It tells the user to remove the Anthropic-issued credential and sign in with `/login`, or, if the provider is managed via `CLAUDE_CODE_USE_*`, notes that no sign-in is needed.

- Area: Cloud Gateway
- Names: `/login`
- Tier: You'll notice
- Useful: 2/5
- Signal: 1/5

### Marketplace plugin listing flags plugins not yet installable on claude.ai

Plugin listings now flag entries not yet installable on claude.ai.

The plugin marketplace UI, in both the primary and secondary plugin list views, now shows a dim-colored `[not installable on claude.ai yet]` label next to plugin entries that aren't yet installable on claude.ai.

- Area: Plugin Marketplace
- Tier: You'll notice
- Useful: 2/5
- Signal: 1/5

### Remote Control disabled-reason now explains missing org policy

Remote Control now explains specifically when it's disabled due to missing org policy.

When Remote Control is unavailable specifically because the organization's policy hasn't loaded, the UI now reports a specific disabled reason instead of a generic one: "Remote Control needs your organization's policy, which isn't loaded - see the Organization policy line above."

- Area: Remote Control
- Tier: You'll notice
- Useful: 2/5
- Signal: 1/5

### claude.ai connector-list fetch gets background retry with backoff

Failed claude.ai connector catalog fetches now retry automatically in the background.

When fetching the claude.ai MCP connector catalog fails transiently, the client now schedules an automatic background retry using an increasing delay table instead of just failing silently once.

- Area: MCP
- Tier: You'll notice
- Useful: 2/5
- Signal: 1/5

### Policy-limits 404 now distinguished as 'route_missing' from a transient cache miss

A confirmed 404 on the policy route now shows a distinct 'policy route not served' message.

Policy-limit resolution for gated features like Remote Control, artifacts, and `allow_cobalt_plinth` now distinguishes a confirmed 404 on the policy route (`route_missing`) from an ordinary transient cache miss, showing "policy route not served" instead of generic unverified-policy messaging in the confirmed-404 case.

- Area: Org Policy
- Tier: You'll notice
- Useful: 2/5
- Signal: 1/5

### New "policy route not served" diagnosis for Remote Control org-policy fetch

Remote Control now diagnoses when its policy route isn't being forwarded by a proxy or gateway.

Remote Control's org-policy fetch (`/api/claude_code/policy_limits`) now distinguishes a `route_missing` outcome from a generic cache miss. This case gets its own user-facing explanation pointing to a proxy or gateway not forwarding the path, its own telemetry reason (`policy_route_missing`), and its own denial-reason error subtype.

- Area: Remote Control
- Tier: You'll notice
- Useful: 2/5
- Signal: 1/5

### Watch-artifact prompts gain reply/comment-wake phrasing

Watch-artifact prompts now clarify Claude auto-replies to comments and won't re-ask to watch other artifacts.

New prompt copy for watched artifacts clarifies that Claude will automatically reply to comments sent to it on a watched artifact, and that it won't ask again to watch other artifacts for the rest of the session.

- Area: Artifacts
- Tier: You'll notice
- Useful: 1/5
- Signal: 1/5

### Artifact comment auto-react can be withheld by rule, logged once per artifact

Artifact comment auto-react can now be silently withheld by a rule, logged once per artifact.

Before scanning an artifact for comments to auto-react to, a rule-gate check now runs first; if the rule withholds, the scan is skipped for that artifact. The first time this happens for a given artifact, a `rule_withheld` telemetry event fires, and the flag resets once the rule stops withholding so the event can fire again later if needed.

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

### New 'Claude Desktop watches PRs itself' message

Sessions now say when Claude Desktop is already watching a PR itself, and poll instead of using webhooks.

When Claude Desktop is detected as already watching a PR with its own tools, the session no longer subscribes to webhooks for it and instead shows "Claude Desktop watches PRs with its own tools, so this session doesn't subscribe to webhooks. It polls every 30 minutes instead."

- Area: Elsewhere
- Tier: You'll notice
- Useful: 1/5
- Signal: 1/5

### Plugin update short-circuits when already at claude.ai-sourced latest version

Updating a claude.ai plugin already at latest now skips reinstalling it.

The plugin update flow now detects when a plugin's source is `claudeai` and the installed version already matches the resolved latest version, returning an `up_to_date` outcome instead of re-running the install. If the version refresh itself failed, this outcome comes with a stale-version warning.

- Area: Plugin Marketplace
- Tier: You'll notice
- Useful: 1/5
- Signal: 1/5

### Bash-progress line capture filters out noise lines

Bash/PowerShell progress output now filters out noisy lines, not just long ones.

The bash and powershell progress line buffer now drops lines matching a filter before pushing them into the captured-output buffer, in addition to the existing length truncation.

- Area: Elsewhere
- Tier: You'll notice
- Useful: 1/5
- Signal: 1/5

### Policy-limits fetch failure log now includes the gateway URL

Policy-limits fetch failure logs now include which gateway host failed.

The error log emitted when a policy-limits fetch fails now includes the gateway host it was fetched from, making it easier to diagnose failures in setups with multiple gateways.

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

### MCP server name redaction in toggle telemetry

MCP server names are now redacted in toggle telemetry events.

The `tengu_builtin_mcp_toggle` telemetry event no longer logs the raw MCP server name. It now passes the name through a conditional hash/redact helper that only includes a hashed value for recognized servers, and omits it otherwise, reducing exposure of arbitrary or custom MCP server names in telemetry.

- Area: Telemetry
- Names: `tengu_builtin_mcp_toggle`
- Tier: Under the hood
- Useful: 1/5
- Signal: 1/5

### MCP CLI commands (`get`/`add`/`remove`) telemetry now hashes/obscures server names via `Up`

MCP CLI commands now hash server names in telemetry instead of sending them raw.

MCP CLI telemetry for commands like `tengu_mcp_get` and `tengu_mcp_delete` now passes the server name through a new `Up(...)` transform combined with scope lookup before sending it, rather than transmitting the raw server name. This obscures or hashes server identity in telemetry events.

- Area: Telemetry
- Names: `tengu_mcp_get`, `tengu_mcp_delete`
- Tier: Under the hood
- Useful: 1/5
- Signal: 1/5

### Local bash task output can now be truncated with a 'pending hint' note

Local bash task output can now include a note about pending or incomplete output.

When reconciling a `local_bash` task's output for the model, the result now passes through a new post-processing step that can append a note about pending or incomplete output, tagged with surface `task_output`, in addition to the existing stdout/stderr truncation.

- Area: Elsewhere
- Tier: You'll notice
- Useful: 1/5
- Signal: 1/5

### Immediate-command telemetry now redacts custom command names

Custom slash-command names are now hidden from telemetry, replaced with 'custom'.

The `tengu_immediate_command_executed` telemetry event no longer sends the raw slash-command name. Shipped commands now have their name hashed, and user-defined commands are replaced with the literal string `custom` before the event is sent.

- Area: Telemetry
- Names: `tengu_immediate_command_executed`
- Tier: Under the hood
- Useful: 1/5
- Signal: 1/5

### Artifact reply/resolve target-changed guard message reworded

Artifact reply/resolve guard messages now state clearly that nothing was posted or read.

The target-changed guards on artifact reply, resolve, and comments actions now spell out exactly what didn't happen: the reply guard states that nothing was posted, and the comments guard states that nothing was read, making it clearer why a retried or rewritten approval failed.

- Area: Artifacts
- Tier: You'll notice
- Useful: 1/5
- Signal: 1/5

### Session adoption gate logs a rejection reason when a custom ID is refused

Resume now logs why a custom session ID was rejected before falling back to a fresh forked session.

When a transcript's session ID fails the adoption check during resume, Claude Code now logs an explicit diagnostic message identifying the rejected session ID and falls back to treating the resume as a fork under a fresh session ID, instead of failing silently.

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

## Bug Fixes

### wakeRouter now retries failed agent-wake dispatches instead of dropping them

Failed wake-ups to background agents are now retried with backoff instead of silently dropped.

The background wake dispatcher that delivers queued commands to agents no longer drops a delivery on the first failure. It now classifies each outcome as delivered, dropped, or retry: non-terminal failures (not an abort/stop error, and under a retry cap) are rescheduled with jittered exponential backoff using a new per-agent timer map. Commands are only dropped, with a new `resume_failed` reason, once an error isn't retryable or the retry-count cap is reached.

- Area: Background Agents
- Tier: You'll notice
- Useful: 3/5
- Signal: 2/5

### Tool-result file writes hardened against symlink/hardlink tricks

Tool-result file writes are now hardened against symlink and hardlink tricks.

Persisting large tool results to disk is now hardened against symlink and hardlink tricks. The write walks the destination path component by component, refusing to write through a symlink or non-directory, deletes any existing symlink at the exact target before writing, and afterward rejects the write if the final path turns out to be a symlink, a non-regular file, or has more than one hardlink.

- Area: Permissions
- Tier: You'll notice
- Useful: 2/5
- Signal: 2/5

### Sandbox write-path restore skips symlinks pointing outside expected location

Sandbox write-path restore now skips symlinks that point outside the expected location.

On Linux sandboxing, restoring bind-mounted write paths now resolves symlinks with `realpathSync` first. If a symlink's resolved target differs from the expected location and points outside it, the path is skipped (with a log message: "Skipping write-path restore for symlink pointing outside expected location") instead of being blindly re-bound.

- Area: Sandbox
- Tier: You'll notice
- Useful: 2/5
- Signal: 2/5

### Gateway proxy hardens X-Forwarded-For handling

The gateway server now denies requests with unparseable or unknown client IPs when access control is on.

The standalone `claude gateway` server now validates the `X-Forwarded-For` header from trusted proxies. If a trusted proxy sends a value that can't be parsed as an IP and `access_control` (allow/deny CIDRs) is configured, the request is denied with a 403 instead of silently falling back to the proxy's own address for rate limiting and audit purposes. Requests where the client IP can't be determined at all are now also explicitly denied (`client_ip_unknown`) when access control is active.

- Area: Elsewhere
- Tier: You'll notice
- Useful: 2/5
- Signal: 2/5

### Tool-result writes now refuse to traverse symlinked directories

Tool-result writes now refuse to traverse symlinked directories.

Writes of tool results now walk the target directory path component by component and refuse to write, with a "tool-results path refused" error, if any segment is a symlink or not a directory. This check applies to both the persisted-tool-result write path and the ensure-scope path.

- Area: Permissions
- Tier: You'll notice
- Useful: 2/5
- Signal: 2/5

### Tool permission cache now keyed on GitHub repo and workspace restriction

Available tools can now correctly differ by GitHub repo and workspace restriction state.

The cached tool pool computation now includes the detected GitHub repository and whether the workspace is restricted as part of its cache key. Tool availability can therefore vary by repo and workspace-restriction state, and the cache invalidates when either changes.

- Area: Permissions
- Tier: You'll notice
- Useful: 2/5
- Signal: 1/5

### New plugin-cache-miss / refused-load error paths for claude.ai plugins

Broken claude.ai plugin installs now show specific errors instead of failing unclearly.

Claude Code now handles claude.ai-sourced plugins whose install record can't resolve. An 'unknown' registry read produces a plugin-cache-miss error; a 'present' record missing its origin pointer is refused with instructions to reinstall; and a non-installable plugin — files missing, no installable version listed, or an unreadable catalog — is refused with a message suggesting signing into claude.ai with the right organization.

- Area: Plugin Marketplace
- Tier: You'll notice
- Useful: 2/5
- Signal: 1/5

### Cloud gateway 403 no longer ends session

A blocked org gateway no longer logs you out; you now see a message to contact your admin instead.

When a cloud gateway rejects managed settings with HTTP 403, Claude Code no longer treats it like a 401: the session is not ended and the user isn't prompted to re-login. Instead the user sees a message saying Claude Code may not be enabled for their organization and to contact their administrator.

- Area: Cloud Gateway
- Tier: You'll notice
- Useful: 2/5
- Signal: 1/5

### GCP credential auth-refresh check gains timeout handling

A slow GCP credential check no longer forces an unnecessary refresh; it waits for an actual rejection.

The GCP credentials validity check used before running the auth refresh command now distinguishes a timeout from an actual valid/invalid result. If the check times out, the refresh command is skipped and a log message notes it's deferring until the API actually rejects the credentials, instead of always re-running the refresh command on any failure or exception as before. If the API had already rejected the credentials before the timeout, the refresh still runs.

- Area: Cloud Auth
- Tier: You'll notice
- Useful: 2/5
- Signal: 1/5

### Layout engine now tracks percent-based width/height dependence for redraw correctness

Fixed stale layout when a container resizes after a percentage-based child was measured.

The layout engine's node now records `_readsOwnerWidth`/`_readsOwnerHeight` whenever `setWidth`, `setHeight`, `setMargin`, `setPadding`, or similar methods set a dimension as a percentage. This tracks percent-based width/height dependence for redraw correctness, fixing stale-layout issues when a container's own size changes after a percentage-based child was already measured.

- Area: Elsewhere
- Tier: You'll notice
- Useful: 2/5
- Signal: 1/5

### Policy-limits cache hardened against account-switch races

Policy-limits fetches that outlive an account switch are now discarded instead of misapplied.

The policy-limits fetch/save pipeline now tracks a `sessionGeneration` per fetch and compares it before applying results, so a fetch or cache write that outlives an account switch is discarded instead of being applied to the new account's session. Look for new log lines "Policy limits: skipped saving a fetch that outlived the account session" and "Policy limits: Discarding a fetch that outlived the account session".

It also handles a 304 response with no outstanding ETag by falling back to stale cache, logging "Policy limits: 304 with no outstanding ETag — using stale cache", and merges/dedupes `compliance_taints` across cache and server responses so entries aren't lost, logging "Policy limits: lossy cached compliance_taints — kept the session taint set" when that happens.

- Flag `tengu_rustling_orbit`: Off in both readings (read for one account on one subscription tier against v2.1.261; this account: off, anonymous baseline: off, compiled default: off) These values were read against a different version of Claude Code, so treat them as the nearest reading available instead of one taken on this release.
- Area: Org Policy
- Tier: You'll notice
- Useful: 2/5
- Signal: 1/5

### Remote Control bridge gains an isTurnLive hook

Remote Control no longer reports a session as running to claude.ai when the local turn isn't actually live.

The bridge-session setup function now accepts an `isTurnLive` callback from its caller and wraps certain 'running' state transitions through it, falling back to an unconditional check when no callback is present. This lets the REPL-v2/remote-control bridge avoid announcing a 'running' state to Claude.ai when the local turn isn't actually live, tightening state-reporting accuracy for Remote Control sessions.

- Area: Remote Control
- Tier: You'll notice
- Useful: 2/5
- Signal: 1/5

### Artifact tool 'verify' action gains an approval/target-changed check

Artifact verify actions now re-check approval before proceeding, matching other read actions.

The artifact tool's "verify" action now runs an additional check before proceeding, throwing if the action or url no longer match what was approved. This brings "verify" in line with the existing re-approval checks already applied to the `read`, `read_file`, and `list_files` actions.

- Area: Artifacts
- Tier: You'll notice
- Useful: 2/5
- Signal: 1/5

### MCP config apply now suspends/reasserts tool permission allows during changes

Fixed a race where tool permissions could be checked against a mid-update MCP config.

When MCP server configs are added, removed, or reconciled, the session now calls `suspendAllowsForApply` before applying the change and `reassertAfterApply` afterward, avoiding a race where tool-use permissions could be evaluated against a config that's mid-update.

- Area: Permissions
- Tier: You'll notice
- Useful: 2/5
- Signal: 1/5

### Plugin enable/disable now checks marketplace 'admission' status and can also disable a shadowed synced copy

Newly-admitted synced plugins no longer get silently shadowed by a leftover local disable.

Enabling a plugin now checks whether its marketplace has been "admitted," and if so, cleans up any stale local/user overrides that had disabled it under both its git and non-git marketplace ids. This prevents a newly-admitted synced plugin from being silently shadowed by a leftover disable override. A related `synced-plugin-shadowed` warning suppresses the managed-policy-lock message in this specific case.

- Area: Plugin Management
- Tier: You'll notice
- Useful: 2/5
- Signal: 1/5

### Publish path denies copy-sourced files matching Read deny rules

Publishing now blocks copy-sourced files that match a Read deny rule, not just the primary file.

When publishing, each copy-sourced file's slug is now run through the standard permission-rule deny check, not just the primary `file_path`/root as before. If any copied file is denied, the whole publish is blocked with a "nothing was published" error.

- Area: Permissions
- Tier: You'll notice
- Useful: 2/5
- Signal: 1/5

### Terminal resume now forces a SIGWINCH

Resuming a suspended terminal session now forces a resize check so layout stays correct.

Resuming a suspended terminal session now sends the process a `SIGWINCH` signal before restoring the alt-screen, so terminal-size-aware code can re-check dimensions after a resize that may have happened while suspended.

- Area: Terminal UI
- Tier: You'll notice
- Useful: 1/5
- Signal: 1/5

### countTokens now falls back to gateway sampling only on HTTP 501

Token counting now only falls back to gateway sampling on a specific HTTP 501 error.

When the direct `beta.messages.countTokens` call fails, Claude Code now checks that the failure is specifically an HTTP 501 before falling back to the gateway sample-count path. If that fallback itself fails, a new error is logged with the underlying failure message.

- Area: Elsewhere
- Tier: You'll notice
- Useful: 1/5
- Signal: 1/5

### Claude-code-hint plugin references now validated as name@marketplace

Malformed plugin-hint tags are now dropped instead of parsed.

Embedded `<claude-code-hint>` payloads of type `plugin` are now validated against a `name@marketplace` pattern; malformed values are dropped with a warning. Overly long hint lines are also dropped rather than parsed.

- Area: Plugin Marketplace
- Tier: You'll notice
- Useful: 1/5
- Signal: 1/5

### Policy-limits fetch tolerates malformed compliance_taints

Policy-limits fetch no longer fails outright when some compliance data is malformed.

Fetching policy limits no longer fails when some `compliance_taints` entries in the response are malformed. Malformed entries are now dropped, the fetch still reports success with a `lossyComplianceTaints` flag set, and a log line records how many entries were dropped.

- Area: Org Policy
- Tier: You'll notice
- Useful: 1/5
- Signal: 1/5

### MCP server config validated via schema before use in `mcp add-json`

mcp add-json now validates server config against a schema before saving.

`mcp add-json` now validates the provided server config through a schema (`wK().safeParse`) to determine its type, rather than coercing the `type` field ad hoc. This tightens validation before the server config is persisted.

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

### Marketplace names starting with "claudeai-" are now rejected during reconciliation, not just on add

Reserved claudeai- prefixed marketplace names are now blocked during reconciliation too, not just on add.

Reconciling declared plugin/marketplace state now blocks entries whose name starts with the reserved `claudeai-` prefix from being materialized, logging an explicit warning and emitting a failed-progress event. Previously this prefix restriction was enforced only at `marketplace add` time.

- Area: Plugin Marketplace
- Tier: You'll notice
- Useful: 1/5
- Signal: 1/5

### Remote-control/session persistence skips uploading rows from a teleported-in conversation

Transcript rows pulled in via teleport no longer get re-uploaded to the remote store.

Transcript persistence now checks whether an entry belongs to a conversation pulled in via `/teleport`, and if so skips uploading that row. This avoids re-mirroring pulled history back to the remote store.

- Area: Elsewhere
- Names: `/teleport`
- Tier: You'll notice
- Useful: 1/5
- Signal: 1/5

### SSE transport connect now passes through common fetch options

SSE MCP connections now consistently apply proxy and agent settings like other connection paths.

The SSE transport's initial connect fetch, along with other internal fetch call sites for auth headers and retries, now spread a shared options helper into the fetch call. Proxy and agent configuration is now applied consistently to the SSE connection request as well, where previously it only applied on some paths.

- Area: MCP
- Tier: You'll notice
- Useful: 1/5
- Signal: 1/5

### System-init status message sent even without a remote bridge on permission-mode change

Permission-mode change status now reaches the UI even without an active remote-control bridge.

When the tool permission mode changes, a `status/permissionMode` system message is now sent directly via a helper even if there's no active remote-control bridge connection. Previously this update only went out through the bridge notifier.

- Area: Remote Control
- Tier: You'll notice
- Useful: 1/5
- Signal: 1/5

### Policy-limits cache deletion failures now tracked

Failed policy-cache deletions are now logged instead of silently ignored.

`deleteCacheFile` now returns a success boolean instead of silently swallowing errors. Callers (`refresh`, `clearCache`) log "Policy limits: could not remove the previous account's cache; disk adoption stays suppressed" when deletion fails, preventing stale on-disk cache from being adopted after an account switch.

- Area: Org Policy
- Tier: You'll notice
- Useful: 1/5
- Signal: 1/5

### New reassertOwnership() call added to MCP client refresh path

Fixed a race where MCP client ownership could be lost during concurrent reconnects.

The routine that rebuilds SDK MCP clients and tool/command lists now calls `reassertOwnership()` both before starting the rebuild and again after applying it, addressing a race where ownership of some MCP state could be lost during concurrent reconnects.

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

### Bridge write-path adds a post-result suppression flag

A reliability tweak fixes when the bridge reports 'running' status right after a turn result.

The bridge write path adds an internal post-result suppression flag, set on `sendResult` and checked when queuing or writing messages and control requests/responses. This changes whether the bridge immediately reports a 'running' status for messages sent right after a turn result, as a reliability tweak to Remote Control session-state reporting.

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

### Artifact publish: copy-source files now individually permission-checked before copying

Each copied file in an artifact publish is now individually permission-checked.

When an artifact publish includes copied files, each source slug is now checked individually via a permission helper with a `copySource` flag before the batch copy proceeds, in addition to the existing batch verification.

- Area: Artifacts
- Tier: You'll notice
- Useful: 1/5
- Signal: 1/5

### Artifact comments tool now validates the read target hasn't changed before serving results

Artifact comments now verify the read target hasn't changed before serving results.

The `comments` action of the artifacts tool now verifies that `action` or `url` still match what was originally approved before it reads results. If they've changed, it throws an error instead of silently reading the wrong target.

- Area: Artifacts
- Tier: You'll notice
- Useful: 1/5
- Signal: 1/5

### Publish (artifact/file publishing) now rejects a malformed files map before proceeding

Publishing now rejects a malformed files map upfront instead of proceeding partway.

Publishing artifacts or files now checks the files-to-publish map for malformed entries up front and denies the operation with the map's own error message, before any of the existing per-file permission checks run.

- Area: Artifacts
- Tier: You'll notice
- Useful: 1/5
- Signal: 1/5

## In Development

### New SDK option pluginDelivery

A new SDK option lets plugins be delivered via the initialize request instead of argv, still opt-in.

The SDK's internal options gain a `pluginDelivery` setting, defaulting to `"argv"`, with an `"initialize"` alternative that defers plugin configuration to the new initialize-request mechanism instead of passing it via command-line argv.

- Area: SDK
- Names: `pluginDelivery`
- Tier: Nothing to try yet
- Useful: 3/5
- Signal: 3/5
- Present in the build but not switched on

### Message-history 'folding' pass reaffirmed behind tengu_chair_sermon, default off

A message-history folding pass stays off by default but now tracks which attachment types get folded.

The conversation-assembly function still gates its message-history folding path behind `tengu_chair_sermon`, off by default, mapping user-turn content through a folding transform before merging it into the prior user message. The folding path now also records which attachment types were folded, via a new `foldedAttachmentTypes` array on the resulting message.

- Flag `tengu_chair_sermon`: Off in both readings (read for one account on one subscription tier against v2.1.261; this account: off, anonymous baseline: off, compiled default: off) These values were read against a different version of Claude Code, so treat them as the nearest reading available instead of one taken on this release.
- Area: Context Management
- Names: `tengu_chair_sermon`
- Tier: Nothing to try yet
- Useful: 2/5
- Signal: 3/5
- Present in the build but not switched on

### New "thinking-binding-controls" beta header is compiled but hard-disabled

A new thinking-binding-controls beta header is built but hardcoded off, so it's never actually sent yet.

A new beta header, `thinking-binding-controls-2026-08-01`, is wired up to be added to outgoing requests, but the condition that enables it is hardcoded to false in this build, so the header is never actually sent yet.

- Area: API Headers
- Names: `thinking-binding-controls-2026-08-01`
- Tier: Nothing to try yet
- Useful: 2/5
- Signal: 3/5
- Present in the build but not switched on

### Prefix-lock-rejection warning message is a no-op stub (always empty content)

Plumbing exists for a prefix-lock-rejection warning message, but it always renders as empty text.

Plumbing for a prefix-lock-rejection warning message is in place, including parsing of the `anthropic-thinking-prefix-mismatch` response header and detection of related safeguards-related 400s, but the function that generates the actual warning text currently always returns an empty string, so no message content is shown yet.

- Area: API Errors
- Tier: Nothing to try yet
- Useful: 2/5
- Signal: 3/5
- Present in the build but not switched on

### Poll tool's "evals" toolState scaffolding is unreachable in this build

Some poll-tool eval-tracking scaffolding exists but can't be reached in this build.

SDK plugins can now be delivered via the `initialize` control request using `pluginDelivery: 'initialize'`, instead of only through argv or `--plugin-dir` at launch. `Query.initialize()` checks the server's `plugins_applied` response field and logs a warning if plugins sent this way weren't applied, noting that the process runs with whatever it was actually launched with.

- Area: SDK
- Tier: Nothing to try yet
- Useful: 2/5
- Signal: 3/5
- Present in the build but not switched on

### Workspace-restriction gating built but nothing in this bundle populates it

An 'evals' mode for the Poll/Wait tool exists but is hardcoded to never trigger.

The harness's Poll/Wait tool gained `toolState` support and an "evals" ingress mode with an eval-mode outstanding-count tracker, but the mode that would select "evals" is currently hardcoded to never trigger, so this path has no live way to run in this build.

- Area: Poll Tool
- Tier: Nothing to try yet
- Useful: 2/5
- Signal: 3/5
- Present in the build but not switched on

### Subagent "harness tail" size accounting behind tengu_swift_whistle

Subagent report truncation accounting for a 'harness tail' section stays inert behind a flag.

New code paths, gated behind `tengu_swift_whistle`, control whether subagent `SendMessage` report truncation reserves extra budget for a `harnessTail`/`inlineHandback` section, and whether a telemetry counter fires when that path is taken. The logic is reachable from report formatting on agent completion and from `mapToolResultToToolResultBlockParam` for `SendMessage`, but the whole branch stays inert until the gate is enabled.

- Flag `tengu_swift_whistle`: Not enough to say (read for one account on one subscription tier against v2.1.261; this account: no value returned, anonymous baseline: no value returned, compiled default: off) These values were read against a different version of Claude Code, so treat them as the nearest reading available instead of one taken on this release.
- Area: Subagents
- Names: `tengu_swift_whistle`
- Tier: Nothing to try yet
- Useful: 2/5
- Signal: 3/5
- Present in the build but not switched on

### New "thinking_binding_controls" beta and its retry classifier stubbed off

A retry classifier for thinking-block binding errors is wired in but half-stubbed to never fire.

A new retry classifier was added to the API retry-eligibility list for errors whose message indicates a thinking block was "not created in this conversation" or "bound to a different conversation." The classifier is wired into the live retry loop, but one of its two conditions is currently a hardcoded stub that always returns false, so this "thinking_binding_controls"-related retry path is effectively stubbed off for now.

- Area: API Errors
- Names: `thinking_binding_controls`
- Tier: Nothing to try yet
- Useful: 2/5
- Signal: 3/5
- Present in the build but not switched on

### PR webhook monitoring hardcoded off

PR webhook updates are hardcoded off; PR-monitoring sessions now always poll every 30 minutes instead.

The GitHub PR-monitoring cron helper now gates real-time webhook subscription behind two internal constants, both hardcoded to `false`, so the subscribe-to-PR path can never run. Sessions monitoring a PR now always see "PR webhooks are turned off right now, so this session polls every 30 minutes instead," rather than ever getting webhook-driven updates.

- Area: Elsewhere
- Tier: You'll notice
- Useful: 2/5
- Signal: 2/5
- Present in the build but not switched on

### New "safeguards" grant-refused error path (currently inert)

A 'grant refused' safeguards error path exists but its triggering checks always return false.

A new branch in the API-error handler can emit "grant_refused" telemetry under a "safeguards_skip" event with a message built from the error, but the checks that would trigger it currently always return false and an empty string, so the branch is unreachable in this build.

- Area: Elsewhere
- Tier: Nothing to try yet
- Useful: 2/5
- Signal: 2/5
- Present in the build but not switched on

### New CLAUDE_CODE_DIR_SYNC_GIT-gated helper for directory git-sync

An internal helper for directory git-sync is gated behind an env var whose purpose isn't stated.

A new helper reads the `CLAUDE_CODE_DIR_SYNC_GIT` environment variable for gating directory git-sync behavior.

- Area: Elsewhere
- Names: `CLAUDE_CODE_DIR_SYNC_GIT`
- Tier: Nothing to try yet
- Useful: 1/5
- Signal: 2/5
- Present in the build but not switched on

### Three inert "stub" tool placeholders unconditionally listed

Three inert stub tool placeholders are now unconditionally listed but forced off.

The internal tool/skill registry now unconditionally includes three placeholder entries whose implementation is just `{ isEnabled: () => !1, isHidden: !0, name: "stub" }`. Previously one of these slots was only conditionally included; now it's always present but forced off via `isEnabled`, marking internal-only functionality not shipped in this build.

- Area: Elsewhere
- Tier: Nothing to try yet
- Useful: 1/5
- Signal: 2/5
- Present in the build but not switched on

### MCP task-sidecar restore in --print mode is hard-gated off

MCP task-sidecar restore in print mode is hard-gated off unconditionally.

When resuming a `--print` session, MCP task-sidecar restoration (`restoreMcpTasks`) is checked against a "tasks gate" before running. That gate function currently always returns false unconditionally, with no dependency on any runtime flag or env var, so the restore path always logs a skip message and returns; `restoreMcpTasks` is unreachable in this build.

- Area: MCP
- Names: `--print`
- Tier: Nothing to try yet
- Useful: 1/5
- Signal: 2/5
- Present in the build but not switched on

### Stubbed/disabled feature placeholder

An unnamed feature is permanently disabled and hidden in this build.

A new stub feature entry (internally `Ufr`) is defined as permanently disabled and hidden (`isEnabled` always returns false, `isHidden: true`), added into a list alongside other real feature entries. This indicates a feature that exists in code but is dark-launched and off.

- Area: Internals
- Tier: Nothing to try yet
- Useful: 1/5
- Signal: 1/5
- Present in the build but not switched on

## Internal Changes

### New workspace-restriction launch state

New internal state tracks restricted workspace roots and which settings sources apply within them.

Launch options gain `workspaceRestrictionState` and `restrictedWorkspaceRoots` tracking, used to determine whether a directory falls under a restricted workspace root and to gate certain features via per-root gate keys. A new `allowedSettingSourcesWithoutRepoDirSources` list also restricts which setting sources apply when a workspace restriction is active.

- Area: Workspace Restrictions
- Tier: Under the hood
- Useful: 3/5
- Signal: 3/5

### Plugin loading gains 'sync-attributed' directories and managed-hooks-only enforcement

Plugin resolution now distinguishes sync-attributed plugins and enforces managed hooks-only rules.

Plugin resolution now distinguishes 'sync-attributed' plugins, which carry `attributedMarketplaceName`, `serverPluginId`, and `installationPreference`, from plain `--plugin-dir` copies. Each is checked against managed settings through a new admission function, and duplicate managed-plugin claims across session and synced copies are dropped. When an organization's managed settings restrict to hooks-only via `allowManagedHooksOnly`, admitted-by-lock plugins are now tagged with a `managed-hooks-restricted` warning.

- Area: Plugin Management
- Names: `allowManagedHooksOnly`
- Tier: Under the hood
- Useful: 3/5
- Signal: 3/5

### New "claudeai" plugin/skill install source

Skills and plugins gain a new claude.ai install source shown as claude.ai.

Skill and plugin source labels now recognize a new source named `claudeai`, which displays as "claude.ai" and is treated like an `archive` install type elsewhere in the code. This is new plumbing for installing skills and plugins directly from claude.ai.

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

### Claude-in-Chrome file uploads bypass local preparation under Cowork

Chrome file uploads can now skip local prep under a Cowork-specific condition.

Claude-in-Chrome file uploads via the `file_upload`/`browser_batch` MCP tool can now skip local input preparation entirely, using a new `passThroughChromeFileUploadInput` handler instead of the existing `prepareChromeFileUploadInput`. This pass-through path only kicks in when the MCP server isn't stdio-based, the process isn't `CLAUDE_CODE_REMOTE`, and `CLAUDE_CODE_IS_COWORK` is set.

- Area: Elsewhere
- Names: `CLAUDE_CODE_IS_COWORK`
- Tier: Under the hood
- Useful: 2/5
- Signal: 2/5

### New prompt-cache-break diagnostics: msg0 shape tracking

New internal diagnostics track the first message's shape to diagnose cache breaks.

Prompt-cache-break diagnostics now capture a structured shape of the first message per cache source, covering block kinds, lengths, hashes, named sections, and worker-tool counts. When a cache break is attributed to the first message, this shape is diffed against the previous call, adding `msg0Sections`, `msg0ChangedSections`, `msg0AddedSections`/`RemovedSections`, and `msg0ChangedBlocks` to the break-diagnosis telemetry.

- Area: Prompt Caching
- Tier: Under the hood
- Useful: 2/5
- Signal: 2/5

### Auto-mode sessions now probe local git state and report telemetry

Auto mode sessions now probe local git state and report telemetry about it.

Autonomous "auto mode" sessions now run a git-state probe that collects the current branch, default branch, remote visibility (public/private), working-copy status, and a Chrome navigation classifier baseline. This feeds into an internal context payload, and completion fires `tengu_auto_mode_git_state_probe` telemetry with timing, an outcome classification such as clean, dirty, or no_status, and truncation flags. It also flags when the collected context exceeds a byte ceiling.

- Area: Auto Mode
- Names: `tengu_auto_mode_git_state_probe`
- Tier: Under the hood
- Useful: 2/5
- Signal: 2/5

### Artifact publish MCP context includes a new artifact_consent_holdback flag

Artifact publish now sends a new consent-holdback flag internally.

The Artifact publish payload sent for consent and telemetry purposes now includes an `artifact_consent_holdback` boolean, backed by a small new helper pair that reads a settable holdback predicate defaulting to true when unset.

- Area: Artifacts
- Names: `artifact_consent_holdback`
- Tier: Under the hood
- Useful: 2/5
- Signal: 2/5

### PowerShell/Bash tool result size and persistence threshold now dynamic

Bash/PowerShell output size limits are now computed dynamically instead of fixed.

The command-execution tool's max result size is now computed at call time via a getter instead of being a fixed 30000-character constant, and a new `persistenceThresholdCeiling` field has been added, suggesting result truncation limits can be configured server-side.

- Area: Output Limits
- Tier: Under the hood
- Useful: 2/5
- Signal: 2/5

### GrowthBook remote-eval fallback no longer reads disk cache

Feature-flag resolution no longer falls back to disk cache once remote eval data has loaded.

Once remote-eval feature values have loaded for a session, the client now falls back directly to the caller-supplied fallback value when a specific flag isn't present in that data, instead of consulting the on-disk cached GrowthBook features. This changes feature-flag resolution behavior for any session that has remote eval data loaded.

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

### Plugin manifest schema changes: id field and display_name refactor

Plugin manifests gain an id field required for claude.ai-sourced plugins.

The plugin config schema now includes an optional `id` field. For claudeai-sourced plugins, the manifest is only valid if `id` is present, whereas previously name-based validation applied uniformly. `display_name` validation was also refactored into a shared helper.

- Area: Plugin Marketplace
- Tier: Under the hood
- Useful: 2/5
- Signal: 2/5

### New system-prompt flag: autoModeContextEnabled

A new system-prompt flag controls auto-mode context injection.

A new field `autoModeContextEnabled` was added alongside other system-prompt feature flags such as `staticSystemPromptEnabled` and `workflowKeywordTriggerEnabled`. This suggests a new controllable context-injection behavior tied to Auto mode.

- Area: Auto Mode
- Names: `autoModeContextEnabled`
- Tier: Under the hood
- Useful: 2/5
- Signal: 2/5

### Disk session-cache adoption can be suppressed

Disk session-cache adoption can now be suppressed internally after an account switch.

New state fields `diskAdoptionSuppressed` and `diskAdoptionEpoch` were added to session-cache tracking. When `diskAdoptionSuppressed` is true, the cache lookup now short-circuits to null instead of adopting a cached session from disk.

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

### New per-phase CPU telemetry, gated behind CLAUDE_CODE_REMOTE

Remote sessions now report per-phase CPU usage split between CLI and tool subprocesses.

When the environment sets `CLAUDE_CODE_REMOTE` and the active transport is the remote/websocket-style transport class, Claude Code now reads the process's cgroup cpuacct usage file (`/sys/fs/cgroup/cpuacct${d}/cpuacct.usage`, located via `/proc/self/cgroup`) and compares it against `process.cpuUsage()` to split CPU time into CLI versus tool-subprocess buckets per session-state phase. This emits `tengu_tool_cpu_by_phase` telemetry, with fields like `<phase>_wall_ms`, `<phase>_cli_cpu_ms`, and `<phase>_tools_cpu_ms`, on state transitions (idle, idle_background, active, exit) and at exit, also stamping the event with the raw value of `CLAUDE_CODE_BG_TASKS_REPORT_RUNNING`. The instrumentation is skipped entirely unless `CLAUDE_CODE_REMOTE` is set.

- Area: Telemetry
- Names: `tengu_tool_cpu_by_phase`
- Tier: Under the hood
- Useful: 2/5
- Signal: 2/5

### Auto-mode server-classifier context now has a size budget with progressive truncation

Auto-mode classifier context now trims progressively to stay within a byte budget.

The context sent to the server-side auto-mode classifier now has an enforced byte budget. When the context is too large, Claude Code progressively trims it: first prior-turn context, then Chrome tab data, then the git visibility cache/remotes, then git status porcelain output. If the static, non-trimmable portion alone exceeds the budget, it logs a warning and fires the `tengu_auto_mode_context_static_over_budget` telemetry event; if the context still exceeds a harder ceiling after trimming, it is withheld entirely instead of being sent oversized.

- Area: Auto Mode
- Tier: Under the hood
- Useful: 2/5
- Signal: 2/5

### New provider-managed env var list for gateway policy checks

A new provider-managed env var list decides gateway sign-in error wording.

A new provider-managed env var list covers `CLAUDE_CODE_USE_BEDROCK`, `CLAUDE_CODE_USE_FOUNDRY`, `CLAUDE_CODE_USE_ANTHROPIC_AWS`, `CLAUDE_CODE_USE_ANTHROPIC_GOOGLE_CLOUD`, `CLAUDE_CODE_USE_MANTLE`, and `CLAUDE_CODE_USE_VERTEX`. Whether the gateway sign-in error message points users to `/login` or tells them no sign-in is needed now depends on whether one of these provider env vars is active and `CLAUDE_CODE_PROVIDER_MANAGED_BY_HOST` is unset.

- Area: Cloud Gateway
- Names: `CLAUDE_CODE_USE_BEDROCK`, `CLAUDE_CODE_PROVIDER_MANAGED_BY_HOST`
- Tier: Under the hood
- Useful: 2/5
- Signal: 2/5

### New mcp_set_servers binding-changed sync hook

MCP server config changes now trigger sync hooks to keep SDK hosts' binding state in sync.

The control-request handler for `mcp_set_servers` now calls a `.sync("binding_changed")` hook before applying server config changes, with a `.sync("startup")` hook invoked earlier during session init. This appears to be new plumbing for keeping an SDK host's server-binding state in sync with dynamic MCP server updates.

- Area: MCP
- Names: `mcp_set_servers`
- Tier: Under the hood
- Useful: 2/5
- Signal: 2/5

### Auto-mode permission context payload (git state, chrome nav, trusted dirs) sent for classification

Auto-mode permission classification now sends a richer context payload including git and Chrome state.

Auto-mode permission classification now sends a richer context payload, including `permission_mode`, `trusted_directories`, rules, the `auto_mode` allow/soft_deny/hard_deny/environment lists, git status and visibility, and chrome navigation baselines. Oversized entries are truncated or dropped before this context is sent to the classifier.

- Area: Auto Mode
- Tier: Under the hood
- Useful: 2/5
- Signal: 2/5

### Chrome extension file_upload path validation hardened and reused

File-upload path safety checks were refactored into shared helpers reused across upload paths.

The `file_upload` tool's path-safety checks, covering network path rejection, Windows-path spoofing detection, percent-encoding/`..` rejection, and kernel alias-namespace rejection (paths like `/dev`, `/proc`, `..namedfork`), are now factored into shared helper functions. These are applied both to a new lightweight pass-through validation path and the existing full resolve-and-check path, tightening protection against path traversal and spoofing when Claude-in-Chrome uploads local files.

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

### `claude ultrareview` gains a distinct "policy route missing" telemetry reason

ultrareview now reports a clearer reason when blocked by a missing policy route.

Telemetry for the `allow_remote_sessions` capability check used by `claude ultrareview` now distinguishes three cases instead of collapsing them into one: a cache miss, a generic `policy_disallowed` reason, and a new `policy_route_missing` reason. This gives clearer diagnostics when `ultrareview` is blocked.

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

### Plugin marketplace admission check for locked/duplicate plugin names

Internal logic now decides whether a plugin name is admitted or locked across marketplaces.

A new helper resolves whether a plugin name found across marketplaces is "admitted" (it matches the given marketplace and isn't marked non-locking) or "locked" by an existing disabled or other-marketplace entry. This refines how name collisions across plugin marketplaces are handled during install and enable.

- Area: Plugin Marketplace
- Tier: Under the hood
- Useful: 2/5
- Signal: 1/5

### Cloud/attach session flag support expanded

Cloud/attach sessions now recognize two more CLI flags for compatibility.

The cloud-session flag-compatibility table gains entries for `awaitInitialize` and `appendSubagentSystemPromptFile`, so these flags are now recognized and handled for attach/cloud sessions.

- Area: Elsewhere
- Names: `awaitInitialize`, `appendSubagentSystemPromptFile`
- Tier: Under the hood
- Useful: 2/5
- Signal: 1/5

### Sandbox deny-rule grouping to shrink generated policies

The macOS sandbox policy generator now groups rules to keep generated policies smaller.

The macOS sandbox profile generator now groups deny and pin file-write rules that share a parent directory into combined regex patterns, splitting `file-write-unlink`/`file-write-create` handling from generic `file-write*` rules, and keeps each generated policy group under a 900-byte size budget.

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

### Plugin records now track claude.ai plugin identity and archive hash

Installed plugin records now track a claude.ai plugin id and archive hash.

Installed-plugin metadata now includes a `claudeaiPluginId` field and an optional `archiveSha256`, populated when a plugin install or update comes with claude.ai info. This lets plugins sourced from the claude.ai marketplace be tracked distinctly from git or local sources.

- Area: Plugin Marketplace
- Tier: Under the hood
- Useful: 2/5
- Signal: 1/5

### New tengu_stdout_backpressure telemetry event

New telemetry tracks stdout backpressure stalls and dropped bytes.

The terminal renderer now tracks stdout backpressure — dropped bytes, peak queued bytes, and duration — and emits a `tengu_stdout_backpressure` event when bytes were dropped or the stall lasted at least a second. On drain, it also resyncs the input querier and forces a redraw or repaint.

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

### New sync action: reload_output_styles

Output styles can now be hot-reloaded across processes like plugins and skills.

The reducer that handles cross-process sync actions, which already covered cases like `mcp_reconnect`, `reload_plugins`, and `reload_skills`, gained a new case `reload_output_styles`. Output styles can now be hot-reloaded the same way plugins and skills are.

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

### Offline flag added to teammate/session listings

Session and teammate listings now carry an internal offline flag.

Session and teammate candidate records can now carry an explicit `offline: true` flag, computed by a new predicate, shown alongside the existing `where: 'cloud'/'remote'` and `lastActive` fields.

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

### New numeric remote-config gate `tengu_cozy_dusk`

A new numeric remote-config gate was added with clamped bounds.

A new remote-config gate, `tengu_cozy_dusk`, reads a numeric value and clamps it between two bounds, falling back to a default when the value is absent or non-finite.

- Area: Internals
- Names: `tengu_cozy_dusk`
- Tier: Under the hood
- Useful: 1/5
- Signal: 1/5

### Plugin command failures now tagged with claude.ai error codes

Plugin command failure telemetry now tags claude.ai-specific error codes.

CLI plugin command failure telemetry for install, uninstall, and update now includes a `claudeai_<code>` reason when the underlying error carries a claude.ai-specific code, instead of always falling back to the generic `unknown`/`not_found` reasons.

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

### New telemetry for auto-mode context being withheld entirely

New telemetry fires when auto-mode context is too large and gets withheld entirely.

When the serialized auto-mode context payload (git state, rules, trusted directories, and similar data) exceeds an internal byte ceiling, Claude Code now logs a one-time `tengu_auto_mode_context_over_ceiling` telemetry event with the byte count. If the assembled context still exceeds the larger byte ceiling even before trimming, the whole context is dropped from the classifier call and a `tengu_auto_mode_context_withheld` event is fired noting the reason and size.

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

### Rate-limit tracker now records last-seen window data separately

Rate-limit tracking now records last-seen window data separately internally.

The claude.ai usage/limits tracker (`probeQuotaStatus`/`extractQuotaStatusFromHeaders`) adds a `lastSeenWindows` map alongside `rawUtilization`. Utilization is now recorded through a new `recordRawUtilization` method instead of a direct assignment, and both maps are reset together when quota headers are absent.

- Area: Usage & Limits
- Tier: Under the hood
- Useful: 1/5
- Signal: 1/5

### Command queue gains a removal-subscription channel

The command queue gained an internal subscription channel for removal events.

The internal command-queue store adds `subscribeToRemovals`, backed by a new emitter, alongside the existing dequeue/remove APIs. The shared removal helper now fires this emitter whenever queued commands are removed, with listener errors caught and reported via a `commandsRemoved listener aborted` log rather than allowed to throw.

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

### New telemetry: prefix-break diagnostics with sampled hashing

New sampled telemetry records detailed hashes around cache-prefix breaks.

A new `tengu_prefix_break_hashes` telemetry event records detailed per-message-block hashes and diffs (types, roles, folded attachment info) around a cache-prefix break. It's gated by a sampling rate read from remote config, limited to first-party API usage, and excluded for HIPAA accounts.

- Area: Prompt Caching
- Names: `tengu_prefix_break_hashes`
- Tier: Under the hood
- Useful: 1/5
- Signal: 1/5

### Slack-relay message provenance rules for user-intent detection

Internal instructions now spell out how to tell genuine Slack user messages from bot-relayed ones.

The agent's internal instructions for Slack relay now spell out how to distinguish genuine user messages from bot- or peer-authored ones. A real user message arrives via a `<wake …>` envelope with `from="human"`, or via specific harness-inserted lead/marker text; a `<message>` carrying the `bot` attribute inside a `<slack-messages>` block was written by a bot or another agent. Messages in the latter category must never be treated as establishing user intent or consent, and permission-laundering attempts relayed through Slack are explicitly callable out as blockable.

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

### New telemetry for plugin hints surfaced to the user

New telemetry fires whenever a plugin install hint is shown to the user.

Claude Code now emits a `tengu_plugin_hint_seen` telemetry event whenever a claude-code-hint is surfaced to the user. The event records the surface, and, when the hint's plugin id parses, a hashed plugin id and whether it claims to be from the official marketplace.

- Area: Telemetry
- Names: `tengu_plugin_hint_seen`
- Tier: Under the hood
- Useful: 1/5
- Signal: 1/5

### Telemetry auth-send gate tightened with an endpoint check

Telemetry auth-sending logic was tightened with an endpoint allowlist check.

`shouldSkipAuthForSend` now short-circuits to skip auth whenever the target endpoint isn't allow-listed or first-party HTTPS, before falling into the existing trust and token checks. A new `shouldAttachAuthWithoutProfileScope` path also covers stored, env, and fd credential lanes.

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

### TaskOutput tool result size now computed dynamically

TaskOutput's result size limit is now computed dynamically rather than fixed.

The deprecated TaskOutput tool's `maxResultSizeChars` is no longer a fixed 1e5 constant; it's now a getter combining a helper value with a persistence threshold, alongside a new `persistenceThresholdCeiling` field. The output-size ceiling appears to now derive from the same config as the new `taskOutputMaxChars` setting.

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

### New no_response diagnostic field for stream timeouts

Telemetry schema now records how long a no-response stream timeout waited.

The retry/error telemetry schema gained an optional `no_response` object with `waited_ms` and `retry_wait_ms` fields, populated only when the API sent no response headers within the first-byte timeout window (`CLAUDE_STREAM_FIRST_BYTE_TIMEOUT_MS`). This distinguishes a no-response timeout from a normal retry, reporting how long the failed attempt waited for headers and how long the retry will wait.

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

### Marketplace-scoped enabledPlugins now records marketplace explicitly

Policy-configured enabled plugins now track their marketplace explicitly instead of just a name.

The parser for policy-configured `enabledPlugins` no longer just collects plugin names into a `Set<string>`. Each key is now parsed into `{name, marketplace}`, tracking whether the marketplace was explicit in the key, so downstream consumers work with an array of richer records instead of a plain set of names.

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

### Weekly usage-limit lookup simplified/hardened

Weekly usage-limit lookup logic was simplified and tightened.

The helper that surfaces "Current week" rate-limit display data for models now filters candidates through a dedicated predicate before mapping, and drops the optional-chaining fallback on `scope.model.display_name`, indicating callers must now guarantee `scope.model` is present for weekly-scoped limits.

- Area: Usage & Limits
- Tier: Under the hood
- Useful: 1/5
- Signal: 1/5

### "claudeai-" prefixed skill/plugin name detection

New helpers detect claudeai-prefixed skill and plugin names.

New helper functions detect whether a normalized name starts with a `claudeai-` prefix, used to identify skills and plugins that originate from claude.ai.

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

### New gate: tengu_swift_whistle

A new feature gate was added, defaulting to false.

A new feature gate `tengu_swift_whistle` was added, defaulting to false.

- Flag `tengu_swift_whistle`: Not enough to say (read for one account on one subscription tier against v2.1.261; this account: no value returned, anonymous baseline: no value returned, compiled default: off) These values were read against a different version of Claude Code, so treat them as the nearest reading available instead of one taken on this release.
- Area: Internals
- Names: `tengu_swift_whistle`
- Tier: Under the hood
- Useful: 1/5
- Signal: 1/5

### Auto-mode classifier fallback now records a `fallbackCause`

Auto-mode fallback telemetry now records why a fallback model was used.

The auto-mode permission classifier telemetry event `tengu_auto_mode_outcome` now includes a `fallbackCause` field distinguishing why a fallback model was used, for example probe demotion, refusal, or capacity issues.

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

### CLI debug/status payload now reports which plugins were applied

CLI debug output now reports which plugins were applied, like it already does for hooks.

The CLI's status/debug info payload, used for diagnostics and IDE integration, now includes a `plugins_applied` field alongside the existing `hooks_applied` field, reporting which plugins were applied.

- Area: Diagnostics
- Names: `plugins_applied`
- Tier: Under the hood
- Useful: 1/5
- Signal: 1/5

### IDE remote-control auto-enable still exposed via a named experiment flag

IDE remote-control auto-enable status remains exposed via its experiment flag.

The status payload continues to expose whether IDE-driven remote-control auto-enable is active via the `ide_rc_auto_enable_gate` field.

- Flag `tengu_ide_rc_auto_enable`: Off by default, switched on for this account (read for one account on one subscription tier against v2.1.261; this account: on, anonymous baseline: on, compiled default: off) These values were read against a different version of Claude Code, so treat them as the nearest reading available instead of one taken on this release.
- Area: Remote Control
- Names: `ide_rc_auto_enable_gate`
- Tier: Under the hood
- Useful: 1/5
- Signal: 1/5

### New tengu_compiled_acorn flag for poll-event formatting

A new flag controls how poll and mid-turn event text is formatted.

A new `tengu_compiled_acorn` flag controls how poll and mid-turn event text is formatted. When active (and a separate feature check also passes), mid-turn text gets one prefix while other cases stay plain, instead of falling back to the previous prefix path.

- Area: Internals
- Names: `tengu_compiled_acorn`
- Tier: Under the hood
- Useful: 1/5
- Signal: 1/5

### New tengu_cobalt_plinth_comfrey flag for artifact relay access

A new flag affects relay routing when reading published artifact files.

A new remote flag, `tengu_cobalt_plinth_comfrey`, is now checked (together with existing checks) when reading published artifact files, to determine relay routing before falling back to the previous checks.

- Area: Artifacts
- Names: `tengu_cobalt_plinth_comfrey`
- Tier: Under the hood
- Useful: 1/5
- Signal: 1/5

### cancel_async_message now triggers an extra Zr() side-effect

Cancelling an async message now triggers an extra internal side-effect.

Handling a `cancel_async_message` remote request now also triggers an additional side-effect after dequeuing and cancelling matching commands, on top of the existing cancellation notification flow.

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

### Hook plugin metrics now resolve plugin id via a lookup helper

Hook plugin telemetry now resolves plugin id through a more robust lookup.

Hook plugin telemetry (`tengu_hook_plugin_metrics` / `hook_plugin_metrics`) now derives the plugin id it reports through a two-step lookup instead of the previous single check, and skips sending telemetry entirely if that lookup returns falsy.

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

### tengu_sdk_result telemetry now includes user_message_uuid

SDK session-result telemetry now includes the user message id being processed at session end.

SDK and headless session-result telemetry events (`tengu_sdk_result`), covering the crash, terminated, and error_during_execution subtypes, now include a `user_message_uuid` field identifying the user message the turn was processing when the session ended, alongside existing fields like `subtype` and `duration_ms`.

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

### REPL bridge init now passes an isTurnLive callback

The REPL bridge now can query whether a turn is currently live.

The terminal REPL bridge's `initReplBridge()` call now receives an `isTurnLive` option, giving the bridge a way to query whether a turn is currently live.

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

### claude.ai catalog telemetry

New telemetry tracks claude.ai marketplace catalog fetches and failures.

New telemetry events track claude.ai marketplace catalog fetches and failures, including page-cap warnings and dropped or malformed rows.

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

### MCP set-servers request can short-circuit on a matching 'hint' during a binding change

MCP server config updates can now short-circuit when nothing actually changed.

When handling `mcp_set_servers`, if the request's hint matches a locally-tracked value, the server now records a `binding_changed` sync event, and if the incoming servers object is empty, returns an empty added/removed/errors result immediately instead of running the full authoritative sync.

- Area: MCP
- Names: `mcp_set_servers`
- Tier: Under the hood
- Useful: 1/5
- Signal: 1/5

### New 'foldedAttachmentTypes' metadata surfaced in transcript debug summaries

Transcript debug summaries can now show which attachment types were folded.

Assembled `api_system`/user messages can now carry a `foldedAttachmentTypes` list, collected from folded attachment types during message building. A debug/summary formatter prints this as a tagged line, such as `index=type1+type2`, whenever the field is present.

- Flag `tengu_chair_sermon`: Off in both readings (read for one account on one subscription tier against v2.1.261; this account: off, anonymous baseline: off, compiled default: off) These values were read against a different version of Claude Code, so treat them as the nearest reading available instead of one taken on this release.
- Area: Elsewhere
- Tier: Under the hood
- Useful: 1/5
- Signal: 1/5

### System-reminder context wrapper extracted to shared constant

The system-reminder wrapper text is now built from shared constants instead of duplicated inline.

The `<system-reminder>` wrapper text used to inject CLAUDE.md-style context into conversations is now built from shared prefix/suffix constants instead of being duplicated as an inline template at each call site, consolidating the wording used across injection points.

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

### Word-boundary tracking drops isWordLike distinction

Word-boundary navigation logic was simplified, dropping a word-vs-punctuation distinction.

The readline word-boundary cache used for cursor and word navigation (`getWordBoundaries`) no longer tracks whether a segment is word-like versus punctuation, only its start/end offsets. This simplifies the previous Intl.Segmenter-based boundary logic.

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

## Removed

### keybindingFlavor setting deprecated; classic word-editing mode removed

The keybindingFlavor setting is deprecated; prompt word-editing always follows readline conventions now.

The `keybindingFlavor` setting ('classic' vs 'readline') is now deprecated and no longer has any effect. Word-editing keys in the prompt always follow Bash (readline) conventions regardless of what the setting was previously set to.

- Area: Terminal UI
- Names: `keybindingFlavor`
- Tier: You'll notice
- Useful: 3/5
- Signal: 1/5

### Staging claude-ai domain matching removed from artifact URL parsing

Internal staging-domain support was dropped from artifact URL parsing.

Code that previously matched `claude-ai.staging.ant.dev` preview URLs when resolving artifact references now always returns nothing for that branch, dropping staging-domain support from this path.

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

### Staging API host removed from claude.ai URL resolver

The claude.ai URL resolver no longer points non-prod environments at a staging host.

The helper that resolves the claude.ai base URL no longer returns the staging host (`https://claude-ai.staging.ant.dev`) for non-prod environments; it now always returns `https://claude.ai` regardless of environment.

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