Skip to content

cmux NEXT: running rows draw orbiting dots on the left - #21954

Closed
teamleaderleo wants to merge 20 commits into
feat-cmux-nextfrom
claude-polish/running-dots
Closed

teamleaderleo wants to merge 20 commits into
feat-cmux-nextfrom
claude-polish/running-dots

Conversation

@teamleaderleo

@teamleaderleo teamleaderleo commented Oct 19, 2026 •

Copy link
Copy Markdown
Collaborator

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).

Before and after, in the gallery

Gallery: ui.running-dots / rows and reduce-motion (MP4). 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):
  • One status icon per row, on the left (from Status icon on the left or right of rows and tabs, by default #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.statusIconSide moves the icon to the right, and sidebar.rowBadge keeps 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 Sidebar: quiet the workspace row (no fake progress line, aligned agent mark) #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
dark light reduced

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

  • OrbitStatusIconSetTests covers:
    • 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.
  • SidebarRunningMarkTests covers:
    • 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 Sidebar: quiet the workspace row (no fake progress line, aligned agent mark) #20409).
  • SidebarRowCornerBadgeTests now pins the corner look explicitly, and CodexStatusIconSetTests no longer asserts the default.
  • The test commit (bd22252) comes before the fix (d353748). 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-colors and pane-english pass; check:layers, check:system-blue, check:type-scale and check:text-focus pass.

Supersedes #20900 and #20409.

🤖 Generated with Claude Code


View with [code]smith Autofix with [code]smith
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.statusIconSide moves 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.

Written for commit 2db3ff2. Summary will update on new commits.

View guided diff Turn on auto-fix

teamleaderleo and others added 3 commits October 19, 2026 05:00
Red until the fix: the Orbit status icon set (four dots that turn and regroup, Claude's orange,
default), the Status icon row badge on the left (from #20900) on workspace and session rows, and
no bar for indeterminate progress (from #20409).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Leo 2026-10-18: a running row gets a running animation on the left, like Claude Code's four
orange dots that slowly rotate and regroup.

- The Orbit status icon set, now the default: agent work is four dots in Claude's orange that
  turn once per two pulse periods and draw in and out once per period. Nothing fades, so at the
  fastest Debug Settings periods they regroup at most twice a second (#21633). Stopped, they stand
  on the axes; under Reduce Motion or the Static mode the static look draws (#21659). Every other
  state keeps the Codex-like marks.
- The Status icon row badge from #20900, now the default: one status icon per row (its most urgent
  state) in a fixed slot on the left, so titles line up; Debug Settings sidebar.statusIconSide puts
  it on the right. No corner badge or count number.
- Session rows listed under a workspace draw their own status on the same side.
- From #20409: an indeterminate report draws no bar under the row; a measured one sits inside the
  pill between the row's insets.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A web copy of the app's Orbit mark (OrbitDots), with a gallery entry (ui.running-dots) that sets
sidebar rows and their sessions in the Codex-like look on the right next to the Orbit look on the
left, the mark at 6x, and the static look under Reduce Motion.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration
  • Configuration used: Repository: manaflow-ai/cmux/.coderabbit.yaml
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: 2099f251-708a-4fdf-99a1-a65c440b7bb6

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Bead cx-83q5m created for this PR by the cmux coordinator.

feat-cmux-next quieted the indeterminate bar itself (0eef92e), so WorkspaceRowContent takes its version.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

cmux status (one comment, edited in place; each line is updated by the job that owns it)

Review 2db3ff2: HQ feed card · gallery before/after runs · checks

App of this head (app.zip, kept 1 day)

gh workflow run reload-build.yml -R manaflow-ai/cmux --ref feat-cmux-next -f tag=pr21954 -f ref=claude-polish/running-dots -f platform=macos -f backend_mode=local

Pending: CI is running on f96d1e5a04 (run); the result below was for 6becfdaacf and no longer applies.

Last result: Unclear: GhosttyKit release check failed: no known signature; failed step: Verify published GhosttyKit release and checksum.

Written by scripts/ci/classify_failures.py (ci-failure-attribution.yml); it is rewritten when this head's CI completes.

red: cmux-next checks (god files, concurrency, crash safety, l10n); base red: the same failure on the base 1fac57d; does not block
red: web / Web status; NEW: green on the base 1fac57d; do not merge until green; see lane-rules
red: web / react-apps-check; no finished base run on 1fac57d to compare; do not merge until green; see lane-rules
red: web / react-apps-check (1); no finished base run on 1fac57d to compare; do not merge until green; see lane-rules
red: web / react-apps-check (2); no finished base run on 1fac57d to compare; do not merge until green; see lane-rules
red: web / react-apps-check (3); no finished base run on 1fac57d to compare; do not merge until green; see lane-rules
red: web / react-apps-check (4); no finished base run on 1fac57d to compare; do not merge until green; see lane-rules

CI fast guards failed on 6becfdaacf (https://github.com/manaflow-ai/cmux/actions/runs/39324724756). It does not block the merge; a red guard merged into main breaks it for every open PR.
The log named no failed step; see the run.

Agents: python3 scripts/ci/guard_attribution.py fix applies the mechanical fixes locally.

@github-actions

github-actions Bot commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

CI fast guards failed on 3c411f93ef (https://github.com/manaflow-ai/cmux/actions/runs/39210872337). It does not block the merge; a red guard merged into main breaks it for every open PR.
The log named no failed step; see the run.

Agents: python3 scripts/ci/guard_attribution.py fix applies the mechanical fixes locally. This comment is updated in place on each push.

@blacksmith-sh

This comment has been minimized.

teamleaderleo and others added 7 commits October 19, 2026 05:34
… the slot, rows speak the drawn state

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…sion rows and VoiceOver follow the left status slot

- StatusIndicatorLayer+Orbit: a new replicator frame drops the turn so updateAnimation starts one in it (a row is configured before layout).
- GroupHeaderRowView: the name starts past the rows left status slot, so headers stay on the rows column.
- WorkspaceRowView: a connecting placeholder keeps the slot with no state; the agent mark never takes the status slot under .status.
- SidebarTabRowView: session rows honour the list badge style and the working row element, as workspace rows do.
- Accessibility: a row speaks the state it draws (rowStatus).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s each tab's status once

The orbit's raw CAKeyframeAnimation failed the Motion tokens check. Motion.sampledKeyframes
builds the same linear keyframe turn (the curve is in the sampled points).

SidebarMapping.row read every tab's status reports three times: for the row's merged
status, its working slot, and the tab row's mark. It reads them once now.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…sh/running-dots

# Conflicts:
#	Packages/macOS/CmuxNext/Sources/CmuxNextSidebar/Logic/SidebarTunables.swift
- regenerated Packages/macOS/CmuxNext/ci-target-graph.json
- vp fmt webviews/src/agent-session/acpmux/replyHref.ts
- vp fmt webviews/src/pages/markdown/README.md
- vp fmt webviews/src/pages/markdown/links.ts
- vp fmt webviews/test/markdown-cmux-app-links.test.ts

Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/39210872231
@teamleaderleo
teamleaderleo temporarily deployed to cmux-tui-merge-tree October 19, 2026 06:49 — with GitHub Actions Inactive
teamleaderleo and others added 2 commits October 19, 2026 07:59
…sh/running-dots

# Conflicts:
#	Packages/macOS/CmuxNext/Sources/CmuxNextBridge/SidebarMapping.swift
#	webviews/src/agent-session/acpmux/replyHref.ts
#	webviews/src/pages/markdown/links.ts
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@greptile-apps

greptile-apps Bot commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 5/5

[Medium impact] The latest changes appear safe to merge; the two earlier, non-blocking display issues remain.

Findings

  1. P2 Detailed icons setting is ignored ▶
  2. P2 Still dots have uneven spacing ▶

Summary

Adds orange orbiting dots for running agents and makes a single status mark the default for sidebar rows.

  • Agent work shows four orange dots that turn and regroup.
  • Workspace and session rows show one status mark on the same side.
  • Measured progress bars sit inside the row's insets.

Reviews (4) · Last reviewed commit: "test(next): by default a working row's t..." · Reviewed by Greptile

Comment on lines +20 to +21
func rowStatus(_ ws: SidebarWorkspace, activity: StatusIndicatorState) -> StatusIndicatorState {
statusSide == nil ? activity : WorkspaceRowBadges(unread: ws.unread, activity: activity).first ?? .idle

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Detailed icons setting is ignored

rowStatus calls WorkspaceRowBadges without detailed:, which defaults to true. With the new default .status style, turning Detailed Status Icons off still shows separate waiting and error icons. A working row with unread work also keeps its working mark instead of showing Ready.

Pass shown.detailedStatus into this path and use the same result for accessibility.

…st a budget red)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@blacksmith-sh

blacksmith-sh Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

Found 6 test failures on Blacksmith runners:

Failures

Test View Logs
/tmp/tmpik3whjsh/summary-fail.json (live):/summary-fail.json (live): View Logs
/tmp/tmptqpzvg1a/summary-missing.json (live):/summary-missing.json (live): View Logs
test_batch_dispatch_runs_every_dispatch_gated_job (main.PathRoutingStructure.test_b
atch_dispatch_runs_every_dispatch_gated_job) (job='request-cmux-next-dev-publish')/
test_batch_dispatch_runs_every_dispatch_gated_job (main.PathRoutingStructure.test_b
atch_dispatch_runs_every_dispatch_gated_job) (job='request-cmux-next-dev-publish')
View Logs
the repository has capability texts that say update/
the repository has capability texts that say update
View Logs
the repository has capability texts that say update/
the repository has capability texts that say update
View Logs
the repository has capability texts that say update/
the repository has capability texts that say update
View Logs

Fix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.

// Where a turn starts: four dots spread on the axes.
let side = rect.width * StatusIndicatorLayer.orbitDotShare
for index in 0..<StatusIndicatorLayer.orbitCount {
let center = StatusIndicatorLayer.orbitPoint(turn: CGFloat(index) / CGFloat(StatusIndicatorLayer.orbitCount), in: rect)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Still dots have uneven spacing

StatusIconSet.orbit.image(state: .working, ...) draws the horizontal dots closer to the center than the vertical dots. Passing index / orbitCount to orbitPoint changes both the angle and the radius. The live stopped mark instead puts all four dots at the outer radius, so the image does not match it.

Rotate the initial point for each copy instead of advancing its animation time.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

I'm holding this PR. Merging the base in conflicts in 4 files (SidebarMapping, StatusIndicatorLayer, SidebarRowBadgeStyle, WorkspaceRowView+Rendering) with 57997c3, which Lawrence landed at 00:04Z: "a tab or workspace row shows one state mark, on the right; only the icon on the left". He wrote: "Nothing should ever be on the left side besides the favicon."

This PR's default is the opposite: the status icon and the orbiting dots on the left (sidebar.statusIconSide). It's also sidebar code, which is Lawrence's. So I won't resolve the conflict by picking a side.

Two ways forward:

  1. Keep the orbit glyph as the running mark and put it in Lawrence's right-hand slot (statusIconSide defaults to right, left stays a Debug Settings toggle).
  2. Leo and Lawrence settle left vs right first.

The orbit work itself (StatusIconSet.orbit, Motion.sampledKeyframes, the reduce-motion handling) doesn't depend on the side.

teamleaderleo and others added 2 commits October 19, 2026 21:01
Conflicts with 57997c3 (Lawrence: one state mark per row, on the right; only
the icon on the left): layoutRowBadge takes no style now, the corner badge is a
trailing glyph, the unread color reads Palette.notificationBlue, and tab rows
take their favicon from browserFaces. The status icon side's default is
unchanged here; the next commits move it to the right.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…efault

Lawrence 2026-10-19 (57997c3): nothing on a row's left but the favicon.
The left-hand running mark stays a Debug Settings choice and keeps its test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
teamleaderleo and others added 4 commits October 19, 2026 21:02
…ays a Debug choice

sidebar.statusIconSide defaults to right, so the Orbit running mark and the
row's one status icon sit at the row's end, the slot 57997c3 gives every
state mark. Debug Settings > Sidebar > Status icon side > Left keeps Leo's
mark before the title (2026-10-18).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… right

With the status icon on the right, an unread session whose agent works drew
the unread dot and the running mark side by side. Lawrence 2026-10-19: a
single indicator on the right. The tests also check that nothing but the icon
draws left of a row's title by default. The unread dot becomes internal so the
test can read it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…atus mark

With the status icon row badge, a session row's mark is its most urgent state
with unread folded in, as WorkspaceRowView.rowStatus does: the running mark
while its agent works, else the done mark. The unread dot draws only with
another row badge, so the right side holds one mark (Lawrence 2026-10-19).
The header comment now says so.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…'s does

Closes the review's gap: no empty status slot is kept on the left when the
mark sits on the right.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Closing: Leo doesn't want the running dots on the left ("i dont want left dots", 2026-10-19). This PR also carried #20900 (status icon on the left) and #20409 (no fake progress line). Those stay as their own PRs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant