Agent pane: status, tool and message rows and the action row line up with the prose

TE
5d ago
+899-42

Leo, 2026-10-30: "see how claude code has those centered tool calls

id like more alignment too"

Leo, 2026-10-30: "1 CODEX 2 US 3 US 4 CODEX 5 CLAUDDE WE NEED TO LINE OUR STUFF UP LIKE THEIRS"

What changed

Agent pane transcript (cmux NEXT), alignment only. No row type, icon or action was removed, and the incoming agent-message action buttons were left alone.

  • One left edge. The first glyph of a reply's action row (copy, …), the "Worked for" label, the footer's action row and the tool, status and agent-message icons all start at the reply text's left edge. Two changes do this. First, the stray padding-inline-start: 2px on .cv-turn-actions and .cv-activity is gone. Second, the first 24px icon button overhangs the column by its glyph's 4px inset (margin-inline-start: calc((16px - 24px) / 2)).
  • One icon column. Received, sent and waiting agent-message rows put their mark in the same 16px slot as tool rows, and their words start at the same x. This part is #28796's two commits, carried here with their authorship. This PR subsumes #28796.
  • Centred status rows. A status row between two replies now has equal room above and below. That covers a tool run, a subagent finishing, a background command finishing, another agent's message, compaction, failover and session start. The gap is --cv-status-gap = 30px; inside an opened "Worked for" fold, where replies draw no action row, it is 12px. model.ts estimates the same edge (statusEdge, part of the row's edge key), so estimated heights match drawn heights and the scroll does not jump.

Measured by the new browser test at 2x (both themes give the same numbers):

before (5179e65)after (8798969, unchanged at b16e37f)
gap above / below a tool row between replies38 / 4 px30 / 30 px
gap above / below subagent finished, background task, agent message38 / 10 px30 / 30 px
first action glyph, from the prose edge6 px0 px
"Worked for" footer label, from the prose edge2 px0 px
agent-message icon, from the prose edge8 px0 px

Before / after (2x, gallery agent-pane.transcript-row-alignment)

I opened both after images. Every row starts on the prose edge, and each status row sits in the middle of its gap.

beforeafter
light
dark
light, reply hovered (action row)
dark, reply hovered (action row)

Gallery variants: mix (shipped), roomy (a wider gap), off (the old spacing), and footer (the summary row hovered).

Tests

  • webviews/test/transcript-row-alignment.test.ts (new, Chromium browser lane, light and dark) checks two things:
    • every lead glyph is at 0 ± 0.5px from the row's left edge, every iconed row has a 16px icon box at 0 with one shared text x;
    • the gap above and below each status row between replies is equal and the same everywhere.
  • webviews/test/transcript-icon-column.test.ts (from #28796).
  • rowEstimates.test.ts: a new estimate test for a status row between two replies.
  • Red at 5179e65: run 41197784141, 2 fail. Green at 8798969: run 41198196381.
  • After the base merge (#28018 made tool rows flex, so the icon's -1.5px margin pulled their words to 22.5px), the margin is gone and every iconed row's words are at 24 again. Green at b16e37f: run 41207768964, 66 pass with #28018's caret tests, tsc clean, fmt clean, design-token ratchet passed.
  • Follow-up from review: #29463.

Risk

Layout only. model.ts row height estimates change for a status row next to a reply. The drawn height is reported with its status edge, and a mismatch drops the cached height, so a stale estimate is re-measured rather than kept.

Performance

statusEdge is O(1) per row and reads only the next row. It adds no timer, observer or animation loop, and no per-token work.

metricbeforeafterdeltaharness or run link
layoutConversation 192k rows, cold (median of 5-6)35.5 ms36.3 ms+2% (within run noise: 26-38 ms)rowLayoutLinearity 192k, base 625b1ca vs head model.ts, https://github.com/manaflow-ai/cmux/actions/runs/41207768964
layoutConversation 192k rows, p50 (median of 5-6)1.51 ms1.58 ms+0.07 mssame

Spec: design/chat-transcript.md, "Rows between replies" (leo-workspace#1916).

Agent session: agent session

🤖 Generated with Claude Code