Skip to content

v2.1.32 — Claude Code v2.1.219/220 compatibility

Choose a tag to compare

@agent-kay-it agent-kay-it released this 28 Jul 13:38
· 51 commits to main since this release
cb7f9b5

Claude Code v2.1.219 reversed v2.1.217 and made subagents spawn nested subagents at depth 3 by default. Combined with v2.1.218 moving /code-review to a background subagent, the main turn now routinely ends while subagents are still alive — which quietly broke assumptions bkit had carried since v1.5.3.

Every defect in this release was reproduced before it was fixed, using claude -p --plugin-dir . against CC v2.1.220 with a depth-2 probe and real concurrent processes. Nothing here was inferred from a changelog.


What changes for you

Your team panel was lying to you

If you have ever run /pdca team or /sprint start and seen an agent stuck at "spawning", or a teammate marked complete while it was clearly still working — that was this.

The Stop hook cleared the team roster while subagents were still running. In a clean reproduction, 4 out of 4 SubagentStop calls were orphaned: the roster was wiped, re-initialised from scratch by the next spawn, and every status update afterwards had nothing to update.

Claude Code was already telling bkit how to tell the difference — the Stop payload carries background_tasks, documented upstream as "lets hooks distinguish 'session is done' from 'session is paused waiting for background work to wake it'". bkit read it nowhere. It does now, at all three cleanup sites.

You will also notice the roster is finally accurate. Every teammate used to be labelled sonnet regardless of its actual model — 18 of bkit's 34 agents are not sonnet. Names were opaque internal IDs. Both are fixed, because the handlers stopped reading four fields Claude Code never sends and started using the ones it does.

The Claude Code version advisory had never once appeared

The install-floor warning, the ENH-368 model-floor notice for Fable-pinned agents, the recommended-version advisory — none of them had ever rendered for anyone.

Detection ran claude --version under a 200 ms budget. Claude Code now ships as a ~264 MB native binary, and that call measures 302–327 ms (5/5 runs). It could never succeed. Worse, the failure was written to cache and served back as a valid answer for the full hour, then re-cached — so it healed itself into permanent silence. This is also how RECOMMENDED_VERSION drifted twenty releases without anyone noticing.

Detection now reads the native installer's symlink first: 0 ms instead of 302–327 ms, no subprocess at all. Only successful detections earn the long cache; failures expire in a minute and retry.

/btw works again

Bare /btw answered "isn't available in this environment" — a different message from "Unknown command", meaning Claude Code knows the name and gates it. A sweep of all 28 user-invocable skills found this is the only such collision. Use /bkit:btw, which the skill now advertises.

Nested-agent guidance is honest again

cto-lead and pm-lead told you Task() was "blocked by Claude Code's nested spawn restriction", under a heading pinned to v2.1.69 — 150 releases stale. That has not been true since v2.1.219.

Worth knowing: the depth limit resolves through CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH → a remote feature gate → a hardcoded 3. It can change server-side with no Claude Code release. If you want a guaranteed bound, set the environment variable explicitly — that is now documented as the only deterministic control.

The three workflow presets are back

default, hotfix and enterprise were specified in detail by the test suite but had gone missing from the tree, so the workflow engine returned null in every installation. Restored from that specification: default keeps all nine PDCA phases at match rate 90, hotfix skips pm and design and drops to 80, enterprise adds a parallel check fan-out carrying a mandatory security-review branch at 95.


Reliability

A file lock could be stolen from its holder. Eight concurrent writers to the team roster produced seven rows, with every worker reporting success. lock() creates the lock file and then writes it, so a competing process could read zero bytes, classify it as corrupt, delete a live lock, and enter the critical section alongside the holder.

8 concurrent writers, 3 trials
before 7/8, 6/8, 7/8
after 8/8, 8/8, 8/8

This was pre-existing and affected every lockedUpdate consumer, including loop-breaker's cross-process counters. A companion fix: lock() never created its parent directory though write() always has, so on a fresh project the persisted counters silently never accumulated.

The test suite went from 20 failures on main to 0 (347/347). Two were genuine isolation defects that made results depend on execution order — one suite was reading and writing the repository's own token ledger, another was reading live project state — and the rest were assertions that had stopped tracking deliberate changes.


Compatibility

No breaking changes. No migration.

  • Recommended Claude Code runtime: 2.1.218 → 2.1.220. v2.1.219 → 2.1.220 was verified a no-op for every surface bkit integrates against (feature gates 1754/1754 identical; hook, subagent, plugin, skill, MCP and fork/background surfaces unchanged).
  • Unchanged: MIN_VERSION 2.1.78, install floor 2.1.143, Fable model floor 2.1.170.
  • Consecutive compatible releases: 163 (v2.1.34 – v2.1.220).

Full detail in CHANGELOG.md. Impact analysis: docs/04-report/features/cc-v2219-v2220-impact-analysis.report.{ko,en}.md.