Agent chat: even transcript spacing, meta rows that hug their message
#22675 has landed. feat-cmux-next 78aaa62 is merged in (merge 537c356). Out of scope here: SteerMark, the prompt's receipt, and when the action rows show. #22773 owns those, and this PR leaves them alone.
Problem
The agent chat transcript has empty bands (Leo: "weird amounts of negative space"):
- An older prompt's action row is hidden with
opacity: 0but still takes 4px of margin and a 20px line, and the row's 16px of padding sits under it. That makes about a 40px band under the bubble before the next message. - A reply's footer (time, Copy, Retry) starts about 22px under the reply. That is the reply row's 16px padding plus a 28px row whose content is centered in it.
- A footer sits only 8px above the next prompt, so turns don't read as turns.
- The row estimates in
model.tsleft out the prompt's action row and its steer line, and put the footer row at 37px against 36px drawn. Rows jumped when they first drew.
Change
Four spacing tokens in conversation.css set the rhythm. model.ts estimates rows with the same numbers.
| Token | Value | Gap | Source |
|---|---|---|---|
--cv-meta-gap | 4px | a message to its meta row (prompt actions, reply footer) | 60.png, Leo's Claude Code desktop capture: the meta row starts about 6px under the bubble at 1x. Rounded down to a 4px step. |
--cv-meta-row | 24px | the meta row's line | 60.png: the ✓ and copy row is about 24px tall at 1x. |
--cv-message-gap | 8px | a message (or its meta row) to the next row in its turn | 60.png: the meta row's center sits 26px above the "5m 54s" line's center, so the gap is about 4–8px. 8px matches the existing step-row padding. |
--cv-turn-gap | 24px | a turn's footer to the next prompt | Inferred. Neither 60.png nor any published Anthropic screenshot shows a turn boundary. The desktop docs and download page have no transcript images. 24px is one meta row, three message gaps. |
Tool blocks keep their margins: the 2px .cv-tools margin, the 26px step rhythm, and the 8px padding of step rows.
.cv-user__actionsgets a fixed 24px height and a 4px top margin. Hidden, it keeps only that line. Its visibility rules are unchanged.- A reply directly above its footer gets
acpmux-row--before-footer: 4px padding and no 34px minimum height, so a one-line reply's footer also hugs it. The footer row drops the 34px minimum, sits on a 24px line, and ends with the 24px turn gap. Its buttons are 24px. - Message rows pad 8px instead of 16px.
- User bubbles are translucent: the theme's text at 12% over
transparent. Before, the fill was mixed into the opaque--acpmux-base. The composer hairline rim stays. The fill and rim sit in one rule block, apart from the bubble's padding, radius and width. The shared glass primitive (#22815,ui-glass) replaces that block once it lands.agent-pane-chat-column.test.tsasserted an opaque fill (alpha 255); it now asserts a translucent one (0 < alpha < 255). - A gallery fixture,
agent-pane.transcript/rhythm, shows two prompts in one turn, a footer, the next turn and a Worked for turn.
The plan had a reserve-or-overlay Debug toggle for the hidden row. I dropped it along with the SteerMark change.
Screenshots
Captured from the gallery builds of feat-cmux-next f6d9065 (before) and this branch at 98e81fe (after). Playwright at 2x, pointer away.
| Before | After |
|---|---|
![]() | ![]() |
![]() | ![]() |
![]() | ![]() |
![]() | ![]() |
The new rhythm fixture, after only (dark, light):


Light theme bubble over the page: 
Changelog
- Fixed: Agent chat transcript spacing: a message's actions and a reply's footer sit right under it, turns are evenly spaced, and prompt bubbles are translucent.
Observed / Not run
Test: webviews/test/agent-pane-transcript-spacing.test.ts (Playwright, real Chromium). It measures:
- the bubble to its meta row;
- an older prompt's bubble to the next row;
- the prompt's meta row to Worked for;
- a reply to its footer's text;
- a footer to the next prompt.
Ran:
-
scripts/web-lint.shon each commit. Format and lint have 0 errors.vp checkexits 1 on twojsx-a11y/prefer-tag-over-rolewarnings atUserBubble.tsxrole="img", which are on feat-cmux-next too. -
Fleet
cmux-ci run --class light --script scripts/ci/run-webviews-tests.shon5b159fa(test only) and8c03dbe(fix). Both ran 581 files with the same 8 failures, none in files this PR touches: column-edges, apps-flow, html-paste, hover-row-sweep, stats-page, minimap-feel, tooltip-surface, whats-new. Those workers had no Playwright browsers installed, so the new test skipped there. Those runs say nothing about it. -
I queued the same runs on a
chromiumworker, for the red (the final test on feat-cmux-next, throwaway commit86ec022) and the green (98e81fe). No fleet worker has both thechromiumandci-stepslabels, so neither step ever started. I cancelled both and deleted the throwaway branch. The new test's only real run is GitHub'sweb / react-apps-check, which installs Playwright browsers, on this PR's head. A red on the base has not been run. -
GitHub
web / react-apps-checkat98e81fe: the new test failed, one-line reply to footer text at 16px (limit 10). The 34px row minimum was still on the reply. Fixed in5df2d8c. The same run failedagent-pane-chat-columnon the opaque-bubble assertion, updated incc530bd. -
GitHub
web / react-apps-checkat5df2d8c:agent-pane-transcript-spacing,agent-pane-chat-columnandagent-pane-turn-footerpass. CI tests the merge ref (Merge 5df2d8c… into f30d3282…), which brings in 59 base commits. The six other red files are base reds: the same assertions fail on unrelated PRs #22816 and #22819 (merged with base41f16153), andcomposer-historyalso fails on #22830.
| File | Assertion here | Same on |
|---|---|---|
composer-history | press ArrowUp: layout shift 0.0002 (limit 0) | #22816, #22819, #22830 |
composer-mention | type "Fix @rea": layout shift 0.0002 (limit 0) | #22816, #22819 |
composer-suggested-prompt | Received: "Type / for commands" (file not on this branch, only in the merge) | #22816, #22819 |
composer-location-strip | Expected: <= 2, Received: 2.5 | #22816, #22819 |
quiet-access-chip | Received: "rgb(125, 129, 153)" | #22816, #22819 |
agent-pane-wheel-pass-through | Expected: < 10, Received: 12 | #22816, #22819 |
agent-pane-background-tasks is a base red too (red on #22675's head); #22833 fixes it.
-
Review follow-up:
1d599f5(red) addswebviews/src/agent-session/acpmux/rowEstimates.test.ts(no browser). It checks the estimates against the CSS: a reply over its footer, a task's result, the footer, the chat's last footer, and re-placing a kept row when the row after it changes its height. The same commit adds lower bounds to the spacing layout test.73cf35efixesmodel.ts:- A reply over its footer is estimated as its text plus 4px with no 34px floor, the text-less fallback too.
- A task's result is
26 + 8. - A Chief prompt gets no action-row height.
- The chat's last footer ends at 8px instead of 24px (
acpmux-row--last-footer), so there's no band over the composer. - Footer buttons use the prompt's 5px radius.
-
Second review follow-up: a footer carries its answer's text for Copy (
turns.ts), so the estimator measured the answer instead of the footer's line.2e89dba(red) gives the fixture footers text, shapes one chat throughturnView, and puts a hidden row after the last footer.64349c8estimates a footer before the text path and treats the last footer as the last row that draws (nextDrawnRow, also used for App.tsx's class). -
Fleet,
cmux-ci run --class light --script scripts/ci/run-webviews-tests.sh, full suite. The 8 files failing in every run lack Playwright browsers on these workers:agent-pane-column-edges,apps-flow,composer-html-paste-edit,hover-row-sweep,stats-page,thread-minimap-feel,tooltip-surface,whats-new-text-selection.
| Round | Commit | Step | Result |
|---|---|---|---|
| 1 red | 1d599f5 | d3004d7755f928757b60a12b | FAIL rowEstimates.test.ts: Expected: 4/Received: 0 (reply over a footer), Expected: < 34/Received: 34 (reply placed again), Expected: 34/Received: 42 (task result). 585 files, 9 failed |
| 1 green | 73cf35e | a0af434d9562156087094407 | PASS rowEstimates.test.ts, PASS agent-pane-transcript-spacing.test.ts. 585 files, 8 failed |
| 2 red | 2e89dba | fcc934d276d93e02f7e68298 | FAIL rowEstimates.test.ts: Expected: 48/Received: 372, Expected: 32/Received: 372, Expected: 48/Received: 303.75; the turnView and hidden-row tests fail too. 585 files, 9 failed |
| 2 green | 64349c8 | 4055486160e22d8b58fc4a8e | PASS rowEstimates.test.ts, PASS agent-pane-transcript-spacing.test.ts. 585 files, 8 failed |
Not run: the macOS app. Webview only, no Swift.
Agent session: cosmic-gray
🤖 Generated with Claude Code







