acpmux: Claude Code's /context breakdown and MCP reconnect

TE
11d ago
+1008-31

Adopted and rebased (2026-10-25). The lane that opened this died on cmux16; hb-acpmux adopted it. The branch is now one squashed commit on feat-cmux-next plus a rustfmt-only commit. #24303 had already landed the web side (the AcpmuxContextBreakdown type, contextBreakdownOf, and the session-start test it reads), so that part is dropped here. What stays is the daemon side that produces contextBreakdown and _acpmux/mcp/reconnect. The daemon's output matches the type #24303 reads: categories[{id?, name, tokens, kind}], memoryFiles, mcpTools, optional skills, totalTokens and maxTokens. Base had changed some of the same code, so four conflicts were resolved by hand:

  • hub/permissions.rs keeps base's goal_write/mark_cleared and saves on goal_write || breakdown_changed.
  • hub/views.rs keeps goal beside contextBreakdown.
  • server/requests.rs: initialize lists base's extensions plus MUX_MCP_RECONNECT.
  • docs/acpmux-schema.json: base's SessionDetail plus the contextBreakdown text.

The earlier "SDK schema drift checker" red was the stale merge. At this head, test_check_sdk_schema.py and check-sdk-schema.py both pass, and bun run acpmux-protocol:check is clean.

Tests at this head (fleet, cmux-ci test)

  • cargo fmt --check is clean and cargo clippy -p acpmux --all-targets -D warnings passes. The first run caught three rustfmt lines; commit 7ed6a0d fixes them.
  • cargo test -p cmux-agent-pane-policy passes (Swift and TypeScript parity included).
  • cargo test -p acpmux: all of the PR's tests pass (claude_stdio::context_usage_tests, hub_integration context_window and claude_failover, local_app_trust_gate). Three tests fail, and each fails the same way on base 337d37c:
    • daemon_chat_open fails its open-read budget (5.3 MB against a 4 MB budget).
    • session_pool::pooled_sessions_end_with_the_daemon_and_after_a_crash fails 3 of 3 runs on base and on head.
    • harness_login::codex_bridge_status is flaky: it passed 3 of 3 on rerun at both base and head.
  • Webviews: agent-pane-session-start.test.ts passes 4 of 4, and bun run typecheck finds no errors.

Review

A fresh Codex (gpt-6-astra, xhigh) reviewed this head and said SHIP. It checked:

  • that the four earlier review rounds' fixes survived the rebase (the trust gate, cleanup when a reconnect times out, breakdown persistence, the failover clear, the generation guard against a retired agent);
  • the conflict resolutions;
  • that the breakdown shape matches what #24303 reads.

Stop conditions: no new timer or observer. The reconnect request has a 30 s bound (RECONNECT_TIMEOUT), and its pending entry is removed when that bound runs out.

The agent pane's Inspector needs Claude Code's /context breakdown for its Context card and a way to reconnect a failed MCP server. acpmux now supplies both for Claude Code chats.

Context breakdown. When a turn ends (its result), acpmux sends Claude Code get_context_usage with detail: "summary". That mode uses the last response's usage, so it makes no token-count API calls. The request goes out after the turn's answer, so the turn never waits on it. acpmux trims the reply and keeps it on the session. _acpmux/info and attach return it as contextBreakdown. It also goes out as a session_info_update with _meta.acpmux.contextBreakdown, so an attached pane gets it live. The shape:

{"categories": [{"id": "system_prompt", "name": "System prompt", "tokens": 3000, "kind": "used"}],
 "memoryFiles": [{"path": "/repo/CLAUDE.md", "type": "Project", "tokens": 120}],
 "mcpTools": [{"name": "mcp__cmux__a", "serverName": "cmux", "tokens": 40}],
 "skills": [{"name": "pdf", "tokens": 30}],
 "totalTokens": 3900, "maxTokens": 200000}
  • id appears only when Claude Code gives one.
  • kind is used, free, buffer or deferred.
  • skills appears only when skills take context.
  • Each list holds at most the 50 largest rows.
  • Grid rows and colors are dropped. The raw reply is not logged; only the trimmed update is.

When Claude Code refuses the request (older CLIs answer "not supported"), the field stays null.

MCP reconnect. The new _acpmux/mcp/reconnect {sessionId, server} sends Claude Code's mcp_reconnect (serverName) to the chat's running process.

  • It answers {} on success, or with Claude Code's own error.
  • On success, the server's row reads connected in mcpServers. Watchers get session_changed kind tools.
  • It never starts a process. A chat without a running Claude Code is refused, because its servers connect when it starts.
  • Other harnesses are refused with data.reason: mcp.unsupported.
  • Remote browsers are refused with tools.remote, the same rule as set_tools, because reconnecting restarts the server's configured command.
  • New capability: mcp-reconnect-v1.
  • Also updated: the docs schema, the protocol IR and the generated web method list.

Web pane. The contextBreakdown type and its reading in direct.ts already landed with the Context card in #24303, so this PR no longer carries them. It adds direct.ts reconnectMcp(server) and clears the breakdown on a failover record. cmux-agent-pane-policy and AcpmuxPaneMethods.swift list _acpmux/mcp/reconnect as a session-scoped request, so the app's pane relay forwards it.

Observed / Not run

  • Observed: scripts/web-lint.sh passed and scripts/cmux-next/prepush-gate.py reported no new violations. Claude Code 2.1.307's own control schema shows the get_context_usage reply shape and the mcp_reconnect request it parses.
  • Not run locally: cargo, per the no-local-build rule. The acpmux Rust tests (new: claude_stdio/context_usage_tests.rs and three tests in tests/hub_integration/context_window.rs) run on the fleet against this head and in PR CI.
  • Not run: a live Claude Code session through the pane.

No capture: acpmux protocol change, no UI

Changelog

none

Agent session: big-red
🤖 Generated with Claude Code