Agent pane: in Minimal Mode another agent's message is one line that opens in place
Leo, 2026-10-24:
"I also wonder if we should, like in minimal mode, have the option for, like, the entire thing to be just collapsed into one line or something. Like, I don't know if we need to, like, prepend, like, received message from blah blah blah, but potentially, like, we could just have the first line be the thing that's there, and then you can expand that, and then that would expand outwards towards, like, the entire thing. I don't know. Like, we can surely do some sort of elegant UI thing, but I just feel like I'm not entirely sure when the previews would make sense for these. I think it's okay right now, but I'm not sure how other people would feel. You know, especially in minimal mode. Because we could just, like the preview. I'm pretty sure, like one line is kind of enough sometimes for the, like the preview of the message or whatnot."
What changed
With cmux's Minimal Mode on (sidebar.minimal, the palette's Enable Minimal Mode), another agent's message in the agent pane is one line:
- Closed: the sender's chip, then the message's first non-empty line, then a chevron. The chip is unchanged and still opens that chat. The line has its Markdown marks and link targets dropped and ends in an ellipsis when it is too long. There is no "Received message from" prefix.
- Opening and closing: clicking the line, or pressing Enter or Space on it (it is a native
<button>witharia-expanded), opens today's full glass card in place. Clicking again closes it. - Motion: the open and close use the transcript's shared fold (
useAnchoredCollapse/useFold, the same one tool rows use). The line stays where it is drawn, and Reduce Motion or the host's animations-off setting makes it happen at once. - Images: a closed message hides its images.
- Normal mode is unchanged. The base and head renders of the same gallery chat with Minimal Mode off are byte-identical PNGs, in both themes.
How the page knows about Minimal Mode: AgentPaneDisplaySetting (Swift) now also sends sidebar.minimal in the chat's display push, and chatDisplay.ts reads it as minimal. The page cannot write that key (writablePath refuses it, and a test covers this). The row estimator (model.ts) counts a closed message in Minimal Mode as its line alone.
Transcript placement (App.tsx), after review:
- A Minimal Mode toggle makes one O(rows) pass, once per toggle and never per event or token. It forgets the drawn heights of incoming-message rows, so offscreen rows are placed by the new estimate.
- A new chat look, including a Minimal Mode toggle, now places every row again: the placement keeps no unchanged prefix across a look change.
- Opening has no fade-in. The fold's height moves at full opacity (
useFold's newfadeIn: false, which defaults to true, so other folds are unchanged). Closing still fades out. - The "Replied" note and images stay hidden while the message is folded.
- The preview skips code-fence markers (a fence closes only on its own marker), lone
>lines and link definitions. It strips links (parentheses in the URL, titles, references, defined shortcut references, images and autolinks) and single*/_emphasis, but not snake_case.
Other changes:
messagePreview(incomingMessage.ts, which nothing else used) now drops a link's target, so the line shows "Opened #24772", not the URL.- New string
message.collapsedLabel("Message from {from}: {preview}"), the closed line's accessible name, is in Localizable.xcstrings with all 21 locales. - The gallery's agent-pane host accepts
displayon a variant, which is how the Minimal Mode variants turn it on.
Hooks and cleanup: the change adds no timer, observer or animation loop of its own. The fold is the existing useAnchoredCollapse/useFold: its Web Animation is cancelled on the next toggle and on unmount, and its motion-policy MutationObserver is disconnected when the fold ends. The text box's existing ResizeObserver measure keeps its disconnect() cleanup and now also re-runs when the mode switches, because the card moves into a new box. The change does no per-token work: the preview is memoized on the message body.
Before / after (gallery agent-pane.incoming-message, Linux Chromium, 560 px)
Before is the base with the same gallery file and Minimal Mode on. On base, Minimal Mode does not reach the chat.
| Before (base, Minimal Mode on) | After (this PR, Minimal Mode on) | |
|---|---|---|
| dark | ![]() | ![]() |
| light | ![]() | ![]() |
The long report's line opened (minimal-open), and Minimal Mode off (minimal-off, identical to base):
| Opened | Minimal Mode off | |
|---|---|---|
| dark | ![]() | ![]() |
| light | ![]() | ![]() |
Variants (gallery only, except A)
| A (shipped): chip, first line, ellipsis, chevron | B: fade instead of ellipsis, "+N lines" | C: no chip, name in bold inline |
|---|---|---|
![]() | ![]() | ![]() |
I picked A.
- It keeps the chip, so a click still opens the sender's chat, and it keeps the harness mark.
- Its chevron is the same affordance every other transcript fold uses, so the line reads as expandable.
- The ellipsis is the quietest way to show that the text was cut.
Why not B or C:
- B's "+N lines" adds a second dim label per row, and its fade hides the last words.
- C drops the clickable chip and the mark, so the sender's chat can no longer be opened from the line.
B and C are drawn in the gallery only (minimal-fade-count, minimal-inline-name), as a stylesheet over the shipped line.
Risk
Small and contained: this only changes how incoming agent messages render in Minimal Mode, plus one read-only key added to the host's display push. Nothing changes with Minimal Mode off. No default changes, and no existing component is removed or replaced.
Overlap: #24085 (anchored, animated open in normal mode) edits the same toggle in IncomingMessageCard.tsx. This PR leaves normal mode's toggle as it is, and whichever lands second rebases.
The Swift part (AgentPaneDisplaySetting + its test) was not compiled locally, because Mac builds don't run on this machine. CI's Swift compile and tests cover it.
Tests
On huge-blue (Linux):
- New test
webviews/test/incoming-minimal-collapse.test.tsx. It checks:- Minimal Mode resolves only from
sidebar.minimal === true. - With Minimal Mode off, the line is drawn over the whole card, as before.
- In Minimal Mode:
- the chip and the first line are shown, the Markdown is stripped, and there is no "Received message from" prefix;
- the chip still opens the chat;
- the line toggles open and closed, with
aria-expandedandaria-controlsset; - turning the mode off draws the card again.
- Minimal Mode resolves only from
messagePreviewlink case added toincomingMessage.test.ts.AgentPaneDisplaySettingTests.thePageFollowsMinimalMode, andsidebar.minimaladded to the not-writable keys (Swift, runs in CI).bun teston the new test,incoming-sender-chip,incomingMessage,agent-pane-chat-display,transcript-received-messagesandrowEstimates: 70 pass, 0 fail.vp check --no-fmt --no-lint(typecheck): no errors.vp fmt --checkandvp linton the touched files: clean.check:catalog-keys,check:motion-scale,check:design-tokensandcheck:layerspass.
No capture: the one native change (AgentPaneDisplaySetting.swift) draws no UI. It forwards the existing sidebar.minimal setting into the chat page, and everything that draws is the webview, captured above from the gallery in light and dark at the base and at this head (gallery agent-pane.incoming-message).
Agent session: cosmic-gray
š¤ Generated with Claude Code









