fix(acpmux, agent pane): Ctrl-B works in the cmux model router's chats; acpmux says which chats it moves

Merged
TE
15d ago
+194-66

Ctrl-B now works in chats from the cmux model-router profile. Before, the pane decided which chats get Ctrl-B from the harness's name (claude or claude-*), but acpmux accepts _acpmux/process/background for any Claude Code (claude-stdio) harness. Two things went wrong:

  • The router profile runs Claude Code under the name cmux, so it got no Ctrl-B.
  • An ACP agent that a user's config named claude-* showed the hint, and acpmux then refused the request.

What changed

  • acpmux: every session summary now has backgroundsWork. acpmux computes it with the same check process/background uses (backgrounds_work in hub/processes.rs: the profile's kind is claude-stdio). So the summary and the request always agree.
  • The spec (spec/acpmux-protocol.json) and the generated types.ts are regenerated. docs/background-processes.md now says clients offer Ctrl-B from this field, not from the name.
  • Pane: backgroundsWork() reads the summary's field, plus the existing no-peer and not-Cloud checks. If the summary doesn't have the field (an older acpmux), the chat gets no Ctrl-B. For another harness, a peer's chat, or a Cloud chat, the hint stays hidden and Ctrl-B stays the composer's, as before.
  • Gallery: agent-pane.background-hint gains a router variant (hint shown) and a claudeAcp variant (no hint). The shared chat() fixture sets the field for Claude chats, so other gallery entries don't change.

Why a summary field: steering already works this way (a capability the session summary reports, which clients read). It also lets the client stop guessing harness names. The other option, initialize's operations list, applies to the whole connection, not to one chat.

Changelog

Fixed: Ctrl-B moves running work to the background in chats from the cmux model router, and the Ctrl-B hint no longer shows in ACP chats that only have a Claude-like name.

Tests: red on the base, green on the head

The tests are committed alone first (763316662ea), and the fix follows (88f6549ed18). Everything ran on cmux16.

  • cargo test -p acpmux --test hub_integration a_chats_summary_says_whether_ctrl_b_moves_its_work
    • Base + tests: FAILED. backgroundsWork is Null where false is expected.
    • Head: ok.
  • bun test test/run-in-background.test.ts
    • Base + tests: 2 fail. The cmux chat got false, and the claude-acp chat got true.
    • Head: pass.
  • CMUX_BROWSER_TESTS=1 bun test test/agent-pane-ctrl-b-background.test.ts
    • Base + tests: 2 fail. "the model router's chat … shows the hint and moves its work" and "an ACP agent named claude-acp shows no hint and keeps Ctrl-B".
    • Head: all pass.

Observed / Not run

Observed on cmux16 at the head (1bc4ff07a83, after merging feat-cmux-next at 1369f27dcd3):

  • Rust:
    • all 38 processes hub tests pass (the new one, Ctrl-B, the Codex processes)
    • protocol_ir_is_current passes
    • cargo fmt --check is clean
    • clippy -p acpmux --all-targets (run before the merge) reports only three warnings, all outside this change and all on the base: sort_by_key in cmux-worktree-care, cmp_owned in steer_now_tests, and double_ended_iterator_last in tests/prompt_images.rs
  • Webviews:
    • vp check finds no warnings, lint errors or type errors
    • the other check scripts pass, and acpmux-protocol:check reports the generated code is current
    • bun run check stops at check:switch-fetches, which is red on 1369f27dcd3 too (composer/keptAttachments.ts:134)
    • the run-in-background unit tests pass. ui-rules fails on CopyButton.tsx:43-44, which is red on 1369f27dcd3 too
    • the browser Ctrl-B test passes (12 tests), including the base's new notice tests

Before the merge, on 3020a012c47 plus this change, bun run check showed 0 errors. Its two warnings are in HistoryPage.tsx and test/sidebar-rail-css.test.tsx, neither touched here.

Four acpmux tests fail the same way on 3020a012c47 with and without this change, so they are base reds:

  • lib: protocol_registry_names_every_served_method
  • lib: care_a_stopped_daemon_s_sessions_are_use_not_open
  • hub_integration: session_offers::an_offered_chat_is_a_chip_only_…
  • hub_integration: transfer_guard::a_chat_with_no_asking_mode_moves_…

Not run:

  • the full acpmux suite on Linux or Windows (CI covers those)
  • a live router chat in a tagged build

No capture: this is a webview-only change. The browser test and the agent-pane.background-hint gallery variants cover it.

🤖 Generated with Claude Code
Agent session: cosmic-gray


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.


Summary by cubic

Fixes Ctrl-B in chats from the cmux model router profile. The pane previously decided which chats offer Ctrl-B from the harness name (claude or claude-*), but acpmux accepts background requests for any Claude Code (claude-stdio) harness. So the cmux router profile got no Ctrl-B, while an ACP agent named claude-* showed the hint and got refused.

Every session summary now reports backgroundsWork, computed with the same check that _acpmux/process/background uses. The pane reads this field instead of guessing from the harness name.

  • Across both cmux and the agent pane, a chat's backgroundsWork comes from the summary, so the hint and the request always agree.
  • An acpmux that does not report the field (older version) gets no Ctrl-B.
  • Tests cover the cmux router chat (hint shown, work moves) and an ACP agent named claude-acp (no hint, Ctrl-B refused).