cmux NEXT: running rows draw orbiting dots on the left
Leo wanted a running row to show "a nice running animation on the left", like Claude Code's four orange dots that slowly rotate and regroup. This PR adds that mark and folds in the two open PRs it needs: #20900 (the status icon on the left) and #20409 (no fake progress line).

Gallery: ui.running-dots / rows and reduce-motion (). The gallery shows a web copy of the native mark at the same geometry and timing; the app draws it with Core Animation (StatusIndicatorLayer+Orbit.swift).
What changes
- Orbiting dots (
StatusIconSet.orbit, now the default):- Agent work draws as four dots in Claude's orange (rgb 215 119 87).
- They turn once every two pulse periods (3.6 s) and draw in to a tight cluster and back out once per period (1.8 s).
- Nothing fades, so nothing blinks. At the fastest Debug Settings period the dots regroup at most twice a second, which keeps #21633's 2 Hz cap.
- When stopped (off screen, loops off) they stand on the axes. Under Reduce Motion or the Static mode the static look draws instead (#21659).
- Every other state keeps the Codex-like marks.
- The previous default, Codex-like, stays in Debug Settings › Status icons.
- One status icon per row, on the left (from #20900, now the default):
- A row shows its most urgent state, with unread work as the done dot, in a fixed slot before the title. Titles line up whether or not a row has a state.
- No corner badge and no count number.
- Debug Settings
sidebar.statusIconSidemoves the icon to the right, andsidebar.rowBadgekeeps the corner, stack and trailing looks.
- Session rows: the sessions listed under a workspace draw their own status (
StatusMapping.summary(tab)) on the same side, in the same fixed slot. - No fake progress (from #20409): an indeterminate report no longer draws a full-width line under the row; the running mark already says the row is working. A measured bar sits inside the pill, between the row's insets. A connecting placeholder keeps its dim bar.
| Dark | Light | Reduce Motion |
|---|---|---|
![]() | ![]() | ![]() |
Not here
#20900 also hid kind icons on tabs and moved the tab status mark to a side. Tabs are out of scope here and come in a follow-up.
Testing
OrbitStatusIconSetTestscovers:- Orbit is the default.
- Work is the orange orbit, and every other state matches Codex-like.
- Stopped, the dots sit still on the axes; under Static the static look draws.
- At the fastest Debug periods the keyframes animate position only, turn in no less than two pulse periods and regroup twice per turn.
SidebarRunningMarkTestscovers:- The defaults.
- A working agent row's mark sits before its title.
- Titles line up with and without a mark.
- The most urgent state shows on the left and on the right.
- Unread work shows the done mark.
- A running session row's mark is on the same side without moving its title.
SidebarRowQuietProgressTests(from #20409).SidebarRowCornerBadgeTestsnow pins the corner look explicitly, andCodexStatusIconSetTestsno longer asserts the default.- The test commit (bd22252fdc) comes before the fix (d353748a87). No Swift build ran on a Mac here: CI on this PR compiles the package and runs these suites.
- Web:
gallery-coverage,gallery-manifest,ui-rules,theme-colorsandpane-englishpass;check:layers,check:system-blue,check:type-scaleandcheck:text-focuspass.
🤖 Generated with Claude Code
Need help on this PR? Tag @codesmith-bot with what you need.
Summary by cubic
Running rows draw Claude Code-style working marks: four orange dots that turn and regroup, in a fixed slot on the right of each row by default. sidebar.statusIconSide moves them left; the Status icon row badge (one status icon per row, no corner badge or count) is now the default, and indeterminate progress no longer draws a full-width bar under the row.
- Work draws as the new Orbit set (now the default); every other state keeps the Codex-like marks, still in Debug Settings. The turn runs as Motion-sampled keyframes and passes the Motion tokens check; under Reduce Motion or Static mode the static look draws instead. A row configured before layout restarts its turn once the row has a frame.
- Sessions listed under a workspace draw their own mark on the same side, and one unread session shows a single mark: the running dots while its agent works, a done mark at rest, so nothing else draws on the right.
sidebar.statusIconSidemoves it to the left, and the old row badge styles remain as Debug Settings options. Group headers start past the left slot, a connecting placeholder keeps it empty, and rows speak the state they draw. - An indeterminate report no longer draws a bar; measured progress sits inside the pill between the row's insets, and the agent mark never takes the status slot under the Status badge.
The feat-cmux-next merge also carries: _acpmux/route/list with routing details (the composer's Account menu lists only matching routes); an agent.sessionStatus Debug toggle; tunable registries listed one entry per line; comments and baselines that clear five base reds; a perf-10x daemon request-latency bench; and #22127, webview tests running past a budget red.
An autofix pass regenerated ci-target-graph.json and reformatted webview files.


