cmux NEXT: one compact group for agents' waiting messages; one grid for the subagent strip

Closed
TE
6d ago
+1636-520

Leo, 2026-10-29:

  • "why the fuck do you guys keep doing this fucking bullshit with the red after this turn?"
  • "And these need to be fucking grouped up... How are there so fucking many messages? ... First off, why the fuck aren't they folded into the big, like 200-plus fucking messages?"
  • "? WHY AM I SEEING TURN OFF QUEUING ON AGENT MESSAGES???? SHOUL DI DO THAT???"
  • "why the fuck do you even have this instead of just being able to click on the fucking name of the thing, the open chat?"
  • "why is this styled like this?" (a sub-session's note to its parent drawn as a plain box of raw text)
  • "You did this alignment in a completely fucked up way. There's this right indent for no reason."
  • "why are you saying sub-agent so many fucking times? Like, you can just add the icon when it's in here."
  • "does it make sense to remove the entire compacted view? No. So don't do it."
  • "this ui is all quite inconsistent and not even that awesome in the first place but it's a bit serviceable i guess..."

Takes back #27312: its one loose line per waiting message is replaced, as Leo asked, by one collapsed "N messages from M sessions" group (each message still its own line, whole when opened).
Takes back #27816: it only taught queuedMessages.test.ts the queue's lead row ("Read after this turn"), which this pull request removes at Leo's ask (removing the "read after this step").

What was wrong

  • Queued agent messages: they drew as a loose list of full-width rows under "Read after this turn". Duplicates showed twice, and the ⋯ menu was the composer's own-prompt queue menu (Turn off queueing, Edit message, Move up/down).
  • Sub-session notes: acpmux send --no-wait delivers through the daemon's outbox (client acpmux-outbox#…). The webview read a "From X:" sender only for acpmux-cli#/acpmux-peer#, so these notes drew as the person's own prompt with the raw prefix and URL.
  • Subagent tray alignment: every line reserved a 40px trailing stop track even with no stop button, the header kept an empty stop slot, and View all reserved nothing. The three chevrons sat at three x positions.

What changed

  • One group for waiting messages: they go in one collapsed "N messages from M sessions" group (PendingMessagesCard), grouped by session when opened and deduplicated by delivery id or by sender plus text. Collapsed rows stay one line; only the row you open shows its full text. The compact view stays.
  • No "after this" labels: "Read after this turn" and "Read after this step" are gone, with no replacement text.
  • Sender name opens its chat: clicking it opens the chat, the separate Open chat button and the "From:" line in the body are gone, and the hover covers only the name.
  • A message's own menu: the ⋯ menu holds Send now (offered once) and Dismiss, never the person's queue actions; Copy is a hover button beside it. The ⋯ stays lit while its menu is open.
  • Hidden duplicates go with the shown copy: Dismiss and Send now also remove the deduplicated twins of a message (twins on the queued entry), so a duplicate never resurfaces after the one you acted on is gone.
  • One row for every agent message: a delivered message and a waiting one draw the same line: one hover plate under the whole line, the same plate open or closed, every chevron on one x, and one action group shown only on hover over the preview's tail (age, Copy, Retry, Pin on a delivered one; Copy and ⋯ with Send now and Dismiss on a waiting one). No Open chat, no From: line, no "Read after this step".
  • Outbox notes: they now name their sender, with the "From X:" prefix stripped. A bare GitHub PR or issue URL previews as owner/repo#N.
  • One tray grid: the header, lines and View all share one inset, one leading icon column and one trailing track. That track holds the stop button's width only while a line has one, and View all's text starts on the names' column.
  • Subagent icon: a subagent line marks its kind with its own icon (agent.fork, distinct from the chat bubble) instead of the word. "Subagent" stays its accessible name, the spinner stays the working mark, and "Command" lines keep their word.

Geometry, measured by the real-Chromium test subagent-tray-columns.test.ts: the header's chevron, every line's chevron and View all's chevron now end on one x. Before, they were at about x=1452 (header), 1460 (lines) and 1513 (View all) in the reported 1568px shot. The grid uses tray-local tokens (--acpmux-tray-inset, -icon, -gap, -lead, -trail) that will fold onto the shared grid tokens once #27539 lands.

Tests

cmux-ci test (fleet Linux, Chromium for the column test), 82 pass:

  • queuedMessage.test.ts: an outbox "From claude-sr2/ui-think-tank: merged …" names that sender, and "From now on: …" stays the person's prompt.
  • incomingMessage.test.ts: PR and issue URLs preview as owner/repo#N, and trailing punctuation stays.
  • queue-agent-message.test.tsx: no "Read after this turn"/"step"; the name opens the chat; a peer row's menu is Send now and Dismiss (Copy on hover), with none of Edit, Move up/down or Turn off queueing; Send now is offered only once.
  • pendingMessages.test.ts / queue-agent-message.test.tsx: dismissing or sending a deduplicated message also drops its hidden twins.
  • subagent-tray.test.tsx: a subagent line has its icon, not the word, and keeps its spinner.
  • subagent-tray-columns.test.ts: the header, line and View all chevrons share one right edge, in dark and light.

Observed / Not run

  • Observed: the runs above. A first run before the test updates failed on the four old tests that asserted the removed copy and menu, and on a trailing-comma case in the new URL label, which is now fixed.
  • Not run: a native capture (webview only; before/after comes from the gallery advisory run on the states below).

Reds

  • Non-browser webview reds: the 77 failing tests fail identically on base (compared per test name).
  • release-notary test_digest highlights: red on base too; this PR changes no whats-new files.
  • react-apps-base-check (4): model-pick-prompt-focus.test.ts (model menu search focus) failed on the head run and passed on the base replay. This PR touches no model picker or composer focus code; re-run to rule out a flake.

Before / after

Viewed after image: yes

StateBeforeAfter
Eleven waiting messageseleven baseeleven head
A waiting message's menumenu basemenu head
Sub-session outbox notes(state new in this PR)subsession outbox head
Subagent traytray basetray head

Gallery: agent-pane.queued-agent-messages/eleven, agent-pane.queued-agent-messages/subsession-outbox, agent-pane.queued-agent-messages/menu, agent-pane.subagent-tray/between-turns

Changelog

Fixed: Messages from other agents wait in one compact group without "Read after this turn", open the sender's chat from its name, and a sub-session's notes show their sender; the subagent strip's chevrons line up.

Daemon side, not in this PR (sent to acpmux's owner): prompt_line.rs has the same acpmux-cli/acpmux-peer-only check, and an outbox delivery should carry the sender's harness so the row can show its logo.

🤖 Generated with Claude Code

Agent session: agent session