# Claude Code v2.1.209

> Claude Code v2.1.209, released 14 Jul 2026 (2026-07-14). 7 entries read out of the shipped bundle. Unofficial, and not affiliated with Anthropic.

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

This release introduces runtime capabilities for published Artifacts, allowing pages to call the user's claude.ai MCP connectors live from within a published Artifact. It also lifts previous restrictions that blocked `/login` and `/model` commands in background sessions, making these commands behave identically across interactive and background contexts.

## New Features

### Artifact Runtime Capabilities (MCP)

**What**

Published Artifact pages can now declare runtime capabilities — starting with `mcp`, which lets the page call the user's connected claude.ai data sources at runtime rather than embedding static data from the conversation.

**Usage**

`Artifact tool: { capabilities: { mcp: { servers: [...] } } }` **Details** - Artifacts accept a new `capabilities` input that declares which runtime abilities the published page requires. - The first supported capability is `mcp`, enabling the page to call the user's claude.ai connectors (Slack, Google Drive, etc.) via `window.claude.mcp` at open time. - Omitting `capabilities` on a republish carries the stored declaration forward; passing `{}` explicitly clears all capabilities. - A new skill, `artifact-capabilities`, must be loaded before declaring any capability or writing `window.claude.*` runtime code — it carries the current contract's typed call definitions and per-capability guidance. - Type definitions (`.d.ts` files) for the runtime contract are extracted to a local cache directory and are authoritative over any memorized API shape. - Connector tools appear in the tool list as `mcp__<connector>__<toolName>`; the `server` value in the capabilities declaration is the `<connector>` segment. - Only claude.ai connectors are valid — locally-configured MCP servers cannot be declared as Artifact capabilities. - The dataviz/artifact skill prompt gains a new "## Live data via connected sources" section when this feature is enabled, explaining the workflow. - The Artifact tool description itself now mentions the `capabilities` input and the requirement to load the `artifact-capabilities` skill. **Status** [Gradual Rollout] — controlled by `CLAUDE_CODE_ARTIFACT_MCP` env var or `tengu_cloth_snorkel` feature flag.

**Evidence**

New skill registered as `registerArtifactCapabilitiesSkill` (search for `"Runtime capabilities for published Artifacts"`); capabilities schema added (search for `"Runtime capabilities this page declares, as {name: config}"`); gated by `n4y()` which checks `CLAUDE_CODE_ARTIFACT_MCP ?? Qe("tengu_cloth_snorkel", !1)`

- Flag `tengu_cloth_snorkel`: On for this account, and not off by default (read for one account on one subscription tier against v2.1.209; this account: on, anonymous baseline: on, compiled default: on) These values were read against a different version of Claude Code, so treat them as the nearest reading available instead of one taken on this release.

## Improvements

### Background Sessions Now Support /login and /model

Background sessions (headless/remote jobs) previously blocked both the `/login` command and the `/model` model picker with hard errors. Those restrictions have been removed — both commands now work the same way in background sessions as in interactive terminals.

The following messages were removed from the codebase:

- "Can't run /login in a background session — log in from a regular interactive terminal (`claude`), then respawn this job."
- "Can't open the model picker in a background session — use `/model <name>` to switch this session's model."

The model fable consent flow (for usage-credits consent when switching to certain models) also no longer short-circuits in background sessions.

**Evidence**

`si()` (is-background-session) guard removed from the `/login` handler (search for `"Can't run /login in a background session"`); same guard removed from the model picker and model-switch flow (search for `"Can't open the model picker in a background session"`)

### Max Subscription Upgrade Flow Simplified

The "upgrade to Max" subscription flow previously showed different messages depending on whether the user was in a background session. Background-session-specific strings were removed:

- "You are already on the highest Max subscription plan. For additional usage, run /login from an interactive terminal to switch to an API usage-billed account." — collapsed to a single message without the background-session qualifier.
- "Visit ... to upgrade to Max, then run /login from an interactive terminal to use your new plan." and "Visit ... to upgrade to Max. Run /login after upgrading to use your new plan." — replaced with a direct call to open the upgrade URL without a fallback text path.

**Evidence**

`B$t` function simplified (search for `"You are already on the highest Max subscription plan"`); background-session URL-open fallback removed (search for `"to upgrade to Max, then run /login from an interactive terminal"`)

### Trusted Devices Check Removed from Remote Control

The Remote Control connection flow previously blocked enrollment if the connecting device was not enrolled in Trusted Devices:

> "Your organization requires Trusted Devices for Remote Control, but this device is not enrolled. Run `/login` from an interactive terminal to enroll this device, then retry."

This check has been removed. Remote Control connections are no longer gated on Trusted Device enrollment in the CLI.

**Evidence**

Block removed from `PNp` function (search for `"Your organization requires Trusted Devices for Remote Control"`)

### Refusal Fallback Tracking Improved

The internal mechanism for tracking model refusal fallbacks now carries additional state across requests. Two new session-level fields were added:

- `refusalFallbackHeaderArmed` — indicates the fallback header should be sent on the next request
- `refusalFallbackLatchOriginRequestId` — records the original request ID that triggered the fallback

When the armed state is active, outgoing API requests now include new HTTP headers:

- `x-cc-fallback-latched-by` — the request ID of the original triggering request
- `x-cc-fallback-from-model` — the model that refused
- `x-cc-fallback-category` — the refusal category
- `x-cc-fallback-trigger` — what triggered the fallback
- `x-cc-original-request-id` — original request correlation ID

The `pZp` helper that searches message history for refusal fallback records was refactored to return the full record instead of a pre-filtered subset, enabling richer downstream handling. The `XNt` function is now called at three points in the main request loop (interactive, forked, and background sessions) to rearm the fallback header when applicable.

**Evidence**

New state fields (search for `"refusalFallbackHeaderArmed"`); new header constants (search for `"x-cc-fallback-latched-by"`); new `kgt` arming function and `XNt` recheck function in `pretty-v2.1.209.js`

### Capabilities Display in Tool Listings

Two new helper functions add capability-aware display to Artifact publish operations. `Nkd` (`capabilitiesFromGatedInput`) safely extracts the `capabilities` field from a tool input only when the field is explicitly present — distinguishing "not provided" (carry the stored declaration forward) from "provided as `{}`" (explicitly clear the grant). `Fkd` (`frameCapabilitiesSummary`) converts a capabilities object into a compact parenthesised summary string.

- For the `mcp` capability key (when config contains a non-empty `servers` array), each server entry formats as `<serverName>[N tool(s)]`, joined into a comma-separated list: e.g. `mcp: slack[3 tools], gdrive[1 tool]`.
- Non-`mcp` capability keys render as their bare key name with no further sub-structure.
- If more than 8 servers (or 8 capability segments) are present, the formatter prepends `[N total]` and shows only the first 8, preventing runaway output on large declarations.
- The assembled string is hard-truncated at 400 Unicode characters with a `…` ellipsis, then wrapped in parentheses and prefixed with a space: ` (mcp: slack[3 tools])`.
- `Fkd` is consumed by the `ArtifactTool`'s `toAutoClassifierInput` method (via the `i4y()` wrapper), so the summary appears in the string the permission auto-classifier reads when deciding how to handle an Artifact publish call.
- When `Fkd` returns empty but a non-empty capabilities object is present (e.g. capabilities stored from a prior publish), the auto-classifier input falls back to `" (carries a stored connector grant)"`; if capabilities were explicitly passed as `{}`, it shows `" (clears stored connector grant)"`; if the stored capabilities could not be read from the control plane, it appends `" (caps: unknown)"`.

**Evidence**

`Nkd` (`capabilitiesFromGatedInput`) and `Fkd` (`frameCapabilitiesSummary`) added (search for `"capabilities" in e ? e.capabilities : void 0`); `Fkd` consumed by `i4y()` inside `ArtifactTool.toAutoClassifierInput` (search for `frameCapabilitiesSummary`); overflow enforced by `oSo` (non-empty `servers` guard) and `qar` helper (8-item cap with `[N total]` prefix, search for `qar`)

## Bug Fixes

- Refusal fallback state fields (`refusalFallbackOccurred`, `refusalFallbackHeaderArmed`, `refusalFallbackLatchOriginRequestId`) are now correctly reset on both session clear and session start, preventing stale fallback state from bleeding across sessions. (search for `"refusalFallbackLatchOriginRequestId = void 0"`)
