# Claude Code v2.1.220

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

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

A retry path that would drop the classifier beta after an HTTP 400 and a successful bare retry is present in the build but inert: it keys off a beta constant that is null in both builds, so the latch never fires. Nothing about classifier behaviour changes as a result. Treat it as groundwork rather than a feature you can exercise today.

Refusal fallback no longer lands on Claude Opus 5 when the client cannot see its model entitlements. A new check detects sessions with no entitlement data at all, and the Opus lineup walk used for refusal fallback filters Opus 5 out in that state; a normalization step also rewrites any model whose canonical id is "claude-opus-5" to "claude-opus-4-8" before it is used as a fallback target, so an affected setup now falls back to Claude Opus 4.8. Separately, the permission classifier behind auto mode now attaches a beta descriptor to its API requests, on both classifier stages, where the previous build sent none.

## What probably matters to you

Anything you can use today, anything that visibly changes, and anything worth poking at. One line each, open for detail.

### Classifier beta-rejection latch still keys off a null placeholder

The automatic retry that would drop a rejected classifier beta can never trigger in this build.

**What**

The path that drops a classifier beta after an HTTP 400 followed by a successful bare retry is keyed on a beta constant that is `null` in both builds, so it never fires.

**Details**

- The latch bails out early when the constant is null, and the constant is declared as `null` in 2.1.219 and 2.1.220 alike.
- The newly-sent auto-mode-classifier beta therefore has no automatic drop-on-400 path in this build.
- The telemetry it would emit, `tengu_auto_mode_beta_latch` and `permission_auto_mode_classifier`, is present but unreachable.

**Evidence**

`tengu_auto_mode_beta_latch`

- Area: Permissions
- Tier: Not switched on
- Useful: 2/5
- Signal: 3/5
- Present in the build but not switched on

## New Features

### Auto-mode classifier requests now send a new beta header

Auto mode's permission classifier now tags its requests with a beta marker on Anthropic-hosted sessions.

**What**

The permission classifier used by auto mode attaches a beta descriptor to its API requests, where the previous build sent none. Both classifier stages now carry it.

**Details**

- Registers `WA("auto_mode_classifier", "auto-mode-classifier-2026-07-16")` and adds it to the frozen known-betas list, so it is also reachable through the header lookup map.
- In 2.1.219 the classifier's request builder was a stub that unconditionally returned an empty `extraBetas` array; it now returns this beta.
- Gated on provider being "firstParty" and the base URL being api.anthropic.com. Suppressed by `CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS` or hipaa mode, in which case the list stays empty.

**Evidence**

`auto-mode-classifier-2026-07-16`

- Area: Permissions
- Names: `CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS`
- Tier: Under the hood
- Useful: 2/5
- Signal: 0/5

## Improvements

### Opus 5 is skipped when the client cannot see model entitlements

If your session has no model access info cached, Claude won't fall back to Opus 5.

**What**

A new predicate detects sessions where Claude Code has no entitlement data at all, and the Opus lineup walk used for refusal fallback filters Opus 5 out in that state.

**Details**

- `isEntitlementOverlayUnavailable` returns true when the provider is first-party, an OAuth token is stored, the profile scope is absent, no Anthropic API key is set, and the cached model-access list is empty.
- A helper combines that predicate with a canonical-name check against "claude-opus-5"; the candidate scan becomes `.find((n) => N1e(lo(n)) && !u2c(n) && r(n))`, and a sibling helper substitutes "claude-opus-4-8" in its place.
- No remote flag is involved. It is driven purely by runtime auth and cache state, so a first-party OAuth session with an empty entitlement cache will not auto-pick Opus 5 as a fallback target.

**Evidence**

`isEntitlementOverlayUnavailable`

- Area: Model Fallback
- Tier: You'll notice
- Useful: 3/5
- Signal: 0/5

### Refusal fallback no longer picks Opus 5 when entitlements are unknown

When a refusal triggers a model switch and entitlements are unknown, you get Opus 4.8 instead of Opus 5.

**What**

The refusal and model-fallback picker gained a normalization step that rewrites any model whose canonical id is "claude-opus-5" to "claude-opus-4-8" before it is used as a fallback target. A refusal that used to fall back to Claude Opus 5 on affected setups now falls back to Claude Opus 4.8.

**Details**

- The first-party branch went from `if (!rm()) return s2c("claude-opus-4-8"); let r = EE();` in 2.1.219 to `if (!rm()) return l2c(c2c); let r = d2c(EE());`, where `c2c` is the constant "claude-opus-4-8" and `d2c` performs the mapping.
- The next-fallback-model resolver applies the same mapping: `l2c(rm() ? r.id : s2c(r.id), "exact")` becomes `f2c(rm() ? d2c(r.id) : l2c(r.id), "exact")`.
- The non-exact candidate scan skips the same models: `Gji().find((n) => N1e(lo(n)) && !u2c(n) && r(n))` versus the old `Uji().find((n) => N1e(lo(n)) && r(n))`.
- The gate is a runtime condition, not a remote flag. The substitution only applies when the helper body `Hn() === "firstParty" && zA() && !bH() && eZ() === null && ZJt().length === 0` holds, the same predicate the build reports elsewhere as `entitlement_blind`. Otherwise behaviour is unchanged.

**Evidence**

`claude-opus-4-8`

- Area: Model Fallback
- Tier: You'll notice
- Useful: 3/5
- Signal: 0/5

## Internal Changes

### Version bumped to 2.1.220

The version shown in /status, bug reports and update checks is now 2.1.220.

**What**

The build-time constant block embedded throughout the bundle carries a new version, timestamp and commit hash, rethreaded through roughly 55 call sites.

**Details**

- VERSION 2.1.219 -> 2.1.220, with a new BUILD_TIME of 2026-07-24T22:17:45Z and a new GIT_SHA.
- Surfaces in the /status version line, the bug-report template's Environment Info, the `claude-code/<version>` user agent, update-check output (`Current version: `), telemetry and analytics payloads, and the npm install/view commands targeting `@anthropic-ai/claude-code`.
- The `BUILD_REF_NAME` suffix helper still returns the empty string, and the JOSE `compactDecrypt` calls in the OIDC JWE path were re-minified with no behaviour change.

**Evidence**

`VERSION: "2.1.220"`, `BUILD_TIME: "2026-07-24T22:17:45Z"`

- Area: Build Metadata
- Names: `/status`
- Tier: Under the hood
- Useful: 2/5
- Signal: 0/5

### Build stamp moved to 2.1.220

Version strings in update messages, doctor output and daemon logs were re-stamped to 2.1.220.

**What**

The inlined build constants appearing in around 40 user-visible and log strings were re-stamped, with no surrounding logic touched.

**Details**

- VERSION 2.1.219 -> 2.1.220, BUILD_TIME 2026-07-24T03:24:19Z -> 2026-07-24T22:17:45Z, GIT_SHA 7006c4c3acac98e554d3997baeda6a7fa4d1ff7c -> 4073f59596e272f39393db4f96abc5f4b10eff21.
- Affected strings include version output, `claude update` messages, user agents, doctor output and daemon logs.

**Evidence**

`GIT_SHA: "4073f59596e272f39393db4f96abc5f4b10eff21"`

- Area: Build Metadata
- Names: `claude update`
- Tier: Under the hood
- Useful: 1/5
- Signal: 0/5

### Reworded the classifier beta-rejection warning

A warning message about a rejected classifier beta was reworded, though you can't reach it.

**What**

The warn-level log emitted when the auto-mode classifier's beta is rejected changes from "the bare retry succeeded" to "the retry without it succeeded".

**Details**

- Log text only, the surrounding logic is unchanged.
- The branch is currently unreachable because the latch it belongs to is keyed on a null constant.

**Evidence**

`beta rejected (HTTP 400) and the retry without it succeeded`

- Area: Permissions
- Tier: Under the hood
- Useful: 1/5
- Signal: 0/5

### Prompt text for /code-review, /simplify, skill-saving and credential paths is byte-identical

Code review, simplify and skill-saving instructions are unchanged despite looking rewritten in the bundle.

**What**

A large group of apparently new and removed code is pure bundler renaming, with prompt wording unchanged from 2.1.219.

**Details**

- Covers the code-review phase prompts including "## Phase 2 \u2014 Verify (1-vote, 3-state)", "## Phase 3 \u2014 Sweep for gaps" and the Artifact publishing block.
- Also covers the /simplify 4-agent and single-pass prompts, the "# Saving skills" system prompt variants, the background-session shipping policy text, the workflow status strings and the credential file paths.
- Only the surrounding minified identifiers and the interpolated tool and skill symbols differ. No user-visible behaviour change.

**Evidence**

`## Phase 3 \u2014 Sweep for gaps`

- Area: Elsewhere
- Names: `/code-review`, `/simplify`
- Tier: Under the hood
- Useful: 1/5
- Signal: 0/5

### Bundle-wide reformatting with no behaviour change

Assorted internal code was reformatted and renamed with nothing you can perceive changing.

**What**

Several unrelated areas were reflowed or had their module-init closures renamed, with no semantic difference found in any of them.

**Details**

- Method-chain reflows in JWT verification, PEM fingerprinting via `createHash("sha1")` and `createHash("sha256")`, MCP server-config mapping, the SDK `set_model` control request, QR-code rendering and several string-splitting sites.
- Renamed module-init closures for the test and typecheck command regexes and for the git worktree path constants `/worktrees/` and `config.worktree.lock`.

**Evidence**

`failed to validate JWT signature`

- Area: Build Metadata
- Tier: Under the hood
- Useful: 1/5
- Signal: 0/5
