Opus 5 replaces Opus 4.8 as the default Opus model in this release, with fast mode support, effort profiles, region variables, and pricing copy wired through, and the bundled Claude API skill docs rewritten around it including a new migration guide. Interrupt handling gained the ability to cancel an entire queued command backlog in a single round-trip, exposed to the SDK through the new interrupt_cancel_queued_v1 capability. MCP gained a DirectoryAdded hook event, environment variable expansion in policy allow and deny rules that fails closed on unsafe URLs, and reporting of servers skipped by --mcp-config. Several reliability fixes landed around memory, including fail-closed team-memory mount conflicts, recall that skips the current session's own logs, and the removal of session-wide push suppression. Fast mode unavailability now reports machine-readable reason codes so the SDK and org notifications can state the actual cause.
Official notes✓ syncedPackage@anthropic-ai/claude-codeDiffv2.1.218 → v2.1.219ProviderclaudeModelclaude-opus-5 (effort medium)
18
Use it now
71
You'll notice
31
Not switched on
18
Env Vars / Flags
Official Changelog
Official · Anthropic
Anthropic’s official release notes
Published verbatim by Anthropic for v2.1.219 — shown here alongside the source-level analysis below. Text is unmodified from the upstream changelog.
Added Claude Opus 5 (claude-opus-5), now the default Opus model — 1M context, fast mode at $10/$50 per Mtok
Added sandbox.network.strictAllowlist setting to deny non-allowlisted hosts for sandboxed commands without prompting
Added DirectoryAdded hook that fires after /add-dir or the SDK register_repo_root control request registers a new working directory mid-session
Added mcp_server_errors to the headless stream-json init event, listing --mcp-config entries skipped by config validation; terminal runs print a startup warning
Added the workflowSizeGuideline settings key so the advisory Dynamic workflow size guideline can be set from any settings file; the /config row is hidden while one does
Added nested subagent forwarding in stream-json: subagents spawned at depth-2+ now appear when --forward-subagent-text is set, keyed by their spawning Agent tool_use id
Fixed claude -p text output dropping the answer already produced when a turn dies on a mid-stream API error
Added HTTP status and error text to claude mcp list and /mcp when a server fails to connect, and a warning for MCP config values with hidden leading or trailing whitespace
Fixed the Fable model row showing "Requires usage credits" for plans that include it, when a stale cache had baked the label in
Fixed the /model picker showing the merged Opus row as plain "Opus" instead of "Opus (1M context)"
Fixed copy-on-select inside GNU screen printing base64 into the terminal instead of copying the selection
Fixed Remote Control clients keeping a stale fast-mode status after a model switch, reconnect, or failed org check
Fixed CLAUDE_CODE_GIT_BASH_PATH on Windows exiting or being used as bash when the path isn't a bash/sh binary; it's now ignored with a warning
Fixed Vim mode: pressing ← on an empty prompt now returns to the agent view from NORMAL mode, not just INSERT
Fixed screen-reader mode rewriting the entire input line on every keystroke instead of echoing only the typed character
Improved the "Remote Control is only available via api.anthropic.com" error to name the specific setting that caused it
Improved claude --teleport to show which repo your current checkout points at when it doesn't match the session's repo
Changed dynamic workflows to default to a medium size guideline (aim for fewer than 15 agents); pick another size or unrestricted with Dynamic workflow size in /config
Changed managed MCP allowlist/denylist ${VAR} entries to resolve from the startup environment and managed-settings env instead of settings-file env
Changed the /model picker to highlight only the newest model's name, so the highlight marks the new release rather than an arbitrary subset of the list
Added the current default workflow size to the running-workflow status line, with a pointer to /config for changing it
Removed Opus 4.7 from fast mode; /fast now applies to Opus 5 and Opus 4.8
Updated the claude-api skill to default to Claude Opus 5, with a migration path from Opus 4.8
Subagents can now spawn nested subagents up to depth 3 by default (was 1); set CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH=1 to disable nesting
Source: anthropics/claude-code · CHANGELOG.md · 24 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
43 items
Anything you can use today, anything that visibly changes, and anything worth poking at. One line each, open for detail.
Opus 5 replaces Opus 4.8 as the default Opus model #
Juicy
Opus 5 is now the default Opus, with a 1M-context option in the model picker.
opusclaude-opus-5VERTEX_REGION_CLAUDE_5_OPUS
You'll notice · Models
What
The bundled model catalog gains claude-opus-5 and the opus alias now points at it, so anything resolving the newest Opus resolves Opus 5 instead of Opus 4.8.
Details
Catalog entry: display name "Opus 5", knowledge cutoff "May 2026", 1M-token context with supports_1m_suffix, max_output_tokens default 64000 and upper 128000, pricing: "tier_5_25", default_effort: "high", fallback_3p: "claude-opus-4-8", vertex_region_env_var "VERTEX_REGION_CLAUDE_5_OPUS", and a new capability tag opus_5_prompt_bundle.
Provider ids ship for bedrock (us.anthropic.claude-opus-5), vertex, foundry, mantle (anthropic.claude-opus-5) and gateway. The opus alias resolves to claude-opus-5 for first-party, bedrock, vertex, mantle and anthropic_aws; foundry still maps to claude-opus-4-6 and gateway to claude-opus-4-7.
Three internal default-model constants changed from the literal "opus48" to "opus5", and the first-party preference order went from ["opus48","opus47","opus46","opus45"] to ["opus5","opus48","opus47","opus46","opus45"]. The alias table gained "claude-opus-5": "opus5" and latest_per_family.opus moved to claude-opus-5.
The picker shows a plain "Opus" row plus an "Opus (1M context)" variant, and Opus 4.8 is demoted to "Opus 4.8 · Previous Opus version". OPUS_NAME is now "Claude Opus 5" with the old pair kept as PREV_OPUS_ID / PREV_OPUS_NAME.
Pricing suffix lookups now query claude-opus-5, unrecognized-model fallbacks return "claude-opus-5" instead of "claude-opus-4-8", and claude-fable-5 falls back to it via fallback_3p.
The catalog data is unconditional in this build; whether a row is offered still depends on the model being available for the active account and provider, which the picker checks via provider id / modelOverrides.
Evidence
Opus 5 - best for everyday, complex tasks, Opus 5 with 1M context window - for long sessions with large codebases, opus_5_prompt_bundle, PREV_OPUS_NAME: "Claude Opus 4.8", claude-opus-5
CLAUDE_CODE_GIT_BASH_PATH no longer kills the process #
Juicy
A bad CLAUDE_CODE_GIT_BASH_PATH on Windows now warns and auto-detects instead of quitting.
CLAUDE_CODE_GIT_BASH_PATH
Use it now · Windows
What
On Windows, pointing the variable at a path that does not exist used to print an error and call process.exit(1). It now warns and carries on.
Details
Falls back to normal auto-detection instead of exiting
The path is additionally rejected unless its basename is bash.exe, sh.exe, bash or sh
Hooks gained a DirectoryAdded event that fires after a working directory is registered mid-session, so you can react to /add-dir and to SDK-driven directory registration.
Details
Described in the hook config as "After a working directory is added mid-session"; fires after the directory is registered and after the sandbox config is refreshed.
Hook input JSON carries the absolute directory and a source; the matcher can match on "slash_command" for /add-dir and "register_repo_root" for the SDK control request.
Registered in the hook config schema, the hook registry, the SDK hook-event enum and the /hooks UI.
Failure handling differs by path: for /add-dir a failure count is summarised to Claude and hook systemMessage output reaches Claude; for register_repo_root failures are debug-logged only, via "DirectoryAdded hook failed: ".
Evidence
"slash_command" for /add-dir, "register_repo_root" for the SDK control_request., After a working directory is added mid-session
SDK init message reports skipped MCP server configs #
Juicy
SDK callers get an mcp_server_errors array naming rejected MCP configs, so CI can fail on it.
mcp_server_errors
Use it now · SDK
What
The system/init SDK message now carries mcp_server_errors, so a programmatic caller can see which MCP config entries were rejected at validation time rather than silently getting fewer servers.
Details
each element is {name, type, message} for a config entry that failed validation and was skipped
entries whose server did connect anyway are filtered out of the array
the MCP config loader tags validation failures with a stable code, adding "invalid_config" alongside the existing categories
the schema note says the key is omitted when empty, and that "CI can fail on (mcp_server_errors?.length ?? 0) > 0"
the REPL bridge currently passes an empty list, so this is populated on the SDK path only
Evidence
mcp_server_errors
Workflow size guideline now defaults to medium instead of unrestricted #
Juicy
Without configuration, sessions now advise fewer than 15 agents per workflow; change it in /config.
/configworkflowSizeGuideline
Use it now · Settings
What
With no workflow size guideline configured, sessions now get a medium guideline advising fewer than 15 agents per workflow, where previously an unset value meant no guideline text at all.
Details
unset resolves to "medium" flagged as a default, injecting the advisory plus a pointer to /config
a value in a settings file, including managed settings, takes precedence and hides the /config row entirely
the settings schema description documenting this precedence is new in this build
Usage
/config
Evidence
This session has the default workflow size guideline:
register_repo_root accepts launch-time directories and rejects duplicates #
Juicy
You can register repo roots under any directory passed with --add-dir, and duplicates now say so clearly.
--add-diradditionalDirectoriesregister_repo_root
Use it now · SDK
What
The SDK register_repo_root request no longer requires the target to be a strict subdirectory of cwd, and now reports an already-registered directory as its own error instead of a subdirectory failure.
Details
the path is realpathed and confirmed to be a directory before anything else
accepted locations are directories under cwd or under any directory passed at launch via cliArg sources, that is --add-dir or the SDK additionalDirectories
registering a directory that is already a working directory fails with a dedicated error
on success, DirectoryAdded hooks are dispatched; hook failures are debug-logged and do not fail the request
the request schema description was rewritten to match
previously this threw register_repo_root: ... is not a subdirectory of cwd
Evidence
register_repo_root: directory is already a registered working directory
Headless text output recovers the last full assistant message on an incomplete run #
In headless text runs, an incomplete ending no longer swallows the last full answer.
-p
You'll notice · Headless Mode
What
In -p runs that print plain text, a run that ends incomplete no longer discards the last complete assistant message.
Details
Applies when the output format is neither json nor stream-json; the last and prior top-level assistant texts are tracked.
If the final result is a success-but-error whose text ends with "The response above may be incomplete." and equals the last assistant text, the prior assistant text is printed above the result.
Compact boundaries and superseded messages reset the tracker.
Evidence
The response above may be incomplete.
MCP connection failures can carry an extra display detail #
Failed MCP connections now tell you why, with the error detail shown in list and get output.
claude mcp listclaude mcp get
You'll notice · MCP
What
Failed MCP connections can now attach a displayDetail explaining why, and the CLI surfaces it instead of just showing a bare status.
Details
displayDetail is optional, threaded through the failure constructor and appended to the user-visible error.
The Authorization-header rejection path attaches Error detail: plus the server response body when that body is non-empty.
claude mcp list builds its status line as the status, an em dash and the issue; claude mcp get prints an Issue: line.
The "! Connected · tools fetch failed" status now carries the underlying error as its issue.
Evidence
displayDetail
Memory sync no longer suppresses pushes for the whole session #
One failed memory sync no longer silently stops all memory pushes for the rest of your session.
You'll notice · Memory Sync
What
A single memory push failure used to silently stop all further debounced pushes and change notifications for the rest of the session; suppression now applies only to individual stores.
Details
The per-scope memory watcher state dropped its pushSuppressedReason field, along with the session-wide suppression it drove (logged as "suppressing retry for the rest of this session")
The two early-returns keyed on that field are gone, and change events now always re-arm the debounce timer
Per-store suppression remains, carrying a suppressedUntilMs expiry, and the "unlink cleared store suppression for" recovery path is unchanged
Evidence
memory-watcher[, pushSuppressedReason
/plugin gained a Stats tab and /skill-doctor moved into it #
Juicy
A Stats tab in /plugin shows skill usage and context costs, with /skill-doctor redirecting there.
The plugin UI has a new stats view showing skill usage and context costs, and /skill-doctor now redirects there.
Details
New "stats" view and a tab titled "Stats"; both /plugin stats and the marketplace argument parser route to it, with help line " /plugin stats - Show skill usage and context costs".
A notice tells users "/skill-doctor moved — skill usage and context costs now live in this Stats tab."
/skill-doctor is registered as two variants, an immediate local-jsx one that renders the view and the existing local one that produces plain text in non-interactive mode, both described as "Show which loaded skills are unused and costing context".
skill-doctor was added to the command log-level map as "info".
Gated on tengu_lantern_prism (fallback false) or the CLAUDE_CODE_LANTERN_PRISM env var; the skill-doctor registration now sits on the same gate as the Stats tab.
Evidence
/skill-doctor moved \u2014 skill usage and context costs now live in this Stats tab., skill usage and context costs now live in this Stats tab.
Interaction schemas are now discovered, not hardcoded #
The artifact tool's schema option now lists whatever schemas your session actually registered.
schema
Use it now · Artifacts
What
The artifact tool's schema argument stops naming "workshop-decisions" in its description and error text and instead reports whatever the session actually registered.
Details
The available schema list is computed per session and the example in the description is taken from it
Requesting an unregistered schema returns a distinct errorCode 8 that lists the available schemas
The schema argument only exists when the session registers at least one interaction schema
Evidence
is not available in this session. Available schemas:
SDK messages now tell you exactly why fast mode was unavailable for a request.
fast_mode_disabled_reason
Use it now · SDK
What
An optional fast_mode_disabled_reason field now travels on SDK init and result messages, so a client can tell why a request could not use fast mode rather than guessing.
Details
Added to the init message and to both the success and error result message schemas.
Populated on every result path, including "tool_deferred_unavailable", "budget_exhausted" and "turn_setup_failed".
The skill documents two beta headers that did not appear in the previous build's docs.
Details
fallbacks: "default" sits behind server-side-fallback-2026-07-01 and lets the server pick the fallback by refusal category; the array form stays on server-side-fallback-2026-06-01, and pairing either header with the other form returns 400.
A new tool-use-concepts section covers mid-conversation-tool-changes-2026-07-01: tool_addition and tool_removal blocks on a role: "system" message change the tool set between turns without invalidating the prompt cache.
Tools involved must be declared with "defer_loading": True.
MCP policy URL allowlists now refuse environment variables that sneak wildcards in and widen a match.
You'll notice · MCP
What
Expanding ${VAR} inside MCP policy URL predicates now detects environment values that smuggle in wildcard semantics and refuses to treat the resulting predicate as safe.
Details
The expander gains a wildcardVars output listing offending variables.
A value counts as a wildcard if it contains after NFKC normalization, matches %2a case-insensitively, or decodes to a after percent-decoding.
A predicate whose expansion pulled in any such variable is marked unsafe alongside the existing host, hash and query checks.
Allowlist URL entries using such an expansion fail closed; denylist entries are unaffected.
The expander also gained a fallback env map so policy-settings env can supply variables missing from the process env.
Neither wildcardVars nor the check existed in the previous build; this closes a route to widening a policy match through an environment variable.
A stats subcommand for plugins would show skill usage and context costs, but it stays hidden unless a flag is on.
/plugin statsCLAUDE_CODE_LANTERN_PRISM
Not switched on · Plugins
What
The /plugin command completion list adds a stats subcommand described as showing skill usage and context costs, listed after list, enable, disable, install, uninstall and marketplace.
Details
gated on the tengu_lantern_prism flag, which falls back to false, or the CLAUDE_CODE_LANTERN_PRISM environment variable
with the gate off the subcommand does not appear in completions
Evidence
Show skill usage and context costs
Bundled workflows can gate model invocation at runtime; deep-research wired to a new flag #
Juicy
Claude could start deep research on its own instead of waiting for you to ask, if enabled.
/deep-research
Not switched on · Workflows
What
Workflow registration accepts a function for disableModelInvocation, and the bundled deep-research workflow now uses one so a remote flag can decide whether the model may invoke it.
Details
When converting a workflow to a command the code checks typeof e.disableModelInvocation === "function" and calls it; v2.1.218 only ever read a boolean.
deep-research previously registered { disableModelInvocation: !0 }, meaning user-invocable only.
It now passes a function checking gate tengu_sorrel_avocet with fallback false, so absent a remote value behaviour is identical to before.
If the gate is turned on remotely, the model can invoke deep-research itself.
Adding `pinned: true` to a memory file's frontmatter would apply it to every session automatically.
pinned: trueCLAUDE_COWORK_MEMORY_INDEX_CONTENT
Not switched on · Memory
What
Memory files whose frontmatter carries pinned: true are injected so they apply to every session rather than only when retrieved.
Details
Pinned files are scanned, sorted by mtime, capped in count, and truncated when oversized
Frontmatter documentation now describes the pinned field
New one-shot telemetry event tengu_memdir_pinned_injected reports pinned_file_count, pinned_injected_count, pinned_injected_chars, truncated and malformed counts
New scan-failure paths log "memory_scan_readdir_failed" and "pin_scan_failed"
Gated on tengu_stone_shell with fallback false, and suppressed entirely when CLAUDE_COWORK_MEMORY_INDEX_CONTENT is set
Evidence
tengu_memdir_pinned_injected
Shutdown-synthesized tool results no longer resolve an interrupted turn #
Juicy
Resuming a turn interrupted by shutdown now correctly sees the tool call as still pending instead of faked-answered.
CLAUDE_CODE_RESUME_INTERRUPTED_TURN
Not switched on · Sessions
What
When history is rebuilt to resume an interrupted turn, tool results that were only synthesized by a shutdown are no longer treated as answers, so the underlying tool call is seen as still pending.
Details
the unwind pass is called with a new option shutdownUnwindResultsDoNotResolve: !0
the affected messages are user messages with interruptedByShutdown === !0 that contain a tool_result block; these no longer resolve their tool_use and are dropped from the rebuilt list
the transcript scan for an unresolved tool_use skips those same messages, so a synthesized result cannot mask a genuinely unresolved tool use
that scan was split into a pure over-messages helper, findUnresolvedToolUseInTranscript, with I/O, warn logging and try/catch left in the async wrapper
consecutive user messages are no longer merged if either was interrupted by shutdown, and the tail-scan for the last live turn skips shutdown-interrupted content
the user-rejected tool denial path now records interruptedByShutdown from the abort signal
the whole path is reached only under the CLAUDE_CODE_RESUME_INTERRUPTED_TURN environment variable
Subagent nudging behaviour can be picked per model, but the whole feature stays behind a gate.
CLAUDE_CODE_THISTLE_GREBE
Not switched on · Subagents
What
Steer mode can now be chosen based on the model in use rather than only env, client data and growthbook.
Details
Resolver values are default, no_nudges and counter_steer
A fourth source runs after env, client data and growthbook: if a model was registered for this resolution it consults a model-keyed lookup and reports source: "model" in tengu_subagent_steer_applied
Env var CLAUDE_CODE_THISTLE_GREBE still wins over everything
Gated on tengu_thistle_grebe / CLAUDE_CODE_THISTLE_GREBE
Evidence
counter_steer
Whiteboard skill reworked with first sketch, named boards and up-front send-permission checks, still switched off #
The whiteboard skill gained opening sketches, named boards and clearer send-permission errors, but stays switched off.
--title
Not switched on · Skills
What
The whiteboard skill and its bundled page were substantially reworked, but registration still gates on a helper that returns false, so none of it is reachable.
Details
Claude is instructed to draw an opening sketch of its read of the design before anything else.
The page is built through merge-state.mjs, which gains a --title flag naming the board "Whiteboard — <topic>" and refuses to silently rename a board that was already sent.
Republishing with capabilities re-declared happens only when the user says Send to Claude is unavailable.
The bundled page restyles onto inlined Claude Design System tokens.
The Send button is now disabled at load with a specific reason when the permission state is permanently blocked, rather than the block being discovered on first click; permanent and transient permission codes are handled separately.
Toasts gain a configurable duration.
Gate: isEnabled returns PQi() && j2e(), and PQi() returns !1.
allowedMcpServers and deniedMcpServers predicates are no longer matched literally; stdio serverCommand entries and remote serverUrl patterns go through environment-variable expansion first, with a safety analysis that discards allowlist entries whose expansion changes what the pattern means.
Details
Denylist expansion uses a merged env drawn from global config, user, flag and policy settings as fallbacks; the allowlist path uses the settings-derived env.
Substituted values are normalised through a placeholder that returns the constant zzenvsubzz (or a digit-zeroed form for numeric values, :: for IPv6-looking ones) so the expanded URL can be re-parsed and compared against the original.
Flagged as unsafe: an injected value that adds wildcard semantics, changes the URL's structure or hostname, or introduces traversal or query/fragment characters.
Allowlist URL entries with an unsafe expansion are skipped, so they fail closed; denylist entries still apply.
Missing variables emit a debug warning that the predicate references environment variables not present in the policy expansion env; unsafe expansions log that the expansion was unsafe.
Neither the placeholder nor the wildcardVars analysis exists in v2.1.218, and the settings schema descriptions were not updated to mention any of it.
Evidence
zzenvsubzz, MCP policy URL predicate expansion was unsafe
A strictAllowlist boolean on sandbox network settings makes the sandbox runtime deny hosts outside allowedDomains outright instead of prompting. The runtime check existed before but there was no way to turn it on.
Details
Added to the sandbox network settings schema and propagated through settings merging (if (o.strictAllowlist === !0) l.strictAllowlist = !0;), derived from any of user, managed or CLI settings
The runtime permission check is if (!r || Hl.network.strictAllowlist); a host matching no rule is denied rather than prompted when this is on
Honoured only from user, managed/policy or --settings sources; per its own description project settings (.claude/settings.json and .claude/settings.local.json) are ignored
Described as "Enforced for sandboxed commands only"; in-process tools such as WebFetch are not gated by it
Absent by default, so behaviour is unchanged unless configured
the sandbox runtime deterministically denies hosts not in allowedDomains instead of prompting, When true, the sandbox runtime deterministically denies hosts not in allowedDomains instead of prompting.
SDK interrupt can now cancel everything queued in one round-trip #
Juicy
Send interrupt with cancel_queued true to stop the current turn and everything queued behind it.
cancel_queuedinterruptcancel_async_message
Use it now · SDK Protocol
What
The interrupt control_request takes a new optional boolean cancel_queued that sweeps the whole main-thread queue along with the abort, so a remote UI can offer a "Stop means stop everything" button without walking uuids one at a time.
Details
When true, every uuid-stamped main-thread command still queued, and any already dequeued for the imminent turn, is cancelled alongside the abort and emits a terminal 'cancelled' lifecycle
The response returns those uuids under a new cancelled array, with still_queued always empty
A wrapper that wants per-uuid control leaves the flag false and keeps using cancel_async_message
Absent or false preserves the existing interrupt_receipt_v1 behaviour exactly
When true, the interrupt also cancels every uuid-stamped main-thread command still in the queue
interrupt control request can now cancel the whole queue (cancel_queued) #
Juicy
An interrupt can now clear your whole queued command backlog at once and report what it cancelled.
cancel_queuedinterrupt_cancel_queued_v1
Use it now · SDK Protocol
What
The control-protocol interrupt request accepts an optional cancel_queued boolean that clears queued main-thread commands along with the in-flight turn, and reports which uuids it killed.
Details
When cancel_queued === !0, every uuid-stamped main-thread command still queued, including ones dequeued for the imminent turn but not yet reachable by the abort, gets a terminal cancelled lifecycle event.
The response comes back with still_queued: [] and the cancelled uuids on a new optional cancelled field.
Without the flag, the previous still_queued behaviour is unchanged.
The capability string interrupt_cancel_queued_v1 is advertised on system/init next to interrupt_receipt_v1 and msg_lifecycle_v1, so clients can feature-detect it. None of these strings exist in v2.1.218.
The in-process SDK client's interrupt() wrapper does not send the flag, so this is for control-protocol consumers only.
Left-arrow backgrounding refuses to eat an unsent draft #
Left-arrow no longer backgrounds agents while you have unsent text, so drafts survive.
You'll notice · Input Editor
What
Pressing left-arrow to open or background agents is blocked while there is unsent text in the input box, so a draft is no longer lost to the shortcut.
Details
the block shows an explanatory message telling you to send or clear the text, noting that double-tapping esc clears it
it emits tengu_left_arrow_blocked with reason draft
the editor disarms the pending left-arrow confirmation on any non-left keypress and when history up or down is used
Evidence
you have unsent text in the input. Send it or clear it first (double-tap esc clears)
MCP servers skipped by --mcp-config are now reported #
MCP servers rejected from --mcp-config are now listed on stderr and in the init message instead of vanishing.
--mcp-configmcp_server_errors
You'll notice · MCP
What
Servers passed via --mcp-config that fail validation are no longer silently absent; they are collected, surfaced on the SDK init message, and printed to stderr on a TTY.
Details
Validation warnings carrying mcpErrorMetadata.skipReason and a server name are collected, and servers that ended up unregistered are recorded
A new optional mcp_server_errors array on the system/init payload lists each skipped entry with name, a stable type category (unknown_type, url_missing_type, invalid_config, reserved_name) and a message, filtered to servers with no live client
On a TTY the same list is printed to stderr as a control-character-scrubbed warning
Affected servers no longer appear only as gaps in mcp_servers[], so CI can fail on a non-empty list
Also new on init: fast_mode_disabled_reason
Neither the collection nor the init-message field existed in 2.1.218
Evidence
MCP server config entries from --mcp-config that failed validation and were skipped, skipped due to invalid config
Opus 5 gets an extra system-prompt instruction restricting AgentTool, workflows and deep-research #
Juicy
On Opus 5, Claude is told not to spawn subagents, workflows or deep research unless you ask.
You'll notice · System Prompt
What
Models carrying the opus-5 prompt bundle now receive a built-in instruction telling Claude not to spawn subagents or run workflows and deep-research unless the user asked for it.
Details
the tengu_heron_brook injection previously came only from client data or the remote flag string; it now falls back to a built-in two-line block
the fallback applies when the model carries the opus_5_prompt_bundle capability
killswitch is tengu_fennel_godwit
the applied event still fires as tengu_heron_brook_applied with fromClientData: !1 on this path
Evidence
Do not use workflows or deep-research unless the user requested it
Plan mode could offer an interactive published page where your choices feed back into the plan.
Not switched on · Plan Mode
What
Plan mode can offer to plan through a published interactive workshop page whose choices feed back into the session, backed by a .workshop.md document alongside the plan file.
Details
Plan-mode attachments gained workshopOfferDocPath and workshopActiveDocPath, which inject the offer text and the active-session text respectively.
Sparse reminders append "and the session's workshop document (…, editable and publishable as previously granted)"; the full form grants create/edit plus Artifact publish for it.
Turn-ending rules gain a third exit, publishing the workshop and ending the turn, and Phase 4's "only file you can edit" line becomes conditional.
The plan file stays canonical; the offer is made once, after judging whether the task has substantive decision points. Forking a plan also copies the .workshop.md sibling, and session resume can rebuild the doc from a file snapshot ("Workshop doc recovered from file snapshot").
Artifact publishing paths thread a workshopSurface flag through their result payloads. New telemetry: plan_workshop_offer and plan_workshop_active.
Gated on Wst() = Xde() && !bV() && !Ke("tengu_cedar_transom",!1) && Ke("tengu_larch_pavise", !1), so off absent remote values.
Evidence
A decision workshop is in progress for this session, ## Interactive Workshop Option, workshopActiveDocPath
Cap how big Claude's dynamic workflows get with a new workflowSizeGuideline setting.
workflowSizeGuideline/config
Use it now · Workflows
What
A settings key that gives Claude an advisory size hint for the dynamic workflows it writes, with four accepted values.
Details
Accepts "unrestricted", "small", "medium" or "large": small is under 5 agents, medium (the default) under 15, large under 50
A settings-file or managed value takes precedence over the "Dynamic workflow size" row in /config, and that row is hidden entirely while a settings file supplies the key
The /config row now also shows whether the current value is the default
The /config row appears only when the workflows feature is on
Usage
{"workflowSizeGuideline":"small"}
Evidence
Advisory size guideline for the dynamic workflows Claude writes
Skill listing tracks a modified timestamp from frontmatter #
Juicy
You can add a modified date in skill frontmatter to influence which skills get pinned.
modified
Use it now · Skills
What
Skill and memory file listings read an explicit modification time from frontmatter, which feeds the recency ordering used when picking pinned candidates.
Details
A modified frontmatter field is parsed into modifiedMs.
When the field is missing or unparseable, the file mtime is used instead.
Evidence
modifiedMs
Subagent-delegation nudges can now be suppressed by the model itself #
Juicy
Subagent delegation nudges are now switched off for Opus 5; you can also control them by env var.
CLAUDE_CODE_THISTLE_GREBE
Use it now · System Prompt
What
The prompt block that nudges Claude to delegate to subagents can be turned off based on the model, not just by env var, client data or remote config.
Details
resolution order was env CLAUDE_CODE_THISTLE_GREBE, then client data, then growthbook; a fourth model-derived resolver was added
the model resolver returns no_nudges for models carrying the opus_5_prompt_bundle capability, suppressing the "## Delegating to subagents" block
telemetry reports source: "model" when this path decides
Evidence
tengu_subagent_steer_applied
Workflow size guideline gets a default and a policy override #
Workflow size now defaults to medium, and an admin policy setting overrides whatever you chose.
/config
Use it now · Configuration
What
The workflow size guideline now resolves to medium when nothing is configured, and a value set in policy settings takes precedence over the user's own setting.
Details
The resolver returns { size, isDefault }.
Prompts distinguish the two cases: "This session has the default workflow size guideline:" versus "A workflow size guideline is configured for this session:".
The /config pointer is only shown when the value is the default.
The unrestricted notice was reworded to "Workflow size is now unrestricted — no size guideline applies." and no longer attributes the change to the user.
Evidence
Workflow size is now unrestricted — no size guideline applies.
Opus 5 wired through region env vars, refusal fallbacks and pricing copy #
Juicy
An Opus 5 model is wired through region variables, fast mode, 1M context and pricing text.
VERTEX_REGION_CLAUDE_5_OPUS
You'll notice · Models
What
Supporting plumbing for a new Opus 5 model lands across region selection, effort/speed handling, context eligibility and billing copy.
Details
VERTEX_REGION_CLAUDE_5_OPUS joins the recognized Vertex region environment variables.
The effort/speed table treats claude-opus-5 like claude-opus-4-8 for fast mode.
1M-context eligibility now matches on claude-opus-5, and the internal model-family list gains "opus5" ahead of "opus48".
The upsell/pricing copy branch keys on claude-opus-5 instead of claude-opus-4-8.
The system-prompt blurb drops Opus 4.8 and now reads "The most recent Claude models are the Claude 5 family and Haiku 4.5."
Some Mythos-era strings were deleted, including one reading "This model's safeguards flagged this message. This sometimes happens with safe, normal conversations."
Evidence
VERTEX_REGION_CLAUDE_5_OPUS
Auto-mode permission classifier can emit a numeric severity instead of a yes/no block #
Juicy
Auto-mode permission checks can score risk 0-100 instead of yes/no, but only for configured models.
Not switched on · Permissions
What
When a severity config exists for the current model, the auto-mode classifier prompt is rewritten to ask for a numeric score rather than a block decision. Without that config the prompt keeps its existing form.
Details
the trailing "## Output Format" section is replaced to demand <severity>N</severity> on a 0 to 100 scale, with 50 as the allow/block boundary, instead of <block>yes/no</block>
gated on severityByModel in tengu_auto_mode_config; models absent from that map take the unchanged path
the permission rules injected into the classifier prompt are wrapped in <cc_automode_permissions> tags
denials taken because auto-mode is active use a distinct user-facing message naming the mode
Evidence
Permission to use ${e} has been denied because Claude Code is running in don't ask mode.
Memory recall could pick documents from a search index instead of asking the model, but it is disabled.
Not switched on · Memory
What
Memory recall has a new branch that selects documents from a search index rather than asking the model to pick, switched off in this build.
Details
The search entry point takes four extra arguments; when the first is true the new branch uses searchMemoryFilesWithIndex in place of the model-driven memory selector.
Emits a memory_recall_select event with via_index, candidate_docs, index_query_term_count, index_hit_count, index_below_floor_count, index_top_score, index_relevance_floor, index_loaded_from_disk, index_took_ms, index_store_held, index_open_wait_ms and index_store_open_ms.
Memory files marked pinned would be injected into every conversation instead of waiting to be recalled.
pinnedCLAUDE_COWORK_MEMORY_INDEX_CONTENT
Not switched on · Memory
What
Memory files can mark themselves pinned in frontmatter and are then injected as their own prompt section on every conversation rather than listed with ordinary memory files.
Details
metadata.pinned is parsed into a pinnedState of true, false or malformed; the most recently modified pinned files are selected up to a cap and read as a new AutoMemPinned entry type.
Rendered as a dedicated section of <pinned-memory path="…"> blocks with control characters stripped from the path, and excluded from the ordinary memory-file editor list.
Telemetry: memory_pinned_inject records injected counts, truncation, malformed pins and cap drops; tengu_memdir_pinned_injected records counts plus truncated/malformed; tengu_memdir_pin_write fires on writes to memory files.
Lives in the cowork memory path, running only when the surrounding index gate passes and the CLAUDE_COWORK_MEMORY_INDEX_CONTENT env var is unset.
Evidence
# Pinned memories (apply to every conversation), AutoMemPinned
A skills stats tab can report unused skills, and /skill-doctor gains a version that works without an interactive UI.
/skill-doctor/pluginCLAUDE_CODE_LANTERN_PRISM
Not switched on · Plugins
What
The Stats tab in the /plugin dialog now receives the context it needs to report unused skills, and a non-interactive variant of /skill-doctor is registered.
Details
the tab is handed a getSkillStatsInputs callback supplying commands, MCP commands and clients, agent id, main-loop model and permission mode
rendering the tab without that callback throws "Stats tab rendered without getSkillStatsInputs"
a second /skill-doctor command variant is registered alongside the existing JSX one, marked supportsNonInteractive and dispatching after text
still behind tengu_lantern_prism (fallback false) or the CLAUDE_CODE_LANTERN_PRISM environment variable
Evidence
Show which loaded skills are unused and costing context
Reserved keybinding action ids for a "strip" surface #
Juicy
Thirteen keybinding names for a surface called "strip" are accepted but do nothing if you bind them.
The list of recognised keybinding action ids gained thirteen entries for a surface called "strip", with no handler present in this build.
Details
the new ids are strip:jump1 through strip:jump9, plus strip:next, strip:previous, strip:toggle and strip:new
the names appear nowhere else in the bundle, so binding them validates but does nothing
this looks like groundwork and validation only
Evidence
strip:toggle
The workshop skill moved from hard-disabled to flag-gated #
Juicy
The workshop skill went from permanently off to flag-gated, so remote config could switch it on.
Not switched on · Skills
What
The workshop skill's isEnabled was a function that returned false unconditionally; it is now a composite check, so it can appear for users whose remote config and Artifact tool schema both line up.
Details
Gated on the artifacts flag tengu_gable_onyx_sluice, whose fallback is false, so it stays off absent a remote value
Additionally requires the Artifact tool schema to expose a capabilities input and a read_page_data action
All three conditions must hold before the skill is offered
Evidence
tengu_gable_onyx_sluice
Everything else · 123
Smaller changes and internals, grouped as the pipeline found them. Nothing is dropped, it is only further down.
New Features
9 items
register_repo_root accepts launch-time roots and rejects duplicates #
Registering a repo root now accepts launch-time --add-dir roots and clearly rejects duplicates or bad paths.
--add-dirregister_repo_root
You'll notice · SDK Protocol
What
The SDK control request for registering a repo root now accepts more legitimate targets and fails loudly on cases it previously handled silently or not at all.
Details
Previously the target only had to be a subdirectory of cwd; it now also accepts subdirectories of directories registered at launch via --add-dir.
Rejects cwd itself with a dedicated message, rejects paths that are not directories, and rejects an already-registered directory instead of silently re-running registration.
Rejection message names both accepted roots: "is not a subdirectory of cwd or of a launch-time --add-dir root".
The tool description now states that the registration pipeline and DirectoryAdded hooks do not re-run on a duplicate.
Evidence
is not a subdirectory of cwd or of a launch-time --add-dir root
Upgrade links now carry a per-surface UTM campaign #
Upgrade links now include tracking parameters so each entry point is attributable.
/upgrade
Under the hood · Elsewhere
What
Every link into the Max upgrade flow is now built with source, medium and campaign query parameters instead of pointing at the bare upgrade URL, so each entry point is attributable.
Details
The flow builds https://claude.ai/upgrade/max?utm_source=claude_code&utm_medium=cli&utm_campaign=<surface>.
Surfaces in use: pro_trial_expired_dialog, rate_limit_options_menu, and upgrade_command from the /upgrade command.
The pro-trial-expired dialog was also switched to the same shared entry point the rate-limit options menu already used.
The API skill's model placeholders now resolve to Claude Opus 5, with the previous Opus kept as a separate placeholder #
The API skill's model placeholders now render Opus 5, keeping the previous Opus named separately.
/claude-api
You'll notice · Skills
What
The substitution map that renders the bundled claude-api skill docs moved OPUS_ID/OPUS_NAME onto Claude Opus 5 and added two keys for the outgoing model.
Details
Every doc writing model="{{OPUS_ID}}" now emits the new ID, as do the deprecation targets and the Bedrock ID table.
The alias table keeps opus and adds an opus 5 row.
PREV_OPUS_ID/PREV_OPUS_NAME carry claude-opus-4-8 so migration text can name both.
The /claude-api skill is registered with no isEnabled gate, so this is what users of that skill get on this build.
Evidence
OPUS_ID: "claude-opus-5"
New protocol capability interrupt_cancel_queued_v1 on system/init #
Sessions now advertise a capability string so clients can detect queue-cancelling interrupts without version checks.
interrupt_cancel_queued_v1
Under the hood · SDK Protocol
What
The capabilities array advertised at init gains a second entry next to interrupt_receipt_v1, letting SDK consumers feature-detect cancel_queued support instead of sniffing the CLI version.
Details
Capability string is interrupt_cancel_queued_v1
The capability list is built unconditionally in this build, so it is present for every session
Pairs with the cancel_queued field on the interrupt control_request
Evidence
'interrupt_cancel_queued_v1' = the interrupt control_request honors cancel_queued:true
Workshop artifacts get a parse and serialize fixed-point check at publish time #
Workshop artifacts that would silently mutate on republish are now blocked at publish time.
You'll notice · Artifacts
What
Pages the verifier classifies as a workshop surface are re-parsed and re-serialized before publishing, and the publish is refused if the round trip changes anything. This catches artifacts that would silently mutate on every decision confirm, since each confirm republishes the page.
Details
two checks run: the round-tripped page must still pass the strict contract, and a second round trip must produce byte-identical output
two new violation rules, reparse-divergence and reparse-not-fixed-point, block the publish and point at the first divergence
only reached for pages that verify as a workshop surface; other pages are unaffected
The local model listing endpoint now includes Opus 5 among its available keys.
opus5
Under the hood · Models
What
Opus 5 now appears in the model enumeration served by the built-in SDK/proxy model-listing endpoint.
Details
The list of model keys now includes "opus5" alongside "opus48" and "fable5".
Evidence
"opus5"
Bundled Claude API skill docs rewritten around Opus 5 #
The bundled Claude API skill docs now target the new Opus, covering thinking defaults, fallbacks and fast mode.
/claude-api
You'll notice · Skills
What
The vendored claude-api skill documents were retargeted from a hardcoded model ID to placeholders resolving to the new Opus, with new guidance on thinking defaults, refusal fallbacks and fast mode.
Details
Python, Go and Ruby guides, the error-code reference, the managed-agents reference and the top-level skill all replace claude-opus-4-8 with {{OPUS_NAME}}/{{OPUS_ID}}, and add a {{PREV_OPUS_NAME}}/{{PREV_OPUS_ID}} row.
On the new Opus, thinking is on by default, so omitting thinking runs adaptive; {type: "disabled"} is accepted only at effort high or lower and returns 400 at xhigh or max.
A new pitfall section covers the two failure modes of disabling thinking.
Refusal fallbacks gain a scalar form fallbacks: "default" under beta header server-side-fallback-2026-07-01; the array form keeps -2026-06-01 and mixing the two returns 400.
Fast mode is documented as new-Opus/4.8 only and Claude API only, with Opus 4.7 fast mode removed rather than deprecated, plus a note that Priority Tier does not cover the new Opus.
Mid-conversation system messages are documented for several models rather than one.
Evidence
server-side-fallback-2026-07-01
New "Migrating to {{OPUS_NAME}}" migration guide with two breaking changes #
A migration guide now spells out the two thinking-related changes that break existing API request code.
You'll notice · Skills
What
shared/model-migration.md gains a section for the new Opus covering the two behaviours that break existing request code.
Details
Breaking change 1: thinking is on by default when thinking is omitted, a silent cost and truncation change measured against max_tokens.
Breaking change 2: thinking: {type: "disabled"} is accepted only at effort high or lower; pairing it with xhigh or max returns 400, validated per request.
Documents disabled-thinking failure modes: tool calls emitted as plain text, and <thinking> tag leakage.
Also notes a 512-token cache minimum, a separate rate-limit bucket, and adds a [BLOCKS]/[TUNE] checklist.
Older Opus rows in the migration table now all target the new ID.
Evidence
### Breaking change 2: disabling thinking is capped at
Safety interruptions now show dedicated wording and a link about the Cyber Verification Program.
You'll notice · Elsewhere
What
Cyber-safeguard interruptions now have their own user-facing text, pointing at the Cyber Verification Program as a way to reduce how often they happen. A new support article URL is used when the flagged model is Opus 5.
Details
new strings cover the cyber-category refusal case specifically, separate from the generic safeguard message
the dedicated support link is selected on the Opus 5 path
Evidence
Apply to the Cyber Verification Program to reduce these interruptions.
Improvements
39 items
Fast mode advertised on Opus 5 in the environment prompt #
Claude is now told Fast mode applies to Opus 5 as well as earlier models.
Under the hood · Models
What
The two environment-info prompt builders that describe Fast mode now list Opus 5 alongside 4.8 and 4.7, so the model is told Fast mode applies to the new default.
Details
Applies to both environment-info prompt builders.
No gate; the line is emitted for everyone.
Evidence
It can be toggled with /fast and is available on Opus 5/4.8/4.7.
Org-disabled fast mode notification now states the actual reason #
The startup notice about Fast mode being off now names the actual reason instead of a generic line.
You'll notice · Models
What
The startup notice about Fast mode being turned off no longer prints a generic organization message; it prints the specific sentence derived from the reason code.
Details
The old text "Fast mode has been disabled by your organization" is gone.
The notification is skipped entirely when no reason resolves.
It fires only when the disabled state came from the server, not from a local guess.
After compaction, Claude stops wasting its re-read budget on memory files it already injects.
CLAUDE.md
You'll notice · Compaction
What
After compaction, the routine that re-reads recently touched files no longer spends its budget re-reading CLAUDE.md-family memory content that is injected anyway.
Details
Builds a set of canonical memory-file paths for every scope in ["User", "Project", "Local", "Managed", "AutoMem"] and filters them out, alongside the agent's own memory file.
A new optional parameter also excludes non-truncated pinned memory-directory entries; that exclusion applies only when the caller opts in and the pinned-memory precondition holds.
Partial compaction (compact_partial) now also passes the message list so the plan-mode attachment is regenerated, and opts into the pinned-file exclusion.
Evidence
tengu_post_compact_file_restore_success, AutoMem
Org memory no longer auto-selects a lone candidate store #
When only one org memory store is found, it is no longer picked for you automatically.
CLAUDE_CODE_DISABLE_ORG_MEMORY
You'll notice · Memory
What
Discovery finding exactly one candidate memory store no longer silently selects it; the choice is left to you.
Details
Three call sites that auto-set the store when a single candidate existed (onlyIfAbsent) were removed, and the helper is gone from the build.
Discovery still records org_memory_discovery telemetry and populates the candidate list.
Org memory overall still requires the tengu_haze_glass gate and respects CLAUDE_CODE_DISABLE_ORG_MEMORY.
Evidence
org_memory_discovery
Prompt-caching doc rewrites the minimum-cacheable-prompt table and adds cache-preserving escape hatches #
Caching docs now list per-model minimums and which request changes keep your cache alive.
You'll notice · Prompt Caching
What
The per-model minimum table was regrouped and a new table lists which top-level request changes can be made without dropping the cache.
Details
Minimums run from 512 tokens for the newest models up to 4096 for Opus 4.6/4.5 and Haiku 4.5, with an explicit note that the value is not monotonic across generations.
The old Amazon Bedrock override is documented as removed.
Cache-preserving forms: tool definitions via tool_addition/tool_removal (beta), and system-prompt content via a role: "system" message with no beta header.
Model switch has no escape hatch.
Mid-conversation system-message availability widens from one model to four, with a caveat that sources conflict on Sonnet.
Evidence
The minimum is not monotonic across generations
Managed-agents docs: mid-session system.message model gate widened, plus two path/method typo fixes #
Mid-session system messages now work with more models, and two doc references were corrected.
sessions.events.list()
You'll notice · Elsewhere
What
The documented model gate for mid-session system messages now covers more models, and two incorrect references were corrected.
Details
The gate list adds the previous Opus alongside the new one, Sonnet, Fable and Mythos; the rejection error name is unchanged.
The polling troubleshooting note now names GET /v1/sessions/{id}/events/stream as the endpoint you may have hit by mistake, where it previously named the paginated endpoint twice.
The overview's SDK advice corrects session.events.list() to sessions.events.list().
Code reviews on Opus 5 use a tighter prompt: one diff pass, at most fifteen findings.
git diff @{upstream}...HEAD
You'll notice · Code Review
What
A new minimal review prompt is selected for both the medium and high review levels when the review model is claude-opus-5.
Details
Prompt cell is named o5-bmin
Instructs a single careful diff pass over git diff @{upstream}...HEAD, falling back to main...HEAD then HEAD~1, plus git diff HEAD for uncommitted work
Caps output at 15 findings, submitted through the review tool and restated one per line in the reply
Not used for other review models
Evidence
minimal prompt \u2192 single careful diff pass \u2192 \u226415 findings
Left-arrow session exit now blocks on unsent input #
Pressing left-arrow to leave a session now warns you when unsent text is still sitting in the input box.
You'll notice · Session Exit
What
The confirmation guarding a session exit, which previously fired only for queued commands or background tasks, now also fires when the input box still holds text you have not sent.
Details
The prompt tells you to send or clear the input first
Queued-command and background-task cases are unchanged
Evidence
you have unsent text in the input
Screen-reader rendering gains an incremental append fast path #
Screen-reader output redraws less, appending only new characters when the line is still anchored.
You'll notice · Elsewhere
What
When the only change to a frame is text appended to the current row and the frame is anchored, the renderer writes just the new characters plus cursor moves rather than redrawing the tail of the output.
Details
an anchor state of "clean", "lastRowAnchored" or "broken" decides when the fast path is safe
a broken anchor falls back to the existing redraw of the tail
lives in the screen-reader rendering path
Evidence
lastRowAnchored
Bundled SDK reference docs updated for the new Opus #
Bundled Java and PHP API docs now describe thinking defaults and a new XHIGH effort level.
You'll notice · Elsewhere
What
The Java and PHP API reference documents shipped inside the binary describe thinking behaviour for the new Opus model.
Details
thinking is on by default for the new Opus, and omitting it runs adaptive, unlike Opus 4.8 and 4.7
ThinkingConfigDisabled (Java) and ['type' => 'disabled'] (PHP) are accepted only at effort high or lower; XHIGH and MAX return 400
XHIGH added to the listed effort enum values
the basic Java example switches to the .model(String) overload, and the refusal-fallback example now points at the previous Opus id
Safeguard refusals are now a one-liner, with longer explanations only for category-flagged cases.
You'll notice · Elsewhere
What
The message shown when a model's safeguards flag your message is shorter and no longer references a model generation, and the longer explanation is now reserved for category-flagged refusals.
Details
the old paragraph beginning "The safeguards are intentionally broad right now and may flag safe and routine coding, cybersecurity, or biology work" is gone, along with the Mythos-capabilities sentence
the assembled string They may flag safe, normal content as well. was removed
the generic case is now a one-liner; the longer explanation appears only for category-flagged refusals
a cyber-category refusal, when the relevant check passes, gets its own message pointing at the Cyber Verification Program plus a dedicated support link
the refusal body reads "can't respond to this message with" rather than "this request with"
Evidence
This sometimes happens with safe, normal conversations., Our intentionally broad safeguards allow us to deliver more capabilities faster, but can sometimes flag legitimate coding, cybersecurity, and biology tasks.
Artifact page-data reads now reject unknown schemas up front and list valid options instead.
read_page_data
You'll notice · Artifacts
What
The artifact read_page_data action validates the requested schema against what the session actually offers and fails with a dedicated error code instead of attempting a lookup.
Details
The check runs before any lookup and throws its own error code on mismatch.
The tool description is generated with the concrete list of available schema names inlined, so the model sees valid options up front.
Evidence
read_page_data: the requested interaction schema is not available in this session.
API-error assistant messages round-trip through the SDK #
Resumed sessions can now still tell which past messages were API errors rather than real replies.
Under the hood · Sessions
What
Assistant messages flagged as API errors keep that flag across serialization, so a resumed or replayed session can distinguish them from real assistant output.
Details
Transcript serialization emits is_api_error_message: !0 for such messages.
The reverse conversion maps it back to isApiErrorMessage.
This joins the existing aborted and is_virtual flags.
Duplicate workshop doc snapshots are no longer written repeatedly, keeping your transcript smaller.
You'll notice · Elsewhere
What
Repeated identical workshop doc snapshots are no longer written to the transcript, cutting duplicate large entries.
Details
The file_snapshot transcript writer remembers the last workshop doc recorded for the current session and skips writing an identical one again
It stores { sessionId, doc } after a successful record
The oversize guard ("Workshop doc over snapshot cap") is unchanged
Evidence
file_snapshot
Generic denial message when permission prompts are unavailable #
Tool denials in background agents now say permission was denied instead of wrongly blaming don't-ask mode.
You'll notice · Permissions
What
The async-agent path that refuses a tool because permission prompts are not available in that context now says "Permission to use X has been denied." rather than blaming don't-ask mode.
Details
the longer wording naming don't-ask mode still exists and is now used only by the don't-ask-mode paths
the two situations are no longer conflated in the message shown to the user
Evidence
has been denied because Claude Code is running in don't ask mode.
Memory-file truncation warning distinguishes index from topic files #
When a memory file gets truncated, the warning now gives advice that fits the file type.
You'll notice · Elsewhere
What
The warning appended when a memory file is truncated for size now says something different for a regular memory file than for the index.
Details
the warning takes a kind argument defaulting to "index"
for a regular memory file it says "this memory file is …" and advises keeping each file focused on one topic
for the index it keeps the advice to keep entries short
the byte-limit phrasing branches on the same argument
Corrupt timestamps in session files can no longer confuse which sessions look live.
Under the hood · Sessions
What
Epoch timestamps read from session sidecar files are now validated before use, so a corrupt or garbage value cannot skew live-session discovery.
Details
The peer-session module exports a new isSaneEpochMs predicate and a MAX_SANE_EPOCH_MS constant set to 4000000000000000.
Non-finite, negative and absurdly large epoch values are discarded rather than passed through.
Not gated; active for everyone.
Evidence
MAX_SANE_EPOCH_MS
Fast mode unavailability reworked into machine-readable reason codes #
Fast mode unavailability is tracked as reason codes internally, feeding clearer messages and telemetry.
fast_mode_disabled_reason
Under the hood · Models
What
The check for why Fast mode is unavailable now returns a code rather than an English sentence, with a separate function that turns the code into the user-facing text.
Details
Codes include not_first_party, disabled_by_env, model_not_allowed, sdk_opt_in_required, pending, plus server-supplied reasons such as extra_usage_disabled.
Telemetry gains a fast_mode_disabled_reason field with a schema enum for the codes.
The org-status cache records provenance as source: "guess" or source: "server", and only emits a change event when the value or the reason actually changed.
Evidence
sdk_opt_in_required
Remote Control now explains exactly which endpoint setting blocks it #
When Remote Control refuses, it now names the exact setting or variable blocking it.
ANTHROPIC_BASE_URL
You'll notice · Remote Control
What
The one-line refusal about Remote Control needing api.anthropic.com is now followed by a diagnosis of the specific configuration in play.
Details
Separate sentences for gateway sessions, Bedrock/mantle, and a custom ANTHROPIC_BASE_URL, each naming the environment variable to unset.
Explicitly notes that the assume-first-party escape hatch does not lift the restriction.
Evidence
_CLAUDE_CODE_ASSUME_FIRST_PARTY_BASE_URL does not apply to Remote Control.
Your MCP allow and deny rules now match servers whose commands or URLs use environment variables.
allowedMcpServersdeniedMcpServers
You'll notice · MCP
What
Matching a server against allowedMcpServers and deniedMcpServers now expands environment-variable references in the configured command and URL before comparing, so rules match what actually runs rather than the literal template.
Details
The deny path uses a fallback env when expansion needs one.
An allow-rule URL whose expansion is flagged unsafeExpansion is skipped rather than treated as a match.
A separate new validator flags untrimmed whitespace in MCP config command, url, args, and env/header names and values.
Evidence
unsafeExpansion
Memory recall skips the current session's own logs #
Memory recall no longer feeds a session its own transcript notes back to itself.
You'll notice · Memory
What
Candidate memory files belonging to the running session are now filtered out, so a session cannot recall its own transcript notes back into itself.
Details
A predicate passed into memory recall rejects any candidate under logs/ whose basename is <id>.md or starts with <id>-, where <id> is the first 8 characters of the current session identifier.
Built defensively: returns undefined if the session id cannot be read, in which case no filtering is applied.
Evidence
if (!r.startsWith("logs/")) return !1;
Tools can opt out of the aggregate tool-result budget #
Individual tools can now skip the shared output size budget and just use the hard ceiling.
Under the hood · Elsewhere
What
A tool definition can now declare that its output is not subject to the shared tool-result budget lookup.
Details
The tool-result size limiter takes a new fourth argument; when set it clamps straight to the ceiling instead of consulting the per-tool remote-config override.
The caller passes e.skipAggregateToolResultBudget === !0 from the tool definition, so the behaviour is gated per tool.
Evidence
skipAggregateToolResultBudget
Advisor tool result payload is now a discriminated union that can be encrypted #
Advisor tool results can come back encrypted with no text field, so reading .text may find nothing.
You'll notice · Elsewhere
What
The advisor-tool docs warn that advisor_tool_result.content differs by advisor model, so code that reads .text unconditionally can silently get nothing.
Details
Plaintext advisors return advisor_result with text and stop_reason.
The newest advisors return advisor_redacted_result with encrypted_content and no text.
The executor-to-advisor compatibility table is expanded with the new Opus, Fable and Mythos IDs.
Evidence
advisor_redacted_result
Background-agent daemon upgrade check is prerelease-channel aware #
Background agent daemons stop mistakenly retiring themselves when you run prerelease builds.
You'll notice · Elsewhere
What
The stale-daemon retire decision and the generic version-newer comparison now understand prerelease channels, so an -engine. build is no longer compared as if it were stable.
Details
A version's prerelease channel is extracted before comparison; the recognized channels are ["dev", "engine"].
If the two versions carry different channels, neither is treated as newer than the other.
If either side is a prerelease and both cannot be parsed as dated builds, the comparison returns false.
Previously the check only special-cased the substring -dev..
Evidence
daemonVersion
Republishing an artifact page now verifies it came from this CLI build #
Republishing an artifact page fails if it was built by a different CLI version; re-run the command.
/artifact-pr-review
You'll notice · Artifacts
What
Republish checks the stored page against this build's template and refuses when they have drifted, instead of pushing a page assembled by a different CLI version.
Details
Pinned markup fragments, script hashes, an inline blind-spots style allowlist and the diagram runtime must all match
On mismatch the republish fails with pr_review_republish_template_drift and advises re-running /artifact-pr-review
A separate new failure, pr_review_republish_mermaid_unavailable, covers a page carrying a diagram runtime this CLI could not load
Refusal messages are shorter, tell you to start a new session, and link somewhere to learn more.
You'll notice · Elsewhere
What
The generic Usage Policy refusal now says the model can't help and tells you to start a new session to continue, instead of the older longer text. A learn-more/feedback line is appended, and it differs depending on whether you are running through the SDK or interactively.
Details
the generic refusal names the model and directs you to start a new session
the cyber-topic variant is reworded around "safeguards flagged this message"
applies to everyone, no gate
Evidence
can't help with this. Start a new session to continue.
Teleport branch-mismatch error explains what the checkout actually is #
Teleport now tells you whether the repo genuinely mismatched or the git remote just couldn't be read.
claude --teleport
You'll notice · Teleport
What
The "You must run claude --teleport ... from a checkout of ..." error now tells you why the current directory did not match, separating a genuine repo mismatch from a git remote it could not parse.
Details
repo mismatch shows the session's repo plus a "This repo is ..." line
an unparseable remote reports that case explicitly instead of implying a mismatch
the session repo is qualified with its host when the host is not the default
Evidence
Couldn't parse your git remote:
Clearer failure text when an artifact PR review can't be matched #
A failed artifact PR review now tells you to re-run the command instead of blaming gh auth.
You'll notice · Artifacts
What
When a review payload names a pull request but no review target was resolved, the mismatch message no longer asks whether gh is authenticated as if fixing it now would help.
Details
the text explains that the target is fixed at invocation time, so nothing changed afterwards can revive that run
it points you at re-running the command instead
applies to everyone
Evidence
the target is fixed at invocation, so fixing anything now cannot revive this run
Model-downgrade chain and effort tables know about Opus 5 #
Model fallbacks and reasoning-effort settings now handle Opus 5, stepping down to Opus 4.8 when needed.
claude-opus-5
You'll notice · Models
What
The stepwise "older model" resolver and the reasoning-effort tables were extended for Opus 5, so downgrades and effort selection land on the right model.
Details
an Opus 5 name now steps down to Opus 4.8
a fable-5 name resolves to Opus 5 instead of Opus 4.8
the reasoning-effort configuration table gained a claude-opus-5 entry
the set of models on the special effort path now contains both claude-opus-4-8 and claude-opus-5
Evidence
if (t.includes("opus-5") || t.includes("opus_5"))
MCP config warns about stray whitespace in values #
MCP config now warns when a value has stray leading or trailing whitespace instead of silently using it.
You'll notice · MCP
What
Loading MCP server entries now warns when a value has leading or trailing whitespace, naming the fields involved, because the values are used exactly as written.
Details
the warning tells you to strip the whitespace rather than doing it for you
reserved-name rejections now carry a machine-readable reserved_name code alongside the existing message
Evidence
Leading or trailing whitespace in:
MCP error text is sanitized and credential-redacted before display #
MCP error messages now hide credentials and strip weird characters before showing them to you.
You'll notice · MCP
What
Server-supplied error text reaching MCP UI surfaces is now normalized and scrubbed before it is interpolated into user-visible strings, and an invalid URL is no longer echoed back.
Details
Reconnect failures pass the tools-list error through a sanitizer (NFKC normalize, strip angle brackets and quote characters, collapse whitespace, truncate with an ellipsis) before interpolation into "Reconnected to ..., but fetching tools failed: ...".
The same sanitizer applies to a caught error message in the artifact/QR surface, and to messages embedded in Error reconnecting to and Failed to reconnect to .
Bearer, api-key and password-looking values are rewritten to [redacted].
MCP conflict notices in the transcript run their message and suggestion through a control-character stripper.
Schema-validation error formatting for MCP goes through the same path.
An invalid MCP url no longer echoes the URL back; the message is now a fixed string.
Evidence
'url' is not a valid URL. Update the server's config and reconnect., Error reconnecting to
Model picker drops the "Requires usage credits" suffix and the manual 1M relabel #
The model picker now shows labels straight from the model data, without extra credit or context suffixes.
You'll notice · Models
What
Entries in the model list are shown as the model data defines them, without two hardcoded rewrites applied at list-build time.
Details
" · Requires usage credits" is no longer appended to the affected entry.
The opus[1m] label is no longer rewritten to "Opus (1M context)"; that label now comes from the entry itself.
The highlighted-name pass in the model description recolours "Opus 5" instead of "Fable 5", "Mythos 5" and "Sonnet 5".
Evidence
Opus 5
"Dynamic workflow size" hidden when a policy pins it #
The workflow size setting disappears from config when your organization has already fixed it.
/configworkflowSizeGuideline
You'll notice · Settings
What
The workflow size setting no longer appears in config when a managed or flag settings source already defines it, so you cannot change a value your organization has fixed.
Details
New computed field workflowSizeGuidelineToggleable is the negation of "a managed/flag settings source defines workflowSizeGuideline"
The workflowSizeGuideline enum row (label "Dynamic workflow size", options unrestricted/small/medium/large) is listed only when that is true
Previously the row appeared whenever workflows were toggleable
Evidence
workflowSizeGuidelineToggleable
Announcement banners can turn off their accent bar #
Announcement banners can now appear without the coloured accent bar, depending on what the server sends.
You'll notice · Elsewhere
What
The remote announcement schema gained an accentBar boolean, so a server-sent announcement can render without the coloured accent bar.
Details
accentBar: boolean defaults to true in the schema
the announcement slot exposes showAccentBar, which treats anything other than an explicit false as true
surrounding chrome draws or omits the bar based on that value
content comes from remote announcement config, so what you see depends on what the server sends; absent a value the bar is drawn
Small polish: credit labels, an extra help link, bigger artifact fetch limit, safer MCP environment handling.
env
You'll notice · Elsewhere
What
A group of small changes to model rows, help links, artifact fetching and MCP environment expansion.
Details
the "Requires usage credits" suffix on model rows moved into a shared helper applied to Fable entries, instead of being appended inline
a third support-article URL joined the set of links auto-marked with a "learn more: " marker
the artifact WebFetch read raises its maxContentLength by an extra 64KB of headroom
MCP env expansion for settings-provided env blocks now builds on a frozen snapshot of process.env, using a variant that no longer stashes NO_COLOR and FORCE_COLOR as a side effect
Evidence
artifact_webfetch_read
Bug Fixes
16 items
OSC 52 clipboard writes are chunked under GNU screen #
Copying long text inside GNU screen now works, since the clipboard escape is split into chunks.
You'll notice · Terminal UI
What
Copying long text while running under GNU screen no longer emits a single oversized escape sequence.
Details
Under screen the payload is split into fixed-size chunks, each re-wrapped in its own DCS passthrough segment.
tmux keeps its previous single-sequence path.
Previously one sequence was built for all multiplexers.
Evidence
]52;c;
MCP reconnect failure text is sanitized and length-capped #
MCP reconnect errors now show cleaned-up, shortened text instead of raw messy error output.
/mcp
You'll notice · MCP
What
The two /mcp reconnect failure messages no longer interpolate a raw error string.
Details
Covers "Tried reconnecting to …, but the connection failed:" and "Got new credentials, but reconnecting to …", both assembled at runtime.
The extracted error now passes through the shared display sanitizer, which NFKC-normalizes, strips angle brackets, quotes and assorted bracket characters, collapses whitespace, and truncates with an ellipsis at 200 characters.
An MCP server literally named __proto__ now warns you instead of silently loading nothing.
mcpServers
You'll notice · MCP
What
An MCP config with a literal __proto__ key under mcpServers used to be swallowed by prototype semantics, loading nothing and saying nothing. It is now detected and reported.
Details
Surfaces as a validation warning with skipReason reserved_name, which feeds the new skipped-server reporting
Warning messages and suggestions are now passed through a sanitizer before being pushed
Evidence
"__proto__" is a reserved MCP server name and was not loaded
Malformed file snapshot records are skipped rather than returned when restoring from history.
Under the hood · Sessions
What
Reading a snapshotted file from history now rejects malformed records instead of returning them.
Details
snapshotFiles must be an array.
Each candidate must be an object with a matching string key, plus string path and content.
A candidate failing any of these is skipped and the scan continues.
Evidence
snapshotFiles
Armed fallback model must belong to the same family #
Fallback model only kicks in when it truly matches the model you asked for.
You'll notice · Models
What
The armed fallback model is only used when it genuinely matches the target, instead of being pushed through a remapping helper first.
Details
The remapping helper call is gone from this path.
The fallback is used only when its normalised family matches the mapped target's family and it has not already been tried.
Otherwise the code falls through to the regular resolution path.
Evidence
armedFallbackModel
Artifact live-edit no longer aborts on a proxy-blocked verification read #
Live editing artifacts works again behind egress proxies that block the artifact host.
You'll notice · Artifacts
What
In environments whose egress proxy blocks the artifact host, live-edit failed on the pre-flight check instead of proceeding.
Details
The pre-flight read that checks whether a live-edit target is a workshop page tags egress-proxy 403s with deterministic: "egress-blocked"
The live-edit guard throws its "could not verify the target page is not a workshop page" refusal only when the failure is not that tag
Evidence
egress-blocked
Vim NORMAL mode passes bare left arrow on an empty prompt to the editor #
In vim normal mode, pressing left arrow on an empty prompt now works as expected.
You'll notice · Terminal UI
What
The left-arrow gesture on an empty prompt did not work while idle in vim NORMAL mode, because only unshifted up and down were forwarded to the underlying input.
Details
The vim-mode key router now also forwards left when the buffer text is empty
This is the gesture guarded by the "Press ← again" arming notification, key left-arrow-again-for-agents
The arming state gained an explicit disarm helper that clears the timer and removes that notification; not every call site of the disarm could be determined
The guard itself reads tengu_left_arrow_editing_guard, fallback true
Evidence
left-arrow-again-for-agents
Sub-agent stream messages keep their own parent tool id #
Output from nested tool calls inside sub-agents is now attributed to the right call.
You'll notice · Sub-Agents
What
Streamed tool events re-enqueued from a sub-agent now carry the parent tool use id from the event itself, so nested tool output is attributed to the right call.
Details
the id on the event is preferred, with the enclosing tool use id only as a fallback
previously output from nested tool calls could be reattributed to the outer tool
Evidence
parentToolUseID
Team-memory mount conflicts fail closed on write and recover automatically #
Shared team memory mounts stop clobbering each other and switch back on once a conflict clears.
You'll notice · Team Memory
What
Writing a store manifest into a shared mount is now race-safe, and a mount suppressed for a conflicting manifest re-enables itself once the conflict is gone.
Details
Manifest writes into an absent non-user mount stage to a temp file and hard-link into place, so a racing store cannot be overwritten.
Finding another store's manifest at write time throws rather than proceeding.
Mounts suppressed as mount_dir_foreign_partition or mount_dir_unmanifested_nonempty are re-adopted automatically, emitting tengu_team_mem_foreign_partition_recovered.
Write-time guidance strings were rewritten to name the conflicting directory and state that sync re-enables itself.
Evidence
mount dir holds another store's .memory-sync manifest at write time (fail closed)
Org memory setup renames aside anything squatting its mount name rather than colliding.
Under the hood · Elsewhere
What
Deriving the org-memory root mount now updates an existing entry in place and renames aside any other config that has taken the derived mount name, instead of colliding with it.
Details
The prompt index is taken from the server config, falling back to a default and reporting prompt_index_absent.
A discovered config squatting the derived mount name is renamed aside, logged as "org-memory-discovery: discovered config squatting the derived mount name".
New event tengu_org_memory_root_mount_derived records the mount name, mode and prompt-index source.
Runs on the org-memory discovery path; whether that feature is enabled in this build was not determined.
Evidence
org-memory-discovery: discovered config squatting the derived mount name
Background sessions no longer respawn when the running one is newer #
Background sessions stop needlessly restarting when your running build is already newer.
You'll notice · Sessions
What
Background session adoption compares the recorded session's cliVersion against the running build and skips the upgrade respawn when the running session is already newer, instead of treating any version difference as stale.
Details
affects both background session adoption and the upgrade-respawn path
a version mismatch alone is no longer sufficient to force a respawn
applies to everyone
Evidence
tengu_bg_adopt_upgrade_respawn
Tool-result eviction no longer double-counts already-seen results #
Duplicate tool results no longer inflate the size math that decides what gets dropped.
You'll notice · Compaction
What
The size accounting that decides which tool results to evict no longer inflates its running total when the same result appears more than once.
Details
In the previously-seen-results total, ids already marked seen contribute zero.
Budget comparisons therefore reflect distinct results rather than repeats.
Evidence
toolUseId
Interrupt no longer double-reports cancelled queued commands #
Interrupting queued commands no longer reports the same cancellation twice or lists it as still queued.
You'll notice · Elsewhere
What
Interrupting a session with queued commands emitted a second "cancelled" lifecycle callback for commands whose cancel had already been acknowledged, and listed them again as still queued.
Details
The command queue gains consumeCancelPendingAcked / hasCancelPendingAcked on top of the existing cancel-pending set
Drain suppresses a second "cancelled" lifecycle callback for a uuid whose cancel was already acknowledged
The interrupt control_response filters those uuids out of still_queued
Affects SDK clients watching command lifecycle around cancel_queued
PR review artifacts now reject repository names like "." or ".." that could escape paths.
You'll notice · Code Review
What
Repository names read back from published review artifacts could be . or .., a path-traversal risk; they are now rejected.
Details
The regex used to validate PR review anchors and the review JSON schema changed from /^[A-Za-z0-9._-]{1,100}$/ to a form with a leading negative lookahead
A repo named . or .. now fails with "anchor.repo is not a valid repository name"
Evidence
anchor.repo is not a valid repository name
Queued-command cancellations are acknowledged once #
Cancelled queued commands are reported once and no longer linger in the interrupt receipt.
You'll notice · Elsewhere
What
A queued command whose cancellation was already reported no longer produces a second cancelled event, and no longer appears as still queued in the interrupt receipt.
Details
the command queue gained consumeCancelPendingAcked and hasCancelPendingAcked on top of the existing cancel-pending marks
commands whose "cancelled" lifecycle event was already emitted are skipped on later passes
those commands are filtered out of the still_queued list in the interrupt receipt sent to SDK clients
Evidence
still_queued
Typing cancels a pending left-arrow confirmation in the prompt input #
An armed left-arrow confirmation now clears the moment you type anything else.
You'll notice · Prompt Input
What
An armed left-arrow-on-empty confirmation in the prompt input is now dropped as soon as you press any other key.
Details
the text-input state object exposes a new disarmLeftArrowConfirm callback
the key handler invokes it for any key that is not a plain unmodified left arrow
previously the armed confirmation could survive intervening keystrokes
Evidence
disarmLeftArrowConfirm
In Development
25 items
Workshop artifact pages get a publish-time structural verifier #
Publishing a workshop page would run a structural check and refuse instead of shipping violations.
Not switched on · Artifacts
What
Publishing a workshop page runs a structural check over the rendered HTML and refuses the publish on violation instead of shipping it.
Details
Verifies against a computed allowlist of blessed inline-script hashes; refusals list rule, where and hint, capped at 12 entries followed by "(and N more)".
Sidecar files are policed: workshop pages may not ship renderable or executable sidecars, and non-workshop sidecars of renderable types are probe-verified individually.
New telemetry: workshop_verifier_refused, workshop_sidecar_refused, workshop_sidecar_contract.
Gated on Xde() = mN() && Ke("tengu_gable_onyx_sluice", !1), so off absent a remote value.
Evidence
workshop pages cannot ship renderable or executable sidecar files
App state tracks verified workshop slugs and sidecar history #
Your session would remember which artifact pages passed verification and which sidecars were refused.
Not switched on · Artifacts
What
Publish results are recorded in app state so later publishes can tell whether a slug already passed verification and what sidecars were refused.
Details
New AppState fields workshopVerifiedSlugs (slugs whose publish passed the workshop verifier) and sidecarHistorySlugs (per-slug record of refused sidecar content types).
A redeploy that omits refusedSidecarHistory is refused as a contract violation rather than quietly skipping the ordering gate.
Same workshop gate as the verifier.
Evidence
workshop publish contract violation: redeploys must pass refusedSidecarHistory
Memory recall now triggers on CJK input with no spaces #
Chinese, Japanese and Korean messages without spaces could trigger memory recall, but that branch is off here.
Not switched on · Memory
What
Recall previously required whitespace in the user's message, which excluded Chinese, Japanese and Korean text written without spaces.
Details
Adds a branch accepting NFKC-normalized text matching CJK and Hangul ranges.
That branch is gated on eJi() = Ke("tengu_mill_orange", !1), so off absent a remote value.
Separately and unconditionally, exhausting the per-session recall byte budget is now reported as a feature error instead of returning silently.
Evidence
session_budget_exhausted
Workshop skill gains a direct-HTML authoring lane, and it is now the default #
The workshop skill would now write HTML documents by default, with a strict publish check, but isn't offered.
Not switched on · Skills
What
The bundled workshop skill text was rewritten around two authoring lanes, with HTML promoted over markdown, though the skill is not offered on this build.
Details
v2.1.218 said flatly that the workshop document is markdown and stays markdown for its whole life.
A new "Choosing the lane" section tells the model to copy a template to a path ending in .workshop.html, fill it, and publish that file.
The markdown .workshop.md lane becomes secondary, reserved for when the user asks for markdown or the document will be dominated by quoted external content.
Publishing runs a structural verifier on the final payload of every publish and refuses out-of-contract pages: fixed scripts, no inline on* handlers, no iframes/forms/base/link, escaped quoted content, island and markup agreement.
Registration uses isEnabled backed by gate tengu_gable_onyx_sluice with in-source fallback false, so absent a remote value the skill is not offered; it additionally needs the Artifact tool's capabilities and the read_page_data action.
Evidence
Default to the TEMPLATE-HTML lane
The decisions island's opening bytes are now a named constant, and reserved page-wide #
Workshop pages would be rejected at publish if they mention the decisions marker more than once.
Under the hood · Skills
What
The literal island-open sequence is lifted into a module-level constant next to the templates, and the skill text makes its uniqueness on the page a hard rule.
Details
Island extraction scans for exactly that byte sequence, so the verifier refuses any page where the scan and the real island could disagree.
An author page mentioning the island id anywhere else, in a quoted example or an attribute, fails the publish instead of being silently mis-extracted.
Only reachable behind the workshop skill gate, which is off here.
The offer to share your transcript was rebuilt, now only appears once per session and records when you dismiss it.
Under the hood · Elsewhere
What
The transcript share offer is restructured around an arm/select/dismiss hook, with its submitting and submitted states moved into a shared component, and dismissals are now reported.
Details
a guard prevents the prompt re-arming within the same session
the arming timer is cleaned up on unmount
dismissal emits a new transcript_share_dismissed event
the separate "frustration" survey branch of the feedback UI was deleted
whether this surface is enabled in this build could not be resolved
The server can now pick a fallback model by category when a request is refused, instead of the app naming one.
Under the hood · Elsewhere
What
A second server-side-fallback beta lets the server choose the fallback model by category rather than the client naming one, but it only takes effect if the server accepts the new beta header.
Details
the descriptor is server_side_fallback_category with header server-side-fallback-2026-07-01
when it applies, the request sends fallbacks: "default" instead of an explicit [{ model: ... }] list, letting the server route, for example, cyber-category refusals to the previous Opus
fallback-error classification gained category_beta_header (the new header was rejected) and default_unconfigured (from a body containing "has no default fallback configuration")
the retry path un-arms the category header on those errors and falls back to the existing explicit-list behaviour
the code path also still requires the existing default-fallback conditions
Evidence
"server-side-fallback-2026-07-01"
Workshop doc: snapshots, plan-mode writes and verified slugs #
A per-session workshop document gets snapshotted with your session files and is only writable in plan mode.
Not switched on · Artifacts
What
The per-session *.workshop.md document is now snapshotted with the rest of the session files and gets explicit read and write permission handling, all behind the workshop gate.
Details
gated on the workshop feature gate, combining tengu_larch_pavise (fallback false) with tengu_cedar_transom as a kill-switch
the doc is included in the file-snapshot system entry under the key "workshop"
it is skipped with a log line when it exceeds the snapshot character cap, and skipped when unchanged
write permission for <session>.workshop.md is granted via an includeWorkshopDoc option only when the caller's permission mode is plan, with the mode newly threaded into that check
the read side always includes it, so "Plan files for current session are allowed for reading" covers the workshop doc unconditionally
publishing a plan records the returned slug in workshopVerifiedSlugs app state
Evidence
Workshop doc over snapshot cap, Plan files for current session are allowed for writing
Org memory: discovery telemetry and store-picker copy #
The memory store picker nudges you to pick a specific project instead of leaving the legacy default.
Org-memory discovery reports a new empty case and reworked candidate counts, and the store picker gains copy nudging users off the legacy selection.
Details
When the server returns no candidates and no stores, discovery settles "empty" and logs org_memory_discovery with stores: 0, cached: !1
Candidate telemetry replaces the old project counts with candidate_count_public and candidate_count_private
The store picker adds a legacy-selection nudge event tengu_org_memory_legacy_pick_nudged, the nudge description "set automatically — pick a project to choose where saves go", a "public project" row description, and the summary label "all public projects" for the legacy selection
Gated on tengu_haze_glass, fallback false, and additionally refused when CLAUDE_CODE_DISABLE_ORG_MEMORY or CLAUDE_MEMORY_STORES is set
Evidence
set automatically — pick a project to choose where saves go
A memory mount that got suppressed can now recover on the next sync instead of staying stuck until restart.
You'll notice · Org Memory
What
Two suppression reasons on multi-store memory sync are now recoverable instead of sticking until restart.
Details
Applies to mount_dir_foreign_partition and mount_dir_unmanifested_nonempty
On the next sync the mount dir is re-examined; if the partition now matches or the dir is empty, suppression is cleared with the log "condition cleared — re-adopting the mount dir" and failure counters reset
In the same area the separate pushSuppressedReason field is gone entirely, so pushes and periodic resync are no longer gated on it and per-mount suppression is the single mechanism
Gating of team memory sync itself was not examined
Evidence
condition cleared — re-adopting the mount dir
Compact recall/remember summaries in the transcript #
Memory recall notes could show as a compact grouped line in normal sessions, but that view is off.
Not switched on · Memory
What
Memory attachments rendered only in verbose or transcript mode; a compact fallback view exists for normal sessions but is switched off in this build.
Details
When the gate is on, non-verbose sessions get a compact grouped node built from the attachment's memories
Labelled "Recalling"/"Recalled" or "Remembering"/"Remembered" depending on whether the group is still active
Gated on tengu_stone_shell, fallback false
Evidence
isActiveGroup
PR-review artifact description has an alternate wording that cannot ship in this build #
An alternate PR-review description exists but you'll always see the original one.
/pr-review
Not switched on · Artifacts
What
The pr-review command description became a function that picks between two strings, one of which describes republish-only editing of composed review pages. The selector can never choose it here.
Details
the alternate string ends "a published composed review page is updated ONLY through the acting loop's republish — never by editing its HTML directly."
the selector combines a hard-coded false with tengu_walnut_sconce, and the helper it bottoms out in returns false unconditionally in this build
Live-edit would be blocked on workshop pages so changes go through the validating publish path.
Not switched on · Artifacts
What
The Artifact tool blocks live-edit actions against workshop pages so edits go through the publish path that validates them.
Details
Target slug is checked against the session's known workshop slugs, then open frame URLs, then a server-side fetch looking for a ws-decisions island.
A match refuses with workshop_live_edit_refused; a transient read failure refuses with workshop_live_edit_unverifiable and tells you to retry or WebFetch the page.
Same gate as the verifier: Xde() / tengu_gable_onyx_sluice, fallback off.
Evidence
live-edit is not available on workshop pages \u2014 edit the local workshop file and republish; the publish path is the validation chokepoint live-edit would bypass
Composed PR-review publish refusal explains whether it is a live switch #
If composed review publishing is unavailable, the refusal now says whether it was turned off mid-session.
/artifact-pr-review
Not switched on · Code Review
What
When composed review publishing is unavailable, the refusal now distinguishes a feature switched off mid-session from one that was never on.
Details
Replaces the blanket "re-run /artifact-pr-review and follow the template flow" message with two cases: an operator turning it off during the session (retry later, do not loop) and a session where it was never enabled (start a new session).
The pr-review skill text now states that a published composed review page is updated only through the acting loop's republish, adds a "Communicating while this skill runs" section, and requires validating a second island prr-anchor whose publishedAt must match YYYY-MM-DDTHH:MM:SSZ.
Driven by a runtime switch checked at publish time.
Evidence
composed review publishing was turned off by an operator during this session
Transcript-sharing prompt wired into the session memory viewer, but unreachable in this build #
A prompt to share your transcript after rating a memory is built but never appears.
The session memory viewer gained a full transcript-share flow that arms when a memory is rated, but the precondition that would show it always returns false here.
Details
The viewer now takes a messagesRef and renders states transcript_prompt, submitting, submitted and thanks.
The success panel shows the saved bundle path with the text telling you to send the file to your Anthropic account representative or attach it to a support request.
Telemetry goes to tengu_session_memory_share_event with transcript_prompt_appeared, transcript_share_yes/no/dont_ask_again, transcript_share_submitted and transcript_share_failed.
The arming precondition calls a predicate whose body is return !1, so nothing is ever shown.
Two further suppressors exist regardless: CLAUDE_CODE_DISABLE_FEEDBACK_SURVEY and a transcriptShareDismissed setting.
Evidence
Send this file to your Anthropic account representative or attach it to your support request.
New bundled template file templates/workshop-page.html#
A second bundled workshop page template ships, showing what the HTML authoring style looks like.
Not switched on · Skills
What
The workshop skill's file map ships a second template, the blessed starting point for the new direct-HTML lane.
Details
The existing templates/artifact-workshop.html remains the mechanically-filled plan-artifact template with {{TITLE}}, {{TAB_TITLE}}, {{EYEBROW}} and {{SUMMARY}} slots.
templates/workshop-page.html describes itself in a header comment as the blessed template for direct-HTML workshops.
It ships a filled sample page: a cache-store decision with Spanner and Redis options, a populated ws-decisions island, and hand-drawn inline SVG figures.
It carries the same vetted decisions script and adds figure/figcaption styling for the inline SVG diagrams the HTML lane prefers over mermaid.
Reachable only behind the same workshop skill gate, which is off here.
Rewritten memory rules would make Claude save corrections and environment quirks immediately, before replying.
Not switched on · Memory
What
The memory instructions given to Claude were rewritten around three criteria and now specify when a memory must be written rather than leaving it to judgement.
New rule that memory writes happen before the reply that engages the correction, not after the conversation settles
The frontmatter template now includes a metadata: pinned: field
Gated on tengu_stone_shell, fallback false
Evidence
A good memory is applicable, durable, and legible
Memory truncation warning now covers ordinary memory files #
Oversize memory warnings would finally say something sensible about ordinary files, not just index entries.
Not switched on · Memory
What
The oversize warning always spoke about index entries regardless of what was truncated; it now branches on file type.
Details
For non-index files it tells Claude to "Keep each memory file focused on one topic"
Adds "its lines are too long" as a stated reason for truncation
Gated on tengu_stone_shell, fallback false
Evidence
this memory file is
Workshop HTML artifact publishing gains a publish-time verifier #
Published HTML artifacts can be checked against rules first and refused outright instead of shipping something unsafe.
Not switched on · Artifacts
What
Artifact publishing can now run the generated HTML through a verifier that refuses to publish when rules are violated, rather than shipping it and relying on later checks.
Details
publishing accepts a new verifyWorkshopHtml option; publishing a plan as an artifact passes verifyWorkshopHtml: "probe" when the gate is on
refusal reports per-rule violations and emits telemetry under workshop_html_publish and verifier_refused instead of publishing
verified slugs accumulate into app state under workshopVerifiedSlugs
for workshop surfaces, a redeploy must pass refusedSidecarHistory, sourced from a new AppState key sidecarHistorySlugs, otherwise publishing is refused rather than skipping the sidecar-ordering gate
sidecar files whose content type is not in the inert text or binary allowlists are flagged as renderable or executable
the gate falls back to false and additionally requires the surrounding workshop feature check; none of these names exist in 2.1.218
Evidence
refusing rather than skipping the sidecar-ordering gate, verifyWorkshopHtml
Opus 5 carries an extra system-prompt block and suppresses subagent nudges #
On some models Claude will stop spinning up subagents or research workflows unless you actually ask for it.
Under the hood · System Prompt
What
Models advertising a new capability get an appended prompt block telling the model not to reach for subagents or research workflows unprompted, and the matching steering nudge is turned off for them.
Details
gated on the opus_5_prompt_bundle capability, with a remote kill-flag checked inside the capability test (fallback: not killed)
the appended block reads "Do not call the AgentTool unless the user requested it" and "Do not use workflows or deep-research unless the user requested it"
application is logged as tengu_heron_brook_applied with fromClientData: !1
the tengu_heron_brook string flag still overrides
the same capability check feeds the "thistle grebe" steering resolver with a new "model" source returning "no_nudges", suppressing the delegate-to-subagents steering text
Evidence
Do not call the AgentTool unless the user requested it
Admin-workspace helpers get a random per-run token and path guards #
Admin workspace helpers gained a random run marker and stricter name and path-traversal checks.
Under the hood · Elsewhere
What
Admin-workspace helper code gained a per-run marker and input validation patterns, with no confirmed user-facing surface in this build.
Details
A module initialiser builds a random zzadminwc-prefixed marker from 8 random bytes.
New regexes reject characters such as /, @, #, ?, \ and whitespace in names.
A separate pattern catches dot-segment path traversal, including the %2e encoded form.
Whether any of this is reachable for users could not be resolved.
Evidence
zzadminwc
Org-memory discovery can return a prompt_index path #
Org memory discovery can pick up a prompt index path from the server and attach it to the mount.
Not switched on · Org Memory
What
The store discovery response can now carry a prompt index path, which becomes part of the derived mount.
Details
New optional prompt_index string field on the discovery response schema, max 512 characters, coerced away on parse failure
It is turned into a mount's promptIndex and reported through prompt_index_source on tengu_org_memory_root_mount_derived
A "prompt_index_absent" signal is reported when the server omits it
Org memory requires tengu_haze_glass, fallback false, and the allow_memory_sync entitlement
Recalled memories no longer get silently dropped when the model echoes back the category label with the name.
You'll notice · Memory
What
A recalled memory could be lost purely because the model echoed the category label shown in the prompt.
Details
When the recall model returns memory names, any that do not match a known memory have a leading bracketed category label stripped by regex before the match/filter step
Covers the [user] / [project] prefixes the prompt displays
Previously such a response was silently dropped
Gating of the memory recall feature was not resolved
Resuming into a same-named repo from a different host can now be labelled host/repo to tell them apart.
Under the hood · Sessions
What
Resuming against a same-named repo on a different forge can now show which is which, though the callers of the new helper were not traced.
Details
The port-stripping normalizer moved out of the inline closure into its own helper
A new function returns sessionDisplay / currentDisplay, prefixing the repo with its host as host/repo only when the two hosts differ after normalization
Evidence
sessionDisplay
Internal Changes
32 items
bun:ffi dropped for native Bun and process APIs in three low-level paths #
Low-level process and hardening paths now use built-in APIs instead of loading system libraries.
Under the hood · Elsewhere
What
Three places that used dlopen through bun:ffi now call native APIs directly, and a fourth FFI helper was deleted.
Details
Process replacement no longer dlopens libSystem/libc for execve; it calls process.execve with a sanitized env object where __proto__ is defined rather than assigned.
The macOS TCC responsibility-disclaim spawn dropped its posix_spawn FFI dance for process.execve(e, r, n, { macDisclaimResponsibility: !0 }).
PR_SET_DUMPABLE hardening now calls Bun.ant.setDumpable(!1).
The SO_PEERCRED/getpeereid FFI peer-credential helpers were removed outright.
These are macOS and Linux paths; the execve helper still returns early on Windows.
Evidence
prctl(PR_SET_DUMPABLE,0) returned nonzero
fast_mode_disabled_reason on turn-completion telemetry #
Turn logs now record why fast mode was skipped, such as env setting or model not allowed.
Under the hood · Telemetry
What
Turn-completion events now report why fast mode was not used, alongside the existing state field.
Details
New fast_mode_disabled_reason sits next to fast_mode_state and is populated from the fast-mode eligibility check.
Values include not_first_party, disabled_by_env, model_not_allowed, sdk_opt_in_required, pending and unknown.
Present at 18 sites in this build; did not exist in the previous one.
Evidence
fast_mode_disabled_reason
Telemetry string extractors routed through a sanitizer #
Error names and file positions pass through a sanitizer before telemetry; nothing changes for you.
Under the hood · Telemetry
What
Error names, errnos and file:line:col values are now marked as vetted before reaching telemetry.
Details
The already-regex-validated result of each extractor passes through a wrapper on its way out.
Literal fallbacks at call sites are wrapped too, including the "unknown" errno defaults in fleet dispatch, render-error reporting and respawn logging.
Queued commands can now be marked cancelled when an interrupt sweeps the queue.
Under the hood · Telemetry
What
The internal schema description for queued-command lifecycle states documents a new way a command reaches 'cancelled' and tells exactly-once resenders how to reconcile against it.
Details
New cause for 'cancelled': the command was swept by an interrupt carrying cancel_queued:true
Resenders should reconcile against the interrupt receipt's cancelled list in addition to their own cancel_async_message responses before resending
The named receipt capability string is new in this build
Evidence
swept by an interrupt with cancel_queued:true
Cross-session safety rule wrapped in a named tag #
A safety rule in the auto-mode prompt got a wrapper tag; the rule text is unchanged.
Under the hood · Permissions
What
The automode safety evaluation prompt now encloses its cross-session clause in a named wrapper element, making the block addressable as a unit.
Details
<cc_automode_session_rules> wraps the existing <cross_session_messages_rule> element
The per-turn bookkeeping in the query loop was restructured with no change you can see.
Under the hood · Elsewhere
What
The per-turn accumulator used by the query loop is now built by a factory rather than assembled inline. No user-visible behaviour changes.
Details
the accumulator holds assistant messages, tool results, tool_use blocks, and the follow-up, end-turn, prevent-continuation and deferred flags
reset can optionally keep assistant messages
rebuildStreamingToolExecutor re-creates the streaming tool executor from the injected constructor
Evidence
rebuildStreamingToolExecutor
Fast mode disable records a source and a new reason #
When fast mode is switched off, it now records why and where from, including hitting extra-usage limits.
You'll notice · Models
What
The fast-mode disabled state now records where the disable came from and distinguishes an overage rejection, and both disable paths avoid redundant app-state writes.
Details
the disabled state object carries source: "server"
an overage rejection sets reason extra_usage_disabled and emits the disabled event
both disable paths skip the app-state write when penguinModeOrgEnabled is already false
the preference-disable path bails out early only when the existing disabled state came from the server and is not a recoverable reason
Automatic compaction passes more context when rebuilding attachments and handles failures on a dedicated path.
Under the hood · Compaction
What
The reactive-compaction path passes more context into attachment building and handles failures through a dedicated path.
Details
The attachment builder is now called with the message list and an agent-context descriptor in addition to its previous arguments.
Errors go through a dedicated handler rather than a generic catch that logged and returned empty attachments.
Evidence
reactive_compact
Memory-directory edits get more telemetry and cache invalidation #
Editing files in your memory directory now clears stale caches right away, so changes take effect sooner.
You'll notice · Memory
What
Edit and Write operations inside the memory directory record extra detail and clear derived caches before refreshing.
Details
In addition to tengu_memdir_file_edit and tengu_memdir_file_write, the tool input is recorded through an extra reporter.
The pinned and index caches are invalidated ahead of the existing refresh call.
Evidence
tengu_memdir_file_write
New "engine" prerelease channel recognized for worker respawn #
Background workers now recognise a second build channel and won't respawn themselves across channels.
Under the hood · Elsewhere
What
Background worker and daemon respawn now understands a second prerelease channel and refuses to upgrade across channels.
Details
The version regex accepts engine alongside dev|alpha|beta|rc|test|nightly as a prerelease tag
A new helper set ["dev", "engine"] classifies a version by which of those tags its build string contains
A -dev. worker is not respawned as -engine. or vice versa; previously only the dev tag was understood
This build reports VERSION "2.1.219"
Evidence
nightly|engine
Dangerous-delete detection uses a prebuilt regex #
Permission checks for risky delete commands do slightly less work each time, with identical results.
You'll notice · Permissions
What
The PowerShell and cmd delete-command matcher no longer rebuilds its alternation on every call.
Details
The matcher takes a second parameter and tests against a module-level regex compiled once from the same rm|remove-item|ri|del|erase alternation
Matching behaviour is unchanged; this removes per-invocation work on a hot permission path
Evidence
rm|remove-item|ri|del|erase
Engine builds recognised by the version-timestamp parser #
Build-age checks now read timestamps correctly from a second class of internal builds.
Under the hood · Elsewhere
What
The helper that pulls a build timestamp out of a version string now understands -engine. prerelease tags, so engine builds get correct build-age handling.
Details
previously only -dev. tags matched
the version-normalising replace matches both forms as well
Evidence
/-(?:dev|engine)\.(\d{8})\.t(\d{6})(?:\.|$)/g
Workshop and sidecar slug state now propagates out of forked agent contexts #
Subagents can now pass workshop and sidecar tracking state back to your main session.
Under the hood · Elsewhere
What
The allowlist of AppState keys a forked or subagent context may write back to the parent session grew from one key to three.
Details
ASYNC_SHARED_APP_STATE_KEYS previously held only frameUrls
it now also includes workshopVerifiedSlugs and sidecarHistorySlugs
Analytics ids are now filtered to safe characters before being sent, with no change you'll see.
Under the hood · Telemetry
What
A large set of analytics call sites now run ids through a validator, bounding what can reach the analytics pipeline.
Details
The validator allows only [A-Za-z0-9_-] up to 128 characters and otherwise reports the literal "nonconforming".
Applied to background job ids and attach shorts, session_id on tengu_remote_attach_session, appearance_id on feedback/survey and transcript-share events, requestId and previousMessageId, and trigger_ids which are now joined through the same validator.
Numeric fields such as http_status and bug-report status_code moved from String(...) to the string-coercing sanitizer.
No user-visible behaviour change.
Evidence
nonconforming
Remainder of this group is minifier churn, not behaviour #
Most changes here are renamed internals with identical behaviour, including unchanged upload and watcher limits.
Under the hood · Elsewhere
What
Most of the added and removed one-liners in this area are renames of identical code between builds, with no user-visible effect found.
Details
The sandbox marker helper still builds CMD64_-prefixed log tokens with the same regex.
The color-error helper still produces the same No color named "..." text.
The skills watcher's polling constant and the review-mode finderBudgetHint helper, which always returns false, both survive under new names.
The design-consent global setter/getter pair is unchanged in substance.
Numeric constants match v2.1.218 under different symbol names, including the 67108864 upload cap, the 0.7 voice-meter smoothing factor and the watcher intervals.
Evidence
No color named "
Artifact review-page validator takes a single options object #
The PR-review page validator was reshaped to take one options object; behaviour is identical.
Under the hood · Artifacts
What
The PR-review template validator's signature collapsed from a positional regex plus a trailing options object into one options bag.
Details
The bag carries crUrlRe alongside allowMermaidFence
The single caller passes crUrlRe: s where s is null, so behaviour is unchanged
Shape refactor only
Evidence
crUrlRe
Bug-report telemetry values now pass through redaction helpers #
Bug report data now goes through the same scrubbing as other telemetry before being sent.
Under the hood · Telemetry
What
Bug report events send their identifier and level fields through the same sanitizing helpers already used for other fields, rather than as raw strings.
Details
affects tengu_bug_report_submitted and tengu_bug_report_description
feedback_id, survey_appearance_id and strip_level are wrapped instead of being sent raw or via String(...)
Sessions now remember which background job they were handed off to, and validate their timestamps more strictly.
Under the hood · Elsewhere
What
Session metadata now carries the id of the background job a session was handed off to, and timestamp fields in the metadata reader are validated more strictly.
Details
parkedJobId is written when a session is handed off to the background agents view and cleared when it returns
the reader parses it as an optional string
startedAt, updatedAt and statusUpdatedAt now go through a shared bounds check for finite, non-negative and below a maximum, replacing a bare typeof number test
Evidence
parkedJobId
Wildcard URL patterns parsed through a dedicated helper #
Wildcard URL patterns are now parsed by a shared helper, including odd cases like a wildcard in the port.
Under the hood · MCP
What
Wildcard URL patterns are now parsed by a dedicated helper instead of ad-hoc string handling, used to decide which URL component a template variable expands into.
Details
the helper substitutes a sentinel for *, parses the result as a URL, and retries with a placeholder port when the wildcard sits in the port position
it returns the URL components with the sentinel mapped back to *
callers use it to classify an expansion as scheme, authority, or the rest, for MCP-style URL templates
the security consequence of the change could not be fully established
Evidence
pathname
New transcript helper for unresolved tool_use lookups #
Looking up an unfinished tool call in the transcript now logs a warning instead of erroring out.
Under the hood · Elsewhere
What
A helper that scans the current transcript for an unresolved tool_use id was added, with non-throwing failure behaviour.
Details
when nothing is found, or the transcript cannot be read, it logs a warning naming the transcript path and message count
it returns null in those cases rather than throwing
Evidence
findUnresolvedToolUse: failed to read transcript
MCP error escaping, typed telemetry ids and shared version normalisation #
MCP server error lines are escaped before display, plus minor telemetry and version-string cleanups.
Under the hood · MCP
What
Three small plumbing changes around display escaping and telemetry value typing.
Details
Server error lines in the MCP UI pass code, path and message through a sanitising helper before rendering.
Prompt-cache diagnosis telemetry wraps requestId and previousMessageId in the typed-value helpers instead of passing raw strings.
Version strings in the logging pipeline are normalised via a shared helper rather than an inline regex.
Evidence
tengu_prompt_cache_diagnosis_received
Artifact publish options moved to an options object #
Artifact publishing takes cleaner options and can report which sidecar types were refused.
Under the hood · Artifacts
What
The artifact publish helper takes a single options bag instead of positional flags, and reports one more field on success.
Details
Options are injectDiagramRuntime, injectHighlightRuntime and composedPrReview.
Successful validation can attach refusedClassSidecarTypes to the result.
Content-type detection for uploaded files moved from an inline extension map to a helper.
Dev and engine build versions collapsed before telemetry #
Internal build versions get trimmed before metrics are sent, so daily builds report one value.
Under the hood · Telemetry
What
A version field matching a dev or engine build pattern has its .tNNN.shaXXXX suffix stripped before the metric is emitted, leaving x.y.z-dev.YYYYMMDD.
Details
Runs alongside the existing metric normalisations that collapse mcp__* tool names to mcp and unknown model names to other.
The effect is lower per-build cardinality, since every dev or engine build of the same day now reports one value rather than one per commit.
Not gated; applies to all builds that emit metrics.
Evidence
(?:dev|engine)
Telemetry values routed through explicit sanitiser wrappers #
Telemetry values now pass through marker helpers that declare them safe; nothing sent actually changed.
Under the hood · Telemetry
What
Several telemetry values are now tagged at the call site with marker helpers that declare them safe to emit, with no change to what is actually sent.
Details
Three new identity-function helpers: one for nullable values coerced to string, one for joining an array, and one that validates each array element against the ID pattern ^[A-Za-z0-9_-]{1,128}$ before joining.
The plugin telemetry id now passes through one of these wrappers. That id is still a sha256 of plugin@version salted with a fixed string and truncated to 16 hex characters.
The hashing is unchanged and the wrappers return their input unmodified, so there is no runtime behaviour change in this build.
Failed memory pushes no longer stay suppressed for your whole session; retries resume normally.
You'll notice · Memory
What
The per-scope latch that stopped team and user memory push retries for the remainder of a session is gone; suppression is now tracked only on individual stores.
Details
pushSuppressedReason and its log line "suppressing retry for the rest of this session" are removed
the unlink-clears-suppression handling and the scheduler skip that consulted the latch are removed with it
tengu_team_mem_push_suppressed is now emitted only from the multi-store path