Running tray: Stop inside its line, one chevron column, the header's time after its counts
Fixes the running-in-background tray defects shown in Leo's screenshots of the cmux NEXT agent transcript (2026-10-31). His message didn't reach this lane, only the screenshots, so this PR builds from them and from his standing words:
- design/chat-transcript.md, quoting Leo (2026-10-29): "Why is it just nothing's aligned? ... It's a proper f***ing, like, grid"
- design/running-tray.md, quoting Leo: "i guess the alignment overall hasn't finished for these yet :(" (on the open tray) and "oh god this is really bad ui" (on the collapsed strip)
- design/foundations.md, under alignment: "Icon columns align across adjacent rows and surfaces. Equivalent controls share one text column and one inset." The tray's own spec adds that a line stays quiet at rest (#27344), and this PR keeps it that way.
What the screenshots show, and the fix
| Defect | Fix |
|---|---|
| The folded header put "2h 43m 19s" in its own column, far from the "Running in background · N subagents · M commands" it measures | The time is muted meta 8px after the counts. When space runs out the counts truncate and the time never does. The header is one row at every width, narrow panes included, so the narrow tray's two-row reservation is gone |
| The header's mark was a chat bubble, which reads as a message | A fixed running-work glyph, never the spinner: #27103 took the spinner off the header on Leo's word ("I NEVER SAID TO PUT THE SPINNER HERE"), and it stays on each working line |
| Each open line's Stop sat below and to the right of the line, outside the row's box and off its centre line | Each line's trailing tracks are now time, state, Stop's track, then the chevron. Stop lies over its track and stays one row tall from the line's top (on the controls row when the line is narrow), centred. Its old absolute top: 12px; right: 14px is reset |
| The header chevron (˅) and the lines' chevrons (>) were in two columns | The header's, every line's and View all's chevrons all end on one x, in one 14px trailing column |
Kept: Stop and what it does, the counts, the elapsed time, the hover wash, the fold, colours and glass. The motion is untouched: #29092 (the line entrance) owns subagents.css's motion block and the gallery's motion arms, and this PR doesn't touch either.
Gallery: three variants, default picked
agent-pane.subagent-tray-head (variants folded, open) with the experiment subagent-tray-head:
- glyph (default): a still running-work ring, in the accent while work runs. It's a fixed icon, as #27103 settled, and it means background work, which the bubble didn't.
- bare: no mark.
- session: the old chat bubble, kept for comparison.
Prior art and overlap
- #27930 (austinywang, open, 176 behind) puts the same Stop-before-chevron order on lines. This PR does the same on current base and also fixes the header and Stop's centring. Overlapping hunks in
AgentLine.tsxand thesubagents.csstrailing tracks would conflict. Whichever lands second takes the other's tracks. - #29030 (austinywang): default fold and per-chat memory. Different lines, no overlap in intent.
- #28587 / #28533 (bottom stack): own the gap and the joined glass between the tray and the card under it, the "no gap, top edge clips" defect in the folded screenshot. This PR doesn't duplicate that stack geometry. Its only
bottomStack.csschange drops the narrow two-row header reservation, which is no longer true. - #28860 / #28291 (row grammar) change transcript tool rows' trailing column, not the tray's tracks.
Tests
- New
test/subagent-tray-trailing.test.ts(browser lane, Chromium). At 760 and 300px, light and dark, it checks that every Stop is inside its line's box, centred on the line's state (and on the row centre when wide), sits in its own track between the state and the chevron, and is the hit target at its centre. It also checks that the header's, every line's and View all's chevrons end on one x, that the header is one row, and that its time sits 8px after its counts. test/subagent-tray-columns.test.tsandtest/subagent-tray-layout.test.tsare updated for the new header geometry. The header's time is no longer a column, the header is one row when narrow, and the chevron comes after Stop.
Risk
Low and contained to the running tray's layout: CSS tracks, one span per line, and the header's mark. No data or behaviour change. Stop still stops only its own subagent or command.
Stills (Linux gallery, Chromium, 2x, synthetic fixture agent-pane.subagent-tray-head)
| Before | After (default: running glyph) | |
|---|---|---|
| Folded, light | ![]() | ![]() |
| Folded, dark | ![]() | ![]() |
| Open, light | ![]() | ![]() |
| Open, dark | ![]() | ![]() |
Other header arms: bare (folded dark, open light), session, the old bubble kept for comparison (folded light, open dark).
I viewed the after images. The header's time now sits right after "Running in background · 3 subagents". The chat bubble is replaced by a still running glyph. Each Stop sits on its line's centre, between Running and the chevron. The header's chevron and every line's chevron end on one x.
Takes back #27103: that change made the header's mark a fixed agent.session chat bubble. This PR keeps it fixed (no spinner, as #27103 requires) but swaps the bubble for a running-work glyph, because the bubble reads as a message. #27103's flush-tray spacing is kept.
Spec: teamleaderleo/leo-workspace#1913 (design/running-tray.md).
Checks run (fast-checks, Linux 16/32 vCPU)
subagent-tray-trailing.test.ts(new, 4 cases),subagent-tray-columns.test.ts(10),browser/glyph-alignment.test.ts,browser/gallery-control-surfaces.test.ts: all pass (run).subagent-tray-layout,subagent-tray,agent-pane-working-counts,agent-pane-background-tasksunit suites: pass.action export areas/autofix repairsfail on "generator merge snapshot is stale" forPageChromiumOffscreenParking.swift, a Swift file this PR doesn't touch. I merged the base again, which cleared it.- The independent visual review (Astra, on the earlier stills) returned VISUAL: SHIP. It found the four claims hold, nothing clips, and the Stop controls stay compact.
🤖 Generated with Claude Code
Agent session: agent session







