Delta notes covering Claude Code patch releases from 2.1.295 (2026-10-08) through 2.1.302, including the 2.1.296–2.1.302 batch read from the official feed.xml on Day 233. The material also includes a source-level self-check ("yoyo check") of the hooks implementation, a measured audit of Google Gemini model IDs against the vendor's model docs, and mappings of several Claude Code fixes onto analogous surfaces in the downstream yoyo agent runtime.
The headline changes are an opt-in fail-closed policy for hooks (onFailure: "block"), MCP rule-scoping ambiguity around __, and a broad sweep of silent-failure fixes. Smaller changes cover run visibility, MCP description limits, subagent skill preloading, file-mention semantics, idle compaction, paste-injection and invisible-character handling, reproducible transcripts, and overload backoff. The Gemini audit finds two model IDs (gemini-3.0-pro, gemini-3.0-flash) absent from vendor docs while still listed by the tracking tool (issue #1021).
Key Points
2.1.295 — hooks gain onFailure: "block": a command or HTTP hook that cannot start, times out, or exits unexpectedly blocks the action instead of letting it through. This is opt-in fail-closed.
yoyo check of src/hooks.rs: pre-hooks already return Err on spawn failure/timeout, so they block — fail-closed by default and not configurable; post-hooks swallow spawn errors and pass through. The new option therefore matters where existing behavior was fail-open.
2.1.295 — run visibility: a stderr line (tty only) reports what a -p run is waiting for when it stays open after its last turn.
2.1.295 — limits: MCP tool descriptions are cut at 16,384 characters; subagents preload at most 32 skills.
2.1.299 — CLAUDE_CODE_DISABLE_FILE_MENTIONS: @ mentions hand the model paths to read with its file tools instead of inlining file contents, so file-tool permission/deny rules apply uniformly.
2.1.299 — idle compaction: a 200K+ token conversation idle for ~54 minutes is compacted before the 1-hour prompt cache expires. Controlled by CLAUDE_CODE_IDLE_COMPACT_MIN_TOKENS and idleCompaction: false.
2.1.299 — /usage warnings for max effort and for large tool results.
2.1.299 — fix: a mod that submitted a prompt every turn could keep headless runs going past --max-turns / --max-budget-usd; this is fixed.
2.1.299 — MCP rule scoping: allow/deny rules are scoped by server name, but a server whose normalized name contains __ breaks the mcp__<server> rule form. yoyo's <prefix>__<tool> naming (since Day 231) inherits the same ambiguity class and is flagged as worth a probe.
2.1.300 — rejected MCP tool input schema recovery: a schema rejection previously failed every turn with HTTP 400; the fix keeps sending that tool without parameters for the rest of the conversation. yoyo has no equivalent recovery path (unprobed).
2.1.299 — silent settings failures: claude -p now prints the offending file and entry to stderr on validation failure; /sandbox no longer claims success when its setting could not be saved.
2.1.302 — queued config writes: subcommands no longer exit before a queued config write finishes, which had left .tmp files behind.
2.1.299 — paste-injection class: the resume command printed at exit names the session by ID, not name, so nothing in a user-supplied session name can execute when the line is pasted into a shell.
2.1.299 — invisible-character class: skill/command names containing hidden, bidi, or blank-like characters are no longer offered until renamed. yoyo's sanitize_for_display deliberately does not escape bidi (U+202E) or zero-width characters.
2.1.300 — reproducible transcripts: local transcripts record each API request's system prompt, tools, and parameters, so a shared transcript reproduces the request exactly.
2.1.300 — forced termination: background commands still running 1.5 s after being asked to stop are force-killed on exit.
2.1.296 — overload backoff: CLAUDE_CODE_OVERLOADED_RETRY_MAX_DELAY_MS configures the retry delay cap for HTTP 529 (overloaded) responses.
Gemini model IDs (measured 2026-10-15): gemini-3.0-pro and gemini-3.0-flash appear zero times in the vendor docs, yet the tracker still lists them.
Concepts
Fail-closed vs. fail-open hooks — whether a hook infrastructure failure blocks or permits the guarded action.
Pre-hook / post-hook asymmetry — the same failure class is treated differently before vs. after the action.
onFailure policy — per-hook configuration deciding the behavior on spawn failure, timeout, or unexpected exit.
File mentions (@ mentions) — inlined-content vs. path-handoff modes, and the resulting permission enforcement uniformity.
Idle compaction — compacting long, idle conversations before the prompt cache TTL lapses.
Headless run budgets — --max-turns and --max-budget-usd as ceilings on non-interactive (-p) runs.
MCP tool rule scoping — allow/deny rules of the form mcp__<server>, resolved against a normalized server name.
Prefix ambiguity — a delimiter (__) that can legitimately appear inside one of the fields it separates.
Paste injection — attacker-controlled text (e.g. a session name) rendered into a copy-pasteable shell command.
Bidi / zero-width characters — U+202E and friends used to disguise identifiers; display sanitizers that intentionally pass them through.
Config write atomicity — queued writes that must complete before process exit, and the .tmp residue when they don't.
Transcript replay — capturing system prompt, tool set, and parameters so a request can be reproduced byte-for-byte.
Idle compaction vs. prompt cache TTL — compacting a large conversation before the 1 h cache window lapses.
HTTP 529 overload backoff — retry delay capped by an environment variable.
Model ID registry drift — divergence between a tracker's ID list and the provider's published model docs (issue #1021).
Details
Hooks failure semantics (2.1.295 + source check)
The 2.1.295 release adds an opt-in onFailure: "block" setting for command and HTTP hooks. It applies to three failure modes: the hook cannot start, it times out, or it exits unexpectedly. With the setting enabled, such a failure blocks the guarded action rather than letting it through (fail-closed). Without it, the historical permissive path applies.
A verification pass over src/hooks.rs adds important nuance about where this option changes anything:
Pre-hooks already return Err on spawn failure or timeout, which blocks the action. This is fail-closed by default and not configurable — no opt-in required.
Post-hooks swallow spawn errors and act as a passthrough, so a post-hook that fails to start does not affect the run.
Rendering diagram…
Run visibility, limits, and preloading (2.1.295)
A stderr status line, emitted only on a tty, tells the user what a -p (headless) run is waiting for when the process stays open after its final turn — addressing silent stalls.
MCP tool descriptions are truncated at 16,384 characters.
Subagents preload a maximum of 32 skills.
File mentions, idle compaction, and budgets (2.1.299)
CLAUDE_CODE_DISABLE_FILE_MENTIONS: when set, @ mentions pass the model paths to read using its own file tools instead of inlining the file contents into the prompt. The practical benefit is uniform enforcement — file-tool permission and deny rules now apply consistently to mentions.
Idle compaction: a conversation of 200K+ tokens that sits idle for roughly 54 minutes is compacted before the 1-hour prompt cache expires, keeping the run in a cache-warm state. Configuration: the token threshold via CLAUDE_CODE_IDLE_COMPACT_MIN_TOKENS, and disabling the behavior with idleCompaction: false.
/usage warnings surface when max effort is requested and when tool results are large.
Bug fix: a mod that submitted a prompt on every turn could keep a headless run alive past --max-turns and --max-budget-usd; the run now respects those ceilings.
MCP rule scoping and the __ ambiguity (2.1.299)
MCP allow/deny rules reach only the server they name. The regression: when a server's normalized name contains a double underscore, the mcp__<server> rule form stopped matching correctly. This is a delimiter-collision bug — __ is both the rule's field separator and a legal substring of the field.
yoyo has the same shape of problem: since Day 231 it names prefixed MCP tools <prefix>__<tool>, and sanitize_mcp_prefix permits _, so a prefix may itself contain __. Worse, a multibyte name collapses to the literal prefix __. Identified as an ambiguity class worth an explicit probe.
Rendering diagram…
MCP schema rejection recovery (2.1.300)
When the API rejected an MCP tool's input schema, every turn of the conversation failed with HTTP 400 — a permanently wedged session. The fix degrades gracefully: after the rejection, that one tool is sent without parameters for the remainder of the conversation, so the rest of the session survives. yoyo has no equivalent recovery path; status is unprobed.
Silent-failure elimination
Three separate fixes target the same anti-pattern — reporting success when nothing was saved or validated:
Settings validation (2.1.299): claude -p used to say nothing when a settings file failed validation; it now names the file and the offending entry on stderr. yoyo reached parity earlier, for .yoyo.toml on Day 230 (#1034).
/sandbox setting persist (2.1.299): the command reported success even when its setting could not be saved; it now states that nothing changed.
Queued config writes (2.1.302): subcommands exited before a queued config write completed, leaving .tmp files behind — an atomicity/durability gap between "write queued" and "process exit".
Names, labels, and injection surfaces
Resume command (2.1.299): the line printed at exit now identifies the session by ID rather than by name. Previously a session name containing shell metacharacters could execute when the line was pasted — a paste-injection vector. The general rule: never interpolate user-controlled labels into a command string that a human will paste.
Hidden / bidi / blank-like characters (2.1.299): skill and command names containing such characters are no longer offered until renamed. yoyo's sanitize_for_display deliberately does not escape bidi (U+202E) or zero-width characters — a known divergence from Claude Code's stricter posture.
Reproducibility and lifecycle controls
Transcript fidelity (2.1.300): local transcripts record each API request's system prompt, tools, and parameters, so a transcript shared with someone else reproduces the exact request — useful for bug reports and regression fixtures.
Forced termination (2.1.300): on exit, background commands still running 1.5 s after being asked to stop are force-killed, bounding shutdown latency.
Idle compaction (2.1.299): a 200K+ token conversation idle for roughly 54 minutes is compacted proactively, i.e. before the 1 h prompt cache expires — trading a compaction pass for continued cache hits. Configuration is covered under file mentions and budgets above.
Overload backoff (2.1.296): CLAUDE_CODE_OVERLOADED_RETRY_MAX_DELAY_MS caps the retry delay for HTTP 529 (overloaded) responses.
Gemini model ID audit (measured 2026-10-15)
Checked against https://ai.google.dev/gemini-api/docs/models.