# Claude Code v2.1.198

> Claude Code v2.1.198, released 1 Jul 2026 (2026-07-01). 26 entries read out of the shipped bundle. Unofficial, and not affiliated with Anthropic.

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

This release removes the `/agents` interactive wizard and the speculation engine, raises the Node.js minimum to 22, and ships an early-access `claude plugin eval` command for authoring and running eval suites against plugins. Additional highlights include precomputed conversation compaction (feature-flagged), two new shareable-artifact skills (PR walkthrough and code walkthrough), auto-mode setup guidance, and expanded Windows sandbox per-exec deny controls.

## New Features

### Plugin Eval Command [Early Access]

**What**

A new `claude plugin eval` CLI subcommand that runs structured evaluation suites against a plugin and scores the results.

**Usage**

`# Interactive interview to author a new eval suite claude plugin eval init # Write a blank case template without the interview claude plugin eval init --bare <name> # Run eval cases against a plugin claude plugin eval <target> [options]` **Details** - Cases live under `evals/` as `case.yaml` or `prompt.md` files with companion graders in `graders/*.md` - Grader types: `regex`, `tool_order`, `tool_used`, `file_exists`, `llm`, `baseline` - LLM grader uses haiku by default; override with `--judge-model <model>` - Scoring options: `--threshold <0..1>`, `--max-cost-usd <usd>`, `--runs <n>`, `--ablation <none|with-without>` - Passes `--scaffold` to execute each case's `scaffold_script` (author-only; off by default) - Emits `aggregate-result.json`; use `--output-dir <dir>` to control placement or `--json` for stdout - Filter cases with `--tag <tag>` (repeatable) or a name glob - Cost ceiling support: if `--max-cost-usd` is hit, remaining paid graders are skipped while free graders still run - Early access: gated behind an invitation; the eval suite format and CLI flags may change **Evidence** CLI help text (search for `"Run eval cases (evals/**/case.yaml or evals/**/prompt.md"`) and interview system (`"Let's set up evals for this plugin."`)

### Auto-Mode Setup

**What**

A new guided setup flow (`/auto-mode-setup`) that helps you configure Claude's auto mode with environment context — trusted repos, sensitive data, domain rules — and optionally proposes adjustments to your CLAUDE.md.

**Usage**

`/auto-mode-setup` **Details** - Reconnaissance phase: Claude reads your project and recent sessions before suggesting an environment section - Proposes trusted repositories, domains, cloud buckets, and org-specific rules - Presents a draft for review before writing anything - Available as a slash command and also surfaced as a setup prompt on first auto-mode activation **Evidence** Description (search for `"Auto mode lets Claude act without asking first. Telling it which repos you trust"`) and the prompt `"Set up auto mode for your environment?"`

### PR Walkthrough Artifact Skill

**What**

A new built-in skill that generates a shareable HTML walkthrough artifact for a pull request — what changed, why, reviewer-oriented before/after narrative, and annotated code sections.

**Usage**

`# Generate a PR walkthrough artifact /explain-pr <PR number or URL> # Explicitly target a specific PR claude "Generate a shareable walkthrough artifact for PR #42"` **Details** - Produces a self-contained HTML page a reviewer can read before opening the diff - Sections: summary of what the diff does, motivation, code walkthrough, open questions - Traces what the code actually does (not just inferred from names) - After generating findings, publishes them as an artifact for sharing outside the terminal - Skill invokable with `"Generate a shareable walkthrough artifact for a pull request"` **Evidence** Skill description (search for `"Generate a shareable walkthrough artifact for a PR"`) and the goal block (`"## Goal Produce a **shareable PR walkthrough artifact**"`)

### Code Walkthrough Artifact Skill

**What**

A new built-in skill that generates an interactive walkthrough artifact explaining code in a project — expandable sections, annotated snippets, and "why this matters" callouts, pitched at a first-time reader.

**Usage**

`claude "Generate an interactive walkthrough artifact for code"` **Details** - Suitable for onboarding, documentation, or architectural overviews - Expandable sections with annotated code snippets - Uses a structured template separate from the PR walkthrough skill **Evidence** Skill description (search for `"Generate an interactive walkthrough artifact for code"`)

### `--bg` and `--allow-tools` Flags for `claude agents`

**What**

Two new flags for the `claude agents` command.

**Usage**

`# Attach to a named background session claude agents --bg <session-name> # Grant specific tools when launching an agent claude agents --allow-tools Bash,Read,Write` **Details** - `--bg` moves a session to the background and detaches (conflicts with `--print` — the interactive session that `claude agents` attaches to is never started with `--print`) - `--allow-tools` grants specific tool permissions inline; denied tools are listed with an advisory to pass `--allow-tools` to grant them - The background session keeps running after detach; re-attach with `claude agents` from another terminal **Evidence** Error message (search for `"--bg and --print conflict"`) and denied-tool notice (search for `": denied tools (pass --allow-tools to grant):"`)

### SSH Sessions Now Support Model Catalog

**What**

SSH-connected remote sessions can now browse and switch models via `/model`, matching the capability previously only available over the CCR transport.

**Details**

- `modelCatalog` capability enabled for SSH transport (was `false`, now `true`)
- `/model` prompts the cloud session's model list and applies the selection there
- The thin-client picker renders disabled rows (models visible but not selectable) so the full catalog is visible even when some models are restricted

**Evidence**

Transport capability table — `modelCatalog: !0` for SSH (search for `"ssh"` in the transport caps block); UI strings (search for `"Models reported by the cloud session. Your pick applies to that session."`)

### Memory Stores Env Var

**What**

A new `CLAUDE_MEMORY_STORES` environment variable activates expanded memory storage, alongside the `tengu_moth_copse` feature flag.

**Usage**

`export CLAUDE_MEMORY_STORES="..."` **Details** - Feature-flagged via `tengu_moth_copse`; setting that flag OR providing a non-empty `CLAUDE_MEMORY_STORES` value enables the multi-store subsystem (`qat()` returns true in either case) - The env var accepts a **JSON array**; each element is either a bare path string or an object with fields: `path` (absolute, required), `mode` (`"rw"` | `"ro"`, default `"rw"`), `scope` (`"user"` | `"team"`, default `"team"`), `mount` (optional alphanumeric name auto-derived from the last path segment if omitted), `promptIndex` (optional relative path), `promptIndexMaxBytes` (optional integer) - Validation is strict: the JSON must parse cleanly, all paths must be absolute and must not override the host, mount names must match `/^[A-Za-z0-9_-]+$/`, duplicate mount names throw, and only one `scope:"user"` entry is permitted - At startup, successfully parsed stores are logged at debug level: `"memory-stores: parsed N store(s): mount(mode), ..."` - When active, the multi-store router (`uL()`) supersedes the default single-directory memory path, routing reads and writes to the configured stores based on scope **Evidence** `qat()` function (search for `"CLAUDE_MEMORY_STORES"` and `tengu_moth_copse` flag); `eue()` parser and `zqd` schema (search for `"CLAUDE_MEMORY_STORES is not valid JSON"` and `"CLAUDE_MEMORY_STORES has duplicate mount"`)

- Flag `tengu_moth_copse`: Off in both readings (read for one account on one subscription tier against v2.1.198; this account: off, 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.

## Improvements

### `/agents` Wizard Removed

The interactive `/agents` UI wizard has been removed. Claude now creates and manages subagents through natural conversation, and files can be edited directly.

What replaced it:

- Ask Claude: "Create a code-reviewer subagent that…" and it will write the file
- Edit `.claude/agents/` for project-scoped agents
- Edit `~/.claude/agents/` for personal agents
- The `(removed)` hint appears when the old `/agents` route is accessed

**Evidence**

Removal notice (search for `"The /agents wizard has been removed. Ask Claude to create or update subagents for you"`)

### TaskStop: Stop Agents by Name

The `TaskStop` tool now accepts agent names and team IDs in addition to task IDs.

**Details**

- Pass `name@team` or bare teammate name to stop an agent-team teammate
- Pass the named agent's name to stop a background agent started with a name
- Previously only raw task IDs were accepted

**Evidence**

Updated tool description (search for `"To stop an agent-team teammate, pass its agent ID (\"name@team\") or bare teammate name as task_id"`)

### Agent Spawn Results: Internal Metadata Privacy

Agent spawn tool results now include an explicit advisory telling Claude not to quote or paste the internal metadata (agent ID, task ID) into user-facing replies.

**Details**

- Async agent spawn: `"(This tool result is internal metadata — never quote or paste any part of it, including the agentId below, into a user-facing reply.)"`
- Cloud agent spawn: same advisory for taskId
- Local spawn: same advisory for agent_id
- Prevents Claude from accidentally exposing internal session identifiers to users

**Evidence**

Updated spawn result strings (search for `"This tool result is internal metadata — never quote or paste any part of it"`)

### Precomputed Conversation Compaction Persistence [Gradual Rollout]

**What**

Conversation compaction results are now pre-computed and persisted to a `.precompact.json` sidecar file, enabling instant compact rehydration when a session restarts.

**Details**

- Feature-gated by `tengu_amber_packet`; not universally enabled yet
- Pre-compact file is written to the session directory alongside the transcript
- At session start, if a valid `.precompact.json` is found and passes age/model/token-drift checks, the compaction result is reused without re-running the LLM summary
- Invalidation conditions: model changed, too old, transcript grew or shrank too much, boundary UUID missing
- Log messages: `"precomputed compact: rehydrated"`, `"precomputed compact: persisted"`, `"precomputed compact: rehydrate rejected (<reason>)"`

**Evidence**

File constant (search for `".precompact.json"`) and feature flag (search for `tengu_amber_packet`)

- Flag `tengu_amber_packet`: Off in both readings (read for one account on one subscription tier against v2.1.198; this account: off, 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.

### Context Fold Tool [Gradual Rollout]

**What**

A new `fold_boundary` task subtype allows the harness to insert context fold points in the conversation — compressing completed work to free context budget.

**Details**

- Feature-gated by `tengu_fold_tool`; additionally requires that the session is not running in remote/cloud mode (`gr()` must be false — the flag is a local-only capability)
- `vhp()` returns true when both conditions are met; `Vda()` then adds `"fold_boundary"` to the set of subtypes the loop dispatcher recognises alongside `"scheduled_task_fire"`
- When a `fold_boundary` system message is written to the transcript, it carries a `foldedUuids` array listing the UUIDs of the messages that were compressed; the display renderer treats this subtype identically to `scheduled_task_fire` (dimmed text with a clock prefix)
- During conversation collapsing, each `fold_boundary` message increments `foldedCount` by `foldedUuids.length`; the running total is then propagated to parent summary messages and included in the per-turn stats displayed to the user
- `foldedCount` is preserved when collapsing nested summaries: `if (t.foldedCount) e.foldedCount = (e.foldedCount ?? 0) + t.foldedCount`

**Evidence**

Feature flag check (search for `tengu_fold_tool`) and new subtype (search for `"fold_boundary"`); collapsing logic at `o.foldedCount = (o.foldedCount ?? 0) + l.foldedUuids.length`

- Flag `tengu_fold_tool`: Not enough to say (read for one account on one subscription tier against v2.1.198; this account: no value returned, anonymous baseline: no value returned, 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.

### MCP Per-Server HTTP Request Timeout

**What**

MCP server configurations now support a `request_timeout_ms` field that raises the per-request fetch deadline and the tool-call watchdog for that specific server.

**Details**

- Set by the host via `mcp_set_servers` control event; not a user-editable field in `.claude/settings.json`
- Capped at 5 minutes
- Applies to both stdio and SSE server types
- Overridden if `timeout` is also set on the server

**Evidence**

Schema description (search for `"Per-server HTTP request timeout in milliseconds, set by the host on the mcp_set_servers control event"`)

### Hooks: Improved Validation Error Messages

Hook configuration parsing now reports cleaner, more specific errors: invalid hook event names, malformed matcher arrays, and wrong top-level types each produce distinct messages with the offending path.

**Details**

- `"must be an object mapping hook event names to matcher arrays; received <type>"` for wrong root type
- `"unknown hook event. Valid events: <list>"` for unrecognized event names
- `"must be an array of matchers; received <type>"` for non-array event handlers

**Evidence**

New validator (search for `"must be an object mapping hook event names to matcher arrays"`)

### Windows Sandbox: Per-Exec Deny Flags

**What**

Windows sandbox commands now support per-exec `denyRead` and `denyWrite` path lists, matching Linux/macOS behavior.

**Details**

- Previously, Windows sandbox was deny-listed only at the session level
- Now individual exec calls can pass `filesystem.denyRead` and `filesystem.denyWrite` path arrays
- `filesystem.allowRead` (re-allow within denyRead) is still not supported on Windows — remove entries or narrow `denyRead`
- `filesystem.allowWrite` is still not supported on Windows (Windows sandbox uses deny-list only)

**Evidence**

Error messages (search for `"Per-exec filesystem.allowRead (re-allow within denyRead) is not supported on Windows"`)

### Atomic Write Staging Dir Tamper Detection

Internal write atomicity now includes inode-level identity checks on sandbox staging directories, rejecting writes if the directory was replaced or moved after being established by a sandboxed command.

**Details**

- When a sandboxed command first opens a staging directory (`qIs`), the directory's `dev` (device number) and `ino` (inode number) are recorded in an in-process map alongside a held open file descriptor (using `O_RDONLY | O_DIRECTORY | O_NOFOLLOW` to prevent symlink traversal)
- Before each subsequent atomic write, `FDt()` re-opens the directory with the same flags, calls `fstatSync`, and compares the live `dev`/`ino` pair against the recorded values; a mismatch (directory removed and recreated, or replaced by a symlink) triggers `_Ie()`, which throws `StagingDirTamperedError` and emits a `sandbox_exec` / `atomic_write_staging_dir_tampered` telemetry event
- A separate path (`zIs`) checks the parent of the staging dir: if the parent resolves to a symlink (ELOOP) or non-directory (ENOTDIR), a `SymlinkWriteRefusedError` is thrown with `"Refusing to stage atomic write under non-directory parent: <path>"`
- If the staging dir itself becomes ENOENT/ENOTDIR/ELOOP between establishment and write-time, the write falls back to a sibling path in the same directory rather than silently using a potentially hostile target
- `StagingDirTamperedError` is included in the harness's set of named sentinel error types reported to telemetry

**Evidence**

Error class (search for `"StagingDirTamperedError"`); inode comparison (`r.dev !== t.dev || r.ino !== t.ino`); throw site `_Ie()` (search for `"Refusing to stage atomic write under non-directory parent"`)

### Expired CA Certificates Auto-Removed

When building the TLS trust bundle from the system certificate store, expired certificates are now silently dropped and the count is logged.

**Details**

- The `kqu()` filter runs inside the lazy-initialised TLS trust-bundle builder (`kje`), which is invoked once and cached
- For each PEM certificate in the bundle, `new X509Certificate(s)` is constructed and its `validTo` field parsed via `new Date(...).getTime()`; if the resulting timestamp is in the past relative to `Date.now()` at load time, the cert is dropped and a counter incremented
- Certs that throw during `new X509Certificate(s)` construction (malformed DER/PEM) are **retained** rather than dropped — only cleanly-parsed, definitively-expired certs are removed
- Certs whose `validTo` parses to `NaN` (unrecognised date format) are also retained
- The log line is only emitted when at least one cert was dropped: `"CA certs: Dropped ${r} expired certificate(s) from system store"` (no message when the count is zero)

**Evidence**

`kqu()` function log (search for `"CA certs: Dropped"`); filter logic `new Date(i.validTo).getTime()` and `catch { return !0 }` retain-on-error branch

### control_cancel_request Message Type

A new `control_cancel_request` message type in the session transcript allows in-flight control requests (such as side questions) to be cancelled mid-flight.

**Details**

- Type carries a `request_id` string matching the outstanding `control_request`
- Workers that receive this message should abort the in-flight request

**Evidence**

Transcript parser addition (search for `"control_cancel_request"`)

### control_request_progress Messages

A new `control_request_progress` system message type provides progress updates for long-running client-originated control requests.

**Details**

- Currently applies to `side_question` control requests
- Status values: `"started"` (worker accepted and launched) and `"api_retry"` (includes retry counters)
- Correlated by `request_id`

**Evidence**

Schema description (search for `"@internal Progress for a long-running client-originated control_request"`)

### Skill Upkeep Guidance Improvement

The skill-upkeep hint now includes explicit instructions to fold user corrections back into the driving project skill file, so the next session inherits the fix.

**Details**

- The guidance is injected whenever Claude saves a `feedback`-type memory for a correction that concerns a repeatable step: verifying changes, committing, opening a PR, or running a project skill
- The instruction text (constant `KQr`) directs Claude to also edit the corresponding `.claude/skills/<name>/SKILL.md` file with a terse, general version of the same correction — so the fix is baked into the skill rather than only stored as a private memory
- Claude is told to **edit existing** skill files rather than creating new ones, because a new project skill shadows a same-named built-in skill by that name
- One explicit exception: if the correction concerns how to verify changes in the current repo and `.claude/skills/verify/SKILL.md` does not yet exist, Claude should create it

**Evidence**

Constant `KQr` (search for `"When you save a \`feedback\` memory because the user corrected how you ran a repeatable step"`)

### Highlight.js Grammar Refreshed

The bundled highlight.js language grammar definitions have been updated. Language definitions now use the modern `scope`/`match` API instead of the older `className`/`begin`/`end` API for improved accuracy and consistency. Plugin-provided hljs grammars are now also watched in worker mode (`hljsLanguages` added to the worker config watcher).

**Evidence**

Grammar modules updated (search for `"scope: \"attribute\""` in the Augmented BNF grammar) and watcher flag (search for `hljsLanguages` in the config object)

### Speculation Engine Removed

The speculative-execution subsystem (which pre-ran tool calls ahead of user confirmation to save latency) has been fully removed.

**Details**

- All `[Speculation]` log messages, state machines, and the pipelined-suggestion pathway are gone
- `totalSpeculationTimeSavedMs` is no longer tracked in usage stats
- Behavioral change: no pre-executed tool calls; permission prompts now always pause before execution

**Evidence**

Removal of all `[Speculation]` strings and `totalSpeculationTimeSavedMs` field from the stats shape

### MCP Tip Improved

The MCP expansion tip (shown when a user is manually pasting data from a service already coverable by an MCP server) now requires the tip to name the specific service being bridged, rather than citing the user's existing unrelated servers.

**Details**

- The `mcp-expand` tip fires when `e.mcpClients.length >= 1` (at least one MCP server is already configured) and the user is manually pasting data the model determines could be sourced via MCP
- The updated `situation` string now contains the explicit constraint: `"The configured servers are an eligibility signal only — the tip must name the service the user is manually bridging (e.g. 'the GitHub MCP would let you query issues directly'), never cite their existing unrelated servers as justification"`
- This prevents the model from producing a generic tip like "you already have MCP, add more" and forces it to identify and name the specific unmapped service
- Feature text presented to the user: `"You can add more MCP servers for services your current ones do not cover."` with action `/mcp`
- Contrast with the `mcp-discovery` tip (no MCP at all, `e.mcpClients.length === 0`) which introduces MCP from scratch

**Evidence**

Updated tip situation string (search for `"The configured servers are an eligibility signal only"`); `when` condition `e.mcpClients.length >= 1` in the `SXn` tip array

## Bug Fixes

- Tool denial kind no longer conditionally omitted based on a flag — `"user-rejected"` is now always set when a tool is denied by the user (search for `"toolDenialKind"`)
- `cd` command path resolution now correctly handles shell-quoted tilde paths and glob segments without returning false negatives (search for `"rqd"` path resolver function)
- Transcript writes during process exit are now guaranteed to flush synchronously via a `process.on('exit')` handler, preventing lost transcript lines when the process exits quickly (search for `".precompact.json.tmp"` flush path)
- PostgreSQL highlight.js grammar now correctly declares `supersetOf: "sql"` so SQL sub-patterns are inherited automatically (search for `"supersetOf"`)

## New Environment Variables

- `CLAUDE_CODE_SKIP_PROMPT_HISTORY` — Disables saving CLI input to prompt history
- `CLAUDE_LOCAL_OAUTH_API_BASE` — Sets a local OAuth API base URL for development
- `CLAUDE_SDK_CAN_USE_TOOL_SHADOWED` — Allows SDK tool shadowing
- `CLAUDE_CODE_MOCK_REMOTE_SETTINGS` — Mocks remote settings responses (development/testing)
- `CLAUDE_CODE_REMOTE_SETTINGS_PATH` — Path to a local file providing remote settings overrides
- `CLAUDE_CODE_CLIENT_KEY_PASSPHRASE` — Passphrase for the mTLS client key
- `CLAUDE_CODE_CUSTOM_OAUTH_URL` — Override the OAuth endpoint URL
- `CLAUDE_CODE_ENABLE_PROXY_AUTH_HELPER` — Enables the proxy authentication helper
- `CLAUDE_CODE_PROXY_AUTH_HELPER_TTL_MS` — TTL for proxy auth helper tokens in milliseconds
- `CLAUDE_CODE_PROXY_RESOLVES_HOSTS` — Signals that the proxy resolves hostnames (affects DNS behavior)

## Notes

**Node.js 22 Required:** This release raises the minimum Node.js version from 18 to 22. Run `node --version` to check; upgrade via your package manager or [nodejs.org](https://nodejs.org) before updating Claude Code. Any existing install scripts or CI environments pinned to Node 18 or 20 will need to be updated.

**`/agents` wizard gone:** Workflows relying on the interactive `/agents` menu (Create agent, Edit agent, Delete agent) no longer exist. Transition to asking Claude directly: `"create a code-reviewer subagent that..."` or edit `.claude/agents/*.md` files manually.
