Skip to content

cmux NEXT: list a run's steps in one bordered group, as Claude Code desktop does - #27896

Merged
teamleaderleo merged 8 commits into
feat-cmux-nextfrom
claude-sr2/transcript-group-rows
Oct 30, 2026
Merged

teamleaderleo merged 8 commits into
feat-cmux-nextfrom
claude-sr2/transcript-group-rows

Conversation

@teamleaderleo

@teamleaderleo teamleaderleo commented Oct 30, 2026 •

Copy link
Copy Markdown
Collaborator

Leo (2026-10-29): "look at these first 4 pictures. we want to have that capabilitiy of rendering like claude code desktop has stuff organized."

PR (a) of three for that ask: grouping and step rows. (b) is the step body (ShellBlock/HighlightedCode), (c) is the question and checklist cards.

What changes

An opened "Ran N commands" group (and "Read N files", "Searched N") now draws the way Claude Code desktop lists a run's steps:

  • It is one rounded group in the cards' ring, under the "Ran N commands" line.
  • The thought that led into the run comes first, as its full text. Thoughts before a run of two or more commands, reads or searches now join that run's group (toolGroups.ts). When the run is a single call, the thought keeps its own row as before.
  • After that comes one row per step. A call shows its one-line summary (Claude's Bash description when there is one). A later thought shows as one line cut with an ellipsis. Each row's ▸ sits right after its words, and hairlines separate the rows.
  • Every step shows. GROUP_TAIL and "+K more" are removed, because Claude desktop lists every step. fix(chat): show every item when expanding a tool group #26591 has since landed and does the same thing. This branch takes it in: commands, reads and searches draw through the step rows here, and edits groups keep fix(chat): show every item when expanding a tool group #26591's row cache.
  • What a step opens to is unchanged: CommandRow and ToolRow still toggle open to their existing body, which is PR (b)'s seam.
  • These all keep working: failure words, the running spinner, background marks, find-in-chat reveal, edits groups with their diffs on the tree guide, a finished run folding when text follows it, keyboard and aria. Group disclosure keys use the first call's id (groupId), so a group keeps its key and its open state when a thought joins it at the front.

The gallery has three looks, selected with the data-tool-steps-look root attribute: card (the default I picked), tree (the old tree guide with hairlines) and zebra (no ring, alternate rows filled). Card is the closest match to the reference and reads as one unit that ends before the next paragraph. Tree keeps the old hierarchy but doesn't separate the run from the prose. Zebra is noisy when rows are short.

I also added a scenario gallery page, agent-pane.claude-desktop-organization. It renders through the real transcript path with a public-safe fixture: a paragraph, an answered QuestionCard, a 3-step plan, a thought followed by 5 shell steps, then prose. PRs (b) and (c) will show up on it when they land.

Gallery: agent-pane.claude-desktop-organization, agent-pane.tool-group-alignment

Performance

Harness: a temporary bun + JSDOM test (not committed). It renders the real ToolRows with an opened group of 13 commands, a leading thought and two merged thoughts, then streams 40 output chunks into the running command. For each chunk it counts CommandRow draws and the wall time. Both runs used the same Linux fast-checks runner (32 vCPU), 3 runs each. Before is the old base be41ec40; after is this branch's code at c7085c7a, before base was brought in.

metric before after delta harness
CommandRow draws per streamed chunk (13 rows shown) 13.00 1.00 -12.00 (-92%) run 41029158038
ms per streamed chunk (3 runs) 1.58 / 1.53 / 1.37 1.03 / 0.72 / 0.61 about -45% run 41029158038

Since then, base landed #26591, which memoizes rows on its own path. The current head keeps this PR's Step path for commands, reads and searches, and #26591's entryNodes path for edits. I did not re-measure against the newest base, because the shared REST quota refused the dispatch.

webviews/test/transcript-group-step-renders.test.tsx keeps this in place. Across 5 streamed chunks only the streaming call draws, the step list is never rebuilt (stepProbe.build), and when a new call joins, the list is rebuilt once and only the new row draws. No new timers, observers or animation loops.

Risk

Medium, contained to the transcript's tool-group rendering. A thought that leads into a run now moves from its own row into the group, as the first step (open). Its open/closed choice is still keyed by the same thought id. Long runs (20+ commands) now list every row instead of the last five.

Tests

  • New: transcript-group-step-renders.test.tsx (render counts).
  • Updated: transcript-density, transcript-group-thought-state (lead thought, no "+K more"), transcript-consolidated-runs (lead-thought grouping).
  • 122 tests across the 10 related files pass on Linux CI, and typecheck is clean.

🤖 Generated with Claude Code

Agent session: agent session

teamleaderleo and others added 2 commits October 29, 2026 14:29
…esktop does

An opened "Ran N commands" (or reads, searches) group draws as one rounded group in the cards'
ring: the thought that led into the run first, in full, then one row per step (a call's one-line
summary, a later thought cut to one line), each with its disclosure right after its words, and
hairlines between rows. Every step shows; "+K more" is gone. Thoughts that lead into a run of two
or more calls now join its group (toolGroups.ts). Each step row is memoized on its activity and
the step list is rebuilt only when the group's shape changes, so a streaming call draws again
alone. Gallery: agent-pane.claude-desktop-organization (card, tree, zebra arms).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-92fa78a91e29868c5eaa
@github-actions

github-actions Bot commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

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

Review 56c70a5: 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=pr27896 -f ref=claude-sr2/transcript-group-rows -f platform=macos -f backend_mode=local

Unclear: web / react-apps-check failed: no known signature; failed step: Check webview test shards.

CI failed on 56c70a5d46 (run 41079698408 attempt 1): 2 code, 1 unknown.

Job Verdict Why
web / react-apps-base-check (2) code a web test failed
web / react-apps-base-check (3) code a web test failed
web / react-apps-check unknown no known signature; failed step: Check webview test shards

Failures:

  • seen on other PRs motion-scale.test.ts motion scale > no webview CSS, TS or TSX animates off the scale: failed (job)
  • seen on other PRs new-tab-cards-template.test.tsx Cards with the agent's chips draws the split, and the mic stays in the box: failed (job)
  • seen on other PRs new-tab-composer-layout.test.tsx Claude New Tab location and model share the quiet row under the box: failed (job)
Matched log lines
web / react-apps-base-check (2): (fail) motion scale > no webview CSS, TS or TSX animates off the scale [752.88ms]
web / react-apps-base-check (3): (fail) Cards with the agent's chips draws the split, and the mic stays in the box [13.86ms]

Not re-run automatically: web / react-apps-base-check (2), web / react-apps-base-check (3), web / react-apps-check are not machine failures.

Written by scripts/ci/classify_failures.py (ci-failure-attribution.yml); signatures are its SIGNATURES table. A machine verdict is the runner's fault, not this PR's; yours means the failing file is one this PR changes, also red on main that main's latest full suite fails the same way, seen on other PRs that it failed on another pull request's run lately.

red: web / Web status; base red: the same failure on the base c66f534; does not block
red: web / react-apps-base-check (2); no finished base run on c66f534 to compare; do not merge until green; see lane-rules
red: web / react-apps-base-check (3); no finished base run on c66f534 to compare; do not merge until green; see lane-rules
red: web / react-apps-check; base red: the same failure on the base c66f534; does not block

Gallery before/after for 56c70a5: 5 states rendered, 6 images differ (picked by the Gallery: line in the PR body). Images are in the run's artifact, not on this public PR.

gh run download 41079698011 -R manaflow-ai/cmux -n gallery-advisory-27896-56c70a5d463df04f82a816d152dc2170a7c16a28 (then read gallery-review.json)

States
State Theme Status Diff Picked by
agent-pane.claude-desktop-organization/card Apple System Colors Light new 0% pr-body
agent-pane.claude-desktop-organization/card Apple System Colors new 0% pr-body
agent-pane.claude-desktop-organization/tree Apple System Colors Light new 0% pr-body
agent-pane.claude-desktop-organization/tree Apple System Colors new 0% pr-body
agent-pane.claude-desktop-organization/zebra Apple System Colors Light new 0% pr-body
agent-pane.claude-desktop-organization/zebra Apple System Colors new 0% pr-body
agent-pane.tool-group-alignment/light Apple System Colors Light unchanged 0% pr-body
agent-pane.tool-group-alignment/light Apple System Colors unchanged 0% pr-body
agent-pane.tool-group-alignment/dark Apple System Colors Light unchanged 0% pr-body
agent-pane.tool-group-alignment/dark Apple System Colors unchanged 0% pr-body

Pick other states with a Gallery: entry.id, entry.id/variant line in the PR body.

@github-actions github-actions Bot added the risk:normal Risk tier (docs/ci/risk-tiers.md) label Oct 30, 2026
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Owned by an agent session · session

@blacksmith-sh

blacksmith-sh Bot commented Oct 30, 2026 •

Copy link
Copy Markdown

Found 12 test failures on Blacksmith runners:

Failures

Test View Logs
main.DeveloperIdAppTests.test_download_prints_the_active_profile_only/
test_download_prints_the_active_profile_only
View Logs
stubs: /System/Library/Frameworks/Security.framework/Versions/A/Security has no stub/
Security has no stub
View Logs
stubs: CoreFoundation.tbd: install-name /System/Library/Frameworks/
CoreFoundation.framework/Versions/A/CoreFoundation, missing 1: ['_CFRetain']/
CoreFoundation, missing 1: ['_CFRetain']
View Logs
stubs: CoreFoundation.tbd: install-name /System/Library/Frameworks/
CoreFoundation.framework/Versions/A/CoreFoundation, missing 1: ['_log2']/
CoreFoundation, missing 1: ['_log2']
View Logs
test/motion-scale.test.ts/motion-scale.test View Logs
test/motion-scale.test.ts/motion-scale.test View Logs
test/new-tab-cards-template.test.tsx/new-tab-cards-template.test.tsx View Logs
test/new-tab-cards-template.test.tsx/new-tab-cards-template.test.tsx View Logs
test/new-tab-composer-layout.test.tsx/new-tab-composer-layout.test.tsx View Logs
test/new-tab-composer-layout.test.tsx/new-tab-composer-layout.test.tsx View Logs

...and 2 more test failures. View all on Blacksmith

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

…transcript-group-rows

# Conflicts:
#	webviews/scripts/design-tokens-baseline.jsonl
#	webviews/src/agent-session/acpmux/conversation/ThoughtRow.tsx
#	webviews/src/agent-session/acpmux/conversation/ToolGroupRow.tsx
#	webviews/src/agent-session/acpmux/conversation/turns.ts
#	webviews/test/transcript-density.test.tsx
#	webviews/test/transcript-group-thought-state.test.tsx
…transcript-group-rows

# Conflicts:
#	webviews/src/agent-session/acpmux/conversation/TurnRows.tsx
#	webviews/src/agent-session/acpmux/conversation/toolGroups.ts
#	webviews/src/agent-session/acpmux/conversation/turns.ts
…nd command as the group's second step

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-92fa78a91e29868c5eaa
@cursor

cursor Bot commented Oct 30, 2026

Copy link
Copy Markdown

Bugbot needs on-demand usage enabled

Bugbot uses usage-based billing for this team and requires on-demand usage to be enabled.

A team admin can enable on-demand usage in the Cursor dashboard.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (codex gpt-6-astra high, next-review): BLOCK at ff42f14

  • [P1] webviews/test/transcript-group-step-renders.test.tsx:27 — CommandRow is exported through React.memo, so RealCommandRow is an object, not a callable function. Calling it directly throws TypeError, making the new test fail. Render it as <RealCommandRow {...props} />.
  • [P2] webviews/src/agent-session/acpmux/conversation/conversation.css:2297 — The DOM places command metadata before the chevron, but these rules assign them columns 4 and 2 without specifying a row. Grid’s default sparse placement moves the chevron onto a second row, breaking the intended single-line steps. Assign these children grid-row: 1 or reorder the markup.

…CommandRow as an element in the render-count test

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-92fa78a91e29868c5eaa
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (codex gpt-6-astra high, router-review): SHIP at 56c70a5

SHIP

No blocking findings. Focused tests were not runnable because bun is unavailable in the review environment.

@teamleaderleo
teamleaderleo merged commit e00f4a1 into feat-cmux-next Oct 30, 2026
154 of 161 checks passed
@teamleaderleo
teamleaderleo deleted the claude-sr2/transcript-group-rows branch October 30, 2026 16:03
@github-actions

github-actions Bot commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

teamleaderleo added a commit that referenced this pull request Oct 30, 2026
…e step tests know the card (base red from #27896) (#28465)

* cmux NEXT transcript: a later thought in a run's card is a quiet "Thought" row again; the step tests know the card (base red from #27896)

#27896 put an opened run's steps in one bordered card with each step's caret right after its
words, and drew a later thought's words where the quiet "Thought" row was. Three react-apps-check
tests went red on feat-cmux-next.

- Code: a closed non-lead step thought reads "Thought" (or "Thought for 12s") with none of its text
  inline, and opens to its whole text under that line (Leo 2026-10-20). The thought that leads the
  run keeps #27896's open full text.
- agent-pane-step-rows: every step is still one 22px row; rows outside a card keep zero gaps, and a
  card's steps sit on one equal pitch of their own.
- agent-pane-transcript-chevron-column: rows outside a card keep the shared trailing edge; a card's
  step carets sit inline after their labels within 4.5px, #28018's criterion.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-63b9964940c20354b639

* cmux NEXT transcript: a step thought opens on click under the React Compiler

StepThought read its open state from a module Map and forced a redraw with an unread counter, so
the compiled render was memoized on `id` and a click never opened or closed the row. The reader's
choice is now state (still kept by `id` in the shared Map for rows that mount again). Formatting of
the label line and the step-rows test header.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-63b9964940c20354b639

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
teamleaderleo added a commit that referenced this pull request Oct 31, 2026
Conflicts resolved by hand:
- ChatHeaderTools: one letter handler. Base #25661 shortcutLabel and menuItemForShortcut stay; a
  row also matches its mnemonic, and every key goes through menuLetters (fields, IME, typeahead).
- ToolGroupRow: base dropped +K more (#26591, #27896), so the :all disclosure goes; Thinking still
  opens a group that holds a thought. StepThought follows the transcript view as ThoughtRow does.
- ToolRow: base ToolOutput with our useRowDisclosure.
- Settings schema, its test, chatDisplay: base rail.side and feature tips beside transcriptView.
- Both xcstrings catalogs: base text plus our five keys (scripts/merge-xcstrings.py, per key).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
teamleaderleo added a commit that referenced this pull request Oct 31, 2026
… keeps them, and a stale press is never reused (follow-up to #28780) (#28324)

* agent transcript: closing a line at the end keeps it where it was clicked

Leo (ask-a736047107): "AND IT'S SO FUCKING AWKWARD TO SEE THEM THERE AT THE
BOTTOM SINCE WHEN I EXPAND THEM IT JUMPS ME DOWN AND WHEN I COLLAPSE IT JUMPS
ME UP"

A click on a transcript disclosure now keeps the content at least as tall as
the view's end, so closing a body near the transcript's end leaves room under
the rows instead of the browser clamping the offset and bringing every row
(and the clicked line) down by what closed. The room follows the view's end
as the reader scrolls up and goes once the rows reach it, on a send, on Jump
to latest and on a chat switch.

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

* agent transcript: every cut row opens to its whole text, and every toggle holds its place

Leo (ask-486cb2cec3): "why the fuck did you guys ffucking ellipsis EVERYTHING
WITH NO WAY TO EXPAND WHAT WAS SAID TO SEE"

- A tool call that is not a shell always opens, and opened its label wraps
  whole (a long search pattern, URL or path); a call with no output opens to
  that alone.
- A dispatch report keeps its whole text (no 2,000-character cut).
- An opened agent message names its other chat whole; an opened sub-session
  line shows its whole state.
- FOLD_TOGGLE now holds every control that opens something in a row (Show
  more, Show all lines, Raw, +N more, a sent message line, an agent message
  line's words); one under its body holds its row's top.

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

* agent transcript: the kept collapse room lets go once the hold ends or the view covers it

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

* agent transcript: no fold room while following; nested controls are not toggles; an opened name wraps

Review findings at d32bcfe: a collapse that leaves room stops following, and a
followed view drops the room; a click on a control inside a toggle (a sent
line's recipient, Copy) holds nothing; an opened agent message's name wraps.

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

* test(transcript): fold-keeps-place waits on painted frames, not a fixed time

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

* Hold every height toggle from the press, and keep holding while the line settles

Wrap lines (aria-pressed) and a diagram's chart/code toggle now hold their line. The hold starts on
pointerdown, flushes drawn heights synchronously while it holds, extends while the line still moves
(capped at 1.5 s, so Reduce Motion gets a real hold), and a sideways wheel no longer lets go.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-06adbde0c46733e12100

* test(transcript): step the settling hold to its cap

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-06adbde0c46733e12100

* agent transcript: the press notes the line's place; only the click holds

A hold that started on pointerdown re-placed the row under the pointer, so a tall prompt's Show less
got its press and release on different nodes and never clicked.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-06adbde0c46733e12100

* agent transcript: a fixed minimum hold instead of one that extends while the line moves

An extending hold kept putting a tall prompt back while the view was scrolled to it, so its Show less
missed its click. A toggle with no fold (Reduce Motion) now holds for at least 400 ms.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-06adbde0c46733e12100

* style: format foldAnchor.test.ts

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-06adbde0c46733e12100

* agent transcript: the row's own anchored-collapse event keeps the click's pressed place

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-06adbde0c46733e12100

* test(transcript): measure trailing chevrons on a run's own rows, not its steps

Every call opens now, so a step with no output has a chevron too, and a step's chevron follows its
words by design (#27896).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-06adbde0c46733e12100

* style: format agent-pane-tool-group-scroll.test.ts

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-06adbde0c46733e12100

* agent transcript: hold only marked press toggles; a sideways wheel keeps the hold; no dangling aria-controls

Pin and Read aloud (aria-pressed, no height change) no longer start a hold that could stop following.
Wrap lines and a diagram's toggle say they fold (data-fold-toggle). cancelProgrammatic keeps the hold
through a horizontal wheel. A no-output call names no body it does not draw. A keyboard click or a
cancelled press never reuses an abandoned press place.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-06adbde0c46733e12100

* style: format DiagramBlock.tsx and foldAnchor.test.ts

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-06adbde0c46733e12100

* agent transcript: an output's Raw and a code block's Wrap hold their line; a file link is no toggle

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-06adbde0c46733e12100

* style: format foldAnchor.test.ts

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-06adbde0c46733e12100

* agent transcript: drop the attributes the base merge doubled; the gallery play names the minimum hold

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-06adbde0c46733e12100

* style: format foldAnchor.test.ts

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-06adbde0c46733e12100

---------

Co-authored-by: ci <ci@example.invalid>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
cmux-bot Bot pushed a commit that referenced this pull request Oct 31, 2026
…he organized turn (#29168)

* Agent chat: one thought branch in toolGroups; a capture fixture for the organized turn

toolGroups had two isThought branches in a row: the first took a thought
inside an open commands/reads/searches run, the second every other thought.
They are now one branch with the two cases inside it, so no reader takes the
second for dead code (#27896 review, P3). Behaviour is unchanged.

debug.agent_pane seed_rows takes fixture "organization": the gallery's
Claude desktop organization turn (answered question, checklist, a thought
and five shell steps, prose), so a real-app capture can show it.
scripts/cmux-next/media/states/claude-desktop-organization.json drives it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-92fa78a91e29868c5eaa

* organizationFixture: copy the answered question instead of importing it from outside webviews/

A shipped bundle that imports a file outside webviews/ must be listed in the web bundle
key's inputs (tests/test_web_bundle_key_inputs.sh); a debug seed does not need that.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-92fa78a91e29868c5eaa

* organizationFixture: vp fmt (format only)

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

This branch was previously deployed

1 inactive deployment
ci-routing-agent — 56c70a5d Deployed Oct 30, 2026 by teamleaderleo via cmux-tui tree preflight #83853
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk:normal Risk tier (docs/ci/risk-tiers.md)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant