cmux NEXT: fold a long reasoning trace the way Codex does
Summary
A long reasoning trace used to fill the transcript: a thought always drew in full, so a model that thinks for a screen pushed everything else away. It now folds the way Codex desktop folds its reasoning trace (Leo's 10-15 feedback, item 7).
- While the agent is still thinking it: a thought taller than seven lines (140 px, Codex's 8.75rem viewport) stays in a fixed viewport. The newest line sits at the bottom and older lines fade out at the top over 16 px. The label reads "Thinking" with the existing shimmer.
- Once the agent moves on (a tool call, its answer, or the turn ending): the thought folds to one line, "Thought for 12s". Its duration runs from the thought's first chunk to its latest. The line opens on a click, Enter or Space. Opened, the full text fades in under it (
cv-enter,--agent-motion-in). Closing is instant, as "Worked for" closes. - A short thought never folds. It shows in full after a muted "Thought", as before (Leo 10-13).
- An opened thought stays open when the virtual list draws its row again, or when the row moves under "Worked for". Find opens a folded thought that holds its match.
How Codex does it, read from its shipped web bundle (ChatGPT.app 26.930.51102):
- The trace's body is a 140 px scroller, pinned to the bottom while it streams, with a 16 px edge fade.
- The header reads "Thinking", then "Thought for {elapsed}".
- Every trace folds when it completes, with a 300 ms height and opacity animation (expo-out).
- The open state is component-local.
cmux differs on purpose in three places:
- Only long traces fold, since Leo asked that thoughts read in full.
- An opened trace shows its whole text, not a 140 px scroller.
- There's no height tween, because virtualized rows place absolutely by their measured height.
The full spec, with each claim marked as read from code, seen, or inferred, is in the lane's brief codex-reasoning-collapse.md.
Mechanism:
turns.tsmarks the live turn's last activity rowstreaming, with a negated version so the memoized row and the height cache redraw when it stops.ThoughtRowmeasures its text before paint, so a long thought never draws full height first.appendThoughtkeeps each thought's first and latest chunk time.- The new string
tools.thoughtForis in all 21 pane locales. English is translated; the other locales are needs_review, like their neighbours.
Testing
Gallery plays at the transcript boundary, run in Chromium through webviews/test/transcript-thought.test.ts. Same command, red then green, on the builder:
sbx -- bash -lc 'export CMUX_BROWSER_TESTS=1 LD_LIBRARY_PATH=...; cd webviews && bun install --frozen-lockfile; bun test test/transcript-thought.test.ts'
- Red at
bb930529355f(tests only):- "a long live thought grows to 426px instead of folding"
- the fold play's
waitFornever found a toggle - the short-thought and existing thought tests passed
- Green at
86013c41740e: all 5 pass.- A long live thought stays within 140 px with its newest line in view and its first line out of view.
- An ended one shows a closed "Thought for 12s" without its text; a click opens it, Enter closes it and Enter opens it again.
- A short live thought has no toggle and isn't cut off.
bun run check: passes (lint, types, format, layers, type scale, system blue).- Crash ratchet: ok.
- Also passed:
transcript-worked-fold,transcript-long-chat-updates,transcript-hidden-follow,agent-pane-follow-live,agent-pane-step-rows,thread-turn-keysandagent-pane-replay. These cover follow-at-end and virtualization. - After the review subagent's findings (green again at the head, with
bun run check):- A thought re-measures on resize until it folds, so one mounted in a hidden pane, or narrowed later, still folds.
- Thoughts key by their place in the row, so a regrouped run never moves an open state.
- Didn't run on the builder:
agent-pane-localeneeds the built pane bundle, which isn't there.
Live Codex wasn't re-recorded this pass. The thresholds and timings come from Codex's shipped code, not from frames.
Changelog
Added: A long reasoning trace streams in a fixed seven-line viewport with its newest line in view, then folds to "Thought for 12s", which opens on a click or Enter
Proof
These are gallery stills of the real transcript components in Chromium (agent-pane.transcript, 760 px), not app captures. A Codex reference stays private and isn't shown here.
A long thought while the agent is still thinking it. Before: the whole trace draws. After: a seven-line viewport with the newest line at the bottom and older lines fading out at the top.
| Before | After | |
|---|---|---|
| Light | ![]() | ![]() |
| Dark | ![]() | ![]() |
After the agent moves on. Before: still the whole trace. After: one line, "Thought for 12s", then opened.
| Before | After, folded | After, opened | |
|---|---|---|---|
| Light | ![]() | ![]() | ![]() |
| Dark | ![]() | ![]() | ![]() |
The folded stills show the focus ring because the play opened and closed the row with the keyboard.
Open and close (clip):

Full quality: ,
Checklist
- Behavior changes have added or updated tests, or Testing says why not
- UI, settings, menu, schema, help-text or user-facing docs change: localization audited, and the result is stated above. One new pane key,
tools.thoughtFor, is in all 21 locales, andgenerated/strings.jsonis regenerated. - Reviewed with a subagent before merge (cmux-review), and all bot and human review comments resolved
š¤ Generated with Claude Code









