Agent chat: flush running card, steady Send now, and an Edit message that never does nothing
Summary
Leo, 2026-10-29, on the agent chat's composer during a running turn:
"Dude, I hate how the fing composer acts like this... Number one: the fing rendering is stupid as hell."
"why the f*** do you still have this fing thing at the bottom of the running thing? Like, look at this. It's just unnecessary, stupid-ass fing padding. Like, it doesn't look good to do this. It doesn't f***ing mean anything."
"Plus this fing edit message thing. It doesn't even fing work. And it fing blinks with the fing send now text. What the f***?"
This PR fixes three of the four things he named. The double composer is not in this PR; see below.
-
The strip under the running card. The bottom stack gives every part a 34px minimum height, but the folded running tray ("9 subagents running · 1 command") is one 28px header row. That left 6px of tray glass, with the tray's rounded bottom corners, under the header, and it read as a second box. With the header hovered, its square highlight made the strip stand out even more. The tray's minimum is now its one row (
--ds-control-row, whichbottomStack.cssalready uses for the tray). It is still flush with the composer and keeps the short-pane behavior. -
Send now blinking. A waiting steer's Send now, X and Copy only showed while the bubble was hovered, with a delayed fade. Both buttons also dimmed to 50% while either click was being answered. Clicking the X dimmed the Send now text, and when acpmux refused, the text came back, which is the blink. While the steer waits, these controls are now always drawn, with no fade and no dimming. They stay disabled while a click is in flight.
-
Edit message doing nothing. "Edit message" is the X's tooltip under a waiting steer. The X asks acpmux to withdraw the steer (
_acpmux/queue_editwithdraw). When acpmux refuses, because Claude Code already took the line or its harness can't drop one, the click did nothing and the X stayed.takeBackSteernow reportsback,refusedorfailed. A refused X gives way to "Read after this step" (an existing localized string), remembered by promptId across transcript remounts, so the row says why the message stays instead of offering a control that can't work. A take-back that failed on the way (an RPC error, or attachments not read) keeps the X so you can try again.When acpmux takes the steer back, Edit message works: its text goes back into the composer, and what you send then is the edited text. The queue's ⋯ menu Edit message works the same way: it opens the prompt for editing in its row, and saving changes what gets sent. Both already worked on the base, and both now have real-browser tests. The case that "doesn't work" is a refusal. Once the agent has already read the steer (Claude Code took it from its queue), acpmux can't take it back, so its text can't come back to edit. Before, the X just did nothing then. Now the row says "Read after this step".
Not fixed here: two composers drawn at once. The page itself draws exactly one composer. A new test keeps the same form and field through running↔idle switches and a pane resize. The page can't draw an idle and a running composer at once either: both placeholders come from one boolean of one snapshot. Leo's capture had a stale idle composer, narrower and offset left, in front of the live running one. That points to something outside the page DOM. The likeliest cause is a second Chromium page window: agent chats run in Chromium by default, each chat page is its own window above the app's views, and the app's view alpha doesn't hide it. A window from an old or hidden chat view that is never hidden or re-placed keeps its old size and state, in front of the live chat. That lives in the native Chromium page hosting code and needs a live repro, so it is left for a follow-up.
Testing
Webview suites ran on the Linux fast-checks runner (cmux-ci test), base source and head source in separate dispatches:
cd webviews && bun test test/agent-pane-steer-take-back.test.tsx test/subagent-tray-layout.test.ts \
test/composer-queued-placeholder.test.tsx test/agent-pane-pending-steer.test.tsx \
src/agent-session/acpmux/conversation/PendingSteer.test.tsx test/running-strip.test.ts \
test/agent-pane-bottom-stack.test.ts test/subagent-tray.test.tsx
Base source (8fe632eae3f), new tests:
(fail) an X acpmux refuses gives way to Read after this step; Send now stays the same element
(fail) a waiting steer's Send now and X are drawn with no fade and no dimming
(fail) the bottom-stack tray's floor is its one row, not the stack's taller row
(pass) Send now keeps its element through 50 transcript events
(pass) an X whose withdraw fails on the way stays to be tried again
(pass) one composer element, the same one, through running↔idle switches and a pane resize
Head (4279f707ebc; aa87297ce29 adds only the queue tests):
test/agent-pane-steer-take-back.test.tsx 8 pass 0 fail
test/subagent-tray-layout.test.ts 2 pass 0 fail
test/composer-queued-placeholder.test.tsx 10 pass 0 fail
src/.../conversation/PendingSteer.test.tsx 6 pass 0 fail
test/running-strip.test.ts 7 pass 0 fail
test/agent-pane-bottom-stack.test.ts 8 pass 0 fail
test/subagent-tray.test.tsx 31 pass 0 fail
src/.../inlinePrompt.test.ts 8 pass 0 fail
test/agent-pane-pending-steer.test.tsx 0 pass 1 fail (base red, below)
test/agent-pane-queue.test.ts 8 pass 0 fail (real Chromium; 8 pass on the base too)
The three tests that fail on the base pin the three fixes. agent-pane-queue.test.ts adds two that drive the real pane against a stand-in acpmux: the ⋯ menu's Edit message saves an update with the edited text, and the X's take-back puts the steer in the composer, where Return sends the edited text. The 50-event identity test, the transient-failure test and the one-composer test pass on the base too. They are regression guards: the first two keep Send now's element and a retryable X through this change, and the third proves the page itself draws one composer (the double composer isn't a page bug). agent-pane-pending-steer.test.tsx fails the same way on the base (expect(pending.querySelector("svg")).toBeNull() at line 91 finds the waiting steer's Copy icon). It isn't from this PR.
Observed / Not run
- Observed: the focused suites above, run on the Linux fast-checks runner with the base source and with the head; the Linux gallery captures below.
- Not run: a tagged macOS build. The Mac-only part is the double composer, which this PR doesn't change.
Changelog
Fixed: The running subagents card in agent chats no longer has a strip under its header, and a waiting steer's Send now no longer blinks. An Edit message (X) that can't take the steer back now says the agent reads it after this step.
Proof
Linux gallery, dark and light (agent-pane.subagent-tray#many-folded, agent-pane.queued-user-footer#balanced).
The running card: before, a strip of tray glass under the header, above the composer. After, the tray ends at its header.

A waiting steer with the pointer away: before, its Send now, X and Copy are hidden until you hover the bubble, then fade in. After, they're drawn while the steer waits.

After a click on the X that acpmux refuses (pointer moved away): before, nothing changed and the footer hid again. After, "Read after this step" stands where the X was, beside Send now.

Localization: no new strings; the refused X reuses message.readAfterStep ("Read after this step").
Risk: normal. Webview CSS and one component; no protocol or native change.
Agent session: agent session
🤖 Generated with Claude Code