This release focuses on permission correctness and worktree safety. Permission responses are now matched against the tool they were issued for, mismatched replies are logged and dropped, and forked or background agent queries require canUseTool by default. Worktree handling was reworked so that git commands run with a scrubbed environment, new worktree roots are validated before use, sessions record a launch anchor for when they exit, and resuming into a missing or unverifiable worktree explains itself instead of failing silently. The remote-control bridge can now self-heal when heartbeats fail while SSE is still alive, with a rebuild budget and better failure telemetry, and shutdown waits for in-flight remote-control work. Artifact comments track which ones were sent to Claude, and commands, skills and plugin manifests accept a free-form metadata object, with warnings on malformed entries.
Official notes✓ syncedPackage@anthropic-ai/claude-codeDiffv2.1.221 → v2.1.222ProviderclaudeModelclaude-opus-5 (effort medium)
9
Use it now
76
You'll notice
8
Not switched on
14
Env Vars / Flags
Official Changelog
Official · Anthropic
Anthropic’s official release notes
Published verbatim by Anthropic for v2.1.222 — shown here alongside the source-level analysis below. Text is unmodified from the upstream changelog.
Fixed worktree-isolated sessions and their subagents being able to run destructive git commands against the main checkout; isolation now applies to file edits and Bash in every session type
Fixed /usage-credits on Team and Enterprise showing "you've already sent a usage credit request" for members whose earlier request was dismissed, blocking them from sending a new one
Fixed the startup connectivity check hanging and then failing behind an HTTPS proxy; it now uses the same proxy-aware transport as API requests and times out with a clear message
Fixed "Connection closed mid-response" errors being reported on responses that had actually completed
Fixed /usage overattributing usage to MCP servers: a server's share now reflects only the requests that actually consumed its tool results, instead of every turn after any call to it
Fixed sessions not linking to pull requests created after the branch was pushed, including through the GitHub REST API
Fixed org-restricted model: opus-style subagent and teammate family aliases dropping to the parent model instead of stepping down to the newest org-allowed model in the family
Fixed stream idle timeout firing on custom ANTHROPIC_BASE_URL gateways despite server keep-alive pings arriving on the wire
Fixed claude.ai connectors being falsely marked as needing authorization when the session token is invalid — they now show a /login hint instead
Fixed tool errors not being displayed for tools no longer available locally, for example after an MCP server is removed
Fixed SendMessage rejecting a long summary — it now truncates instead, so sends no longer fail on a character limit
Fixed the spinner's effort label in a subagent's transcript view showing the session's effort level instead of the subagent's own effort: setting
Fixed rare crashes when a file watcher hit a filesystem error or during file-watcher teardown
Fixed screen readers re-reading the whole input line on every backspace in --ax-screen-reader mode — end-of-line deletions now echo just the deleted characters
Fixed host model-selection keys not taking precedence over a stale on-disk managed-settings.json when CLAUDE_CODE_PROVIDER_MANAGED_BY_HOST is set
Improved auto mode safety: messages sent to other agent sessions via SendMessage are now evaluated by the permission classifier before dispatch
Improved the refusal when Claude tries to invoke a skill with disable-model-invocation: Claude is now told to ask you to run the skill instead of replicating its workflow
Improved the /diff view, the Remote Control workspace diff, and file-edit diffs in Claude Code on the web sessions to use raw git blob content, ignoring workspace-configured diff drivers and textconv
Changed Remote Control auto-start so repo-local settings (.claude/settings.json or .claude/settings.local.json) can no longer turn it on (they can still turn it off); enable it at user scope via /config
Removed ultraplan feature
Source: anthropics/claude-code · CHANGELOG.md · 21 entries · synced automatically when Anthropic publishes official notes for a version.
Source-Level Analysis
Reverse-engineered from a diff of the bundled CLI — deeper, structured detail. Unofficial.
Shipped inside the bundle with its gate off, its guard hardcoded false, or nothing calling it. What the code shows, not a roadmap: no claim about what is released, announced or planned.
Filter
What probably matters to you
25 items
Anything you can use today, anything that visibly changes, and anything worth poking at. One line each, open for detail.
In the artifacts frames dialog, press x to detach the highlighted frame from your session.
/artifactsx
Use it now · Artifacts
What
The frames dialog now takes attachedSlugs and an onDetach callback, marks each row with isAttached, and adds an x chord that removes the highlighted frame from the session's list, followed by a confirmation line.
Details
Each frame row renders with an attached indicator so it is clear which frames are currently in play.
Pressing x on the highlighted row detaches it from the session rather than deleting the artifact.
Dismissal is confirmed inline in the dialog.
Usage
/artifacts
Evidence
frame_link_dismiss_dialog
Commands, skills and plugin manifests accept a free-form metadata object #
Juicy
You can add a free-form metadata block to command, skill and plugin files that Claude Code keeps but ignores.
metadata
Use it now · Plugins
What
Authors can attach an arbitrary metadata object to command and skill frontmatter and to plugin manifests; it is preserved through parsing but never interpreted by Claude Code.
Details
Frontmatter parsing keeps metadata when the value is an object; the parsed command shape and its serialization allowlist both include "metadata".
Plugin manifest validation warns with the fragment "'metadata' must be a free-form object" and states the value will be ignored at load time when it is not an object.
Both the plugin manifest schema and the skill schema document the field as a free-form map for the author's own use, for example entitlement or catalog fields.
Metadata keys are no longer folded into the computed declaredFields set.
Evidence
Free-form metadata for the plugin author's own use (e.g. entitlement or catalog fields). Preserved on the parsed manifest but not read by Claude Code., 'metadata' must be a free-form object
MCP: rejected claude.ai session token is now visible #
Your MCP server list now flags a rejected login token, and clears the warning once it recovers.
/login/mcp
Use it now · MCP
What
A connected MCP server whose discovery bearer token was rejected now says so in the server list and in the reconnect result, rather than the state being tracked only internally.
Details
Message directs you to run /login and then reconnect.
A successful tools/list now clears discoveryAuthFailure in both MCP client implementations, so a recovered server stops showing the warning.
Evidence
but your claude.ai session token was rejected. Run /login, then reconnect.
Exiting a worktree no longer widens the permission anchor #
Leaving a worktree can no longer quietly widen what the session is allowed to touch.
You'll notice · Permissions
What
ExitWorktree and the session-exit path only move the permission anchor when the target is already covered, so leaving a worktree cannot broaden what the session is allowed to touch.
Details
the move requires coverage by the session's live launch anchor and witnesses
a record-derived widening is refused and logged instead of applied
Evidence
ExitWorktree: not moving the permission anchor to
Model refusal fallback no longer claims your session model changed #
Fallback notices now say only that one response came from another model; your session model is unchanged.
/status
You'll notice · Models
What
When a request falls back to another model, the notice explains that only that response came from the other model, and the session model display marks the switch as automatic.
Details
The old "Switched to X" wording is gone; the notice now says the response was generated or completed by the other model and that the session model is unchanged.
/status and the model display append a note that the model was automatically switched.
The fallback notice is carried into the extracted last-assistant-response text with a ⚠ prefix.
Evidence
This response was generated by ${n} instead. Your session model is unchanged.
If a connection fails through your proxy, the error now names the proxy environment variable to check.
HTTPS_PROXY
You'll notice · Internals
What
When a connectivity check fails and the request went through a configured proxy, the error panel now points at the proxy rather than leaving you to guess.
Details
The panel names the environment variable the proxy is configured through and asks you to check that it allows the host.
A docs link is appended alongside the hint.
The extra line only appears when a proxy is configured and was actually used.
Evidence
See https://code.claude.com/docs/en/network-config
Resuming into a missing or unverifiable worktree is now explained #
Resuming into a missing worktree now warns you, and headless runs exit with an error instead of continuing.
You'll notice · Worktrees
What
Worktree re-entry on resume returns a structured outcome that the session reports, instead of quietly continuing without isolation.
Details
a vanished worktree clears the binding and continues without isolation
an unverifiable or rejected pin keeps the binding
interactive sessions show a warning message; headless and print paths write an error to stderr and exit non-zero rather than continuing unisolated
telemetry tengu_worktree_resume_root_rejected carries the reason and a poisoned flag
Evidence
The worktree binding has been cleared.
remoteControlAtStartup can no longer be turned on by repo-scoped settings #
Juicy
A cloned repo's settings can no longer switch on Remote Control at startup; only your own settings can.
remoteControlAtStartup
You'll notice · Permissions
What
A checked-in project or local settings file can no longer enable Remote Control at startup, closing off a path where cloning a repo changed your startup behaviour.
Details
The setting is read through the security-sensitive settings path, so only user, policy or flag scope can enable it.
Project and local settings can still disable it: a false value wins.
A true value at repo scope is ignored and logged.
projectSettings is ignored entirely when it aliases user settings.
Evidence
repo-scoped settings cannot enable Remote Control; set it at user scope (/config)
Bad metadata in frontmatter and manifests now warns #
You now get a warning when metadata in a skill, command, plugin or marketplace file is the wrong type.
metadata
Use it now · Plugins
What
Authoring a skill, command, plugin manifest or marketplace entry with a non-object metadata value produces a validation warning instead of silent loss.
Details
The warning names the type actually found and states that the value is dropped or ignored at load time.
Applies to skill and command frontmatter, plugin manifests, and marketplace plugin entries.
Evidence
'metadata' must be a mapping (key: value pairs); got
Host-managed provider sessions take model policy from the parent process #
Juicy
Setting CLAUDE_CODE_PROVIDER_MANAGED_BY_HOST makes the parent process dictate your model settings, ignoring your settings file.
CLAUDE_CODE_PROVIDER_MANAGED_BY_HOST
Use it now · Settings
What
When Claude Code runs under a host that manages the provider, settings-file model configuration is ignored in favour of policy handed down by the parent process.
With that env var set, model, fallbackModel, modelOverrides and provider env vars are stripped from the policy view.
A hostModelOverlay built from parent-managed settings is applied in their place; admin modelOverrides are stashed and re-applied to enforcement.
The managed-settings source enum gained a "parent" value, returned when a parent slice or host model overlay exists.
Inactive unless CLAUDE_CODE_PROVIDER_MANAGED_BY_HOST is set.
Evidence
hostManagedProvider
Parked AskUserQuestion prompts can survive stream shutdown #
Juicy
Questions left open when the stream closes could stay answerable, but that behaviour is switched off for you today.
Not switched on · Permissions
What
When the SDK control stream closes with an AskUserQuestion permission request still parked, the request can now be kept answerable instead of being cancelled and denied.
Details
preserved requests are added to preservedParkRequestIds
telemetry tengu_auq_park_preserved_at_shutdown, plus tengu_auq_park_preserve_reverted when a hook decision retracts a preserved park
gated on tengu_cinder_heron with fallback "off"; the helper returns true only when the value resolves to the string "preserve"
absent a remote value, the old cancel-and-deny behaviour is what you get
The rule for wrapping a text/event-stream body in the stall watchdog was widened from a single caller-supplied boolean to name the providers explicitly.
Details
Now instruments firstParty, gateway and anthropicAws responses.
Gated on tengu_stream_watchdog_default_on, which falls back to true when the flag is unavailable.
CLAUDE_ENABLE_BYTE_WATCHDOG overrides the decision, and CLAUDE_ENABLE_BYTE_WATCHDOG_BEDROCK covers Bedrock specifically.
Evidence
tengu_stream_watchdog_default_on
MCP server panel explains a rejected claude.ai session token #
An MCP server rejecting your login token now tells you to run /login and reconnect.
/login
Use it now · MCP
What
A connected MCP server whose discovery bearer token was rejected now tells you to re-login instead of showing a generic tools-list failure.
Details
A dedicated Issue line instructs you to run /login and then reconnect.
The generic tools-list error is suppressed in that specific case.
Evidence
claude.ai rejected the session token. Run /login, then reconnect.
Dedicated error when claude.ai rejects a session bearer token #
If claude.ai rejects your session token, you now get a clear message telling you to run /login instead of endless retries.
/login
You'll notice · MCP
What
MCP connections proxied through the claude.ai connector now surface a specific error telling you to re-login, instead of a generic auth failure that gets retried.
Details
New ClaudeAiProxyBearerRejectedError class with code CLAUDEAI_BEARER_REJECTED.
Message: "claude.ai rejected the session token — it may lack connector scopes or be invalid. Run /login."
Two retry classifiers return false for it, so it is neither retried nor treated as a generic auth failure.
Added to the known-error name allowlists, alongside McpAuthError and McpError.
Connection failures report errorCode: "CLAUDEAI_BEARER_REJECTED" on tengu_mcp_server_connection_failed.
Evidence
CLAUDEAI_BEARER_REJECTED
Forked and background agent queries require canUseTool by default #
Background and forked agents now run your permission callback even when a hook says allow, and deny rules win.
canUseTool
You'll notice · Permissions
What
Forked query tool contexts now default requireCanUseTool to true, so a hook returning "allow" no longer bypasses the permission callback there, and deny rules can now beat a hook allow.
Details
requireCanUseTool is set to true when the caller does not specify it.
The hook decision path was reordered so deny and ask rules are evaluated before the "hook allowed but canUseTool is required" fallback, letting a deny rule override the hook even when canUseTool is required.
Evidence
requireCanUseTool
Permission responses are checked against the tool they were issued for #
A permission answer meant for a different tool is ignored, so nothing gets wrongly approved.
You'll notice · Permissions
What
A can_use_tool answer that names a different tool than the one being asked about is now ignored, so a stale or crossed response cannot approve the wrong call.
Details
both the SDK control-protocol client and the remote permission bridge record the pending tool name
the hook and permission response schema gained an optional toolName field
telemetry distinguishes a match from a mismatch
in the remote session manager, a mismatch is logged and the local prompt stays up rather than being dismissed, since the worker would drop the answer anyway
Evidence
bridge_permission_toolname_check, worker will drop it, keeping prompt
Resume no longer inherits a stale config directory or a half-copied file #
Resumed sessions no longer inherit a stale config directory or abort on a failed file copy.
CLAUDE_CONFIG_DIR
You'll notice · Sessions
What
Session-store resume tolerates copy failures and strips configuration environment variables from copied data.
Details
A failed file copy removes the partial destination and logs a skip instead of aborting resume.
A JSON transformer removes a set of keys plus CLAUDE_CONFIG_DIR from any copied env object, so the resumed session does not pick up the recorded config directory.
Evidence
sessionStore resume: skipping
claude.ai MCP proxy surfaces a rejected session token #
When your claude.ai session token is rejected, you now get a clear error telling you to run /login.
/login
You'll notice · MCP
What
A 401 from the claude.ai proxy that a token refresh cannot fix now becomes a typed error telling you to run /login, instead of silently returning the original failed response.
Details
error code CLAUDEAI_BEARER_REJECTED, recognised by connect, tools/list, prompts/get and skills/list
sets discoveryBearerRejected on the client and skips the usual "degraded" telemetry
emits mcp_connect_claudeai_bearer_rejected and mcp_reconnect_bearer_rejected
the failed entry is evicted from the connection cache so a later attempt retries
Evidence
claude.ai rejected the session token — it may lack connector scopes or be invalid. Run /login.
/btw answers can now show a refusal-fallback notice #
If a /btw answer came from a fallback model after a refusal, you now see a warning.
/btw
Use it now · Slash Commands
What
When a /btw question is answered by a fallback model after a refusal, the panel shows a warning notice above the answer naming the swap.
Details
The panel accepts initialFallbackNotice and stores a fallbackNotice alongside each question/response pair in its history
The notice renders prefixed with a warning sign, above the answer
Text comes from a refusal_fallback payload returned with the response, carrying original_model, fallback_model and content (truncated)
Usage
/btw what does this repo use for tests?
Evidence
initialFallbackNotice
Frame strip points to /artifacts when frames overflow #
When too many frames fit on the row, you now see a pointer to /artifacts instead of a bare count.
/artifacts
Use it now · Artifacts
What
The frame row layout now reserves space for a browse hint instead of showing a bare "+N" counter when there are more frames than fit.
Details
The hint names the command that lists everything, so overflow is actionable rather than just a count.
Layout reserves the room up front, so the hint does not push frames off the row.
Evidence
/artifacts to see all
Destructive MCP tools can be included in remote auto-mode #
Juicy
Destructive MCP tools could stop skipping permission prompts in remote auto mode, but that is off.
tengu_remote_auto_mode_include_destructive_mcp
Not switched on · Permissions
What
A new predicate combines the auto/plan remote mode check with a tool's isDestructive result, so destructive MCP tools still get a permission prompt. It is off in this build.
Details
When on, an MCP ask-override no longer exempts destructive tools from the prompt.
Gated on tengu_remote_auto_mode_include_destructive_mcp, fallback value in source is false.
A new mcpServerAskOverride field was added to four permission telemetry payloads.
Evidence
tengu_remote_auto_mode_include_destructive_mcp
Unsafe-PATH command resolution guard, off in this build #
Juicy
A guard that would reject commands found only in your current directory stays disabled.
Not switched on · Sandbox
What
A third spawn wrapper picked up the same guard as the other two: resolve the command and refuse it if it only resolves inside the current directory.
Details
The predicate that controls all three call paths is a function that returns false in this build, so no command is refused at runtime.
If enabled, a command found only in the current directory would be rejected as being in an unsafe location.
Evidence
not found or is in an unsafe location (current directory)
Sessions can now track branch links alongside pull-request links, with detection for git, gh, glab and curl commands.
Not switched on · Session State
What
Session state carries pending branch links alongside pending PR links, with the PR-created path folded into one helper.
Details
A pendingBranchLinks Map was added to the session state object and to both reset paths.
Sits next to the existing pendingPrLinks set.
A new regex matches git, gh, glab and curl in commands.
Evidence
pendingBranchLinks
Everything else · 96
Smaller changes and internals, grouped as the pipeline found them. Nothing is dropped, it is only further down.
New Features
7 items
Artifact comment auto-reply understands "sent to Claude" lanes #
Artifact comment threads now track which comments were actually sent to you, and re-sending one triggers a reply.
You'll notice · Artifacts
What
Comment threads are now classified per comment into human, agent and unknown lanes, and sending or re-sending a comment to Claude is itself a trigger for auto-reply rather than only a new comment being one.
Details
each comment carries a lane; a toClaudeAt timestamp marks it as sent to Claude
new trigger kind redesignated covers existing comments newly toggled to Claude, tracked through a per-thread sentToClaudeAt map
the composed prompt now explains the row heads [human], [assistant], [human, sent to you] and [unverified lane]
Evidence
A human sent an EXISTING comment in the thread to you on an artifact you published
Skill import from other agents refuses unsafe copies #
Importing a skill from another agent now skips bad copies and tells you why instead of silently breaking.
You'll notice · Skills
What
Importing a skill from another agent now inspects the source directory and skips the copy with an explanation instead of producing a skill Claude Code cannot load.
Details
Skips when SKILL.md is larger than the size Claude Code loads.
Skips when SKILL.md starts with --- YAML frontmatter, which Codex treats as plain text.
Skips when the directory contains subdirectories that Claude Code would adopt as plugin components.
Skips when several case or encoding variants of SKILL.md exist in the same directory, and tells you to copy it manually.
A copy that proceeds rewrites SKILL.md and removes the destination if the copy fails part way.
Evidence
skill directory has multiple SKILL.md case/encoding variants \u2014 copy the skill manually
Artifact comments now mark which comments were sent to Claude #
Comment rows are now labelled "sent to you" so you can tell requests apart from side chatter.
You'll notice · Artifacts
What
Comment rows carry an explicit label when the comment was addressed to Claude, so it is clear which parts of a thread are a request to you and which are other people talking to each other.
Details
Rows can show a ", sent to you" label, with an "awaiting reply" variant and a variant for when the status cannot be read.
Threads containing such comments are sorted to the top of the list, and the header count mentions them.
The tool description now states that only labelled comments are addressed to Claude.
The anti-injection preamble gained explicit rules that the attribution bracket only ever appears at the start of a row.
Evidence
Threads with comments sent to you are listed first; list order is not chronological.
Remote bridge self-heals when heartbeats fail but SSE is alive #
The remote bridge tears down half-dead sessions so the connection rebuilds instead of hanging.
tengu_bridge_selfheal_heartbeats
You'll notice · Remote Bridge
What
The v2 remote bridge can now detect the case where heartbeats keep failing while the SSE read stream is still delivering data, and tears the session down so the transport is rebuilt instead of sitting in a half-dead state.
Details
Session state tracks consecutiveHeartbeatFailures and heartbeatStreakStartedAtMs, plus a new onHeartbeatLost callback.
Liveness is judged by a new isReadStreamRecentlyAlive() helper backed by lastLivenessEvidenceAtMs.
On trigger the session closes with code 4093 and logs "[bridge:repl] CCR v2: heartbeats failing while SSE healthy — closing for transport rebuild".
Wired through a selfHealHeartbeats option read from the tengu_bridge_selfheal_heartbeats gate, whose fallback is true; the real value comes from remote config.
Evidence
tengu_bridge_selfheal_heartbeats
Artifact tool output exposes sent-to-Claude and awaiting-reply flags #
Threads with comments addressed to you sort first, and each comment shows whether it awaits your reply.
You'll notice · Artifacts
What
Thread listings sort threads with comments addressed to Claude first, and individual comments now report whether they were sent to Claude and whether they are still waiting on a reply.
Details
per-comment fields sent_to_claude, sent_to_claude_degraded and awaiting_reply
size-capped elisions state how many hidden comments were sent to Claude, including a count for those whose addressed status could not be read
Evidence
addressed-status-unreadable
/btw side questions show a fallback-model notice #
Side questions now show a banner naming the original and fallback model instead of switching silently.
/btw
You'll notice · Slash Commands
What
When a side question falls back to a different model, the answer is now preceded by a warning banner naming the original and fallback models instead of silently switching.
Details
The side-question flow returns a refusalFallback object carrying the original model, the fallback model and the notice content alongside the response.
The UI renders the banner above the answer only when a fallback is present.
The control-request response carries the same information as refusal_fallback with original_model, fallback_model and content fields.
Evidence
fallbackNotice
Remote-bridge presence heartbeats can self-heal the transport #
Remote sessions now rebuild a stuck connection when heartbeats keep failing but data still flows.
tengu_bridge_selfheal_heartbeats
You'll notice · Remote Bridge
What
The v2 remote-control transport now counts consecutive presence heartbeat failures and, when heartbeats keep failing while the SSE read stream still looks alive, closes with a new code 4093 and rebuilds the transport rather than sitting on a dead connection.
Details
New close code 4093 with human-readable reason text explaining that presence heartbeats to the server kept failing.
New internals: resetHeartbeatStreak, onHeartbeatLost, and isReadStreamRecentlyAlive, which is what distinguishes a stalled heartbeat from a genuinely dead read stream.
Gated on tengu_bridge_selfheal_heartbeats; the fallback value in source is true, with the real value coming from remote config.
Skipped entirely when the session is outboundOnly.
Evidence
presence heartbeats to the server kept failing (code 4093)
Improvements
42 items
Bridge recovery has a rebuild budget and richer failure telemetry #
A remote bridge that cannot recover now stops retrying after a budget and tells you why.
You'll notice · Remote Bridge
What
Recovery from 401, 4091 and 4093 transport closes is now table-driven, and repeated transport rebuilds are capped so a bridge that cannot heal stops retrying and says why.
Details
each close code maps to its own reconnect detail, cause, diagnostic, terminal-vs-retry fetch failure classification and recovered code
4093 rebuilds within a one hour window are budgeted; exceeding the budget stops recovery with an explicit message
The MCP server list now shows a distinct line when a server failed because your session token was rejected.
You'll notice · MCP
What
In the MCP status UI, a server that is connected but whose discovery failed because the claude.ai session token was rejected gets its own line rather than the generic tools-fetch-failure line.
Details
rendered only for the bearer-rejected case; other discovery failures keep the existing wording
Evidence
connected · session token rejected
Auto-reply stands down when lane or send-status data is unreadable #
Auto-reply now stays quiet when it cannot tell who wrote a comment or whether it reached Claude.
You'll notice · Artifacts
What
Rather than guessing, auto-reply now defers when it cannot read who wrote a comment or whether it was sent to Claude.
Details
new defer notices: activation_read_absent (thread no longer shows as activated), newest_lane_unknown (newest comment's author lane unreadable, or an unknown-lane comment follows a sent-to-Claude human comment), and fresh_trigger_degraded
each reported once per thread through the existing artifact_comments_autoreact telemetry
Evidence
artifact_comments_autoreact
Worktree git commands run with a scrubbed git environment #
Stray git environment variables in your shell can no longer misdirect worktree operations.
GIT_DIRGIT_WORK_TREEGIT_INDEX_FILE
You'll notice · Worktrees
What
Worktree plumbing no longer inherits ambient git environment variables, so a stray GIT_DIR or a repo fsmonitor cannot redirect worktree operations.
Details
covers create, remove, lock, status, reset, rev-parse and sparse-checkout
blanks GIT_DIR, GIT_WORK_TREE, GIT_INDEX_FILE, GIT_CONFIG_COUNT, GIT_CONFIG_PARAMETERS, the per-index GIT_CONFIG_KEY_n and GIT_CONFIG_VALUE_n pairs, and more
all calls go through the shared -c core.hooksPath=/dev/null -c core.fsmonitor= prefix
Evidence
GIT_ALTERNATE_OBJECT_DIRECTORIES: void 0
Isolation refusal messages distinguish session from agent #
Isolation refusal messages now say whether the session or the agent is the one confined.
You'll notice · Worktrees
What
The refusals you get when a shell cwd or file edit escapes a worktree now name the right subject.
Details
picks between "This session is isolated…" and "This agent is isolated…" based on whether the pin is the session's own worktree, with a matching possessive
shell cwd and file edit paths now share one escape-detection routine
Evidence
possessive: "a worktree-isolated agent's"
Plugin and skill search now degrade to empty on 403 #
Plugin and skill search shows nothing rather than an error when your account lacks access.
You'll notice · Plugins
What
A 403 from the plugin and skill search or list routes returns an empty result instead of surfacing an error, so an unentitled account sees nothing rather than a failure.
Details
The degraded path logs the route and status and records a not_entitled telemetry code.
Other 4xx responses still throw.
The error envelope parser now tolerates a response missing type or message.
Evidence
[plugin-skill-list] degraded to empty: list-plugins 403
Shutdown waits for in-flight remote-control work #
Quitting waits up to 30 seconds for pending remote-control work instead of cutting it off.
You'll notice · Elsewhere
What
Teardown now gives a pending remote-control operation time to finish before tearing down the rest of the session.
Details
Waits up to 30 seconds and swallows the timeout rather than failing shutdown.
Runs before MCP client cleanup and session state clearing.
Evidence
remote_control operation still pending at teardown
Deferred PR-existence checks retry on later git commands #
Claude now re-checks later whether your pull request was actually created, instead of giving up after one try.
gh pr createglab mr create
You'll notice · Git Integration
What
Detection of a newly created pull or merge request no longer depends on a single check right after the create command.
Details
Pending checks are tracked per cwd plus branch with an attempt counter, in a bounded map.
A successful gh pr create or glab mr create clears the entries for that cwd.
Later matching git commands re-check pending branches until the attempt cap is reached.
Evidence
tengu_git_operation
Connectivity check rewritten on fetch, with a timeout and proxy awareness #
Connection checks now time out properly and record whether your proxy was used.
You'll notice · Internals
What
The hello-endpoint probe used by the connection diagnostics now runs on fetch with an explicit timeout and reports whether a proxy was involved.
Details
Uses AbortSignal.timeout rather than the previous HTTP client, and cancels the response body.
A timed-out probe is reported as a distinct error rather than a generic failure.
The result records usedProxy so the failure UI can tell whether a configured proxy was actually in play.
Evidence
usedProxy
Agent-to-agent messaging gets a classifier review path #
Messaging another agent may now require classifier review instead of being automatically allowed.
You'll notice · Permissions
What
The tool for messaging another agent no longer auto-allows in every permission mode; in some modes it defers to classifier review.
Details
The permission check can now return a passthrough behavior with a message stating that classifier review is required.
Recipient names must match a single-line pattern.
Over-long summaries are truncated rather than rejected outright.
The classifier input string now carries the summary, shutdown reason, request id and plan feedback.
Evidence
Message to another agent requires classifier review.
When a subagent can't use its requested model, you now see why it fell back.
You'll notice · Subagents
What
When a subagent cannot get the model it asked for, the notify callback now carries a reason distinguishing a same-family step-down from inheriting the parent's model, and the message shown downstream differs accordingly.
Details
Reason is either family_step_down, meaning a fallback within the same model family was picked, or parent_inherit, meaning the subagent fell back to the parent session's model.
The refusal message for git commands escaping a worktree now words itself to fit the context.
Under the hood · Git Integration
What
The refusal shown when a git command would escape a worktree now derives the noun and possessive it uses rather than always saying "This agent" and "a worktree-isolated agent's".
Details
Same refusal behaviour, only the phrasing is now computed from context.
Evidence
Refusing to run it —
Skill refusal message tells the model not to work around it #
Skills you mark as user-only now tell Claude not to reimplement them by hand.
disable-model-invocation
You'll notice · Skills
What
When the model tries to invoke a skill marked as user-only, the returned error now appends an explicit instruction against achieving the same thing another way.
Details
Applies to skills with disable-model-invocation set.
The added sentence closes the loophole of the model reading the skill and re-implementing its steps by hand.
Evidence
Do not replicate this skill's workflow by other means
Teammate summaries are trimmed, truncated and colour-checked #
Long teammate summaries get trimmed instead of breaking the status line or rejecting the message.
You'll notice · Elsewhere
What
Summary and failureReason text from teammates now passes through a trim-and-truncate helper before it reaches the teammate XML tag or the status line.
Details
The tag's color attribute is validated against the known colour list rather than escaped and passed through.
SendMessage input repair gained a case that truncates an over-long summary instead of rejecting the call.
The temp directory built to resume a stored session now copies settings.json and cowork_settings.json next to .claude.json, with plugin registration stripped.
Details
enabledPlugins and extraKnownMarketplaces are deleted from the copied settings.
The projects directory inside the snapshot is created with mode 448.
Evidence
cowork_settings.json
Git diffs ignore external diff drivers and textconv filters #
Diffs now ignore your repo's custom diff drivers, so Claude sees the real file contents.
--no-ext-diff--no-textconv
You'll notice · Git
What
Diff reads now pass --no-ext-diff and --no-textconv, so a repo's own git configuration cannot change the content Claude sees when computing patches.
Details
New exported constant RAW_BLOB_DIFF_FLAGS = ["--no-ext-diff", "--no-textconv"].
Spread into the git diff invocations used for whole patches and per-file hunks.
Includes the --no-optional-locks diff calls, which previously passed no such flags.
Evidence
RAW_BLOB_DIFF_FLAGS
Design OAuth refresh lock holds longer and reports compromise #
Slow token refreshes no longer trip the lock early, cutting spurious login hiccups.
You'll notice · Elsewhere
What
The lock guarding OAuth token refresh tolerates slower refreshes and lets the holder find out if its lock was taken away mid-flight.
Details
Stale window raised from 10s to 60s, with a 5s update interval.
The callback now receives an object exposing isCompromised().
Lock contention throws a dedicated error class rather than a bare Error.
The ultraplan banner now just tells you it's ready and which key to press.
You'll notice · Terminal UI
What
The web-ultraplan banner now says the plan is ready and tells you which key to press, replacing the older "Monitor progress in Claude Code on the web" wording.
Details
Old text was retired rather than kept alongside the new form.
Evidence
ultraplan ready
Turn effort display now tracks the model the turn is running on #
The effort label in your status line stays correct when the model changes mid-turn.
You'll notice · Terminal UI
What
The effort label in the status line is computed against the model actually running the turn, so it stays correct after a mid-turn model change or a fallback.
Details
The agent status store gained turnModel alongside turnEffort
setTurnEffort(effort, model) is called at turn start with the resolved agent model, and again on query_model_change and on fallback-model events
Cleared with setTurnEffort(null, null) at turn end
The spinner/status component takes the new turnModel prop and uses it when computing the label
Evidence
setTurnEffort
Plugin sync list failures carry HTTP status and 403 is not retried #
Plugin syncing fails fast on a forbidden response and tells you the HTTP status.
You'll notice · Plugins
What
A forbidden response when listing plugins fails fast instead of burning through the retry schedule, and the failure now reports which HTTP status caused it.
Details
The list-plugins error envelope returns status along with success: !1, and the status is included in the plugins_sync_list_error warning
The retry wrapper returns immediately when t.status === 403 rather than sleeping and retrying
A sibling retry helper was simplified to test t.ok only
Evidence
plugins_sync_list_error
Remote-control bridge heals a socket whose heartbeats keep failing #
A remote connection with failing heartbeats now rebuilds itself instead of hanging on a half-dead socket.
tengu_bridge_selfheal_heartbeats
You'll notice · Remote Bridge
What
The CCR v2 transport now spots heartbeats failing repeatedly while the SSE read stream still looks healthy, and closes the socket with code 4093 so the bridge rebuilds the transport instead of sitting on a half-dead connection.
Details
close code 4093 has its own recovery entry reporting reconnectingDetail: "presence heartbeats failing — reconnecting"
a successful rebuild emits the presence code recovered_heartbeat_4093
gated on tengu_bridge_selfheal_heartbeats whose in-source fallback is true, so absent a remote value it runs
additionally requires !outboundOnly
Evidence
[bridge:repl] CCR v2: heartbeats failing while SSE healthy — closing for transport rebuild
Thread rendering keeps summoning comments and marks new truncation kinds #
Comments that triggered a turn are always kept in view instead of being trimmed away.
You'll notice · Artifacts
What
The thread renderer was replaced so the comments that actually caused this turn are never dropped to fit the budget.
Details
always keeps the newest comment plus every comment that summoned this turn, budgeting characters across them
new markers [summoning comment truncated] alongside [newest comment truncated] and [N comment(s) elided]
summoning_truncated added to the compose_thread_elided telemetry
Evidence
[summoning comment truncated]
Artifact auto-reply failure notices no longer say "@claude" #
Failure replies on artifacts no longer tell viewers to mention @claude, matching how sending actually works.
You'll notice · Artifacts
What
The canned edit-failure replies were reworded to match the send-to-Claude mechanism instead of telling viewers to mention @claude.
Details
affects the replies posted when an auto-reply edit fails
Evidence
send a comment to Claude again later to retry.
Worktree creation validates the resulting root before use #
New worktrees are checked before use, and creation fails loudly if the directory is unusable.
You'll notice · Worktrees
What
After creating a worktree, Claude Code checks that the new directory is acceptable as an isolation root and fails loudly if it is not.
Details
applies to every creation path: interactive, agent, hook-based and resumed
throws on rejection and records telemetry git_worktree_create_root_rejected
Evidence
git_worktree_create_root_rejected
Parked agents refuse to resume into a worktree that vanished #
A parked agent refuses to resume if its worktree disappeared, instead of landing in the wrong directory.
You'll notice · Worktrees
What
Resuming a parked or isolated agent verifies the recorded worktree first and refuses rather than silently landing somewhere else.
Details
stats and verifies the recorded worktree and touches it
falls back to a covered directory only when the session's fences cover it
otherwise raises a terminal error saying the agent cannot be resumed
Evidence
This agent cannot be resumed: its worktree
Subagent models outside the allowlist step down within their family #
Subagents asking for a disallowed model now drop to the newest allowed model in the same family.
availableModels
You'll notice · Models
What
A subagent or teammate asking for a model that is not in availableModels now falls to the newest allowed model in the same family rather than straight to the parent or default model.
Details
Only applies when a same-family allowed model exists; otherwise the old parent/default fallback still runs.
Emits telemetry code family_alias_stepped_down and a matching warning log.
Evidence
family_alias_stepped_down
Messages from other sessions get a sanitized sender label #
Messages arriving from another session now show who sent them plus a chord to expand.
You'll notice · Transcript
What
Transcript rows for messages arriving from another session render through a shared component that names the sender and offers an expand chord.
Details
Shows "Message" or "N messages" followed by "from @<name>" plus the expand chord.
The name is restricted to letters, digits, dot, underscore and hyphen, and truncated with an ellipsis.
SendMessage tool labels and teammate summaries use the same sanitizer.
Evidence
from @
Agent-proxy tunnel now times out waiting for HELLO_ACK #
A stalled agent proxy tunnel now fails quickly with a clear reason instead of hanging in limbo.
You'll notice · Elsewhere
What
A WebSocket tunnel that never gets its protocol v2 negotiation acknowledged now fails fast instead of continuing in an undefined state.
Details
Connecting arms a helloAckDeadline; if the server does not acknowledge protocol v2 within the open timeout, negotiation fails with "tunnel protocol v2 negotiation failed" and a reason built from the fragment "no HELLO_ACK within" plus the elapsed limit.
An ack carrying an unexpected version is rejected, and the connection is closed with a 502 "Bad Gateway".
The deadline is cleared both on receiving HELLO_ACK and on teardown.
A new telemetry event agent_proxy_request_v2_not_acked fires on the failure path.
Evidence
requires tunnel protocol v2; the server did not acknowledge the negotiation (, agent_proxy_request_v2_not_acked
model_refusal_fallback events gain a scope field #
Model fallback events now say whether the swap affects your whole session or just one subagent.
/btw
Under the hood · Elsewhere
What
Fallback events now distinguish a session-wide model swap from a one-off fallback in a subagent or side question, so consumers can tell how far the change reaches.
Details
The SDK schema adds an optional scope enum with values "session" and "local".
"session" means the main thread swapped models for the rest of the session; "local" means only a subagent, a /btw side question or a background fork fell back.
The field is absent from older CLIs and should be treated as "session" when missing.
The event builder sets scope and selects different wording for local fallbacks.
Evidence
'local': a subagent / side-question (/btw) / background fork fell back
The skill import warning now spells out that bundled scripts and instructions go live once you import.
SKILL.md
You'll notice · Skills
What
The confirmation shown before importing a plugin or skill no longer talks about allowed-tools frontmatter, and instead spells out that bundled scripts and body instructions become active once imported.
Details
Warning now asks you to review SKILL.md and its directory, not just the file.
States that the import is unchecked by default.
Evidence
bundled scripts and body instructions become active in Claude Code. Unchecked by default; review SKILL.md and its directory before importing.
Remote control enable/disable runs as a tracked async task #
Toggling remote control now carries pending permission prompts over to the new session instead of losing them.
You'll notice · Remote Control
What
Handling of the remote_control control request is now wrapped in a single async operation with its own error handling, and it hands off state to the newly created remote session instead of dropping it.
Details
Old session is torn down only after its callbacks are cleared.
Pending permission requests and pending user-dialog requests are replayed to the new remote session.
The initial name supplied in the request is preserved across the swap.
Evidence
getPendingUserDialogRequests()
Git invocations hardened with sanitized args and environment #
Many more git commands now run with a scrubbed environment so stray variables can't redirect them.
GIT_DIRGIT_WORK_TREEGIT_INDEX_FILE
You'll notice · Git Integration
What
Many more git call sites now prepend the frozen safety arguments and run with an environment scrubbed of git overrides, closing off paths where inherited env vars could redirect a git command.
Details
Newly covered call sites include rev-list, ls-files --others --ignored, worktree remove --force, and config core.hooksPath.
Sanitized environment strips GIT_DIR, GIT_WORK_TREE, GIT_INDEX_FILE, and the GIT_CONFIG_KEY_n / GIT_CONFIG_VALUE_n family, among others.
Two additional git diff call sites now also pass --no-ext-diff and --no-textconv.
Evidence
core.hooksPath=/dev/null
Artifact comments use server delivery timestamps #
Artifact comments track when the server delivered them, so you should stop seeing the same comment twice.
You'll notice · Artifacts
What
Comment state now records when the server actually handed a comment to Claude, and the client uses that instead of local bookkeeping to decide what has already been shown.
Details
The comment schema gained sent_to_claude, sent_to_claude_degraded and awaiting_reply.
The client maps the server's to_claude_at into toClaudeAt and toClaudeAtDegraded.
A helper parses the timestamp and returns null when it cannot be parsed, so an unreadable value is treated as not-yet-delivered rather than crashing.
When a turn falls back to a different model after a refusal, the display now shows the model actually used.
You'll notice · Model Fallback
What
When a turn falls back after a model refusal, the agent's displayed model is rewritten to the model actually used, and the fallback message now carries a scope.
Details
A new agent event kind propagates turn effort together with the turn model.
The async-agent reader applies system/model_refusal_fallback by rewriting the agent's model rather than leaving the old one on screen.
The optional scope field was added at three emit sites and in the parser.
Codex import now tells you exactly why a command was skipped and to port it manually.
You'll notice · Elsewhere
What
Three new refusal strings spell out why a command was not imported when its body mixes shell execution markers with argument placeholders.
Details
Covers dangling markers, placeholders combined with backticks or !, and shell blocks containing ! next to argument placeholders.
Each reason tells the user to port the command manually rather than silently dropping it.
Evidence
Contains a dangling shell-exec marker that argument substitution could complete into a live command at invocation time. Port it manually.
Bridge attestation warnings are reported once per event #
A failing device attestation now warns you once instead of spamming repeated notices.
You'll notice · Elsewhere
What
The attestation notice emitter now keys on event_id and skips events it has already reported, so a single bad event no longer produces repeated warnings.
Details
The set of seen event ids is bounded.
The hint about re-pairing a device is no longer restricted to control_request payloads and now shows for any attestation failure.
A drop-sender notice writer is registered on the remote-io transport and unregistered when it closes.
Evidence
Re-pair the sending device in Trusted Devices.
Shell tools get an explicit worktree isolation root #
Agent commands now have a concrete worktree boundary, so escapes get blocked with a clearer log line.
You'll notice · Sandbox
What
Bash and shell execution paths now take an isolationRoot so the checks that keep agent commands inside their worktree have a concrete boundary to compare against.
Details
isolationRoot is resolved from the agent worktree, falling back to the session worktree path.
Used by the checks that block commands whose cwd escapes the isolation worktree, and those that redirect git into the shared checkout.
Blocked commands log with isolationRoot= in the message and report tengu_agent_worktree_cwd_escape_blocked.
The field itself is new in this build.
Evidence
isolationRoot
Screen-reader rendering erases trailing characters in place #
Screen-reader mode repaints less, so assistive tech hears less redundant output.
INK_SCREEN_READERCLAUDE_CODE_ACCESSIBILITY
You'll notice · Elsewhere
What
In screen-reader mode the renderer can now erase trailing characters instead of repainting the line, cutting redundant output for assistive tech.
Details
Diffing tracks a new prevScreenReaderParkDeclared flag.
The flag guards a new branch taken when the previous frame had an explicitly declared cursor park.
Only active in screen-reader mode, under INK_SCREEN_READER / CLAUDE_CODE_ACCESSIBILITY.
Collapsed teammate panels say "teammate" instead of showing a blank label.
You'll notice · Elsewhere
What
Collapsed teammate status panels now show a generic label when no specific one is available, instead of rendering an empty descriptor.
Details
Two collapsed-panel renderers pass fallbackLabel: "teammate" to the count component.
Evidence
fallbackLabel: "teammate"
Model refusal fallback banner now also shown in non-main threads #
You now get told when a subagent swaps models after a refusal, not just the main thread.
You'll notice · Models
What
A refusal-driven model swap that happens inside a subagent or other non-main thread now surfaces a banner, where previously only main-thread swaps did.
Details
The refusal-fallback result gained bannerScope, set to "session" for main-thread swaps and "local" otherwise
Non-main-thread turns emitting local scope now show the banner
The emitted model_refusal_fallback system message uses different wording depending on the scope
Evidence
bannerScope
Telemetry model-name sanitizer accepts a bracketed context suffix #
Telemetry now records long-context model names properly instead of labelling them nonconforming.
Under the hood · Telemetry
What
Dated model ids that carry a 1m-context suffix are now reported verbatim in telemetry instead of being replaced with "nonconforming".
Details
The gate regex widened from ^[A-Za-z0-9._:[\]-]{1,91}@\d{8}$ to allow an optional trailing [<digits>m] group
Model identifiers that still fail the pattern continue to report as "nonconforming"
Evidence
nonconforming
Bug Fixes
15 items
Design OAuth refresh distinguishes lock contention from failure #
Design sign-in refreshes no longer report a failure when another process just got there first.
You'll notice · Elsewhere
What
A refresh that loses the cross-process lock race is now reported as contention rather than as a failed refresh, and a compromised lock can still succeed.
Details
New DesignOauthLockContendedError marks the case where another process holds the refresh lock.
On a compromised lock the stored token is re-read and accepted if it is still fresh.
New telemetry codes: design_oauth_refresh_lock_contention, _lock_compromised, _lock_error.
Evidence
Design OAuth lock contention: another process is holding the refresh lock
Duplicate comment ids are dropped when building thread views #
Comment threads no longer show the same comment twice.
You'll notice · Elsewhere
What
A thread that returns the same comment id twice no longer renders that comment twice.
Details
The comment-collection loop keeps a set of already-seen ids and adds each id as it is collected.
Repeats are skipped rather than appended.
Evidence
g.add(v.id)
File watcher no longer emits errors nobody is listening for #
File watching errors no longer blow up as unhandled crashes when nothing is listening for them.
ignorePermissionErrors
You'll notice · File Watcher
What
The watcher checks the error listener count before emitting, so a watch error or an error during a pending write can no longer surface as an unhandled 'error' event.
Details
Check sits alongside the existing ENOENT/ENOTDIR filtering and the ignorePermissionErrors option.
In the pending-write path, when no error listeners are registered the pending write is discarded rather than emitting an ERROR event.
The observer restarts fresh on it and logs the error name.
The wake router drops queued events for the affected agent.
The resume subscriber no longer swallows the error silently.
Evidence
AgentResumePermanentlyRefusedError
Worktree cleanup will not chdir into a network path #
Cleaning up a worktree no longer tries to switch into a network drive path, falling back to your home directory.
You'll notice · Worktrees
What
The keep/restore-cwd path now detects a UNC or network-spelled original working directory and throws instead of changing into it.
Details
The recovery loop falls back to the home directory when the original cwd is network-spelled.
The path is screened and never touched.
Evidence
network-spelled original cwd (screened, never touched)
Agent records remember that their worktree was cleanly removed #
Resuming an agent whose worktree you deliberately removed no longer warns about missing worktree state.
You'll notice · Worktrees
What
An isolated agent whose worktree was deliberately removed no longer warns on resume that the worktree "is not recorded for this isolated agent". The removal is recorded in the agent's metadata instead of looking like missing state.
Details
Agent metadata gained worktreeCleanlyRemoved: !0, written at the point the worktree is removed
The flag is inherited from the parent agent record, so child agents do not re-trigger the warning
Consulted on resume, and suppresses the git_worktree_resume_binding_missing telemetry event
Messages with a blank summary now show their full text instead of collapsing into an empty line.
You'll notice · Transcript
What
A message whose summary is only whitespace is no longer treated as having a summary, so it renders in full instead of collapsing to an empty summarized form.
Details
Message rendering and filtering now pass summary through a trim/normalize helper rather than testing truthiness
A whitespace-only value no longer counts as present and no longer forces the summarized render path
Evidence
summary
Active MCP server/tool markers are cleared on conversation reset #
Errors after a conversation reset are no longer mislabelled with the MCP server and tool from a previous turn.
You'll notice · MCP
What
Stale MCP attribution no longer survives a conversation reset, so a later error or event is not tagged with the server and tool from a previous turn.
Details
The query loop's tool-state object gained an onReset hook
The hook calls a new helper that clears activeMcpServer and activeMcpTool on the options object, guarded by try/catch
The same helper is also invoked at the start of the API loop
Evidence
activeMcpServer
File watcher teardown no longer assumes a watcher exists #
A crash when unwatching a file that was never actually being watched is fixed.
You'll notice · Elsewhere
What
Removing the last listener for a watched entry whose watcher never started no longer throws.
Details
Both unsubscribe paths check for a watcher object before calling close or unwatch.
Evidence
mku(a.listeners) && a.watcher
Pending-permission cleanup respects a preserved park at shutdown #
Answering the last permission prompt no longer wrongly flips your session back to running when a question is still waiting.
You'll notice · Permissions
What
Resolving the last pending permission or dialog request no longer unconditionally flips the session back to "running" when a park was preserved at shutdown.
Details
If a park was preserved, the session re-tees waiting-on-user and republishes the surviving pending action instead of reporting running.
Evidence
hasPreservedParkAtShutdown
Mismatched permission replies are logged and dropped #
A permission answer meant for one tool can no longer accidentally approve a different tool call.
You'll notice · Permissions
What
A permission response whose tool name does not match the pending request is now rejected with a warning instead of resolving the wrong tool call.
Details
New helper hasCanUseToolNameMismatch guards three paths: injectControlResponse, the resolve path, and the transcript-side matcher.
Evidence
does not match pending
Tunnel sockets are destroyed on protocol violations #
Misbehaving tunnel connections are torn down properly instead of leaving stuck half-open sockets behind.
You'll notice · Elsewhere
What
The local tunnel now treats data arriving before HELLO_ACK as a protocol error and tears the socket down.
Details
Error and close paths destroy the socket rather than half-closing it.
This applies whether or not the connection negotiated v2, so a stuck half-open socket is no longer left behind.
Evidence
server sent data before HELLO_ACK
Dismissed usage credit requests no longer block the flow #
If you dismissed a usage credit request, you can now ask again instead of being told one was already sent.
You'll notice · Usage & Limits
What
The check for an outstanding admin request now looks only at pending requests.
Details
Previously a request that had already been dismissed also triggered the "already sent" notice, leaving no way to ask again.
Evidence
You've already sent a usage credit request to your admin.
Worktree sessions record a launch anchor and use it when leaving #
Leaving a worktree session now reliably drops you somewhere sensible even if the original directory is gone.
You'll notice · Worktrees
What
Leaving or cleaning up a worktree session now returns you to a directory resolved from a recorded anchor, rather than potentially failing when the original cwd is gone or unsafe.
Details
Active worktree sessions carry liveLaunchAnchor, stripped out before the session is persisted into app state
On leave/cleanup, a new helper resolves the chdir target; when the original cwd is unsafe it falls back to a repo root inferred from a .claude/worktrees path shape, and failing that to the home directory
The anchor is also part of the accepted path set when validating changed files
Tunnel connections that close before a response always shut down now, instead of lingering.
You'll notice · Elsewhere
What
When an agent-proxy tunnel closes before a response arrives, the socket is now destroyed in all cases, removing a path where non-v2 connections could linger after a graceful end.
Details
The branch that ended the socket gracefully for non-v2 connections was removed from the teardown path
The socket is destroyed unconditionally after "tunnel closed before response"
The import command exists but just prints a message instead of starting a session here.
claude import--yes/import
Not switched on · Internals
What
The import argument handling was rewritten into a parser plus a rewrite decision, but the command itself is not wired up here and prints a message instead of starting a session.
Details
Gated on a config-derived availability flag; when unavailable it prints the message below and exits.
If the config cannot be read at all it prints a recovery message instead.
The --yes help text now mentions a digest taken from the /import preview.
Evidence
claude import is not yet available in this build. Run claude and use /mcp or edit ~/.claude/settings.json directly.
Themes, settings, tasks and transcripts gained alternative storage paths that stay dormant without a backend.
Under the hood · Internals
What
Several stores now have a v5 backend path sitting alongside the existing file path, taken only when a backend is supplied.
Details
Covers theme listing and saving, MCP task metadata (write, delete and list under an mcp-tasks sidecar), scheduled-task status, user settings writes, and ranged transcript reads.
Settings write failures now raise a distinct error naming the failure class.
Each path is inert unless a v5 backend is passed in; what supplies it could not be determined.
The footer reserves room for an IDE indicator, though whether it actually shows is unresolved.
Not switched on · Elsewhere
What
The status footer computes an indicator element rendered in the "ide" color with a lozenge glyph, and the compact-footer width maths now reserves space for it. Whether it renders in this build could not be resolved.
Details
Thresholds deciding whether the compact footer fits add the indicator's width plus five.
An extra check hides content below 48 columns when the indicator is present.
Evidence
"footer-indicator"
Codex config import parses TOML with Bun's built-in parser #
Importing another agent's config now parses TOML natively, reachable only through the gated import path.
tengu_import
Not switched on · Internals
What
Reading a foreign agent's Codex config during import now uses Bun's native TOML parser through a one-line wrapper, before the config is mapped.
Details
The wrapper calls Bun.TOML.parse(e) on the config file contents
Reachable only via the import path, which is behind tengu_import
A filename/label normalizer was added alongside it: NFKC normalize, lowercase, strip trailing dots and spaces
Evidence
Bun.TOML.parse
Telemetry retry batches can persist as v5 streams #
Failed telemetry batches can be stored and retried differently, but only with a backend that nothing here supplies.
Under the hood · Telemetry
What
The first-party event exporter gained a path that stores failed-event batches as append-only v5 streams keyed by run id and retries earlier runs in the background.
Details
Leftover flat JSON batches are migrated into streams using deterministic record ids of the form flat-migration.<index>.<hash>, and the flat file is deleted afterwards.
Only taken when a storageV5 backend is passed to the exporter; what enables that backend could not be determined.
Without a v5 backend the existing flat-file path is unchanged.
Evidence
1P event logging: failed to persist failed-event queue to v5 stream
Transcript writes and head/tail reads can go through the v5 storage backend #
Transcript writing can be redirected to a different storage layer, but nothing turns that on here.
Under the hood · Internals
What
Transcript append, truncate and read helpers can now be pointed at a v5 storage backend instead of the filesystem, but only when a backend handle is passed in.
Details
The helpers take an optional backend handle; when present they call backend.append, backend.delete, backend.readText and backend.stat with a key rather than touching files.
storageV5 existed in the previous build but only on the read path; the write path is new here and inert without a handle.
Evidence
transcript stream append failed
SDK stream shutdown can preserve parked permission requests #
Pending permission prompts can survive an SDK stream closing instead of vanishing.
Under the hood · SDK
What
The control client can remember pending can_use_tool requests for a parked tool when the input stream closes, so they survive shutdown instead of being dropped.
Details
Preserved ids live in a preservedParkRequestIds set.
While any are preserved the session is not flipped back to "running".
Ids are cleared as responses arrive or when the park is retracted.
Guarded by two internal predicates evaluated at shutdown time that could not be resolved to a flag name.
Evidence
preservedParkRequestIds
Internal Changes
23 items
Heartbeat-failure streak detection in the CCR client #
Dropped connections are detected by counting repeated heartbeat failures instead of reacting to one.
Under the hood · Elsewhere
What
Failed heartbeat POSTs are no longer fire-and-forget; the client tracks a failure streak and reports it upward once it is long enough to matter.
Details
a set of statuses is ignored outright
checks isReadStreamRecentlyAlive() before counting, then increments consecutiveHeartbeatFailures
fires onHeartbeatLost only once the streak passes both a count and a duration threshold
a successful heartbeat calls resetHeartbeatStreak()
the onHeartbeatLost handler is only installed when selfHealHeartbeats is on
Wording around messages from other sessions moved to one place, with an extra old header now stripped.
Under the hood · Sessions
What
The wrapper text applied to messages from peer and coordinator sessions, including the permission-laundering warning, now lives in a module of constants rather than inline.
Details
The wording of the guidance itself is unchanged.
The list of legacy prefixes stripped before re-wrapping now also matches an alternate "A peer session sent a message…" header.
Evidence
A peer session sent a message while you were working:
Artifact comment auto-scan tracks its in-flight promise #
Artifact comment scans now track their running work so overlapping scans can be spotted.
Under the hood · Artifacts
What
The debounced comment scan stores its running promise and clears it on completion, so overlapping scans can be detected rather than the scan being fire-and-forget.
Details
Promise is held in inFlightScan for the duration of the scan.
Empty effort updates no longer leave junk state behind for each agent.
Under the hood · Elsewhere
What
The per-agent UI state updater no longer materializes a store entry for a no-op write.
Details
The updater takes a materialize option.
It skips creating an entry when both the effort and the model being set are null.
Evidence
materialize
Prefilled-prompt warning notification rendered from text segments #
The external-link prompt warning is built differently but looks exactly the same.
Under the hood · Terminal UI
What
The pinned warning shown for pre-filled and deep-link prompts is now built as plain text segments rather than a rendered element. Nothing visible changed.
Details
The notification is pushed as segments produced by a small helper instead of a JSX element
A JSX segment-list component was removed
User-visible strings are unchanged, including "Prompt from an external link" and the scroll/review suffixes
Evidence
Prompt from an external link
Tool-input string extraction hardened against hostile objects #
Reading tool inputs is now hardened so a crafted object cannot run code during extraction.
Under the hood · Permissions
What
The helper that pulls values like command, file_path, prompt and args out of tool input no longer trusts the shape of the object it is given.
Details
Rejects Proxy objects outright.
Reads own property descriptors rather than invoking getters, so extraction cannot run attacker code.
Bails on array-like values whose length is not a safe integer or exceeds the cap.
Evidence
OYa.types.isProxy(e)
Shell output handoff can be re-rooted for adoption #
Background shell output can be relocated so another process adopting the task can still read it.
Under the hood · Elsewhere
What
Detached shell handoff accepts a root to re-anchor output files, so an adopting process can read outputs that would otherwise sit outside its tree.
Details
Takes a rerootOutputsTo root; outputs resolving outside the task-output tree are dropped and the shell is killed.
Escaping but known outputs are hardlinked, or copied when linking fails, into <root>/rerooted/<id>.output, with inode identity checks.
Task output paths and the handoff payload gained an adopt root plus mergeShellOutputReadRoots.
Evidence
mergeShellOutputReadRoots
Code-review, /simplify and batch orchestration prompts moved between modules #
Three prompt texts moved between files with their wording intact, so nothing changes for you.
/simplify
Under the hood · Elsewhere
What
Three prompt bodies were relocated into different lazily-initialised modules with no visible change to their wording.
Details
The multi-agent code-review angle text, the /simplify cleanup prompt and the Batch parallel-work orchestration prompt all moved.
One call site now returns a short bullet line rather than the full batch prompt.
Prompt wording itself appears unchanged; only placement and one call site differ.
Evidence
# Batch: Parallel Work Orchestration
Status-line notices moved from JSX to a segments array #
Status-line notices are now built as plain text pieces, so they render more consistently.
Under the hood · Terminal UI
What
Notification producers now hand back plain data instead of React elements, so the notification layer owns rendering.
Details
Each producer emits a list of {text, color, dim, bold} segments.
Affected producers: the option-as-Meta hint, the idle /clear hint, the Remote Control disconnect and unsigned-attestation warnings, the closed-issue notice and the prefilled-prompt warning.
Evidence
idle-return-hint
Bridge connect timeouts are classified for recovery reporting #
Remote connection timeouts now record whether they happened during recovery or a token refresh.
Under the hood · Remote Control
What
A repl-bridge connect timeout now records which path triggered the attempt, so timeouts during recovery can be told apart from those during a token refresh.
Details
recovery_connect_timeout is used for the auth-401, init-4091, and heartbeat-4093 recovery paths.
refresh_connect_timeout is used for a proactive token refresh.
The existing tengu_bridge_repl_connect_timeout event still fires.
Evidence
recovery_connect_timeout
Workflow prompt interpolates the parallel/pipeline item cap #
The workflow prompt now quotes the real item cap, so the stated limit matches the enforced one.
Under the hood · Elsewhere
What
The agent-workflow system prompt now substitutes the cap constant into the sentence describing how many items one parallel() or pipeline() call accepts, instead of hardcoding the number in prose.
Details
Keeps the prompt text and the enforced limit from drifting apart.
Evidence
A single parallel()/pipeline() call accepts at most ${soe} items
Remote-io warns when the drop sender notice cannot be written #
A failed remote notice write now logs a warning instead of disappearing silently.
Under the hood · Remote Control
What
The remote-io transport writes an attestation drop notice through the CCR client and now logs a warning if that write fails, rather than dropping the failure silently.
Details
New handler on the transport; the warning text is "[remote-io] drop sender-notice write failed".
Terminal color names are stored differently; nothing changes for you.
Under the hood · Elsewhere
What
The terminal color name list is now an object literal, with the lookup Set derived from its keys.
Details
Moved into a separate module init.
Evidence
magentaBright
Task output files use a memoized path and lazy directory creation #
Task output files skip repeated path work and only create folders when actually writing.
Under the hood · Elsewhere
What
Task output writing resolves its file path once per task and creates the containing directory only when the file is opened, replacing an upfront directory-creation step.
Details
<taskId>.output is resolved through a per-task path cache
The parent directory is created at open time with mkdir(dirname, { recursive: true })
The previous upfront directory creation helper was removed
The cache entry is dropped when the task output is flushed, cleared or cleaned up
Evidence
.output
Removed
2 items
"Permission denied" system messages are no longer surfaced #
You no longer see a "permission denied" line in output when a tool is blocked.
You'll notice · Permissions
What
The stream converter no longer emits a visible system message when a permission_denied event arrives, so that line disappears from output.
Details
Previously the event became a warning-level system message naming the tool and the reason.
The handler now returns an ignored result unconditionally, with no mode or flag that restores the old line.
Evidence
Permission denied:
Resume no longer validates or touches the worktree directory #
Resuming a session skips worktree checks, so no fallback to the parent folder or log line.
You'll notice · Sessions
What
Resuming a session no longer stats the recorded worktree, no longer falls back to the parent cwd with a log line when it is missing, and no longer bumps the directory's mtime.
Details
The fallback block and the associated worktree chdir and restore helpers are gone from this build.