# Claude Code v2.1.259

> Claude Code v2.1.259, released 2 Sep 2026 (2026-09-02). 210 entries read out of the shipped bundle. Unofficial, and not affiliated with Anthropic.

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

Eighteen entries in this build sit behind flags or unfinished wiring. Plugin hooks can now be written as real JS modules, but they stay off unless CLAUDE_CODE_ENABLE_FUNCTION_HOOKS or a flag forces them on. Artifact pinning is built end to end, including a hidden CLAUDE_CODE_ARTIFACT_PIN override and relay-error handling, but it's gated off by default and unavailable in cloud sessions. A new --proactivity CLI flag can be typed already, though its value is discarded and a matching proactivityLevel setting is being plumbed through sessions with no UI or behavior yet. A "signed cache" verification system exists with an empty list of trusted signing roots, and a consent system for unattended tool serving is wired up but still waiting on its feature flag.

Of the 106 shipped changes, several open up new control over hooks, models, and permissions. The CLAUDE_CODE_ENABLE_FUNCTION_HOOKS environment variable can force on function hooks, and plugins can now hook into new session.start and prompt.context events, the latter capped at 32 contributed text blocks. Settings.json can now set a default model that takes precedence over ANTHROPIC_DEFAULT_MODEL, and a new --permission-prompts none flag makes headless or SDK sessions auto-deny anything needing approval instead of prompting. Organizations can push MCP servers directly to every user via managedMcpServers, locked from local removal, and headless SDK sessions gain a tool.register API for adding, removing, and checking the status of MCP servers. A new CLAUDE_CODE_SKILL_ATTRIBUTION variable attributes actions to a specific skill for telemetry and testing.

Among 29 fixes, permission and shutdown handling get several corrections. A skill or slash command's model override now checks compatibility with auto-mode before switching, rather than always applying. Resumed sessions correctly restore default, plan, dontAsk, and bubble permission modes instead of losing them, and killing a task that looked already finished but was secretly still running now actually stops its loop. Agents mid-shutdown can no longer launch workflows, send messages, or run shell commands during teardown. Separately, the allow_desktop_handoff policy and the built-in claude-api agent's Read, Grep, and Glob access have been removed, narrowing that agent to fetching from platform.claude.com only.

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

### Artifact pin/unpin — gated off by default

Artifacts gain full pin and unpin actions, wired end to end but off by default behind a gate with an env override.

Artifacts gain full pin/unpin support, wired end-to-end but gated off by default behind a growthbook gate (overridable by an env var). The artifacts tool's action enum now includes `pin` and `unpin` alongside `publish`, `list`, `read`, and others, and the action list conditionally exposes these two verbs based on a new capability flag. The `list`/`read` schemas gain a `pinned` field and a `pins_enabled` flag.

Pinning an artifact you didn't create triggers an approval prompt; pinning your own session's artifact or unpinning is auto-allowed. The UI renders "pinned to the sidebar" / "unpinned" for these actions, and tool-use rendering now has a dedicated branch for `action === "pin"` or `"unpin"` that prints the resolved title and address. The tool description gains the line "(then pins it to the user's own sidebar - private, reversible)", and accounts lacking the capability see "(Pinning isn't available for this account: 'pin' and 'unpin' will not work.)" Cloud sessions refuse the action with "Pinning artifacts isn't available in this cloud session yet...", and pin state is tracked via new store fields including `frozenArtifactPins`.

- Flag `tengu_cobalt_plinth_holly`: Off in both readings (read for one account on one subscription tier against v2.1.259; 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: Artifacts
- Names: `pin`, `unpin`, `pins_enabled`
- Tier: Nothing to try yet
- Useful: 5/5
- Signal: 5/5
- Present in the build but not switched on

### New "teleport relay" path for streaming completions

A teleport relay path can route streaming requests through a remote session's ingress endpoint, with fallbacks to the normal path.

A new "teleport relay" path can intercept outgoing streaming `/v1/messages` requests and, when a remote/CCR session is active, route them through a `/teleport/conversations/.../completion` endpoint on the session's ingress origin instead of the normal path. It tracks an arming state machine (`inactive`/`active`/`reverted`) and falls back to standard dispatch on model mismatches, changed tool fingerprints, non-SSE responses, HTTP errors, timeouts, or a 409 with a `teleport_relay_refused` discriminant, logging `cli_teleport_relay_fallback` and a telemetry event `upgrade_teleport_cache` with a `reason` such as `context_reduced`, `tools_changed`, `relay_unreachable`, `relay_dispatch_timeout`, `relay_refused`, `relay_not_sse`, or `model_mismatch`.

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

### New --proactivity CLI flag (scaffolding only)

A --proactivity flag is accepted and threaded through session creation, but its value is discarded before it has any effect.

A new `--proactivity` CLI flag has been added to the accepted-flags list, and a `proactivityLevel` field now flows through session creation, telemetry, and query dispatch. In this build the resolving function calls a stub that unconditionally returns undefined, so the flag's value is currently discarded before it has any effect.

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

### Plugin hooks as JS modules — gated off by default

Plugins can load hooks from real JS modules with per-action permission checks, but the rollout gate defaults off.

New machinery loads a plugin's hooks from actual JS modules (function hooks) rather than only declarative config, with permission checks for `call_handler`, `run_script`, and `get_handlers` actions. A loader logs `hooks module of plugin "X" not loaded: ...` with reasons such as `--bare` mode, `disableAllHooks`, or the rollout flag being off. The rollout is controlled by a growthbook gate, `tengu_plugin_hooks_modules`, that defaults to off, and can be forced on or off via the `CLAUDE_CODE_ENABLE_FUNCTION_HOOKS` env var, which takes priority over the gate.

- Area: Plugin Hooks
- Names: `CLAUDE_CODE_ENABLE_FUNCTION_HOOKS`, `tengu_plugin_hooks_modules`, `--bare`, `disableAllHooks`
- Tier: Nothing to try yet
- Useful: 5/5
- Signal: 5/5
- Present in the build but not switched on

### CLAUDE_CODE_ENABLE_FUNCTION_HOOKS env override

A new environment variable can force plugin function hooks on or off, overriding the remote feature gate.

A new `CLAUDE_CODE_ENABLE_FUNCTION_HOOKS` environment variable can force-override the function-hooks feature gate, taking precedence over the existing remote/experiment gate. A debug string documents this as "overridden by the CLAUDE_CODE_ENABLE_FUNCTION_HOOKS environment variable".

- Area: Plugin Hooks
- Names: `CLAUDE_CODE_ENABLE_FUNCTION_HOOKS`
- Tier: Use it now
- Useful: 5/5
- Signal: 4/5

### New functionHooks event: prompt.context

A new prompt.context hook event lets plugins add named context blocks to a prompt, capped at 32 blocks and 32000 characters.

A new hook event, `prompt.context`, joins `prompt.section`, `ui.render`, and `tool.describe` in the SDK/plugin hooks event registry. A hook can now contribute named context blocks to a prompt via `{blocks: [{name, text}]}`, subject to a validator that caps the count at 32 blocks, requires unique names, and enforces a combined 32000-character budget on top of what the engine itself adds. The event is fully wired through the event list, the site/core hook dispatch tables, and new cache-invalidation hooks `invalidatePromptContext` and `invalidateHookedPromptContext`.

- Area: Plugin Hooks
- Names: `prompt.context`, `invalidatePromptContext`, `invalidateHookedPromptContext`
- Tier: Use it now
- Useful: 5/5
- Signal: 4/5

### New plugin/hook events 'prompt.context' and 'session.start'

Two hook events arrive: session.start fires on terminal session start, and prompt.context is registered but has no emitter here.

Two new hook/event kinds, `prompt.context` and `session.start`, are now recognized for host-plugin messaging validation and payload-shape mapping. `session.start` is wired up: the terminal REPL calls a new `_raiseSessionStart()` unconditionally during session start, sending `{loaded, surface: "terminal", interactive: true}`, with a corresponding event schema payload of `{cwd}`. `prompt.context` appears in the same validation and telemetry site tables alongside other prompt-family events, but no direct emitter was found in this slice. Both event kinds were also added to the telemetry site registry alongside existing tool/prompt/agent/turn sites.

- Area: Plugin Hooks
- Names: `session.start`, `prompt.context`
- Tier: Use it now
- Useful: 5/5
- Signal: 4/5

### New `Svg` render element type for engine/dialog UI trees

Dialog and engine UI trees can include an Svg element, and the validator now reports when an element isn't allowed on a surface.

Dialog and engine UI trees can now include an `Svg` element, validated with `source`, `alt`, `width`, `height`, and `interactive` props subject to size and length limits. The dialog-tree validator also gained a surface-restriction check that reports "`<type>` is not an element of the `<surface>` surface" when an element like `Svg` or `Button` doesn't belong on the current surface.

- Area: UI Elements
- Names: `Svg`
- Tier: Nothing to try yet
- Useful: 5/5
- Signal: 4/5

### ExitPlanMode gains a swarm plan-approval submission path

Exiting plan mode inside a team context submits your plan to the team lead's inbox for approval instead of just switching modes.

Exiting plan mode inside a swarm/team context can now submit the plan for approval instead of just switching modes: `ExitPlanMode` writes a `plan_approval_request` message to the team lead's inbox and returns an `awaitingLeaderApproval` state, showing "Your plan has been submitted to the team lead for approval."

- Area: Plan Mode
- Names: `ExitPlanMode`
- Tier: You'll notice
- Useful: 4/5
- Signal: 4/5

### MCP session resume can adopt served tool calls left in-flight by a prior worker

Resuming an MCP session can adopt tool calls a previous worker left in flight instead of re-issuing the interrupted turn.

When an MCP session resumes, tool calls that a previous worker process had already dispatched but not yet resolved ("served calls") can now be adopted directly by the new process instead of re-issuing the interrupted turn. The model is told which calls' results were lost via an "orphaned-permission" meta-message, and adoption is logged as `tengu_remote_tool_restart_adoption`.

- Area: Remote Tools
- Tier: You'll notice
- Useful: 4/5
- Signal: 4/5

### Remote tool serving can be centrally killed by Anthropic

Anthropic can centrally switch off remote tool serving, and messages explain that plugins and hooks aren't sent to cloud sessions while it's off.

Anthropic can now centrally disable remote tool serving via a global "emergency switch." New user-facing messages explain that while it's off, a computer's plugins and hooks are not sent to cloud sessions, and normal operation resumes once it's back on. Corresponding state changes mark serving as muted or stopped with reason `'muted'` rather than idle.

- Area: Remote Tools
- Tier: You'll notice
- Useful: 4/5
- Signal: 4/5

### Artifact tool gains a publish-time 'pin' parameter, behind a flag

The artifact publish action can offer a pin field, but it is refused outright in cloud sessions and otherwise depends on an env var or gate.

The Artifact tool's publish action now accepts a `pin` boolean, which also pins the published artifact to the user's claude.ai sidebar once published. Whether this field is even offered to the model is controlled by an internal check that returns false outright for remote/cloud sessions (unless a separate override applies), and otherwise reads `CLAUDE_CODE_ARTIFACT_PIN` or falls back to a gate.

- Flag `tengu_cobalt_plinth_holly`: Off in both readings (read for one account on one subscription tier against v2.1.259; 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: Artifacts
- Names: `CLAUDE_CODE_ARTIFACT_PIN`, `pin`
- Tier: Nothing to try yet
- Useful: 4/5
- Signal: 4/5
- Present in the build but not switched on

### Artifact-toolset tool-name substitution layer (data/comments/check)

A substitution layer can rewrite legacy artifact tool actions into consolidated data, comments and check tools, adding a spelling notice to prompts.

A new indirection layer rewrites references to legacy tool actions, such as the artifact tool's `action: "read_db"`/`"write_db"`, into new consolidated tool names covering `data`, `comments`, and `check`. When enabled, it also injects a "Tool spelling in this session" notice into prompts.

- Flag `tengu_cobalt_plinth_damson`: Off in both readings (read for one account on one subscription tier against v2.1.259; 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: Artifacts
- Tier: Nothing to try yet
- Useful: 4/5
- Signal: 4/5
- Present in the build but not switched on

### New `proactivity` cloud-session config field

Cloud sessions now treat a proactivity key as a supported passthrough option alongside systemPrompt and thinking.

A new `proactivity` key was added to the cloud session flag-mapping table, treated as a supported passthrough option alongside `systemPrompt` and `thinking` rather than being unsupported.

- Area: Cloud Sessions
- Names: `proactivity`
- Tier: Nothing to try yet
- Useful: 4/5
- Signal: 4/5
- Present in the build but not switched on

### Prompt context blocks now pass through a resolver/invalidator pipeline before assembly

User context is assembled into named blocks and passed through a resolver that can rewrite it; by default it passes through untouched.

User-context construction (`claudeMd`, `userEmail`, `attachedProject`, `currentDate`) is now assembled into a `name`/`text` array and passed through a `pR.resolvePromptContext` pipeline before being used in the prompt. By default this is a passthrough, but a resolver can be installed via `setPromptContextResolver` to rewrite the context. If the resolver rewrites `claudeMd`, `instructionFiles` is now conditionally cleared accordingly.

- Area: Prompt Context
- Names: `setPromptContextResolver`, `claudeMd`
- Tier: Nothing to try yet
- Useful: 4/5
- Signal: 4/5
- Present in the build but not switched on

### Unattended tool serving requires explicit consent, gated by a feature flag

A consent subsystem records whether a host may serve tool calls unattended, behind a feature flag that falls back to no on error.

A new consent subsystem asks whether a host may serve tool calls unattended, persisting the answer to `unattended-serving-consent.json` and checking it before allowing unattended serving. The check runs through an async gate lookup that falls back to `false` on error, and the whole subsystem is further gated by a feature flag.

- Flag `tengu_violin_fret`: Gate removed from the code (read for one account on one subscription tier against v2.1.259; this account: on, anonymous baseline: on, 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: Remote Tools
- Names: `unattended-serving-consent.json`
- Tier: Nothing to try yet
- Useful: 4/5
- Signal: 4/5
- Present in the build but not switched on

### proactivityLevel plumbed through session/task creation

A proactivityLevel field now flows through session creation, agent launch, config parsing and telemetry, with no UI or semantics yet.

A new `proactivityLevel` field is now threaded through session/task creation, agent-launch options, config parsing, and telemetry, alongside `permissionMode`. This looks like plumbing for a configurable proactivity setting, though its UI and semantics aren't part of this change.

- Area: Sessions
- Names: `proactivityLevel`
- Tier: Nothing to try yet
- Useful: 4/5
- Signal: 4/5
- Present in the build but not switched on

### CLAUDE_CODE_SKILL_ATTRIBUTION test/override env var

A new environment variable lets you inject per-content-hash skill and plugin attribution into command and skill telemetry.

A new `CLAUDE_CODE_SKILL_ATTRIBUTION` env var lets a caller inject per-content-hash skill and plugin attribution (`skill_id`, `plugin_id`) into telemetry, mirroring the existing `CLAUDE_CODE_PLUGIN_ATTRIBUTION` mechanism. It feeds a new `CX()` attribution helper used across command and skill telemetry events. Entries that aren't a JSON object are ignored.

- Area: Telemetry
- Names: `CLAUDE_CODE_SKILL_ATTRIBUTION`, `CLAUDE_CODE_PLUGIN_ATTRIBUTION`
- Tier: Use it now
- Useful: 5/5
- Signal: 3/5

### Headless SDK sessions expose a bindable `$.tool.register` API for MCP servers

Headless SDK sessions expose a session object for MCP servers with addMcpServer, removeMcpServer, toast, status and refreshContext.

Headless SDK sessions now expose a `$.tool.register`-style session object with `addMcpServer`, `removeMcpServer`, `toast`, `status`, and `refreshContext` hooks for MCP servers. In a headless session, calls to `toast` and `status` are logged rather than displayed, since there is no notification bar or status row to show them in.

- Area: SDK
- Names: `addMcpServer`, `removeMcpServer`, `refreshContext`
- Tier: Use it now
- Useful: 5/5
- Signal: 3/5

### Managed settings can now supply MCP servers directly ("managed" as a first-class MCP source)

Organizations can push HTTPS MCP servers straight from managed settings; they can't be removed locally and their URLs are masked.

Managed settings can now supply MCP servers directly via a new `managedMcpServers` key, read from policy settings and merged in alongside enterprise, local, project, and user MCP servers. This key only allows http/sse servers with `https://` URLs (no stdio/command, no `${VAR}` expansion) and is validated with checks for control/invisible characters; if it appears in any settings source other than managed settings, it is rejected and a warning is shown. Servers delivered this way cannot be removed locally, and their URLs/headers are masked in the UI as "(value set by your organization)".

A new "managed" scope joins enterprise/user/project/local throughout the settings and MCP system, with its own settings file, a "Managed settings (provided by your organization)" label, and an "MCP servers" label of "Managed MCPs." A helper (`WJ`) now treats "managed" the same as "enterprise" for the managed-policy gate governing MCP approval and server lookup. When running under Claude Desktop's third-party entrypoint or as a local agent, this new source is skipped entirely, and a warning explains that Claude Desktop supplies and locks the session's MCP servers itself. Managed gateway settings validation also now points admins at `managedMcpServers` instead of the previous "not supported yet" message when it sees `mcpServers` under managed settings.

- Area: MCP
- Names: `managedMcpServers`
- Tier: Use it now
- Useful: 5/5
- Signal: 3/5

### New `--permission-prompts host|none` CLI/SDK option to silently auto-deny prompts

A new --permission-prompts option lets print sessions auto-deny anything that would prompt instead of asking the host.

A new `--permission-prompts <target>` CLI/SDK option controls who answers permission prompts in a `--print` session. `host` is the previous behavior, where the SDK host or `--permission-prompt-tool` answers; `none` means nothing is consulted and anything that would prompt is auto-denied locally, while the permission mode still governs everything else. Setting `none` logs "`--permission-prompts none`: permission prompts are answered with a local deny; the SDK host is not consulted" and disables `hostAnswersElicitations`. At the SDK level, `none` is separately marked unsupported for cloud/remote sessions today, since their prompts reach the host over stdio.

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

### New CLAUDE_CODE_SKILL_ATTRIBUTION environment variable

A new CLAUDE_CODE_SKILL_ATTRIBUTION variable lets entries declare a skill id alongside a plugin id for attribution.

A new `CLAUDE_CODE_SKILL_ATTRIBUTION` environment variable parallels the existing `CLAUDE_CODE_PLUGIN_ATTRIBUTION` mechanism. It lets entries declare a `skill_id`, matched against a `skill_(staging_|local_)?` id pattern, alongside `pluginId` for attribution purposes.

- Area: Environment Variables
- Names: `CLAUDE_CODE_SKILL_ATTRIBUTION`, `CLAUDE_CODE_PLUGIN_ATTRIBUTION`
- Tier: Use it now
- Useful: 5/5
- Signal: 3/5

### New consent setting for unattended cloud-session commands

A new config toggle lets you accept or decline whether cloud sessions may run commands unattended on your machine.

A new config toggle, "Unattended commands from cloud sessions on this computer," lets a user accept or decline whether cloud sessions may run commands unattended on their machine. The setting can be locked by an org, and changes emit a telemetry event.

- Area: Remote Tools
- Tier: Use it now
- Useful: 5/5
- Signal: 3/5

### New per-command sandbox filesystem deny lists

Shell execution accepts per-command sandboxDenyRead and sandboxDenyWrite path lists on top of the global sandbox config.

Shell execution now accepts explicit `sandboxDenyRead` and `sandboxDenyWrite` path lists that get merged into the sandbox's filesystem config for a single command, in addition to the existing global sandbox config.

- Area: Sandbox
- Names: `sandboxDenyRead`, `sandboxDenyWrite`
- Tier: Use it now
- Useful: 5/5
- Signal: 3/5

### New settings key to disable unattended remote-tool serving

A new settings key turns off unattended remote tool serving, at org or user level.

A new `remoteTools.allowUnattendedServing` settings key, settable at org or user level in `~/.claude/settings.json`, turns off unattended tool serving. When set to `false`, the UI explains whether it was disabled by the org or by the user, reporting the scope as `managed` or `user` respectively.

- Area: Remote Tools
- Names: `remoteTools.allowUnattendedServing`
- Tier: Use it now
- Useful: 5/5
- Signal: 3/5

### New settings key: remoteTools.allowUnattendedServing

A new remoteTools.allowUnattendedServing setting controls unattended remote tool serving and falls back to false when invalid.

A new managed/user setting, `remoteTools.allowUnattendedServing`, controls whether unattended remote tool serving is allowed. Invalid values fall back to `allowUnattendedServing: false` (no unattended serving), and the key is registered as non-restrictive in the settings policy list.

- Area: Remote Tools
- Names: `remoteTools.allowUnattendedServing`
- Tier: Use it now
- Useful: 5/5
- Signal: 3/5

### '--cloud <session-id>' reattach picker referenced as upcoming

Resume, continue and login inside a cloud session now point you at claude --cloud with a session id, and note a picker is not built yet.

When `resume`, `continue`, or `login` is attempted inside a cloud session, the feedback now tells users to instead re-run with `claude --cloud <session-id>` to re-attach to another session, and notes that a picker UI for choosing a session is not yet built ("a picker is coming").

- Area: Cloud Sessions
- Names: `claude --cloud`
- Tier: You'll notice
- Useful: 3/5
- Signal: 4/5
- Present in the build but not switched on

### Remote tool calls now survive session restarts with explicit status messaging

Tool calls sent to remote hosts are tracked so a session restart can adopt them and explain whether the command actually ran.

A new tracking class records tool calls dispatched to remote hosts in `in_flight_served_calls`. On restart, it tries to adopt these in-flight calls and generates detailed status messages depending on whether the command definitely ran, was still pending approval, or its fate is unknown, including messaging that the session restarted while a command was under way.

- Area: Remote Tools
- Tier: You'll notice
- Useful: 3/5
- Signal: 4/5

### Remote tool serving gets an emergency off switch

When remote tool serving is muted by the emergency switch, served-call requests are answered empty with an explanatory reason.

MCP and device hooks now check `e.isMuted?.()` before answering a served-call request. When muted, the request is silently answered empty and logged as 'serving is switched off (emergency switch)', with a corresponding UI reason string explaining that remote tool serving was turned off by Anthropic via the emergency switch.

When this emergency switch is off, the client-facing message now says that any command a cloud session was running on the local machine was cancelled and Claude was told it may have partially run, rather than just stating that no new commands will run. A second, hooks-specific pair of messages mirrors this for plugins, confirming that hooks offered to cloud sessions are likewise suspended and resumed by the same remote emergency switch.

- Area: Remote Tools
- Tier: You'll notice
- Useful: 3/5
- Signal: 4/5

### Artifact 'pinned' support added, gated by frozenArtifactPins

Artifacts and listings carry a pinned field with a pins_enabled flag, gated by frozenArtifactPins.

Artifacts and artifact listings now support a `pinned` field, with list results carrying a `pins_enabled` flag. Create and publish responses now include messaging that reflects the current pin state.

- Area: Artifacts
- Names: `pinned`, `pins_enabled`, `frozenArtifactPins`
- Tier: Nothing to try yet
- Useful: 3/5
- Signal: 4/5
- Present in the build but not switched on

### Artifact pinning gated behind new flag, with richer relay error handling

Pin and unpin go through a relay path with clearer failure messages, and a gated helper decides whether pinning is offered at all.

Pin and unpin actions now go through a dedicated relay-aware path with new failure states: relay unavailable, relay error, ok-from-foreign-service, and credential refused. User-facing errors are clearer, telling the user to check with action "list" before retrying, and a gated helper now determines whether pinning is offered at all.

- Flag `tengu_cobalt_plinth_holly`: Off in both readings (read for one account on one subscription tier against v2.1.259; 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: Artifacts
- Names: `list`
- Tier: Nothing to try yet
- Useful: 3/5
- Signal: 4/5
- Present in the build but not switched on

### CCR client can hold event uploads while no one is subscribed

Event uploads can be held while a session has no subscribers, but the hold duration comes from a remote flag defaulting to zero.

The CCRClient's durable and internal event uploaders can now hold event uploads when a session has no subscribers. A new `noSubscriberUploadHoldMs` setting, set via `setNoSubscriberUploadHoldMs`, works with a `holdMaxItems: 50` cap on the internal-event uploader; releasing a hold logs telemetry event `ccr_no_subscriber_hold` with lane, reason, held_events, and held_ms. The hold duration comes from remote flag `tengu_ccr_no_subscriber_hold_ms` and defaults to 0 (also forced to 0 for outbound-only sessions), so the hold is inactive unless the server pushes a positive value.

- Flag `tengu_ccr_no_subscriber_hold_ms`: Not enough to say (read for one account on one subscription tier against v2.1.259; 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: Remote Control
- Names: `noSubscriberUploadHoldMs`, `tengu_ccr_no_subscriber_hold_ms`, `setNoSubscriberUploadHoldMs`
- Tier: Nothing to try yet
- Useful: 3/5
- Signal: 4/5
- Present in the build but not switched on

### Cloud device-hooks bridge gains a "muted" state

The cloud device-hooks bridge gains a muted phase that unregisters from the cloud session and restores registration on unmute.

The cloud device-hooks bridge used by `claude --cloud` now supports a distinct `muted` phase, separate from stopped, idle, and registered. A new `servingMute` method transitions the bridge into `{kind:"stopped", reason:"muted"}`, unregisters and releases the current registration with the cloud session, and logs a `muted` outcome; unmuting restores registration and clears the `muted` note.

The device-hooks client-register flow also recognizes `muted` as an outcome alongside `registered`, `unregistered`, `dormant`, and `no_consent`, routed through the same success-telemetry path, with a `servingMuted` flag threaded through to consumers. Plugin-forwarding feature status reporting now reports muted state as `{ state: "off", source: "stored", reason: "muted" }`, distinct from `declined`, `unreadable`, or `could_not_send`.

- Area: Cloud Sessions
- Names: `claude --cloud`, `servingMute`
- Tier: Nothing to try yet
- Useful: 3/5
- Signal: 4/5
- Present in the build but not switched on

### New proactivityLevel parameter threaded into remote/teleport session creation

Remote session creation events accept a proactivityLevel field alongside permissionMode, ultraplan, title and thinking.

Remote (teleport) session creation events now accept a `proactivityLevel` field, alongside `permissionMode`, `ultraplan`, `title`, and `thinking`, when building session creation events.

- Area: Cloud Sessions
- Names: `proactivityLevel`
- Tier: Nothing to try yet
- Useful: 3/5
- Signal: 4/5
- Present in the build but not switched on

### Skill-proposal tool gating tightened, still cloud/remote-only

The skill-proposal tool now requires a remote environment and a specific entrypoint or env var, and can be vetoed per session.

The `isEnabled` gate for the skill-proposal tool (which proposes skills from recurring procedures for the user to review and save) is now stricter: it bails out for child sessions and nested Claude Code, requires `CLAUDE_CODE_REMOTE_ENVIRONMENT_TYPE` to be set, and only fires under the `remote_cowork` entrypoint or the `CLAUDE_CODE_SKILL_PROPOSALS` env var, with an additional per-session "skills sync vetoed" flag that can veto it.

- Area: Skills
- Names: `CLAUDE_CODE_SKILL_PROPOSALS`, `CLAUDE_CODE_REMOTE_ENVIRONMENT_TYPE`
- Tier: Nothing to try yet
- Useful: 3/5
- Signal: 4/5
- Present in the build but not switched on

### prompt.context dispatch hook point

Computed prompt context blocks are forwarded through a registered prompt.context handler when one exists, alongside a session-bound extension point.

A new dispatch path forwards computed `prompt.context` blocks through a registered handler, via `zc.hasModuleHandlers("prompt.context")` and `eS("prompt.context", ...)`, if one exists, falling back to the untouched blocks otherwise. Related definitions `x0e = kj("session.start")` and `tst = () => rb.whenSessionBound(y0e)` point to a session-bound extension point.

- Area: Plugin Hooks
- Names: `prompt.context`, `session.start`
- Tier: Nothing to try yet
- Useful: 3/5
- Signal: 4/5
- Present in the build but not switched on

### Bridge teardown can hold for pending uploads before closing transport

Remote bridge teardown can hold briefly to flush pending uploads before closing the transport, with the hold time recorded.

Remote-bridge teardown (Remote Control/teleport) can now hold briefly before closing the transport, waiting for pending uploads and internal events to flush via a new `settleUploadsBeforeHandoff` hook and `setNoSubscriberUploadHoldMs` on the transport. The hold duration is configurable, and only applies when set to a positive value. A new `hold_preflush_ms` telemetry field records how long the hold took.

- Flag `tengu_ccr_no_subscriber_hold_ms`: Not enough to say (read for one account on one subscription tier against v2.1.259; 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: Remote Control
- Names: `setNoSubscriberUploadHoldMs`
- Tier: Under the hood
- Useful: 3/5
- Signal: 4/5

### Declared-tools filtering for always-loaded claude.ai MCP tools

Always-loaded claude.ai MCP tools are held out of the declared tool set and loaded lazily until the tool-use decision settles.

A new code path filters out MCP tools flagged `isMcp === true`, `alwaysLoad === true`, and `mcpInfo.scope === 'claudeai'` from the initially declared tool set until the model's tool-use decision settles, wrapping the remainder in a lazy collection. This only fires when the caller hasn't already decided declared tools and at least one matching tool is present.

- Area: Tool Loading
- Tier: Under the hood
- Useful: 3/5
- Signal: 4/5

### MCP connect: caching/rejecting the /v1/mcp_servers discover projection

MCP connections can cache a discovery projection to skip a round trip, discarding and re-probing it if the server rejects it.

For claude.ai-proxy MCP connections, the client can now cache and adopt a "discover projection" from `/v1/mcp_servers`, skipping the `server/discover` round trip on connect. If the upstream later rejects a request built from that cached projection, the client discards it for that connector, re-probes `server/discover` on a fresh transport, and logs a `tengu_mcp_listing_prior_rejected` event.

- Area: MCP
- Names: `tengu_mcp_listing_prior_rejected`
- Tier: Under the hood
- Useful: 3/5
- Signal: 4/5

### hostOwnsModel flag added alongside hostOwnsPermissionMode

An embedding host is now treated as authoritative for the active model as well as for permission mode.

Two SDK/host integration points now pass `hostOwnsModel: !0` alongside `hostOwnsPermissionMode: !0`, meaning the embedding host, not the CLI, is now treated as authoritative for the active model as well as for permission mode.

- Area: SDK
- Names: `hostOwnsModel`, `hostOwnsPermissionMode`
- Tier: Under the hood
- Useful: 3/5
- Signal: 4/5

### New CLAUDE_CODE_SESSION_ORIGIN env var passthrough

A new CLAUDE_CODE_SESSION_ORIGIN environment variable is read and passed through to spawned subsessions.

A new `CLAUDE_CODE_SESSION_ORIGIN` environment variable is now read and added to the allow-listed passthrough env var sets used when spawning subsessions.

- Area: Environment Variables
- Names: `CLAUDE_CODE_SESSION_ORIGIN`
- Tier: Use it now
- Useful: 4/5
- Signal: 3/5

### New env vars added to allowlists/passthrough

Several environment variables were added to passthrough allowlists, including GIT_ALLOW_PROTOCOL and CLAUDE_CODE_SKILL_PROPOSALS.

`GIT_ALLOW_PROTOCOL` was added to the git-environment-variable passthrough allowlist. `CLAUDE_CODE_SESSION_ORIGIN` and `CCR_SESSION_PROFILE` were added to separate internal environment-variable lists, one for eval/runner context and one for a startup-context safelist. `CLAUDE_CODE_SKILL_ATTRIBUTION` was also added, in two separate allowlists, and `CLAUDE_CODE_SKILL_PROPOSALS` was added to another allowlist used for spawning subprocesses/sandboxes.

- Area: Environment Variables
- Names: `CLAUDE_CODE_SESSION_ORIGIN`, `CCR_SESSION_PROFILE`, `CLAUDE_CODE_SKILL_ATTRIBUTION`, `CLAUDE_CODE_SKILL_PROPOSALS`
- Tier: Use it now
- Useful: 4/5
- Signal: 3/5

### Gerrit change detection for PR-lifecycle announcements

Gerrit remotes are now detected via Change-Id lookup, so PR-lifecycle announcements work there as they do for GitHub and GitLab.

Claude Code can now detect a Gerrit code-review remote by matching a `googlesource.com` URL pattern, extract the `Change-Id` from the last commit, and query the Gerrit REST API for the matching open change. When found, this powers the same 'started' PR-lifecycle announcement already used for GitHub and GitLab.

- Area: Git Integration
- Tier: You'll notice
- Useful: 4/5
- Signal: 3/5

### Plugin hooks directories are now hot-reloaded

A plugin's directory is now watched and its hooks module reloads automatically when files change, with a success/failure log line.

Claude Code now watches a plugin's root directory, ignoring `node_modules` and `.git`, and automatically reloads its hooks module when files change. Reloads are debounced, and a UI log line reports the success/failure counts of reloaded hooks.

- Area: Plugin Hooks
- Tier: You'll notice
- Useful: 4/5
- Signal: 3/5

### Unattended-serving consent prompt for headless/desktop cloud sessions

Headless and desktop cloud sessions in auto or bypass mode now ask once whether Claude may act unattended, and the answer is saved.

Headless or desktop cloud sessions created with permission mode `auto` or `bypassPermissions` now trigger a one-time consent dialog asking whether Claude may act unattended (auto-approving tool use). The answer is saved to `unattended-serving-consent.json` and shown later in settings as "Not asked yet," "Allowed," or "Not allowed." Organizations or users can preemptively turn this off with `remoteTools.allowUnattendedServing: false` in `~/.claude/settings.json` or org policy, which surfaces the message "Turned off in your user settings (remoteTools.allowUnattendedServing: false in ~/.claude/settings.json) — remove it there to re-enable." A related, separate consent dialog asks once per computer whether a cloud session running in auto mode may run commands locally without asking each time; until answered, the cloud session keeps asking before each command.

- Flag `tengu_violin_fret`: Gate removed from the code (read for one account on one subscription tier against v2.1.259; this account: on, anonymous baseline: on, 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: Remote Tools
- Names: `remoteTools.allowUnattendedServing`
- Tier: You'll notice
- Useful: 4/5
- Signal: 3/5

### New SDK option `permissionPrompts` alongside permissionPromptToolName

The Agent SDK query builder accepts a permissionPrompts option of host or none, passed through to the CLI.

The Agent SDK / CLI query builder now accepts a `permissionPrompts` option with values `"host"` or `"none"`, passed through to the CLI as `--permission-prompts`. This lets SDK consumers specify that permission prompts should not be shown (`"none"`) versus shown by the host (`"host"`).

- Area: SDK
- Names: `permissionPrompts`, `permissionPromptToolName`
- Tier: Use it now
- Useful: 5/5
- Signal: 2/5

### Cloud plugin admission gated by new session-mute state

Cloud plugin admission checks a muted session state and stays disconnected while muted, reconnecting and flushing on unmute.

The cloud-plugins consent/admission flow now checks a `muted` session state before connecting. When muted, it emits a `flag_off`/`muted` admission event and stays disconnected instead of requesting consent; unmuting reconnects and flushes any pending messages.

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

### Served-tools mute flag added (tengu_violin_mute)

An internal flag controls whether the local tool server runs in a muted state, toggling serving mute on the sender.

A new internal flag, `tengu_violin_mute`, controls whether the local tool server is served in a muted state. Session/sender wiring uses an `isServingMuted` check to call `servingMute(true/false)` on the sender when the flag toggles.

- Area: Remote Tools
- Names: `tengu_violin_mute`
- Tier: Nothing to try yet
- Useful: 2/5
- Signal: 4/5
- Present in the build but not switched on

### Plugin UI hooks can now invalidate on prompt.context, not just prompt.section

Plugins can now invalidate prompt.context specifically through ui.invalidate, alongside ui.render and prompt.section.

The plugin SDK bridge's `ui.invalidate` call now also accepts `"prompt.context"` as an event to invalidate, alongside the existing `"ui.render"`, `"prompt.section"`, and `"tool.describe"`, letting plugins force a refresh of that section specifically.

- Area: Plugin Hooks
- Names: `prompt.context`, `ui.invalidate`
- Tier: Use it now
- Useful: 3/5
- Signal: 3/5

### Settings can now supply a default model, ahead of ANTHROPIC_DEFAULT_MODEL

A model set in settings.json now takes precedence over the ANTHROPIC_DEFAULT_MODEL environment variable at startup.

Startup model resolution now checks for a settings-provided model before falling back to `ANTHROPIC_DEFAULT_MODEL`. The resolution order is now CLI flag, then `ANTHROPIC_MODEL` env var, then the model from settings, then `ANTHROPIC_DEFAULT_MODEL`, giving a `settings.json`-configured default precedence over the legacy env-var default.

- Area: Models
- Names: `ANTHROPIC_DEFAULT_MODEL`, `ANTHROPIC_MODEL`
- Tier: Use it now
- Useful: 3/5
- Signal: 3/5

### Artifact publish gains a `pin` action to pin to the claude.ai sidebar

Publishing an artifact can now also pin it to your claude.ai sidebar, and the reply says whether the pin worked.

Artifact publish now supports a `pin` action that pins the published artifact to the sidebar on claude.ai. On success, the tool reply confirms it was 'Pinned to the user's sidebar on claude.ai (it shows there the next time the sidebar loads)'; on failure it appends a note that the pin didn't go through. The result payload also includes a `pinned` field reflecting whether the pin succeeded.

- Area: Artifacts
- Names: `pin`
- Tier: Use it now
- Useful: 4/5
- Signal: 2/5

### Generated .d.ts for built-in tool inputs

A generated claude-code.d.ts now types built-in tool inputs, so TypeScript can narrow on checks like tool === Bash.

A new `BuiltinToolInputs` generator writes a `claude-code.d.ts` declaration file that merges built-in tool input schemas into `ToolCallInput`, mirroring the existing MCP tool-input declaration file. TypeScript users can now narrow on checks like `e.tool === "Bash"` to get typed arguments for built-in tools, not just MCP tools.

- Area: Plugin SDK
- Names: `claude-code.d.ts`, `ToolCallInput`
- Tier: Use it now
- Useful: 4/5
- Signal: 2/5

### New 'pin' option when publishing artifacts

The artifact publish tool takes a pin parameter that also pins the artifact to your claude.ai sidebar.

The artifacts/files publish tool now accepts a `pin` parameter that also pins the artifact to the user's claude.ai sidebar once published. If the pin operation fails, the publish itself still succeeds.

- Area: Artifacts
- Names: `pin`
- Tier: Use it now
- Useful: 4/5
- Signal: 2/5

### New `--permission-prompts none` CLI flag for headless print sessions

In print mode you can pick who answers permission prompts: the host, or none, which auto-denies without asking.

In print/headless mode, a new `--permission-prompts <target>` flag lets you choose who answers permission prompts: `host` (the default, using the SDK host or `--permission-prompt-tool`) or `none`, which auto-denies anything that would need a prompt without consulting the host, printing a warning to that effect. Other permission-mode behavior is unaffected, and `--permission-prompts none` is explicitly rejected for cloud/non-stdio sessions since those prompts reach the host over stdio.

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

### SDK turn results now list all consumed user message uuids

SDK turn results now list every user message uuid consumed by the turn, up to 64, not just the first.

Assistant message/result frames (the complete, partial-first-frame, and stream-event variants) now include a `user_message_uuids` array listing every user message uuid consumed by or merged into that turn, in order, capped at 64 entries. SDK consumers can use this to bind a reply to any of the sends it answers, not just the first.

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

### 'Signed cache' trust-root list is empty

A signed-cache subsystem with write, remove and shadow-check paths exists, but its list of trusted signing roots is empty.

A signed-cache subsystem now exists, with its own logging prefix, an accepted-iat lock, a shadow check, and write/remove paths, computing a frozen list of trusted signing roots. In this build the literal roots array is empty (`roots: []`), so whatever verification it is meant to gate currently has nothing to verify against.

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

### Cloud review poll timeout now server-configurable

The cloud review poll timeout is no longer hardcoded at 30 minutes and now comes from remote config.

The remote/cloud-review task poller's timeout, previously hardcoded to 30 minutes, is now derived from a remote config value read once and cached, used consistently everywhere the timeout is checked or reported, including the timeout error message and `BUGHUNTER_RESULT_RELAY_MAX_SEC`.

- Flag `tengu_review_bughunter_config`: Not enough to say (read for one account on one subscription tier against v2.1.259; 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: Code Review
- Tier: You'll notice
- Useful: 2/5
- Signal: 3/5

### Bughunter feature's result-relay wait time is remotely configurable

The autonomous review agent's result-relay wait is now set remotely, clamped between 30 and 55 minutes.

A new helper reads `client_wait_minutes` from a remote config object and clamps it to 30-55 minutes (default 45), used to compute `BUGHUNTER_RESULT_RELAY_MAX_SEC` for the autonomous bug-hunting/review agent feature, making its result-relay wait time remotely configurable.

- Flag `tengu_review_bughunter_config`: Not enough to say (read for one account on one subscription tier against v2.1.259; 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: Code Review
- Names: `client_wait_minutes`
- Tier: Under the hood
- Useful: 2/5
- Signal: 3/5

### `claude mcp marketplace list` now shows claude.ai-hosted marketplaces not yet added locally

Marketplace listing now also shows claude.ai-hosted marketplaces you haven't added locally, plus browse-only ones.

`claude mcp marketplace list` now also queries claude.ai and adds a "From claude.ai:" section listing marketplaces available there but not yet added locally (marked "— not added"), plus browse-only marketplaces (marked "browse on claude.ai"). This applies to both text and JSON output.

- Area: MCP
- Names: `claude mcp marketplace list`
- Tier: Use it now
- Useful: 3/5
- Signal: 2/5

### Manage-marketplaces screen can now suggest marketplaces to add

The manage-marketplaces screen now suggests marketplaces synced from claude.ai that you haven't added yet.

The manage-marketplaces screen now fetches a synced list of marketplaces from a claude.ai-linked plugin sync feature and shows ones not yet added alongside the user's installed marketplaces, letting them pick one to add directly. A 'browse-only' subset of these is tracked separately. Previously the screen only showed already-configured marketplaces.

- Area: Plugins
- Tier: Use it now
- Useful: 3/5
- Signal: 2/5

### Plugin type declarations file now also documents the built-in hooks API

Generated plugin declarations now include a claude-code.d.ts covering the plugin API and built-in tools.

Generated plugin TypeScript declarations now also emit a `claude-code.d.ts` file covering the plugin API and built-in tools, in addition to the previous MCP tool types. Guidance text for tsconfig setup has been updated to point at both declaration files.

- Area: Plugin SDK
- Names: `claude-code.d.ts`
- Tier: Use it now
- Useful: 3/5
- Signal: 2/5

### plugin-types command now also emits claude-code.d.ts

The plugin-types command now also writes claude-code.d.ts, useful for typing a hooks module against the session.

The built-in `plugin-types` local command now also writes `claude-code.d.ts`, the plugin API's TypeScript declarations, in addition to the previously-generated `claude-code-mcp.d.ts` file for connected MCP tool inputs. This is useful for typing a hooks module against the current session.

- Area: Plugin SDK
- Names: `plugin-types`, `claude-code.d.ts`, `claude-code-mcp.d.ts`
- Tier: Use it now
- Useful: 3/5
- Signal: 2/5

### remoteTools.allowUnattendedServing setting formalized in schema

The settings schema documents remoteTools.allowUnattendedServing, and project, local and --settings values are ignored for it.

The settings schema now formally documents `remoteTools.allowUnattendedServing`. When set to `false` in managed or user settings, a cloud session running in auto mode cannot run commands on the local computer without per-command approval, and project, local, and `--settings` values are ignored for this key.

- Area: Remote Tools
- Names: `remoteTools.allowUnattendedServing`, `--settings`
- Tier: Use it now
- Useful: 3/5
- Signal: 2/5

### `claude plugin validate` gains `--json` output

claude plugin validate gains a --json flag for machine-readable validation results.

The `claude plugin validate` command gains a `--json` flag, emitting machine-readable validation results (with `success`/`strict` flags) instead of only human-readable text, using the same exit codes as normal output.

- Area: Plugins
- Names: `claude plugin validate`, `--json`
- Tier: Use it now
- Useful: 4/5
- Signal: 1/5

### Add-marketplace flow accepts a claude.ai listing directly

Picking a suggested marketplace opens the add flow with its name and source already filled in.

Selecting one of the newly-suggested marketplaces in the manage-marketplaces list now routes into the add-marketplace flow with that listing's name and source pre-filled.

- Area: Plugins
- Tier: Use it now
- Useful: 2/5
- Signal: 1/5

## New Features

### New claude.ai marketplaces sync path

Marketplace listings are now synced from claude.ai into a local etag-keyed cache, with typed failure reasons.

A new sync routine pulls marketplace listings from claude.ai into a local cache keyed by etag. Failures are surfaced through a new `MarketplacesSyncFailed` error with typed reasons such as `bucket_unresolved`, `root_refused`, and `denied`, along with telemetry including a `marketplaces_sync_starting` event.

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

### Artifact database usage warnings when nearing capacity

Artifact shared databases now warn when they are full or nearing capacity, suggesting you prune or aggregate documents.

A new helper builds usage warning messages for an artifact's shared database, alerting when it is full ("writes that create a document will fail until some are deleted") or over a threshold percentage full, advising to prune or aggregate existing documents rather than creating one document per item.

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

## Improvements

### Cached remote managed MCP servers withheld until session confirms them

Cached org-managed MCP servers are withheld until the server reconfirms them this session, with a warning explaining the wait.

If `managedMcpServers` exist in a cached remote settings payload but haven't been reconfirmed by the current session's live payload, they are withheld from taking effect rather than applied immediately. A status-only warning is shown explaining that the organization's MCP servers are withheld until the server confirms them this session, and they connect automatically as soon as it does.

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

### Workflow runs now watch for a 'runaway' condition and self-kill

A workflow run now watches for a runaway event on its scope and kills itself when it sees one.

`found()` on a workflow run now subscribes to world events and calls `this.kill("runaway")` if a runaway event is seen for its scope, letting a run self-terminate when it detects it has gone runaway. The subscription is cleaned up on abort or completion.

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

### Context-usage telemetry callback added

Used and maximum token counts are now computed and pushed out as context usage whenever they change, feeding live usage indicators.

A new helper computes used and max token counts from the current message history and model, and calls `notifyMetadataChanged({ context_usage })` whenever the totals change. This feeds live context-window usage indicators, such as a status bar, rather than being purely internal bookkeeping.

- Area: Context Window
- Names: `context_usage`
- Tier: You'll notice
- Useful: 3/5
- Signal: 3/5

### MCP tool-wait logic reworked with grace period and per-server state resolution

MCP tool resolution now waits across connected servers with a grace window and reports per-server states like pending, needs-auth and failed.

MCP tool resolution has been reworked to walk connected servers and wait up to `maxWaitMs` before giving up, followed by an `absentGraceMs` grace window if the tool still isn't found. The resolver now exposes `serverState` and `initialServerState` values such as `pending`, `needs-auth`, `failed`, and `disabled` for telemetry and UX, replacing the previous simpler resolution logic.

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

### Background/local-shell task delivery can now append to the same assistant turn instead of always starting a new turn

A finished background task's result can now be appended into the current assistant turn instead of always starting a new one.

When a background or local-shell task finishes, its result can now be appended as a `tool_use` into the current assistant turn if that turn already made a tool call, instead of always being inserted as a new synthetic turn. This distinction is tracked via a new telemetry dimension recording whether delivery was an `append` or a `new_turn`.

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

### Reactive compaction gains a last-resort "summarize everything" mode

When compaction runs out of room it now summarizes the whole conversation, truncating the head and retrying, instead of failing.

When reactive compaction's normal ladder of progressively-preserving-fewer-groups runs out of room, it no longer fails outright with `exhausted`. It now falls back to summarizing the entire conversation, and if that request is still too long, truncates the head of the conversation and retries, up to a bound, before giving up.

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

### Orphaned MCP permission responses now carry richer resumption context

Orphaned permission responses now carry sibling tool-use and resumption details so an interrupted multi-tool turn resumes faithfully.

When a permission `control_response` arrives for a `tool_use` with no live handler, such as after a reconnect, the queued orphaned-permission entry can now carry `initFirst`, `resumesInterruptedTurn`, and sibling tool-use information. This lets the main loop resume an interrupted multi-tool turn more faithfully instead of just replaying the single orphaned permission.

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

### Early hydrate prefetch for SDK/remote-control resume sessions

Starting with --sdk-url and --resume now warms session and history state in parallel with the rest of startup.

When starting with `--sdk-url` and `--resume`, the CLI can now kick off an early hydrate-reads prefetch (`startEarlyHydrateReads`) concurrently with the rest of startup, to warm session/history state ahead of the SDK connection coming up. The result is threaded through as `earlyHydrateReads` in the prepared-session config.

- Area: SDK
- Names: `--resume`
- Tier: You'll notice
- Useful: 3/5
- Signal: 3/5

### Gerrit / glab support added to PR-tracking heuristics

PR tracking now recognizes Gerrit remotes and classifies glab merge-request commands, feeding the existing announcements.

PR-tracking heuristics now recognize Gerrit remotes, detected via a `googlesource.com` host plus a `Change-Id` trailer, and query the Gerrit REST API for an open change. They also classify `glab mr create`, `update`, `merge`, `note`, `close`, and `reopen` commands, feeding the existing `pr_started_announce` telemetry with a new `provider: "gerrit"` branch.

- Area: Git Integration
- Tier: You'll notice
- Useful: 3/5
- Signal: 3/5

### Background-forked sessions now inherit proactivityLevel

Backgrounding a session now carries the parent conversation's proactivity setting into the forked session.

The background-session-fork request builder now passes `proactivityLevel` into the fork call, wiring the parent conversation's proactivity setting through to a newly backgrounded session. This field was previously absent; the argument slot it now occupies held `alwaysDenyRules` in the prior build's order. The background-fork flow itself, triggered from the "Background this session?" confirmation dialog, is an existing feature, so this extends already-reachable functionality rather than adding a new gate.

- Area: Sessions
- Names: `proactivityLevel`
- Tier: You'll notice
- Useful: 3/5
- Signal: 3/5

### Background sessions get a narrower permission snapshot

Background sessions run with session allow-rules cleared and a narrower set of working directories, and always snapshot the system prompt.

A new permission-context snapshot publisher zeroes out session allow-rules and restricts additional working directories to session-sourced ones specifically for background sessions, giving them a narrower permission footprint than foreground sessions. System prompt snapshotting is also now forced on whenever the session kind is `bg` (`CLAUDE_CODE_SESSION_KIND=bg`), in addition to being triggered by the existing explicit `systemPromptSnapshot` flag.

- Area: Permissions
- Names: `CLAUDE_CODE_SESSION_KIND`, `systemPromptSnapshot`
- Tier: You'll notice
- Useful: 2/5
- Signal: 3/5

### Subagent-initiated artifact publishes can be adopted by the parent/session after the subagent finishes

A subagent's pending artifact publish subscriptions are handed to the parent session when it finishes instead of being dropped.

When a subagent that initiated a live artifact publish finishes, its pending publish subscriptions are now adopted into the parent session context instead of being dropped, via a new queue of "pending subagent arms." The queue is capped, and evictions are reported through a new `subagent_arm_evicted` telemetry event.

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

### Artifact tool result now reports publish quota fields

Artifact tool results can report how many publishes remain and when the quota resets.

Artifact tool results can now include `publishesRemaining` and `publishesResetAt` fields, surfacing a rate limit on artifact publishes to the client and UI.

- Area: Artifacts
- Names: `publishesRemaining`, `publishesResetAt`
- Tier: You'll notice
- Useful: 3/5
- Signal: 2/5

### /status shows a distinct Cloud session ID

/status now shows a separate Cloud session ID next to the local one when they differ.

The `/status` panel now shows a separate 'Cloud session ID' label alongside the local Session ID whenever they differ, such as for teleported or remote sessions, instead of showing only a single session id field.

- Area: Cloud Sessions
- Names: `/status`
- Tier: You'll notice
- Useful: 3/5
- Signal: 2/5

### New sandbox refusal message for protected credential directories

Claude now refuses with a clear message when the sandbox can't run a command while still protecting credential files.

A new `refused.sandbox_custody` message covers the case where a local sandbox cannot run a command while also protecting its credential files. Claude Code now refuses to run and explains the situation, instead of silently failing or running the command unprotected.

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

### Auto-deny message when no approval surface exists

A session with no approval surface now auto-denies with a message saying nothing ran and that further prompts will also be denied.

When a session with no approval surface, such as one using `--permission-prompts=none`, hits a tool requiring permission, it is now auto-denied with an explicit message stating the action was not performed, instructing not to retry, and warning that all further approval-requiring actions will be denied for the rest of the session.

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

### GitLab merge-request links supported in PR footer

GitLab merge request links now render as MR badges instead of being forced into GitHub PR formatting.

Publish/footer-link rendering now detects GitLab merge request URLs and renders them as "MR !123" badges instead of always assuming a GitHub "PR #123" format, passing a new `kind: "mr"` to the link component.

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

### Plugin marketplace management now surfaces claude.ai marketplaces

Both the manage-marketplaces screen and the CLI list now show claude.ai marketplaces you haven't added, plus a browse-only section.

The 'Manage marketplaces' TUI screen and the CLI marketplace list output now show marketplaces available from claude.ai that haven't been added locally yet, alongside a browse-only section and the marketplaces already configured.

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

### Daily artifact-publish quota surfaced in UI

The publish confirmation now shows how many artifact publishes you have left today and when the quota resets.

The publish/update confirmation UI now shows how many artifact publishes remain for the day and when the quota resets, rendering a line like "No artifact publishes left today on your plan · resets ...". New helpers validate the remaining count and reset timestamp before showing this.

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

### Subagent artifact live-watch handoff on agent completion

When a subagent finishes, its artifact watch is re-armed for the launching session and reported as publish_adopted.

A subagent watching a published artifact can now surface a `publish_adopted` live-subscription state: when the subagent holds no watch on the artifact but the launching session will take over notifications once the subagent finishes, the handoff re-arms the subscription for the parent session and emits `subagent_publish_adopted` telemetry. This is wired to fire on subagent completion and is consumed by the artifact tool's status text.

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

### Parked-permission fallback can now serve adopted responses instead of always re-asking

A parked permission that can't be resolved now checks for an already-served response before cancelling and re-asking.

When a parked tool-use permission can't be resolved from a persisted `control_response`, the code now first checks for served or adopted responses and uses one if found, instead of always canceling and re-asking. The outcome is logged as `fallback_served_adopted` or `fallback_reask`.

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

### Served/remote-tool commands warn when running without the credential-file sandbox mask

Remote-tool commands on a machine with no strict sandbox filesystem now warn once that credential files rely on permission rules alone.

When a served (remote-tools) command runs on a machine with no sandbox filesystem configuration, or with a relaxed sandbox policy, Claude Code now logs a one-time warning that credential files are protected only by permission rules, and suggests enabling strict sandbox filesystem isolation for the additional mask.

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

### Artifact pinning availability surfaced to users

Listing artifacts on an account with pinning disabled now notes that pin and unpin will not work.

When listing artifacts for an account that has pinning disabled (`pins_enabled === false`), the tool result now appends a note that `pin` and `unpin` commands will not work for that account.

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

### Interactive shell allowlist shrunk, 'hush' added

Many shells including fish, powershell and wsl lost special interactive handling, and hush was added to the list.

The interactive-shell allowlist used for special interactive handling dropped `fish`, `csh`, `tcsh`, `rsh`, `busybox`, `toybox`, `cmd`, `powershell`, `pwsh`, `wsl`, `su`, and `runuser`, and added `hush`, a busybox-style shell. Shells removed from the list no longer get the special interactive-safe treatment.

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

### MCP 'not served' error now lists which tools the server does serve

When a remote host doesn't serve a requested MCP tool, the error now lists which tools it does serve.

When a remote MCP tool call fails because the target host doesn't serve that tool, the error message now lists which tools the host does serve there, making it easier to redirect the call correctly.

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

### `mcp remove` now blocks removing organization-managed servers

claude mcp remove now refuses org-managed servers with an explicit message instead of reporting them as not found.

Running `claude mcp remove` on a server with no configured local scope now checks whether it's actually provided by managed or enterprise settings; if so, it refuses with an explicit message saying the server cannot be removed locally, instead of just reporting it as not found. `claude mcp get` gained a matching message for the same case.

- Area: MCP
- Names: `claude mcp remove`, `claude mcp get`
- Tier: You'll notice
- Useful: 2/5
- Signal: 2/5

### New wake-up notice text distinguishing background task results delivered alongside real user messages

A new notice tells Claude that a real user message arriving alongside a background result is genuine input to answer.

A new wake-up notice clarifies to the model that when a background task's result is delivered in the same turn as a genuine new message from the user, that user message is real input and should be responded to normally.

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

### Skill-invoked model overrides now respect auto-mode/fast-mode compatibility

A model override declared by a skill or command is now ignored when the model isn't supported under the current auto or fast mode.

When a slash-command or skill declares its own model override, Claude Code now checks whether that model is actually supported under the current auto-mode/fast-mode configuration before applying it. If the model isn't supported in auto mode, or if the auto-mode `disableFastMode` setting (from `tengu_auto_mode_config`) rules it out, Claude Code logs a warning and keeps the session's current model instead of switching. Previously the override was applied unconditionally whenever a skill or command specified one.

- Flag `tengu_auto_mode_config`: Not enough to say (read for one account on one subscription tier against v2.1.259; 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: Models
- Names: `disableFastMode`
- Tier: You'll notice
- Useful: 2/5
- Signal: 2/5

### Publish responses now surface remaining publish quota

Publishing an artifact now reports remaining quota and reset time once you are down to 20 or fewer publishes.

Publishing an artifact now surfaces quota information when it's running low: if the server reports 20 or fewer publishes remaining, the tool result includes `publishesRemaining` and `publishesResetAt` fields instead of silently dropping that state.

- Area: Artifacts
- Names: `publishesRemaining`, `publishesResetAt`
- Tier: You'll notice
- Useful: 2/5
- Signal: 2/5

### New 'killed (runaway)' guidance surfaced to workflow rows

Rows retracted by the per-scope cap now say killed (runaway) and point you at the rule that blew the row cap.

Rows retracted by the new per-scope cap now carry explanatory 'killed (runaway)' text pointing to inspecting retracted facts and fixing the rule that caused the run to exceed the per-run row cap.

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

### Auto-mode gate fallback notification on plan exit

Exiting plan mode when auto mode is unavailable now tells you it is falling back to the default mode instead of doing it silently.

If the mode active before entering plan mode was `auto` but the auto-mode gate is currently disabled, exiting plan mode now shows an immediate notification that it's falling back to the default mode, instead of switching back to `auto` silently.

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

### Model catalog now honors dropped_model_ids and dropped_confidential_ids from config

The model catalog now hides ids listed as dropped in remote config, and a flag can mask every id in a served catalog.

The visible model catalog now excludes models listed in `dropped_model_ids` and `dropped_confidential_ids` from remote config, on top of previous exclusion logic. A new `dropped_unidentified_rows` flag can mark an entire served catalog as masking every id.

- Area: Models
- Names: `dropped_model_ids`, `dropped_confidential_ids`
- Tier: You'll notice
- Useful: 1/5
- Signal: 2/5

### Policy limits fail open on 404/unsolicited 304 with no cache

A missing policy-limits response with no cache no longer counts as a failure; the session runs with no restrictions instead.

In the policy-limits fetch/cache loader, a 404 or an unsolicited 304 response with no local cache is no longer treated as a hard fetch failure. The client logs `Policy limits: ${n.httpStatus} with no cache, no restrictions for this session (not persisted)`, applies an empty restriction object for that session, and records telemetry as `route_missing_fail_open` or `unsolicited_304_fail_open`. This fail-open path is gated by `tengu_rustling_orbit`, which defaults to off in the resolved gate table, so failing open is the default shipped behavior; turning the gate on remotely falls back to the old failure-closed path instead.

- Flag `tengu_rustling_orbit`: Not enough to say (read for one account on one subscription tier against v2.1.259; 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: Policy Limits
- Names: `tengu_rustling_orbit`
- Tier: You'll notice
- Useful: 1/5
- Signal: 2/5

### Bash path-restriction checks now track `cd`/`pushd`/`popd` across compound commands

Path deny rules now follow cd, pushd and popd across a compound command, denying reads when a directory target can't be resolved.

Bash path-restriction checks now follow directory changes across a compound command. A new walk tracks `cd`, `chdir`, `pushd`, and `popd` (including popping the pushd stack) through a command's statement list, so later commands in the same line are evaluated against deny rules relative to the resolved working directory. If a `cd` target can't be resolved, subsequent reads are denied rather than silently checked against the wrong directory.

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

### New deny-checked commands: grep/rg/diff/git/cp/mv and generic argument-path extraction

Path deny rules now extract file arguments from more flag shapes and apply to grep, rg, diff, git, cp and mv.

Path-restriction deny rules now reach further into command arguments: file-like arguments are extracted from `-e`/`-f`/`--file` flags, `key=value` pairs, `@file` tokens, colon-separated tokens, and combined short flags, and denied if the resolved path matches a `Read()` deny rule. Separately, `grep`, `egrep`, `fgrep`, `rg`, `diff`, `git`, `cp`, and `mv` get this same path check, falling back to an 'ask' prompt when the path can't be resolved after a `cd`.

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

### /install-github-app now recognizes non-GitHub remotes

/install-github-app now checks the git remote first and explains itself on GitLab or Bitbucket instead of proceeding.

Before launching the GitHub App install flow, `/install-github-app` now checks the repo's git remote provider. If the remote is GitLab or Bitbucket, it shows a specific explanation instead of proceeding; for GitLab, it also points to CI/CD docs.

- Area: Git Integration
- Names: `/install-github-app`
- Tier: You'll notice
- Useful: 2/5
- Signal: 1/5

### git tool's allowed-subcommand shim gains `git grep` and worktree flag parsing

The restricted git wrapper now parses -C and --work-tree flags and fully handles git grep.

The sandboxed git command allowlist now parses `-C`, `--work-tree`, and `--work-tree=` flags before the subcommand and resolves relative paths against that worktree. It also adds a full handler for `git grep`, alongside the existing expanded handling for `git diff`. This applies to everyone using the restricted git wrapper.

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

### Live-subscription status gains a 'publish_adopted' state for handed-off agents

An artifact watch inherited from a finished subagent now reports a publish_adopted state explaining the handoff.

When a background or sub-agent's artifact watch is inherited by the launching session because the agent finished normally, the live-subscription status now reports a dedicated `publish_adopted` state explaining the handoff, instead of leaving it unexplained.

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

### Database write tool results now report usage

Artifact database write results now include a usage field, echoed into the confirmation text shown to the model.

Successful artifact/database write and batch-write tool results now include a `usage` field from the server response alongside version info, and this usage is appended to the human-readable confirmation text shown to the model.

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

### grep tool supports -d/--directories flag and refined recursive detection

The grep argument parser now recognizes -d and --directories and defaults the search path when a recursive flag is present.

The internal grep argument parser now recognizes `-d`/`--directories` alongside the existing recursive flags `-r`, `-R`, and `--recursive`, and defaults the search path to `.` when any of these flags are present.

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

### --timeout default for review command raised to 45 minutes

The review wait timeout help text now states a 45-minute default, up from 30.

The CLI help text for the review-wait timeout option now states a default of 45 minutes, up from 30.

- Area: Code Review
- Names: `--timeout`
- Tier: You'll notice
- Useful: 2/5
- Signal: 1/5

### SDK MCP server timeout changes on already-registered servers are ignored with a warning

Re-sending initialize with a different timeout for a registered SDK MCP server now warns that the change is ignored.

If `initialize` is re-sent specifying a different timeout for an SDK MCP server that's already registered, Claude Code now logs a warning that the timeout change is ignored until the server is removed and re-added, rather than silently applying or dropping the new value.

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

### Command-safety analyzer now parses ANSI-C quoted strings ($'...')

The command-safety analyzer now understands ANSI-C quoted strings instead of treating them as opaque dynamic content.

The bash command-safety analyzer that decides whether a command is safe to auto-run now understands ANSI-C quoted strings like `$'...\n...'` and unescapes them to their literal value, instead of treating them as opaque dynamic content.

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

### Bash safety guard adds sudo-prefix handling

The shell safety checker now treats sudo like env when scanning for prefixed variable assignments, plus a few more git-reach checks.

The shell-command safety checker, which determines whether a bash command could reach git, now treats `sudo` the same as `env` when scanning for prefixed environment-variable assignments. It also adds checks for commands run via a variable or file descriptor and for git-naming text piped into other commands.

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

### Clearer error when uploading a partial git clone for a cloud session

The partial-clone upload error no longer suggests starting the cloud session from the repository's GitHub source.

The error message shown when a repository can't be uploaded to a cloud session because it's a partial or sparse clone no longer suggests starting the cloud session from the repository's GitHub source instead; that workaround sentence was removed.

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

### Turn status simplified: 'streaming' states collapse into 'turn_running'

Spinner status no longer separates requesting, responding, thinking and tool-input; they collapse into one running state.

The status computed for spinner/turn display no longer distinguishes `'requesting'`/`'responding'`/`'thinking'`/`'tool-input'` as separate streaming vs tool-running states; these now collapse into a single `'turn_running'` state. `'subagent_running'` remains a distinct state for delegated work.

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

### Bash safety analysis flags cd/pushd into /dev or /proc

Changing directory into a path under /dev or /proc is now flagged as unsafe and needs approval.

The bash-command risk analyzer that decides whether a command needs approval now flags `cd` and `pushd` invocations that target a path under `/dev` or `/proc` as unsafe, in addition to its existing checks.

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

### Bash safety analysis extended to more shell builtins (shopt, setopt, unsetopt, sort)

The dynamic-option-argument safety heuristic now also covers shopt, setopt, unsetopt and sort.

The option-argument-taint heuristic for detecting dynamic/unsafe option arguments, previously applied only to `set` and `rg`, now also covers `shopt`, `setopt`, `unsetopt`, and `sort`.

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

### Background command status hint rewording

The hint shown while a background command runs was reworded to simply warn against checking on it repeatedly.

The hint text shown when a background command is still running was reworded from warning against "repeated ... calls" with a placeholder metric to simply warning against "checking on it repeatedly." The underlying advice about foreground versus background waiting is unchanged.

- Area: Background Tasks
- Tier: You'll notice
- Useful: 1/5
- Signal: 0/5

## Bug Fixes

### Rewind now distinguishes 'poll' tool_result targets from ordinary ones

Rewinding onto an in-progress poll result is now refused with a specific reason instead of quietly corrupting state.

Rewind now checks whether its target message is a `tool_result` for a still-in-progress poll, and rejects the rewind with a specific reason for that case as well as for a target whose poll events have already landed later in the transcript. Previously these cases could silently corrupt state; now the rewind is refused outright.

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

### Block new subagent spawns while an agent's stop is still completing

Launching a subagent, skill fork or monitor is now refused while the invoking agent's stop is still completing.

Subagent, skill, and monitor launches now check a `stopPendingAgentIds` registry before starting. If the invoking agent's stop is still completing, launching a new subagent, skill fork, or background monitor is refused with an explicit error instead of racing the in-flight stop.

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

### Config lock acquisition now retries with backoff instead of failing on ELOCKED

Saving or deleting config now retries with backoff when the lock is held instead of failing outright.

Saving or deleting global and project config (`saveGlobalConfig`, `saveCurrentProjectConfig`, `deleteProjectConfig`, `deleteCurrentProjectConfigFields`) now retries lock acquisition with exponential backoff when the config lock is already held, instead of failing outright. Fallback writes skipped or suppressed due to lock contention are now tracked with distinct telemetry, including `tengu_config_fallback_skipped_contention`.

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

### New guard: resuming a workflow whose run has ended but not exited is blocked

Resuming a workflow is blocked while its run process is still exiting, so two copies can't run against the same journal.

Resuming a `local_workflow` is now blocked not only when it is still running, but also when it has ended while its run process has not yet exited. This avoids running two copies of the workflow's agents against the same journal, with the refusal message: "Resuming now would run two copies of its agents against the same journal."

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

### Stopped agents can no longer launch workflows or send messages while their stop is still finishing

A stopped agent can no longer launch workflows or send messages while its teardown is still in progress.

Both the workflow-spawning tool and the send-message tool now throw an error if the calling agent has been stopped and its stop is still completing, instead of letting the action proceed mid-teardown: "This agent has been stopped and its stop is still completing; it cannot launch workflows or act on existing runs."

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

### Additional CLI permission modes surfaced when replaying session state

Replayed sessions now round-trip the default, plan, dontAsk and bubble permission modes, not just the three previously handled.

The helper that reconstructs a `--permission-mode` CLI flag for a resumed or replayed session now recognizes `default`, `plan`, `dontAsk`, and `bubble`, in addition to the previously supported `bypassPermissions`, `acceptEdits`, and `auto`. Sessions using these modes now round-trip correctly when replayed.

- Area: Permissions
- Names: `--permission-mode`
- Tier: You'll notice
- Useful: 2/5
- Signal: 2/5

### Killing an already-ended task now re-signals its still-live loop

Killing a task that shows as ended but whose loop is still live now aborts it for real instead of doing nothing.

Stopping a task whose record already shows it ended, but whose execution loop hasn't actually exited, now re-signals the loop: it aborts the loop's abort controllers and kills its process groups, and returns a note explaining that the record stayed listed because the loop was still live. Previously this case was a silent no-op.

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

### Skills tool now enforces a description length cap

The skill-proposal description field now has a hard length cap, with guidance to stay under 200 characters.

The `propose_skills` tool's `description` field now enforces a hard maximum length, rejecting overly long descriptions with an explicit error message. Guidance for the field now asks for descriptions under 200 characters and never exceeding 1024, where previously no limit existed.

- Area: Skills
- Names: `propose_skills`
- Tier: You'll notice
- Useful: 2/5
- Signal: 2/5

### Remote settings 304 mismatch now surfaces as an error

A 304 response to a non-conditional remote settings request now raises an explicit error instead of quietly using the cache.

If the server responds with HTTP 304 Not Modified to a request that was not conditional (no cached ETag was sent), this now surfaces as an explicit error, "Unexpected 304 Not Modified", with `skipRetry` set, instead of silently falling back to cached remote settings.

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

### Policy-limits endpoint 404 gets an explicit error

A 404 from the policy-limits endpoint now explains that your proxy must forward that path, instead of failing silently.

If the org policy-limits check returns a 404, for example when going through a proxy or gateway, Claude Code now shows an explicit error explaining that the proxy must forward `/api/claude_code/policy_limits` rather than failing silently.

- Area: Policy Limits
- Names: `/api/claude_code/policy_limits`
- Tier: You'll notice
- Useful: 2/5
- Signal: 2/5

### PR-link publishing now validates the PR URL before linking

A PR URL is now validated before a session is linked to it, and the call reports explicit outcomes.

Publishing a PR link now validates the PR URL against a strict pattern before linking a session to it, returning `url_rejected` instead of proceeding when the URL doesn't match. The underlying call also now returns explicit outcomes `no_session` and `linked` instead of nothing.

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

### New guards prevent resuming an agent whose stop hasn't finished

Resuming an agent is now blocked while either the caller's or the target's stop is still finishing.

`resumeAgentBackground` now guards against resuming an agent whose stop is still in progress. If the agent attempting the resume has itself been stopped and that stop hasn't finished, the resume throws immediately. Separately, if the target agent's previous run was stopped but hasn't fully exited yet, the resume is blocked with a message telling the user to re-run the stop tool or wait for it to exit. This closes a race where an agent could be resumed, or could resume others, mid-teardown.

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

### Shell exec refuses commands for agents with a pending kill-loop settlement

Shell commands are refused while the owning agent has a kill still settling, rather than being run anyway.

Before spawning a shell command, Claude Code now checks whether the owning agent has a kill pending loop settlement in progress, and refuses to run the command if so instead of executing it.

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

### Partial compaction now preserves thinking-stripped markers across the summary boundary

Partial compaction now marks stripped thinking content across the summary boundary so the state carries over correctly.

When partial compaction starts from a point in the transcript where earlier assistant thinking content had already been stripped, the compaction logic now inserts a synthetic `thinking_stripped` attachment marker so the summary boundary correctly reflects that stripped state. The set of thinking-stripped responses is also passed into the summarization call.

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

### Command-name normalization now checks a known-binary allowlist before stripping version suffixes

Command-name normalization only strips a trailing version number when the result is a known binary, so names like python3 stay intact.

The helper that normalizes command/process names for detection, used in bash-safety and permission logic, used to unconditionally strip trailing version digits (e.g. `python3` → `python`). It now only strips the suffix if the resulting stripped name is in a known-binary allowlist, otherwise it keeps the original name intact.

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

### Policy-limits fetch now distinguishes conditional vs unconditional 304 responses

An unexpected 304 to an unconditional policy-limits request is now a hard failure, and the 404 fast path was removed.

An unconditional (non-etag) request to the policy-limits endpoint that unexpectedly receives a 304 Not Modified response is now treated as a hard failure instead of being accepted as valid cached data. The 404 'no restrictions found' fast path has also been removed from this handler.

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

### Managed plugin ordering conflict warning

A managed plugin listed in both prepend and append lists now warns about the conflict and is prepended.

When a managed plugin is listed in both `prependPlugins` and `appendPlugins`, Claude Code now warns about the conflict and prepends the plugin instead of silently picking one placement.

- Area: Plugins
- Names: `prependPlugins`, `appendPlugins`
- Tier: You'll notice
- Useful: 2/5
- Signal: 1/5

### Windows registry proxy reads now guard against oversized values

Windows proxy registry reads now check value size and explain when a value is too large instead of failing quietly.

Reading Windows proxy settings from `HKLM`/`HKCU` via `reg query` now checks the value size before reading. Oversized values surface an `hklmUnreadReason` explaining that the value exceeded a size cap, given in MiB, instead of failing silently or hanging.

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

### Skill model-var substitution now limited to .md files

Model-variable substitution in skill files now applies only to .md files; other files pass through untouched.

The skill-files templating helper now only performs model-variable substitution on files ending in `.md`; other skill files pass through unmodified.

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

### Rewind reports 'unseen later turn' vs 'stale target'

A refused rewind now distinguishes an unseen later turn from a stale target when explaining why.

When a rewind targets a message but a later, unobserved turn exists past it, the CLI now picks between two more specific rejection reasons: an "unseen later turn" case and a separate "stale target" case, depending on whether the target message itself is still known.

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

### send_message gets the same stop-pending guard

Sending a message to an agent that has been stopped but hasn't settled is now refused with a dedicated error.

Sending a message to another agent via `send_message` now checks whether that agent has been stopped but hasn't finished settling. If so, the send is refused with a dedicated error instead of proceeding against an agent mid-stop.

- Area: Subagents
- Names: `send_message`
- Tier: You'll notice
- Useful: 1/5
- Signal: 1/5

### Cloud review timeout messages now show actual wait duration

Cloud review timeout messages now report the actual wait duration instead of always saying 30 minutes.

Cloud and ultrareview session timeout messages ("cloud session exceeded ...") now report the actual configured wait duration via a minutes parameter, instead of always saying "30 minutes". If no duration is available, the message falls back to "its wait".

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

### Session-end hook flow now also runs an additional flush/callback pass and handles a bad timeout getter

Session-end hooks now fall back to a default timeout if the lookup fails, and get an extra flush pass first.

Session shutdown now wraps the session-end hook timeout lookup in a try/catch, falling back to `SESSION_END_HOOK_TIMEOUT_MS_DEFAULT` if the lookup fails, and adds an extra await step before the session-end hooks run.

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

### MCP retry loops for tools/list and generic retry helper stop early on abort

Cancelled MCP retries now stop during the backoff window instead of continuing through it.

The generic backoff-retry helper and the `tools/list` retry loop now check for cancellation both before throwing and again after the backoff delay, so a cancelled operation stops retrying instead of continuing through its backoff window.

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

### Task eviction now double-checks local-workflow tasks aren't still local agents

Idle eviction no longer drops a workflow task whose agent is still live locally.

Idle-task eviction for `local_workflow` tasks now also requires that the task is not still a live local agent, in addition to having passed its `evictAfter` timestamp. This prevents evicting a task whose agent is still considered local/active.

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

### Companion message for still-stopping target agent

Resuming an agent that is still stopping now tells you to re-run the stop or wait for it to exit.

When the agent targeted for resume is still stopping and hasn't reached a terminal status, the resume attempt is refused with guidance to re-run the stop command or wait for it to exit, rather than racing the in-flight stop.

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

## In Development

### Artifact listing supports a 'pins' option, gated by server-reported starsEnabled

Artifact listing takes a pins option, active only when the server reports starsEnabled, and reports pinsEnabled back.

Artifact listing now accepts a `pins` option. When set and the server response reports `starsEnabled === true`, starred rows are marked `pinned: true` in the listing, and the result also reports `pinsEnabled`.

- Area: Artifacts
- Names: `pins`, `starsEnabled`, `pinsEnabled`
- Tier: Nothing to try yet
- Useful: 3/5
- Signal: 3/5
- Present in the build but not switched on

### Artifact listing gains a "pins" mode

Artifact listing accepts a pins option that marks starred rows as pinned when the server reports stars enabled.

Artifact listing now accepts a `pins` option. When set and the server reports `starsEnabled`, starred rows are marked `pinned: true` and the response includes a `pinsEnabled` field.

- Area: Artifacts
- Names: `pins`, `pinsEnabled`
- Tier: Nothing to try yet
- Useful: 3/5
- Signal: 3/5
- Present in the build but not switched on

### Artifact schema now advertises a 'pin' capability flag

The artifact schema computes whether pinning is enabled and appends a pin clause to the tool description when it is.

The artifact tool's input schema construction now computes whether pinning is enabled, stores the result on `ue().frozenArtifactPins`, and logs it. When active, a pin-related description clause is appended to the schema.

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

### New mcp discovery projection prior gate

A new gate resolves MCP discovery projection to legacy-only, all or off, and defaults to off.

A new gated function resolves `tengu_mcp_discover_projection_prior` to one of `"legacy_only"`, `"all"`, or `"off"`, defaulting to `"off"` for any other value.

- Flag `tengu_mcp_discover_projection_prior`: Not enough to say (read for one account on one subscription tier against v2.1.259; 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: MCP
- Names: `tengu_mcp_discover_projection_prior`
- Tier: Nothing to try yet
- Useful: 2/5
- Signal: 3/5
- Present in the build but not switched on

### New tengu_hidden_frog gate

A new internal boolean gate was added and defaults to false, with no stated purpose.

A new gated boolean check, `tengu_hidden_frog`, was added, defaulting to false.

- Flag `tengu_hidden_frog`: Not enough to say (read for one account on one subscription tier against v2.1.259; 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: `tengu_hidden_frog`
- Tier: Nothing to try yet
- Useful: 1/5
- Signal: 2/5
- Present in the build but not switched on

## Internal Changes

### Dynamic tool loading can seed deferred-tool references from a previous process

A new process can reconstruct which deferred tools an earlier process already surfaced, so they don't need re-announcing.

When starting a new process, the harness can now reconstruct which deferred/lazy-loaded tools a previous process had already surfaced, using `deferred_tools_delta` attachments, and seeds references to them in the new process so those tools don't need to be re-announced. This is logged as `Dynamic tool loading: seeded N tool reference(s)`.

- Area: Tool Loading
- Tier: Under the hood
- Useful: 3/5
- Signal: 3/5

### Workflow facts gain a status lifecycle and reserved-key protection

Workflow facts now carry a five-state lifecycle and reject keys that collide with reserved internal ones.

Workflow world facts now carry one of five statuses as part of their lifecycle. A new schema also rejects any fact whose keys collide with reserved keys, preventing accidental overwrites of internal state.

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

### Plugin marketplace served-catalog sync from claude.ai

An organization's marketplace list is fetched from claude.ai, validated, deduped and cached to disk for plugin discovery.

New code fetches an organization's marketplace list from claude.ai via `/api/oauth/organizations/:orgUUID/marketplaces`, validates and dedupes the entries, and caches them to disk with an etag and `parserVersion`. This exposes both available marketplaces and browse-only, claude.ai-hosted marketplaces for plugin discovery and sync.

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

### Glob/Grep tools gain an auto-classifier fast path for permission checks

Glob and Grep now feed a structured pattern and path into permission auto-classification and report that they suppress rule updates.

The Glob and Grep tools' auto-classifier input can now return a structured object with `pattern`, `path`, and a computed field instead of a bare pattern string, feeding permission-rule auto-classification. Both tools also now report `suppressesAllPermissionUpdates`, affecting how their calls interact with permission rule updates.

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

### New deferred_tools_record attachment tracks full tool schemas across turns

A new attachment records full deferred tool schemas and name-only announcements, diffed so only changes are re-emitted.

A new `deferred_tools_record` attachment type now also records full tool input schemas (`toolEntries`) and name-only announcements (`nameOnlyAnnouncements`) alongside the existing per-turn deferred tool descriptions. These are diffed turn-over-turn so only new or changed entries are re-emitted.

- Area: Tool Loading
- Tier: Under the hood
- Useful: 3/5
- Signal: 3/5

### Permission-prompt-tool routing gets a bypass for an explicit "none" sentinel

A permission-prompt tool named none now routes through an ask-based fallback resolver instead of the MCP prompt tool.

`canUseTool` construction now checks whether the permission-prompt-tool server name is the literal sentinel `"none"`. When it is, or when no MCP prompt tool was configured, requests can go through an ask-based fallback path that resolves `ask` behaviors via a new resolver before falling through to normal permission-denied handling.

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

### Per-scope row cap added to the agent-orchestration "world" engine

The workflow fact engine now caps rows per scope, emitting a runaway event and retracting the scope when it is exceeded.

The internal fact/rule engine backing `agent()` / `parallel()` / `pipeline()` workflows now tracks how many rows accumulate under each scope. If a scope exceeds a per-scope cap, it emits a 'runaway' event and automatically retracts that scope, rather than relying solely on the existing global `maxRows` cap.

- Area: Workflows
- Names: `maxRows`
- Tier: Under the hood
- Useful: 3/5
- Signal: 3/5

### New event-uploader 'no subscriber' upload holding mechanism

Event uploads can be held for a configurable period while nobody is watching the session, then flushed with a log.

The CCR (client-side reporting) client can now hold back durable/internal event uploads for a configurable duration, via `noSubscriberUploadHoldMs`, when no subscriber is watching the session, instead of uploading immediately. Held events are flushed later, with a log of how long and how many events were held.

- Area: Remote Control
- Names: `noSubscriberUploadHoldMs`
- Tier: Under the hood
- Useful: 3/5
- Signal: 3/5

### Dynamic tool loading: deferred MCP tools re-seeded from prior worker's transcript

Deferred MCP tools announced by a previous worker are re-seeded from the transcript during query preparation.

New machinery re-seeds tool references for MCP tools that a prior worker process had already announced with `defer_loading: true`, by scanning transcript attachments of type `deferred_tools_delta`. It logs `Dynamic tool loading: seeded ${n} tool reference(s) to ${k} deferred tool(s) the previous process sent` and is wired into the query-preparation path, guarded by `Oe.readsTranscriptRecord`.

- Area: Tool Loading
- Names: `defer_loading`
- Tier: Under the hood
- Useful: 3/5
- Signal: 3/5

### Artifact auto-react edit can be rejudged/withdrawn by auto mode

Auto mode can now veto an artifact edit late in the pipeline even after it was judged eligible.

The artifact-editability check used by the comment auto-reply/auto-edit pipeline now accepts an extra flag that, when set, marks an edit as not editable even after it was already judged eligible. This rejudgment logs a new `edit_rejudged_by_auto_mode` telemetry breadcrumb, letting auto mode veto an edit late in the pipeline.

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

### New cache slot for GitHub web connection status

A new cache for GitHub web connection status is now cleared alongside the existing session caches.

Session state cache invalidation now also clears a new `githubWebConnectionStatusCache` alongside existing caches like `autoCompactWindowsCache`, indicating a new cached lookup for GitHub web connection status.

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

### Org-level artifact pin preference synced after a successful direct pin

After a successful direct pin, the client marks your organization as having used pinning in account settings.

After a successful direct (non-relay) pin, the client now fetches `/api/oauth/account/settings` and PATCHes `artifact_pins_by_org` to mark the organization as having used pinning, with the stored org list capped in size.

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

### Device hook serving can now be muted

The device-hooks serving session accepts a muted parameter that is forwarded into the hook servicer config.

The device-hooks-serve session constructor now accepts a new `isMuted` parameter, which is forwarded into the hook servicer config when provided.

- Area: Remote Tools
- Names: `isMuted`
- Tier: Under the hood
- Useful: 2/5
- Signal: 3/5

### managedMcpServers added to managed-settings merge semantics

Managed-settings merge semantics now cover org-supplied MCP servers, with the higher-priority source winning name collisions.

The `managedSettingsSourcePolicy` 'merge' mode now explicitly covers `managedMcpServers`: server names union across sources, but if two sources define the same server name, the higher-priority source's whole entry wins.

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

### PR/change announcements can carry a branch name for Gerrit

Change announcements can carry a branch name for providers like Gerrit whose changes have no head branch.

The session-activity announcement schema gains an optional `branch` field, populated only for providers whose changes lack their own head branch, currently Gerrit, so a host can place the change on the right checkout.

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

### MCP client-capabilities header gains a discover-protocol-version companion header

claude.ai MCP calls now send a discover-protocol-version header whenever the discovery mode isn't off.

Outgoing headers for claude.ai MCP calls now also include an `anthropic-mcp-discover-protocol-version` header, added when the mode value is not `"off"`. The existing client-capabilities header is now skipped only when both a renamed check and `mode === "off"` fail, whereas previously it was skipped whenever a single check failed.

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

### Prompt snapshot tool replay comparison telemetry

Prompt-snapshot replay now compares recorded tool schemas and reports mismatches as telemetry.

A new function compares recorded `input_schema` for tools during prompt-snapshot replay and emits `strict_mismatch`, `schema_differs`, or success telemetry under the `prompt_snapshot_tool_replay` event.

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

### remoteExecution.supported enabled on Grep and Search tools

Grep and Search now declare remote execution support, so those calls can be routed to a remote host.

The `Grep` tool and a `Search` tool now declare `remoteExecution: { supported: !0 }`, joining other tools that already had this. This feeds into the dispatcher logic that, combined with a separate remote-capability check, decides whether a tool call is routed to a remote host instead of run locally.

- Area: Remote Tools
- Names: `remoteExecution`
- Tier: Under the hood
- Useful: 2/5
- Signal: 3/5

### Turn-attribution metadata added to background/notification message sends

Background and notification sends now carry turn attribution so the system knows which turn they belong to.

Background and notification message sends, including task notifications, hook stop messages, and WebSocket housekeeping messages, now carry a `turnAttribution` value of `"inherit"` or `"none"`. A new helper resolves `turnAttributionKey` for task-notification mode, as internal bookkeeping to track which conversational turn a background message belongs to.

- Area: Terminal UI
- Names: `turnAttribution`
- Tier: Under the hood
- Useful: 2/5
- Signal: 3/5

### Two new CCR (remote-control) heartbeat/upload tuning gates

Remote-control worker connections gained tuning gates for an upload hold delay and for skipping redundant heartbeats.

The remote-control (CCR) worker connection gained two new tuning gates: a hold delay, `tengu_ccr_no_subscriber_hold_ms`, before dropping uploads when there's no subscriber, and a switch to skip sending redundant heartbeats.

- Flag `tengu_ccr_no_subscriber_hold_ms`: Not enough to say (read for one account on one subscription tier against v2.1.259; 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.
- Flag `tengu_ccr_skip_redundant_heartbeat`: Not enough to say (read for one account on one subscription tier against v2.1.259; 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: Remote Control
- Names: `tengu_ccr_no_subscriber_hold_ms`
- Tier: Under the hood
- Useful: 2/5
- Signal: 3/5

### MCP cold-start now waits for a second, unverified-cache confirmation stage

MCP cold start now waits for remote managed-settings confirmation when org MCP servers are withheld from the cache.

MCP cold start now has an added wait stage for a case where `managedMcpServers` is withheld from the unverified cache: it logs a wait on remote managed-settings confirmation and awaits the settled-fetch promise before falling back to the older managed-settings-load check. A parallel code path gained the same fallback.

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

### New destructive-MCP auto-mode gate added alongside the existing one

Destructive MCP calls under remote auto mode can now be allowed by either the existing gate or a new flag.

Whether destructive MCP tool calls are allowed under remote auto mode is now decided by either of two checks: the existing gate, or a new one controlled by the `tengu_modular_mochi` flag.

- Flag `tengu_modular_mochi`: Off by default, switched on for this account (read for one account on one subscription tier against v2.1.259; 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_remote_auto_mode_include_destructive_mcp`: Off in both readings (read for one account on one subscription tier against v2.1.259; 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: Permissions
- Names: `tengu_modular_mochi`
- Tier: Under the hood
- Useful: 2/5
- Signal: 3/5

### Reverify flow now distinguishes 'manifest authenticated' from 'signature verified'

Binary reverification now reports manifest authentication and signature verification as separate results.

The retained-binary reverification flow now tracks `manifestAuthenticated` and `signatureVerified` as separate fields returned from the verify call, rather than conflating both under a single `signatureVerified` field as before.

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

### Remote MCP tool calls gain send/addressed callbacks

Remote MCP tool dispatch gained callbacks for when a call is first sent and when a recipient acknowledges it.

The remote MCP tool-call dispatcher now accepts optional `onFirstSend` and `onAddressed` callbacks, fired when a tool call is sent over the transport and when a recipient acknowledges it.

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

### Headless/SDK session loop tracks command lifecycle and attachment notifications

The headless session loop now handles command lifecycle events and records attachments in its telemetry.

The headless/SDK session loop now handles a `command_lifecycle` event, calling `noteCommandStarted` when a command starts, and records attachment events via `noteAttachment`. Result and error telemetry payloads are enriched accordingly.

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

### Skills sync detects skill attribution moves between plugins

Skills sync detects when a skill's attribution moves between plugins and re-syncs its metadata even with no file changes.

Skills sync now compares old and new skill rows by `backingPluginId` to detect when a skill's attribution moved between plugins, persisting and re-syncing metadata when that happens even if no files changed.

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

### glab (GitLab CLI) actions now recognized for PR-lifecycle telemetry

PR-lifecycle telemetry now recognizes glab merge-request commands alongside gh and git.

PR-lifecycle telemetry now recognizes `glab` (the GitLab CLI) alongside `gh` and `git`. `glab mr create`, `update`, `merge`, `note`, `close`, and `reopen` map to `pr_create`, `pr_edit`, `pr_merge`, `pr_comment`, `pr_close`, and `pr_reopen` respectively.

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

### History retention prune rewritten to a two-pass, integrity-verified streaming scan

History pruning now scans lock-free and verifies the file hasn't changed, deferring the prune instead of erroring if it has.

Pruning of `history.jsonl` under retention rules now runs a lock-free scan first, verifying the file's identity (inode/birthtime) hasn't changed, and only takes the retention lock and rewrites the file if there's actually something to prune. If the file changes underneath the scan, pruning is deferred rather than erroring, logged as `History retention prune deferred: history.jsonl changed under the scan`.

- Flag `tengu_hipaa_history_retention_prune`: Not enough to say (read for one account on one subscription tier against v2.1.259; this account: no value returned, anonymous baseline: no value returned, compiled default: on) 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: Sessions
- Tier: Under the hood
- Useful: 2/5
- Signal: 2/5

### Artifact publish rate-limit headers now parsed and surfaced

Artifact publish responses now parse a rate-limit header and attach remaining-publish and reset values to the result.

Artifact publish responses now read the `x-frame-push-remaining` header along with the response's `date`, and when present attach `pushRemaining` and `pushResetAt` to the publish result, plus record a `push_remaining_seen` telemetry field on `artifact_publish` events.

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

### Plugin attribution parsing now shares a size-capped, case-normalizing JSON parser

Plugin attribution parsing now goes through a size-capped JSON helper that logs exactly why a value was ignored.

Parsing of `CLAUDE_CODE_PLUGIN_ATTRIBUTION` now goes through a shared helper that enforces a byte-size cap and validates that the value is a JSON object. Invalid input is now logged with specific messages ("Ignoring ... larger than the size cap", "not valid JSON", "not a JSON object") instead of failing silently.

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

### Workflow journal writer now detaches permanently on a failed append instead of silently continuing

A failed workflow journal write now detaches the writer permanently instead of retrying every append.

If a write to a workflow's journal fails, the journal writer now marks itself permanently detached for that run instead of logging a warning and retrying on each subsequent append. Later rows are kept in memory only rather than being repeatedly re-attempted against a failing journal.

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

### Skills sync resync now backs off and detects long sleeps

The skills resync loop now backs off exponentially and skips an immediate resync after the process was asleep.

The background skills-sync resync loop now uses exponential backoff capped at 2400000ms. It also detects when the process was asleep for longer than half the max backoff, in which case it skips an immediate resync and logs `skills_sync_resync_skipped_after_sleep` instead.

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

### Git operation telemetry extended to GitLab merge requests

Creating a GitLab merge request now counts toward the same PR-created telemetry as a pull request.

The git-command telemetry and PR-tracking logic, which already detects `gh pr create` and pushes, now also matches merge-request creation patterns via a second matcher alongside the existing pull-request one. Creating a GitLab merge request increments the same PR-created counter used for pull requests, and pushed-branch PR links are now tracked even without an existing `gh pr view` match.

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

### Heartbeat cadence beats can now be skipped when other traffic already confirmed liveness

A scheduled heartbeat is skipped when a recent events upload already proved the connection is alive.

The CCR background job client can now skip a scheduled heartbeat tick if a non-ephemeral events POST already succeeded recently, logging `Heartbeat skipped (events beat)`. This reduces redundant heartbeat traffic.

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

### MCP allowedMcpServers check bypassed for non-plugin, non-env-expanded project scope

Project-scoped MCP servers that aren't from a plugin or env expansion now skip the allowlist check entirely.

The `allowedMcpServers` restriction check now short-circuits to 'allowed' for servers whose scope is a project scope and which were not expanded from an environment variable or sourced from a plugin, skipping the full allowlist matching logic in that case.

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

### Gerrit added as a recognized code-review provider

Gerrit joins GitHub, GitLab and Bitbucket as a recognized provider in published-change events.

The `code_change_published` system event's `provider` field now recognizes `gerrit` for changes made on googlesource.com Gerrit hosts, joining the existing github, github-enterprise, gitlab, and bitbucket classifications.

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

### Session identity now cached per host and derived from a new token source

Remote session identity is now cached per host and read through a helper instead of the access-token variable directly.

The remote-session identity resolver, which derives `organizationUuid`, `accountUuid`, and `emailAddress`, now caches its result per host and reads its token through a new internal helper instead of reading `CLAUDE_CODE_SESSION_ACCESS_TOKEN` directly. This avoids repeated JWT parsing when the token hasn't changed.

- Area: Cloud Sessions
- Names: `CLAUDE_CODE_SESSION_ACCESS_TOKEN`
- Tier: Under the hood
- Useful: 2/5
- Signal: 2/5

### Config load now distinguishes parse errors from read errors

Config loading now distinguishes read errors from parse errors, and both trigger the fallback-to-cache path.

Internal config-loading state now tracks a `lastGetConfigOutcome` enum with values `"parsed"`, `"parse-error"`, `"read-error"`, and `"enoent"`, replacing the previous boolean `lastGetConfigWasParseError`. Callers now branch on both parse-error and read-error cases to trigger fallback-to-cache behavior, where previously only parse errors did, and the outcome is surfaced as a `readRejected` flag alongside the returned config.

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

### Notification enqueue calls gained turnAttribution

Task notifications can now say which conversational turn they belong to via a turn-attribution option.

The task-notification enqueue path now accepts a second options argument with `turnAttribution`, controlling how a notification is attributed to a conversational turn. The ultrareview-failed notification now passes `{ turnAttribution: "inherit" }`.

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

### New validator function warns on managedMcpServers entries

A validator now warns about org-supplied MCP server entries that are ignored.

A new validator function processes `managedMcpServers` from settings and emits warnings for entries that are ignored, feeding into the managed-settings validation output.

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

### client_wait_minutes now clamped to a numeric range

The remote wait-minutes value is now clamped between 30 and 55, defaulting to 45 when unset or invalid.

The remote-config value `client_wait_minutes` is now validated as a finite number between 30 and 55; if it is unset, non-numeric, or out of range, it falls back to 45.

- Area: Code Review
- Names: `client_wait_minutes`
- Tier: Under the hood
- Useful: 2/5
- Signal: 2/5

### New integrity-checked incremental reader for history.jsonl

History reads now stream in chunks with a running digest and verify the file wasn't rewritten mid-scan.

`history.jsonl` reads now go through a new low-level incremental reader that streams the file in chunks, computes a running sha256 digest, and verifies the file wasn't rewritten out from under an earlier scan by comparing inode, birthtime, and a previously-recorded digest before returning parsed lines.

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

### Conversation transcript builder gains thinking-stripped-response tracking

Transcript assembly now tracks which assistant responses had thinking stripped and removes those blocks before returning.

The message-history assembly function now derives a `thinkingStrippedResponses` set and strips thinking blocks from assistant messages whose IDs are in that set before returning the transcript.

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

### Async agent task loops now track per-agent controllers for settlement

Async agent tasks now register per-agent controllers so stop and cleanup only settle once no subagents remain attached.

Background/async agent task execution now registers a kill controller and a per-agent controller map per task through a new loop-settlement mechanism, calling settle callbacks only once agent associations are empty when required. This makes task stop/cleanup sequencing more reliable when subagents are still associated with a task.

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

### Multi-queued-prompt UUID tracking added to turn telemetry/errors

Turn telemetry now tracks up to 64 user message uuids, including prompts queued but not yet started.

Turn telemetry and error reporting now track up to 64 recently-seen user message UUIDs, including ones for prompts that were queued but not yet started during a turn. These are attached as `user_message_uuid`/`user_message_uuids` to result and error telemetry, and a matching `user_message_uuids` array field has been added to the result schema, fully wired into the query loop's telemetry emission.

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

### Retention sweep now also cleans up 'tiny_memory' directories per project

The retention sweep now also cleans tiny_memory directories under each project.

The periodic retention sweep now also walks `tiny_memory` directories under each project in `~/.claude/projects/*`, cleaning them up alongside transcripts and messages.

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

### New telemetry for orphaned permission handling

Three telemetry events now track permissions parked across turn boundaries and whether they were applied.

Three new telemetry events track permissions that were parked and applied across turn boundaries: one for when a parked permission is applied, and two for when it goes unapplied, at turn end or on turn resume, including `tengu_orphaned_permission_applied`.

- Area: Permissions
- Names: `tengu_orphaned_permission_applied`
- Tier: Under the hood
- Useful: 1/5
- Signal: 2/5

### New telemetry events for MCP listing races and model-catalog comparisons

Two telemetry events were allowlisted, one for rejected MCP tool listings and one comparing served model catalogs.

Two telemetry events are now allowlisted: `tengu_mcp_listing_prior_rejected`, fired when an MCP tool listing response is rejected because a newer one already arrived, and a second event for comparing served model catalogs.

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

### Reactive compaction telemetry distinguishes full-summary splits

Compaction telemetry now records the split kind and head truncations, and flags when the whole conversation was summarized.

`tengu_reactive_compact_succeeded` now reports `splitKind` and `headTruncations`, and fires a distinct `compact_reactive_summarized_all` gate event when the compaction summarized the entire conversation instead of doing an incremental split.

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

### New telemetry when killing an agent whose task has no local loop entry

Killing a local agent with no matching task-loop entry now fires a telemetry event flagging the mismatch.

Killing a running local agent that has no matching entry in the local task loop now fires a new `task_kill_missing_loop_entry` telemetry event with source `local_agent`, flagging the bookkeeping mismatch.

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

### Telemetry for deny-list requested without sandbox

A telemetry event now fires when per-command deny paths are requested but the command isn't actually sandboxed.

If per-command deny paths are requested but the command isn't actually running sandboxed, a new `per_command_deny_unsandboxed` telemetry event fires noting the deny list was ignored.

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

### Task summary field description clarifies source

Task summary docs now spell out that local agents give a model-written progress summary and MCP tasks give the server's status.

The `summary` field on task status objects is now documented to clarify its source: for a `local_agent` task it is a model-generated progress summary, shown only when `agentProgressSummaries` is enabled, while for a backgrounded `mcp_task` it is the MCP server's own status message and is always emitted.

- Area: Background Tasks
- Names: `agentProgressSummaries`
- Tier: Under the hood
- Useful: 1/5
- Signal: 1/5

### Skill model field description updated

A skill result's model field is documented as the model the turn actually ran on, not the raw frontmatter override.

The `model` field returned for a skill's execution result is now documented as the resolved model the skill turn actually runs on when the skill's frontmatter `model` override took effect, rather than just the raw override value.

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

### Config parse-error tracking becomes tri-state

Config load outcome is now recorded as parsed, parse-error or missing rather than a single parse-error boolean.

The prior boolean `setLastGetConfigWasParseError` is replaced by `setLastGetConfigOutcome`, which records one of `'parse-error'`, `'enoent'`, or `'parsed'`, giving more granular diagnostics on config load outcomes.

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

### Plugin bucket-root quarantine check is now memoized

The plugin bucket-root quarantine check is memoized so it doesn't redo directory work on every sync.

The plugin bucket-root quarantine check, which quarantines an unmarked plugin bucket directory, has been extracted from the sync routine into a helper named `ensureBucketRoot` that memoizes itself per plugins-sync state, avoiding repeated directory-quarantine work on every sync call.

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

### Skills sync tracks consecutive failed rounds

The skills sync loop now counts consecutive failed rounds in its persistent state.

The background skills-sync loop now maintains a `consecutiveFailedRounds` counter in its persistent state, incrementing it on list failures and unexpected errors and resetting it to 0 on success.

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

### Skills sync failure logs now include structured failure detail

Skills sync failure logs now include structured failure detail rather than just a duration.

Skills sync list-failure log and telemetry events now include extra structured failure detail extracted via a new helper, rather than just a duration.

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

### Plugin sync failure telemetry gains error kind/status detail

Plugin sync failure logs and telemetry now break the failure down by kind and HTTP status.

When a plugins sync round fails to list plugins, the `plugins_sync_list_failed` warn log, the `tengu_plugins_sync_list_failed` telemetry event, and the `plugins_sync_round` failure event now include a `kind`/`status` breakdown of the failure extracted from the response, in addition to the timing fields already sent.

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

### Internal events uploader now caps hold batch size

The held-upload batch is capped at 50 events so it can't grow unbounded.

The internal-event uploader's hold mechanism now caps the number of events it will accumulate at `holdMaxItems: 50`, so it won't grow unbounded while holding uploads for a session with no subscribers.

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

### getProjectDirsUpToHome now stats candidate .claude dirs in parallel

The walk up to home for .claude directories now stats candidates in parallel instead of one at a time.

`getProjectDirsUpToHome`, which walks up from the current directory to home collecting `.claude` subdirectories, now collects all candidate paths first and stats them concurrently via `Promise.all`, keeping only the ones that exist, instead of stating each one sequentially during the walk.

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

## Removed

### Sandboxed bash deny-list enforceability check removed

Sandboxed bash no longer errors out when a remote call carries file deny lists it cannot enforce.

The sandboxed bash execution path no longer throws an error when a remote call carries `additionalDenyRead`/`additionalDenyWrite` lists that can't be enforced there; the guard and its message, "This call carries file deny lists that cannot be enforced here yet," along with the telemetry gate `sandbox_exec`/`remote_deny_list_unenforceable`, have been removed.

- Area: Sandbox
- Names: `additionalDenyRead`, `additionalDenyWrite`
- Tier: You'll notice
- Useful: 2/5
- Signal: 3/5

### 'allow_desktop_handoff' policy removed

Desktop handoff is no longer a separately gated capability in the permission and HIPAA lists.

The `allow_desktop_handoff` permission entry has been removed from both the HIPAA permission-pair list and the general capability list, so desktop handoff is no longer a distinct gated capability.

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

### claude-api built-in agent tool access tightened

The built-in claude-api agent lost Read, Grep and Glob and now only has WebFetch scoped to one docs domain.

The built-in `claude-api` agent's tool access is narrowed: it previously had `Read`/`Grep`/`Glob`/`WebFetch`, and now only has `WebFetch` scoped to `platform.claude.com`.

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