← All changelogs v2.1.217 claude · claude-sonnet-4-6
Claude Code · Source-level changelog

Version 2.1.217

This release introduces MCP tool errors that now throw typed exceptions in workflow scripts (a behavioral change to be aware of), a new emoji shortcode typeahead feature with a user-controllable toggle, and session memories accessible directly from the chat footer. It also ships a major path-containment security overhaul, a remote workflow launch system for CCR (server-driven workflows), and a migration from resource-based to skills/list paginated discovery for MCP skill providers.

Official notes ✓ synced Package @anthropic-ai/claude-code Diff v2.1.216 → v2.1.217Provider claudeModel claude-sonnet-4-6
21
Features & Changes
10
Bug Fixes
4
In Development
0
Env Vars / Flags

Official Changelog

Official · Anthropic
Anthropic’s official release notes
Published verbatim by Anthropic for v2.1.217 — shown here alongside the source-level analysis below. Text is unmodified from the upstream changelog.
View on GitHub ↗
  • Added emoji shortcode autocomplete in the prompt input: type :heart: to insert ❤️, or :hea for suggestions — disable with the emojiCompletionEnabled setting
  • Added warnings when transcript writes are failing (e.g. disk full) or when session saving is off due to an inherited environment variable, instead of losing transcripts silently
  • Fixed a memory leak where truncated MCP tool outputs kept the full untruncated result in memory for the rest of the session
  • Fixed Windows auto-update failures that could leave claude.exe missing; failed updates now restore the preserved executable automatically
  • Fixed background session isolation not canonicalizing symlinked working directories, which could let sessions escape their workspace folder
  • Fixed auto-compact never triggering for Claude Opus 4.8 on Bedrock and /compact failing once over the limit
  • Fixed corporate mTLS, TLS-verify, OAuth scope, and proxy settings being ignored in Claude Desktop sessions
  • Fixed screen reader mode's startup announcement being cut off by the first prompt render, and the thinking status row re-rendering every few seconds to update elapsed time and token counts
  • Fixed managed settings that set OTEL_EXPORTER_OTLP_ENDPOINT not governing all signals — lower-scope signal-specific overrides no longer redirect telemetry away from the managed endpoint
  • Fixed --resume/--continue and /resume failing with a TypeError when a transcript has a malformed attachment entry
  • Fixed Remote Control sessions not showing a pending permission prompt or dialog to viewers that connected after it appeared
  • Fixed background shells sometimes becoming impossible to stop after a session is sent to the background (/background or ) or when the session exits on a heavily loaded machine, most visible on Windows
  • Fixed a CLAUDE.md or SKILL.md paths frontmatter value with many brace groups OOM-killing or stalling the CLI at startup — brace expansion is now budget-bounded
  • Fixed the transcript preview sitting flush against the input area when attaching to a starting background session; it now leaves the same one-line gap as the live layout, so the transcript no longer shifts when the session takes over
  • Improved footer PR badge links to be clickable hyperlinks even when terminal support can't be detected (e.g. over ssh/tmux); set FORCE_HYPERLINK=0 to opt out
  • Changed the login-expiry warning to appear 3 days before expiry instead of 5
  • Capped the frontend-design plugin suggestion tip at 3 lifetime impressions instead of repeating indefinitely
  • Added a cap on concurrently-running subagents (default 20, override with CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS) so one message can't fan out unbounded background agents
  • Changed subagents to no longer spawn nested subagents by default; set CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH to allow deeper nesting
  • Fixed --max-budget-usd not stopping background subagents: once the cap is reached, new spawns are denied and running background agents are halted
Source: anthropics/claude-code · CHANGELOG.md · 20 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.

New Features

8 items

Emoji Shortcode Typeahead #

New

A comprehensive emoji shortcode autocomplete system has been added. When you type : followed by an emoji name in the chat input, a suggestion popup appears showing matching emoji. Typing :thumbs suggests :thumbs_up: 👍, :thumbsdown: 👎, etc. Selecting a suggestion inserts the emoji character inline.

The feature is enabled by default. To turn it off, set emojiCompletionEnabled to false in user settings.

Details
  • The suggestion popup appears after : and filters in real time as you type
  • Suggestions are ranked by prefix match first, then by name length
  • Up to a configurable number of suggestions are shown at once
  • Multi-code-point emoji (family groups, flags, ZWJ sequences) are included
Evidence

Emoji shortcode search function (search for "emoji:" in suggestion IDs) and new setting (search for "the :emoji: shortcode typeahead")

Transcript Persistence Warnings #

New

New persistent warning banners appear in the TUI when transcript saving is suppressed or failing:

  • If CLAUDE_CODE_SKIP_PROMPT_HISTORY is set: shows "Transcript saving is off — CLAUDE_CODE_SKIP_PROMPT_HISTORY is set" with "· --resume will not find this session; if unintended, unset it and restart"
  • If running as a child session (inherited CLAUDE_CODE_CHILD_SESSION marker): shows "Transcript saving is off — inherited CLAUDE_CODE_CHILD_SESSION marker" with "· restart with CLAUDE_CODE_FORCE_SESSION_PERSISTENCE=1 to keep future transcripts"
  • If transcript writes are failing: shows "Transcript writes are failing (…)" with "· recent messages may not be saved for resume" — error codes are translated: ENOSPC → "disk full", EROFS → "read-only filesystem", EDQUOT → "disk quota exceeded", etc.
Evidence

Persistence suppressed notification (search for "Transcript saving is off") and transcript writer degraded notification (search for "Transcript writes are failing")

Rate Limit Grace Window Banner #

New

When your account enters the usage-limit grace window (reported via anthropic-ratelimit-unified-grace-status and utilization headers), a persistent warning now appears in the session:

> [Usage limit reached — grace window active. Wrap up: finish or checkpoint; don't start subagents or long work.]

The grace state is tracked from anthropic-ratelimit-unified-grace-5h-utilization and anthropic-ratelimit-unified-grace-7d-utilization response headers. The signal is latched on first observation (grace > 0) and cleared when a subsequent response reports it back at zero.

Evidence

Grace window message (search for "grace window active") and header names (search for "anthropic-ratelimit-unified-grace-5h-utilization")

Bridge Fork Session Warning #

New

When Claude Code detaches from a remote (CCR) session by resuming it locally (fork via bridge), it now shows an informational notice:

> This terminal now has its own copy of the session: new work here stays local and will not appear in the Claude app. To continue on your phone later, run /remote-control in this session.

Evidence

Bridge fork message (search for "This terminal now has its own copy of the session")

Screen Reader Startup Quiet Period #

New

Screen reader output (for accessibility tools) is now suppressed briefly after startup, preventing the initial UI state from being announced as changes. The quiet duration is controlled by CLAUDE_AX_STARTUP_QUIET_MS (environment variable, optional override of the internal default).

Evidence

Startup quiet timer (search for "srStartupQuietTimer")

Improvements

13 items

MCP Tool Errors Now Throw Typed Exceptions in Workflow Scripts #

New

This is the most impactful behavioral change in this release for workflow authors.

Previously, MCP tool call failures inside workflow scripts silently resolved to {error: string} objects, making them indistinguishable from a successful tool call that returned an object with an error field. Now, MCP tool failures throw a proper McpToolError exception that crosses the VM sandbox boundary with structured fields.

The thrown error has:

  • .name === "McpToolError"
  • .toolName — the name of the MCP tool that failed
  • .error — the error message string
  • .detail — parsed JSON of the response body, if the error response was JSON

In scripts, use try/catch:

try {
  const result = await mcp__server__tool({ ... })
} catch (e) {
  if (e.name === "McpToolError") {
    console.log(e.toolName, e.error, e.detail)
  }
}

The behavior is gated by tengu_repl_mcp_error_throw (default: true). The system prompt documentation for workflow scripts has been updated to reflect that MCP tools THROW on failure while built-in tools return {error: string}.

Evidence

McpToolError class (search for "McpToolError") and VM sandbox bridge (search for "_throwMcpVM")

Skills Discovery Migrated to skills/list Paginated Method #

New

MCP servers providing skills no longer need to expose a skill://index.json resource. The discovery protocol has changed to use a standard skills/list MCP method that supports cursor-based pagination.

Changes:

  • Old: MCP server exposes skill://index.json resource with a JSON index of skills (URL-based)
  • New: MCP server implements the skills/list method, returning pages of skills with uri fields and optional digest and nextCursor
  • Pagination is handled automatically — Claude Code iterates until all pages are fetched or limits are reached
  • Dropped entries are logged: "N skills/list entries skipped (malformed, missing, or oversized fields)"
  • If a page fails mid-pagination, already-fetched entries are used and a warning is logged

If you operate an MCP server that provides skills, update it from the resource-based index to the skills/list method.

Evidence

New discovery function (search for "skills/list failed") and old discovery removed (search for "skill://index.json" — now gone)

Worker Agent System Prompt #

New

Worker agents launched in multi-agent workflows now receive a structured system prompt covering environment awareness, scope limits, resumed task handling, error escalation, and output format. Key guidelines:

  • Don't modify code you don't understand; stop and report to the coordinator if confused
  • Complete exactly what was asked; suggest follow-ups for unrelated issues found
  • If you have the Task tool, you may use it to fan out — but workers at the depth cap don't receive it
  • Output structured: "What you did or found" then "Summary: one sentence"

The subagent spawn depth ceiling is now configurable via tengu_hazel_trellis (feature flag) or CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH (environment variable).

Evidence

Worker prompt (search for "You are a worker agent executing a task assigned by the coordinator") and depth env var (search for "CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH")

Path Containment Security Overhaul #

New

The system that prevents worktree-isolated agents from writing outside their assigned worktree has been substantially rewritten to handle complex path forms that could previously bypass containment.

New protections:

  • UNC shares (Windows \\server\share paths) are detected and blocked when the session root is local
  • /net/ automount paths (Linux/macOS NFS automounts) are recognized and normalized
  • Apple /System/Volumes/Data/ paths are remapped to their real root
  • Paths with raw dot-segments that survive path.normalize are blocked
  • Windows paths with trailing dots or spaces (a Windows security concern) are detected
  • Device namespace paths (\\?\) are unwrapped or blocked as appropriate
  • Symlink resolution now iterates up to 8 rounds to reach a stable canonical form

Error messages are more specific. For example, a network-shaped path against a local checkout says: > This write was blocked because the path is network-shaped (a UNC share or /net automount spelling) while this session's checkout is local.

A path that can't be safely resolved says: > This write was blocked because the path is spelled in a form that cannot be safely resolved (for example through a symlink storing a raw dot segment, a network-share or device-namespace shape, or an unreadable ancestor directory).

Commands run by worktree-isolated agents now get a more specific rejection if their working directory resolves outside the worktree due to letter-case mismatch: "(this path differs from the registered spelling only by letter case — respell it to match exactly)".

Evidence

Path resolution (search for "resolves-to-trailing-dot-or-space") and network-shaped block (search for "network-shaped (a UNC share")

Concurrency Slot Tracking for Subagents #

New

Subagents now properly claim and release a concurrency slot via takeConcurrencySlot() / onRunSettled(). The store now tracks runningSubagents as a counter. This enables accurate display of running agent count and proper enforcement of concurrent subagent limits (controlled by CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS).

Evidence

Concurrency tracking (search for "Concurrent subagent limit reached")

Import Fingerprinting for MCP Servers and Slash Commands #

New

Import proposals for MCP servers, slash commands, and GEMINI.md files now include a fingerprint field. The fingerprint is a stable hash of the entry's configuration, enabling detection of drift when an import item's config has changed since it was last imported.

Evidence

MCP server fingerprint (search for "fingerprint: JSON.stringify")

Brace Pattern Expansion Budget #

New

Glob patterns with brace expansion ({a,b,c}) now have a budget guard. If expanding a brace pattern would produce too many results or exceed the byte budget, it is used unexpanded with a warning:

> Brace pattern expansion exceeds the budget; using it unexpanded: {pattern}

This prevents accidental combinatorial explosion from deeply nested or wide brace patterns.

Evidence

Budget guard (search for "Brace pattern expansion exceeds the budget")

/auto-mode-setup Gets --apply-target, --request-id, and --expect-sha256 #

New

The /auto-mode-setup command now supports:

  • --request-id <uuid> — must come first; the UUID is echoed back in the JSON result as requestId so a host with multiple in-flight commands can match replies
  • --apply-target <user|project> — specifies where to save settings; the apply step validates that the proposal's scope matches the target (user ↔ scope=all, project ↔ scope=project)
  • --expect-sha256 <64-hex> — required before --apply-file; the apply refuses unless the file's bytes hash to the given SHA256

The proposal object returned by --propose now also includes the scope field.

Evidence

Command usage string (search for "--apply-target must be")

Workshop Artifact Skill: Page-Based Decision Resolution #

New

The /workshop skill (interactive decision artifact) has been updated to a page-self-publish model. Decisions are now resolved by readers clicking option rows directly on the published page, with the page republishing itself via window.claude.self.publish — no separate server-side interaction store is polled. The session loop now detects pending decisions by diffing the live page's DOM state (resolved vs. open call-items) rather than reading from an interactions API.

Additional clarity added to the skill prompt: when building or publishing a workshop, talk about the workshop at the product level — don't narrate internal machinery (publish declarations, renderer wiring, etc.) to the user.

Evidence

Workshop self-publish JS (search for "window.claude.self" or "data-decision-state")

Remote Workflow Launch via Server Events (CCR) #

New

Claude Code Remote sessions can now receive workflow_launch SSE events from the server, which trigger automatic workflow execution. This enables server-initiated multi-agent workflows in remote sessions without requiring a user to type a command.

The flow:

  1. Server pushes a workflow_launch event with a signed workflow bundle (filestore path + SHA256)
  2. Claude Code fetches the bundle, verifies the SHA256, and validates the format (version byte, script frame, args frame)
  3. If all checks pass, the script is executed via the workflow engine
  4. Results are posted back to the server as a workflow_launch_result system event

Policy gates:

  • Blocked entirely if disableWorkflows is set in managed settings (separate message from org policy block)
  • Blocked if org policy allow_workflows is false
  • At most one workflow_launch event per session is permitted

The CLAUDE_CODE_REMOTE_SESSION_ORIGIN env var (set to "review") bypasses the org policy check for server-authored carriers.

Evidence

Launch handler (search for "workflow_launch received outside a remote (CCR) session") and bundle validation (search for "unsupported bundle format version")

Bridge Placeholder Sweep #

New

A new background cleanup task archives orphaned bridge placeholder session records. When a session is initiated via the bridge but then abandoned (never received any messages after creation), its placeholder entry is cleaned up. The sweep runs at startup (after a delay) and checks each placeholder: if the underlying session record shows created_at === updated_at (never used), the placeholder is archived. Records older than 30 days are removed unconditionally.

Evidence

Sweep (search for "[bridge:placeholder] archived orphaned placeholder")

Session File Update via Method Call #

New

The session file path is now set via a setSessionFile() method call rather than direct property assignment, preparing for more controlled session lifecycle management.

Evidence

Method call (search for "r.setSessionFile(o)")

Worktree Auto-Compaction Trigger #

New

When the remote hydration process (CCR delta sync) appends entries and the session file grows past a threshold, it now automatically requests compaction via requestCompact(). This keeps remote session transcripts from growing unboundedly.

Evidence

Auto-compact trigger (search for "requestCompact")

Bug Fixes

10 items
  • Fixed resume attachment validation: malformed or missing attachment payloads in saved transcripts are now dropped with an error log rather than causing resume to fail (search for "the session transcript appears partially corrupt")
  • Fixed the workflow VM sandbox to properly handle MCP-thrown errors in resolveDeep's auto-await loop — a script ending on an unawaited MCP call no longer silently swallows the error (search for "mcpToolError: true")
  • Fixed request cancellation in the load-balancing request router: when a request can't be sent and falls back to local handling, the outstanding remote request slot is now explicitly cancelled via cancelRequest() (search for "i.cancelRequest(a)")
  • Fixed the bridge prependUserMessage method: adding a prepended message now wakes the async input reader immediately rather than waiting for the next chunk, which fixes a race in remote workflow dispatch (search for "prependWaker")
  • Fixed fleet view: deleting a pinned background agent now also unpins it before deletion, preventing stale pin state (search for "Gos(o.id, !1).catch")
  • Fixed skills/list validation to also reject oversized fields (previously only checked for malformed/missing required fields) (search for "malformed, missing, or oversized fields")
  • Fixed discoveryCache leaking into serialized MCP server config: the field is now deleted before the config is stored (search for "delete a.discoveryCache")
  • Fixed injectControlResponse to return a boolean indicating whether the response was consumed — previously it always returned void, making it impossible for callers to detect no-op responses (search for "injectControlResponse")
  • Fixed word-wrap rendering in the terminal output renderer to use the correct source array (E vs v) when iterating tokens without wrapping (search for "R = E.map")
  • Fixed the workflow VM context builder to use the correct budget_usd registration path, ensuring budget tracking is available in the right VM scope (search for "ab(\"budget_usd\"")

In Development

4 items

Features with infrastructure added but not yet enabled or gated behind feature flags currently being rolled out.

tengu_moth_copse — Voice/MCP URL Elicitation Toggle [Feature-Flagged] #

Dev
What

A feature flag tengu_moth_copse controls whether the MCP URL elicitation flow (asking users to provide a URL for MCP server connection) is active. When the flag is on, a separate function rVi() is also checked.

Status

Feature-flagged (tengu_moth_copse)

Details
  • The gated function POe() returns true if either tengu_moth_copse is set or rVi() returns true; rVi() returns true when the CLAUDE_MEMORY_STORES env var is non-empty or the internal discovery latch YXn has fired (set by nVi(), which emits the v6c event when an external store announces itself)
  • When POe() is true, AutoMem-type local auto-memory entries are suppressed in two places: uso() filters them from context arrays and YAu() returns false for them, preventing local CLAUDE.md auto-memory from appearing in the model context alongside externally-discovered stores
  • Auto-memory prompt variant injection (prompt_variant: "base") is suppressed when POe() is true, removing local-index writing instructions from the system prompt
  • Full local memory-index content injection in I$u() is disabled when POe() is true (the s path is only taken when !POe())
  • The per-turn memory selector oHs() — which routes memory writes to the appropriate registered external store — only activates when both Em() (auto-memory globally on) and POe() are true; without POe(), the selector never runs even when auto-memory is otherwise active
Evidence

POe() function (search for "tengu_moth_copse" inside it), AutoMem suppression callers (search for "e.type === \"AutoMem\" && POe()" in YAu() and "filter((t) => t.type !== \"AutoMem\"" in uso()), memory selector guard (search for "!n || t.agentId || !Em() || !POe()" in oHs())

tengu_heron_tallow — New Feature Gate [Feature-Flagged] #

Dev
What

A new feature flag tengu_heron_tallow is available. It can also be enabled via the CLAUDE_CODE_HERON_TALLOW environment variable or via managed settings.

Status

Feature-flagged (also overridable via CLAUDE_CODE_HERON_TALLOW env var)

Details
  • Ohd() returns true if Z.CLAUDE_CODE_HERON_TALLOW env var is truthy, the managed settings object has tengu_heron_tallow: true, or the feature flag is on via Ke()
  • Ohd() is called inside mks(), which generates the hint text appended to tool-not-found errors in the model context when a tool call cannot be routed to any registered tool
  • When Ohd() is true and the tool name resolves to an existing-but-not-enabled tool: the hint changes from "X exists but is not enabled in this context. Use one of the available tools instead." to "X is disabled for this session, in subagents as well as here."
  • When Ohd() is true and the tool is in the known-but-session-unavailable set (sat()): the hint changes from "X is not available in this context. Use one of the available tools instead." to "X is disabled for this session."
  • The change shifts the model's framing from "try a different tool" toward "this tool is a session-level prohibition", which may affect how the model responds to tool-call failures in restricted sessions
Evidence

Ohd() function (search for "CLAUDE_CODE_HERON_TALLOW") and its changed hint strings (search for "is disabled for this session, in subagents as well as here")

Four New Unnamed Feature Flags [In Development] #

Dev

Four new feature flag constants have been added without any observable user-facing behavior yet:

  • tengu_amber_astrolabe (also: CLAUDE_CODE_AMBER_ASTROLABE env var)
  • tengu_bison_cairn (also: CLAUDE_CODE_BISON_CAIRN env var)
  • tengu_larch_cistern (also: CLAUDE_CODE_LARCH_CISTERN env var)
  • tengu_alder_wicket (also: CLAUDE_CODE_ALDER_WICKET env var)

These are infrastructure additions that will be wired to behavior in a future release.

Details
  • tengu_amber_astrolabe / CLAUDE_CODE_AMBER_ASTROLABE: accessor ekc() is checked in Fa_() alongside the existing max/autonomous mode gate (VMe(e)); when true, the autonomy system prompt section is injected even outside max mode, instructing Claude to proceed with reversible actions without asking "Want me to…?" permission questions and to stop only for destructive actions or genuine scope changes
  • tengu_bison_cairn / CLAUDE_CODE_BISON_CAIRN: accessor tkc() gates the "delivering_work_max" system prompt slot (el_); when true, a # Delivering work instruction block is added telling Claude to: act on what is in the request rather than speculation; deliver complete work under stated assumptions; explicitly report blocked sub-tasks; carry mid-task questions to the end of a turn that also delivers progress (rather than blocking); and treat user reaffirmation as a final decision to proceed
  • tengu_larch_cistern / CLAUDE_CODE_LARCH_CISTERN: accessor rkc() gates the "overcorrection" system prompt slot (tl_); when true, a # Corrections instruction block is added telling Claude to: only correct errors that would change the user's code, conclusions, or decisions; state corrections plainly and continue without apology, preamble, or rumination; not treat a follow-up question as a signal of prior error
  • tengu_alder_wicket / CLAUDE_CODE_ALDER_WICKET: accessor nkc() gates the "scope_fidelity" system prompt slot (rl_); when true, a second # Delivering work instruction block (a tighter variant) is added telling Claude to: interpret ambiguity as a careful colleague would; briefly state concerns then proceed as asked; finish the whole task not just the easy parts; stop short of actions clearly beyond what the request implies
  • All four use the shared helper gYt(envVar, flagName) which returns true if the env var is set, managed settings has the flag true, or Ke() returns true for the flag name
Evidence

Accessor functions and system prompt slots (search for "ekc()" near Fa_() for amber_astrolabe; "delivering_work_max" for bison_cairn; "overcorrection" for larch_cistern; "scope_fidelity" for alder_wicket)

rateLimitGraceActive Session State Field [In Development] #

Dev
What

A new rateLimitGraceActive boolean field has been added to the session state schema (marked @internal). It tracks whether the account is currently in the usage-limit grace zone, as observed from extended-request response headers. The field is described as observation-lagged — it stays latched when extended requests stop and should be expired via resetsAt rather than waiting for a clearing event.

Status

Infrastructure added; the header parsing and state tracking are live (see rate limit grace window under New Features), but rateLimitGraceActive as a schema field is documented as internal.

Evidence

Schema field (search for "rateLimitGraceActive" or "tengu_lantern_spool")