# Claude Code v2.1.206

> Claude Code v2.1.206, released 9 Jul 2026 (2026-07-09). 18 entries read out of the shipped bundle. Unofficial, and not affiliated with Anthropic.

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

This release delivers a significantly revamped Claude in Chrome setup experience with an interactive wizard and multi-browser detection, introduces a new EndConversation tool (feature-flagged, rolling out to eligible models), adds `/plan share` artifact publishing, a new dashboard artifact skill, and Chart.js runtime support for richer artifact charts. Plugin binary provisioning gains mismatch detection, and push permission rules now dynamically pick up non-origin remotes.

## New Features

### Claude in Chrome — Revamped Setup Wizard

**What**

The Claude in Chrome installation flow is now an interactive step-by-step wizard inside the terminal, replacing the previous one-shot skill registration.

**Details**

- When Claude needs browser tools and the extension isn't installed, a new "Claude wants to use your browser" upsell prompt appears with three options: install the extension, skip for now, or "Don't ask again."
- Choosing to install opens a "Setting up Claude in Chrome" dialog that follows the connection progress in real time — tracking "Install the extension" and "Connect to Chrome" as live steps with loading/success/error states.
- If setup stalls, the dialog shows: "Taking longer than expected. Check that the extension is added and that you're signed in to it in Chrome."
- On success: "Browser tools are ready. Continuing keeps them enabled for future sessions too — manage anytime with /chrome."
- Browser detection now covers seven Chromium-family browsers: Chrome, Brave, Arc, Edge, Chromium, Vivaldi, and Opera across macOS, Linux, and Windows.
- Auto-enable is gated by the `tengu_chrome_auto_enable` feature flag: when enabled, Claude activates browser tools automatically if the extension is already installed/paired.
- The extension install page URL and `/chrome` management command are unchanged.

**Evidence**

Setup wizard UI (search for `"Setting up Claude in Chrome"`); upsell dialog (search for `"Claude wants to use your browser"`); browser path map (search for `"BraveSoftware"`)

- Flag `tengu_chrome_auto_enable`: On for this account, and not off by default (read for one account on one subscription tier against v2.1.206; this account: on, anonymous baseline: off, 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.

### Plan Publishing as Artifact

**What**

`/plan share` can now publish the current plan as a shareable web artifact on claude.ai, letting reviewers read the plan in a browser before the session exits.

**Details**

- When a plan artifact is available, a new "Review plan as artifact" option appears alongside the existing skip option.
- While publishing, the session shows: "Publishing plan for review…"
- On success, the URL is displayed: "Review your plan: {url}"
- If the plan changes after publishing, the status updates to show "(plan changed since publish — after exiting, /plan share publishes the updated plan)"
- If publishing fails: "Couldn't publish plan — run /plan share to retry, or --debug for details."
- If the feature is unavailable: "Publishing plans isn't available right now — the plan was not published."

**Evidence**

Status strings (search for `"Publishing plan for review"`); stale state (search for `"plan changed since publish"`)

### Dashboard Artifact Skill (`artifact-dashboard`)

**What**

A new built-in `artifact-dashboard` skill provides a production-ready template for creating operational dashboard artifacts with KPI tiles, a primary chart, and a breakdown table.

**Usage**

`Load the artifact-dashboard skill and build a dashboard from its template.` **Details** - The skill includes a `template.html` fragment with slot markers (`<!-- SLOT: ... -->`) for the title, KPI tiles, chart spec, breakdown rows, and footer note. - KPI tiles support directional delta styling with `up`/`down` classes plus `good`/`bad` overrides for cases where a decrease is an improvement (e.g., latency, error rate). - The primary chart slot takes a compact JSON spec (`"type": "line"` | `"bar"` | `"donut"`, `"series"`, `"x"`, `"y"`) and is rendered by a built-in SVG fallback plus the injected Chart.js runtime (see below). - A `CONTRIBUTING.md`-style notes section warns against fabricating data: "Replace every placeholder number — and never invent one." - Theming uses CDS token values with full dark mode support via `@media (prefers-color-scheme: dark)` and `data-theme` overrides. **Evidence** Skill FRONTMATTER (search for `"artifact-dashboard"`); slot guidance (search for `"SLOT: KPI_TILES"`)

### Chart.js Runtime in Published Artifacts

**What**

Artifacts that include a `<script type="application/json" data-chart-runtime>` chart spec now receive an injected Chart.js runtime at publish time, enabling bar and donut charts in addition to SVG line charts.

**Details**

- The publish pipeline detects the `data-chart-runtime` attribute and injects a bundled Chart.js into the artifact HTML between `<!-- chart-runtime -->` / `<!-- /chart-runtime -->` sentinel comments.
- Safety checks reject bundles containing `</script`, HTML comment injection risks, or the sentinel strings themselves.
- The runtime reads the spec from the `data-chart-runtime` element and renders into `#primary-chart` via Chart.js, fully replacing the SVG fallback.
- Theme support: resolves CSS custom properties from `getComputedStyle` at render time and re-renders on system dark-mode changes or `data-theme` flips — same data, same pixels per theme.
- Multi-series line/bar charts include a legend; donut charts accept per-slice color overrides.
- The SVG fallback remains for environments without the runtime, covering the standard time-series line case.

**Evidence**

Sentinel string (search for `"bundle contains the chart-runtime sentinel"`); runtime injection (search for `"chart-runtime -->"`); Chart.js integration (search for `"new Chart(canvas"`)

### Dynamic Git Remote Detection for Push Permissions

**What**

Permission rules for `git push` now automatically include the repo's configured push remote, not just `origin`.

**Details**

- Before adding a `Bash(git push origin *)` rule, Claude now queries `git config remote.pushDefault` to find the actual configured push target.
- If only one remote is configured, it is used regardless of name.
- The resolved remote is added alongside `origin` in the allowed-patterns list, so both `git push origin *` and `git push {remote} *` are permitted.
- This prevents unnecessary permission prompts for repos that push to `upstream`, a fork remote, or any non-`origin` name.

**Evidence**

Remote resolution (search for `"remote.pushDefault"`); dynamic rules (search for `"git push -u"` alongside `"rwn"`)

## Improvements

### Plugin Binary Provisioning — Mismatch Detection and Bare Name Linking

**What**

Plugin binary installation now removes and re-fetches binaries whose on-disk digest doesn't match the manifest, and creates hard links from arch-specific binary names (e.g., `tool-aarch64-apple-darwin`) to bare names (e.g., `tool`) for easier execution.

**Details**

- If a `bin/` entry exists but its SHA-256 doesn't match the manifest, Claude logs "removed bin/{name} — it is not the artifact pinned by the manifest" and re-downloads it.
- After placement, a hard link from the arch-specific filename to a bare name is created on macOS/Linux when exactly one declared entry derives that bare name (collision-safe).
- Four target triples are recognized for bare-name derivation: `aarch64-apple-darwin`, `x86_64-apple-darwin`, `aarch64-unknown-linux-musl`, `x86_64-unknown-linux-musl`.
- New telemetry fields track `mismatch_removed_count` and `bare_placed_count` separately from download and cache-hit counts.
- A new validation pass checks `.mcp.json` and nested MCP server configs for binary references that aren't in the `binaries` map, warning: "bin/{name} is not a shipped file, a declared binaries entry, or a name derivable from the declared entries — the server will fail to start."

**Evidence**

Mismatch removal (search for `"it is not the artifact pinned by the manifest"`); validation (search for `"Check for a typo against the \"binaries\" map in plugin.json"`)

### Model Pricing Catalog

**What**

Model pricing is now baked into the model catalog at build time rather than fetched at runtime, with validation that every catalog entry has complete pricing data.

**Details**

- A new pricing-tier resolver (`BVo`) maps model entries to their pricing shapes, supporting both direct pricing objects and shared tier references.
- Pricing requires `input`, `output`, `cache_write_5m`, `cache_read`, and `web_search` fields; missing fields throw at startup: "model catalog entry '{id}' has incomplete pricing — baked entries need the full ModelCosts shape."
- Model IDs must be registered in `CATALOG_MODEL_IDS`; unregistered IDs throw: "model catalog id '{id}' missing from CATALOG_MODEL_IDS — regenerate with 'bun run generate:model-catalog'."
- The first-party billing UI uses the catalog pricing to display per-token costs in the model picker.
- Claude Sonnet 5 can show promotional pricing text when a promo expiry date is set (search for `"promo through"`).

**Evidence**

Validation error (search for `"baked entries need the full ModelCosts shape"`); catalog check (search for `"model catalog id missing from CATALOG_MODEL_IDS"`)

### Refusal Category Fallback Routing

**What**

When the API returns a refusal with a known category, Claude can now route the retry to a specific fallback model rather than always using the armed default fallback.

**Details**

- The `cyber` refusal category routes to `claude-opus-4-8` on Opus plan configs.
- The `bio` category additionally routes to `claude-opus-4-8` on Opus plan configs.
- A new env var `CLAUDE_CODE_REFUSAL_FALLBACK_CATCH_ALL` (if set) enables a catch-all fallback for unmapped categories.
- Per-category routing is overridable by config; unresolvable mapped targets return `matched: "none"` with reason `"mapped_target_unresolvable"`.

**Evidence**

Category map (search for `"cyber": "claude-opus-4-8"`); env var (search for `"CLAUDE_CODE_REFUSAL_FALLBACK_CATCH_ALL"`)

### Observer Sidecar Persistence and Reattach

**What**

Agent observers (sidecars that monitor running tasks) can now persist across session restarts and reattach to their observed task rather than always spawning fresh.

**Details**

- Observer state is written to the conversation journal as `"observer-ref"` entries containing the observer task ID, agent type, and arming mode.
- On a new turn, if a prior observer task ID is found in the journal and the task transcript is still readable, Claude reattaches to the existing observer rather than spawning a new one.
- If the sidecar transcript is unreadable: "[agentObserver] reattach: observer sidecar unreadable — fresh under a new id"
- If the prior observer's agent type doesn't match the declared type, a fresh observer is started.
- Observer teardown now tombstones the sidecar via a `stopped: true` journal entry to prevent reattach loops.

**Evidence**

Journal type (search for `"observer-ref"`); reattach log (search for `"observer sidecar unreadable"`)

### Screen Reader Mode Reports Activation Source

**What**

The screen reader mode status indicator now shows how the mode was activated (e.g., via environment variable or CLI flag) rather than just showing it's on.

**Details**

- Old: `[Accessible screen reader mode: on]`
- New: `[Screen Reader Mode: on via {source}]` when an activation source is known, or `[Screen Reader Mode: on]` otherwise.
- The three possible `{source}` values are: `"flag"` (when the `--ax-screen-reader` CLI flag is passed), `"env"` (when the `CLAUDE_AX_SCREEN_READER` environment variable is set to a truthy value), and `"settings"` (when `axScreenReader: true` appears in the settings file). The priority order is flag → env → settings.
- Activation is additionally gated by the GrowthBook feature flag `tengu_ax_screen_reader`. If the flag disables the feature, screen reader mode does not activate regardless of the CLI flag, env var, or settings value, and `activationSource()` returns `undefined` — so the `on via {source}` suffix will not appear even if an activation mechanism is present.
- When the GrowthBook resolver is not yet available (e.g., before first-party initialization), the check defaults to `true`, allowing the mode to activate locally without a network round-trip.

**Evidence**

New format (search for `"[Screen Reader Mode: on via"`); activation sources (search for `"activationSource()"`); GrowthBook flag (search for `"tengu_ax_screen_reader"`)

- Flag `tengu_ax_screen_reader`: Gate removed from the code (read for one account on one subscription tier against v2.1.206; this account: on, anonymous baseline: on, compiled default: not a boolean we can read) 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.

### OAuth Token Expiry Error

**What**

Expired OAuth refresh tokens now throw a distinct `OAuthRefreshDeadError` with a clear message, rather than a generic error.

**Details**

- Message: "OAuth refresh token is no longer valid; run /login to re-authenticate"
- The error class name `"OAuthRefreshDeadError"` is surfaced in logs and can be caught specifically by error handlers.
- The error is thrown at API client construction time when all three conditions hold: no API key is available, no current OAuth access token exists, and `OGt()` is true — meaning the stored OAuth refresh token is either an empty string `""` or is found in an in-memory dead-token blacklist set (populated whenever a token refresh request fails).
- When this error propagates to the request error handler, the displayed UI message branches by session type: interactive REPL sessions show `"Login expired · Please run /login"`; agent/non-interactive sessions show `"Failed to authenticate: OAuth session expired and could not be refreshed"`.
- The error condition is also checked in the first-party HTTP client's teleport-org auth path: after a forced token refresh attempt, if `OGt()` is still true, the request returns `{ ok: false, reason: "no-auth" }` with the same detail message rather than throwing.
- Previously, token expiry produced ambiguous error messages that did not distinguish between a missing token and a definitively-expired one.

**Evidence**

Error class (search for `"OAuthRefreshDeadError"`); dead-token check (search for `"OGt()"`); UI message branching (search for `"Login expired"` alongside `"OAuthRefreshDeadError"`)

### Login Expired Message

**What**

The "login expired" notification now includes the action to take directly in the message.

**Details**

- New: "Login expired · Please run /login"
- Previously the message and the suggested action were separate.

**Evidence**

String (search for `"Login expired \xB7 Please run /login"`)

### Health Check Description Update

**What**

The `/doctor` health check command description now mentions bloated memory files in addition to duplicated ones.

**Details**

- Old: "Health-check your setup and fix issues: installation, unused extensions, duplicated memory files, slow hooks, updates, permissions"
- New: "Health-check your setup and fix issues: installation, unused extensions, duplicated or bloated memory files, slow hooks, updates, permissions"

**Evidence**

Description string (search for `"bloated memory files"`)

## Bug Fixes

- Push permission default rules (`Bash(git push origin *)`) now correctly add both `Bash(...)` and `PowerShell(...)` variants for dynamically resolved remotes, matching the behavior for the static `origin` entry. (search for `"git push -u"` in `ANd`)
- The `"scroll to bottom"` button in the terminal now truncates its label to fit the available column width rather than overflowing. (search for `"wrap: \"truncate-end\""`)

## In Development

Features with infrastructure added but not yet enabled for all users.

### Artifact Gallery (`/artifacts`) [In Development]

**What**

A new `/artifacts` command to browse, open, copy links to, and delete your published and shared artifacts from within the terminal.

**Status**

Disabled (hardcoded `isEnabled: () => !1`)

**Details**

- Full UI built: scrollable list with selection, title truncation at 50 characters, view count and date metadata, and "shared" badge for artifacts shared by others.
- Keyboard actions: arrow keys to select, Enter or `o` to open in browser, `c` to copy URL to clipboard, `d` to delete (own artifacts only, with `y`/`n` confirmation), `r` to refresh, Escape to close.
- Fetches from `/api/frame/frames?limit=200` — up to 200 artifacts.
- Soft-deleted artifacts are filtered from the list automatically.
- Error states: "Couldn't load artifacts (network error)", "Couldn't load artifacts (HTTP {status})", "No artifacts yet. Publish one with the Artifact tool."
- Delete errors: "Artifact not found — it may already be deleted, or you are not the owner."

**Evidence**

Command registration (search for `"Browse your published and shared artifacts"`); disabled flag (`isEnabled: () => !1` in the command definition); API path (search for `"/api/frame/frames?limit=200"`)

### EndConversation Tool [Feature-Flagged]

**What**

A new deferred tool (`EndConversation`) allows the AI to end a conversation in cases of sustained, serious user abuse — after prior warnings and with strict eligibility checks.

**Status**

Feature-flagged (requires server-side feature flag to enable) and model-gated (opus 4-8, sonnet 5, fable 5, mythos 5).

**Details**

- The tool is `shouldDefer: true` and only enters a model's tool list after an explicit `ToolSearch("select:EndConversation")` call; its `searchHint` is "end the conversation — only for sustained user abuse, or when the user explicitly asks to see it demonstrated." The GrowthBook feature flag `tengu_umber_kestrel` must be enabled server-side; if the flag is off, `isEndConversationToolEnabled()` returns `false`, the tool is disabled, and the deferred hint is suppressed entirely.
- Model floor check (`modelMeetsEndConversationFloor`): parses the model ID as `claude-{family}-{version}` and compares version numerically against `[["opus", [4,8]], ["sonnet", [5]], ["fable", [5]], ["mythos", [5]]]`. Models below these thresholds (e.g., `opus-4-7`) never receive the deferred hint and cannot enable the tool.
- In fork/background-task contexts (`agentId` is set on the tool context), the call immediately returns `ended: false` with a message stating forks cannot end the main conversation and instructing the fork to return welfare concerns as output instead. No session state is changed.
- Two-call confirmation via `lastAssistantTurnCalledEndConversation`: scans messages backward from newest; if any assistant turn contains an `EndConversation` tool-use block and no real user message has appeared since that turn, the check returns `true` and the tool proceeds to end. If no such prior call exists (first invocation), the tool returns `ended: false` with the full reflection prompt plus guidance, asking the model to call again to confirm.
- Before terminating, a journal marker is written to disk (`oHs(Ct())`); then `abortController.abort("end_conversation")` fires with the reason string `"end_conversation"`.
- In interactive (REPL) sessions: sets `endedByModel: true` in app state; the UI renders a styled result box displaying the tool result string: "Claude has ended this chat."
- In non-interactive (print/pipe) sessions: calls `gracefulShutdown(1, "other", { finalMessage: "Claude ended the conversation. To continue, please start a new session." })` — exits with process exit code 1.
- Strict "must NOT use" list: stuck loops, task completion, harmful content requests (redirect instead), general frustration, any self-harm or imminent harm scenario. In crisis/self-harm cases the model must not even mention the possibility of ending the conversation.
- A deferred-tool hint is surfaced only in interactive sessions (`$B()` check) to eligible models: "use only for sustained user abuse directed at the assistant, or when the user explicitly asks to see it demonstrated."

**Evidence**

Feature flag name (`"tengu_umber_kestrel"` in `JUi`); deferred hint (search for `"Load the full guidance via ToolSearch"`); end message (search for `"Claude has ended this chat"`); two-call check (`lastAssistantTurnCalledEndConversation`); model floor list (search for `"Re-read the"`); non-interactive exit (search for `"gracefulShutdown"`); model eligibility list (search for `"mythos"`).

- Flag `tengu_umber_kestrel`: Gate removed from the code (read for one account on one subscription tier against v2.1.206; this account: on, anonymous baseline: off, compiled default: not a boolean we can read) 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.

## Notes

The built-in `claude_design` first-party MCP server (`https://api.anthropic.com/v1/design/mcp`) has been removed from the auto-provisioned server list. Users relying on Claude Design should ensure it is configured via their MCP settings or the `/design login` flow, which routes through the updated hub command rather than a built-in server entry.
