cmux NEXT: Session Info is drawn natively, full length, and its toggle shows when it's open

TE
6d ago
+3758-105

HOLD: Leo 2026-10-29 put the web UI fixes first ("you can just edit the fucking web UI"); this native port waits until they land.

Summary

Leo's words (2026-10-26): "the session rail session info thing, like, you literally didn't do. I mean, why is the button not toggled? Why is the button area still, like, just garbage? What is this? There's still that line of that box with the background that just always is there, and, like, you still haven't done the full-length thing. It's still just this constrained height for, like, no reason at all." Clarified: "i literally meant the ui depicting it as toggled or not". And on 2026-10-29: "plus we're gonna be doing that part natively in swift anyways?" / "But I literally fucking said to do that."

Session Info is now drawn by the App in Swift, not by the page:

  • Native panel. The page still works out what each section lists. It sends that model (pane.sessionInfo: sections, rows, SF Symbols, action ids) to the App and draws nothing itself. The App draws a glass panel (Glass.makeOverlayPanel, theme tokens) floating over the agent pane, above the page in both hosts. Under Chromium it is a nativeRects hole. Row clicks, buttons, folds, Esc and the edge drag go back to the page as action ids, so the existing handlers run unchanged.
  • Full length. The panel runs from under the header (or the tab row) to the pane's foot, less the 8px float margin, whatever it lists. When it floats over the chat's column on a narrow pane, it still stops above the composer, as design/session-info.md says.
  • No layout shift. The panel is an overlay outside the page's layout: opening it, closing it or a count changing never reflows the chat. The existing left shift when both fit is unchanged.
  • The toggle reads as on. While the panel is open, the header toggle takes the selection fill (--cmux-selection, the web side of the toolbar's Palette.selectionFill) on its own 24px square. Nothing else in the strip gets a fill, and there is no box behind the strip.

A tension to name. #26092 removed the toggle's fill on 10-27 ("wack background"). This brings back a fill only on the pressed toggle's own square, as Leo's clarification asks, and nothing on hover or on the strip.

Kill switch. Debug Settings › agent.sessionInfo.native (on by default) brings back the page's own panel at once, with no reload. Nothing else changes default, and no gate is removed.

Not ported to native rows yet (each still works in the page's panel with the switch off):

  • Changes' ⋯ menu and hover card
  • the machine colour tint
  • Remote Control's real switch (it is a check button here)
  • Sources' "open failed" alert
  • per-part colours on the context bar
  • the running-limit stepper's asked and refused states
  • Stop's stopping and failed states

Drag-to-reorder the sections in the native panel comes next, as its own PR.

Before / after

Before (base 7f7576e)After
Open
Closed

Before, the panel is a short card under the strip, and the toggle shows no on state. After, the panel runs the pane's length and the toggle is filled while it is open. Light, open: . Captures come from cmux-ci capture with the tours scripts/cmux-next/media/tours/session-info{,-closed}.json.

Testing

  • Swift (on the fleet, package-test-lane.sh): AgentPaneNativeSessionInfoTests covers the model's decode and refusals, the request and its withdrawal, the panel following the open state, the full-height frame (zoomed, beside a side panel, over the chat), clicks reaching the page, the edge drag, and the kill switch taking effect with no reload. Also run: AgentPaneSessionInfoTests, AgentPaneTabRowHolesTests, AgentPaneInspectorHeaderTests. All 4 suites passed at 3cb5bb0 (fleet step aa8fb90a).
  • Webviews (on the fleet, cmux-ci test): bun run check; native-session-info-panel checks that the toggle's aria-pressed follows the panel, the host flag, the panel's own actions, action dispatch, long ids and section order; native-session-info-about-made and -running cover the eight section mappers; also run: chat-inspector, inspector-section-order, chat-header-plain-icons and inspector-dead-clicks, plus the browser-lane tests chat-header-tab-row-surface, chat-inspector-overlay-toggle and chat-inspector-placement. Check clean; 72/72 pass at 3cb5bb0, and the browser-lane tests (68/68) pass at 5c626b0, whose only later change is in Swift and model.ts.
  • Independent review: gpt-6-astra (high, fast), with a full review and then a delta review. The first returned five findings. Four are fixed: the kill switch now applies live; the panel steps aside for the gallery; long action ids are bounded; the clock ticks for workflows. The fifth (cover the composer too) was declined, per the spec. The delta review found two more minor issues: a kill-switch flip before the observer starts, and an emoji split at the id cut. Both are fixed. Final re-review: VERDICT: SHIP at 3cb5bb0e5e61244ab023dc92a9f50017d98ae288.

Observed / Not run

  • Observed: the captures above, from the real app on a capture mini, at this branch and at base.
  • Not run: a live session with subagents, tasks and changes listed. The captures show an empty chat. The section mappers are covered by unit tests only.

Changelog

Changed: Session Info is drawn natively, runs the full height of the agent pane, and its header button shows when it is open

Agent session: agent session

🤖 Generated with Claude Code