Skip to content

Agent chat: the composer keeps a thin scrollbar while its draft overflows - #23854

Merged
teamleaderleo merged 7 commits into
feat-cmux-nextfrom
cmux/composer-persistent-scrollbar
Oct 22, 2026
Merged

teamleaderleo merged 7 commits into
feat-cmux-nextfrom
cmux/composer-persistent-scrollbar

Conversation

@teamleaderleo

@teamleaderleo teamleaderleo commented Oct 21, 2026 •

Copy link
Copy Markdown
Collaborator

Leo, 2026-10-21: "STOP HIDING THEN SHOWING THEN HIDING THE SCROLLBAR. IF THERE ARE THINGS TO SCROLL, JUST KEEP THE SCROLLBAR IN THE COMPOSER, LIKE CLAUDE DOES."

The agent chat's prompt (.acpmux-md-field) scrolled with the engine's own scroller. WebKit's overlay scroller shows while the field scrolls and fades out a moment later, so a long draft's scrollbar flashed on every line typed and went away when you stopped.

Now the prompt has the shared minimal scroller: MINIMAL_SCROLLER_ATTRIBUTE (data-cmux-minimal-scroller) and MINIMAL_SCROLLER_CSS in webviews/src/scrollers.ts, installed with the other shared scroller rules by installScrollers. It draws a thin thumb (--cmux-scroller-size, --cmux-scroller-thumb) with no track, the whole time the content overflows. Typing, focus, hover and resize never fade it. Its track stops --cmux-minimal-scroller-inset short of each end, clear of the card's rounded corners. A draft that fits has no scrollbar (overflow: auto). The style uses theme tokens only.

This is the smallest fix, the composer only. The transcript and the sidebar move to the same style, and an opt-in auto-hide variant gets added, in follow-ups (chat-load and sidebar-rows lanes). Other code can opt in by putting the attribute on its scroll container.

Base merge and the reserved lane (orphan-sweep, head ee2217d)

After one merge of feat-cmux-next, composer-draft-wrap.test.ts failed in WebKit at 300 px: the minimal scroller is a classic WebKit scrollbar, so when a draft first overflowed its 8 px lane took layout width and the text rewrapped (8 lines became 9, and the caret left the view). The minimal scroller now reserves its lane (scrollbar-gutter: stable), and the agent composer takes that lane out of its right padding in both looks, so the draft keeps base's width whether or not it overflows. The lane stays empty while the draft fits. The Home composer (pages/home-channels/styles.css) uses the same field and does not adjust its padding, so its text area is 8 px narrower than before.

Test

webviews/test/composer-persistent-scrollbar.test.ts, in Chromium (scrollbars on) and WebKit. It pastes past the prompt's eight lines, then reads the scrollbar lane after every painted frame (cmuxAfterPaint) and samples the drawn thumb through typing, a 2.5 s idle, blur, focus and the pointer leaving. Every frame must have a thin lane (1 to 10 px) and every sample a thumb with no track. Then it cuts the draft back to one line and expects no scrollbar on any frame.

cmux-ci run --class light --script scripts/ci/run-webviews-tests.sh --env CMUX_BROWSER_TESTS=1 --env CMUX_WEB_TEST_FILES=test/composer-persistent-scrollbar.test.ts

  • red, test commit 67c9680: pending (two earlier runs, steps f2a30bd7fcf026c4236c7dda and e6466b5f0098e88125470674, stopped at a 180 s WebKit launch timeout on the worker, before any assertion)
  • green, head 708f7b0: pending

Observed / Not run

  • Observed: the fleet runs above. cmux-ci compile-check --app passed on the head. scripts/web-lint.sh and prepush-gate.py ran locally. The web lint's only reds come from the sparse worktree (no Packages/, no cmux-tui/, no generated strings), and the same checks are red on base in that checkout. None of them is in a changed file.
  • Not run: a native capture. No capture: a webview CSS change; the gallery compare covers it.

Changelog

  • Fixed: The agent chat composer keeps a thin scrollbar visible while a long draft overflows, instead of flashing it on each line typed.

Agent session: cosmic-gray

🤖 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

Fixes the agent chat composer so a long draft keeps a thin scrollbar visible while it overflows, instead of flashing it on each line typed and fading out at rest.

The prompt (.acpmux-md-field) now uses the shared minimal scroller (MINIMAL_SCROLLER_ATTRIBUTE / MINIMAL_SCROLLER_CSS in webviews/src/scrollers.ts), which draws a thin thumb on no track the whole time content overflows, clear of the rounded corners.

  • The lane is always reserved with overflow-y: scroll — WebKit ignores scrollbar-gutter on a box with a custom scrollbar — and is taken out of the composer's right padding, so drafts keep their width and never rewrap when the scrollbar appears or disappears. The Home composer uses the same field without this adjustment, so its text area is 8 px narrower.
  • Adds a browser test covering Chromium and WebKit that verifies the thumb stays on every painted frame through typing, idle, blur, focus, and pointer leave, and disappears when the draft fits.
  • Other scroll containers can opt in by adding the attribute.

Written for commit e762574. Summary will update on new commits.

View guided diff Turn on auto-fix

teamleaderleo and others added 2 commits October 21, 2026 15:06
… on every frame (red)

Fills the prompt past its eight lines and reads the scrollbar lane after every painted frame and
the drawn thumb through typing, a 2.5 s idle, blur, focus and the pointer leaving, in Chromium and
WebKit; then cuts the draft back and expects no scrollbar. Fails on base: the prompt has the
engine's own scroller (a 15 px classic bar or an overlay that hides at rest).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15bf1-fdc7-79b0-b869-8ac78b0edd90&host=cosmic-gray
…lows

The prompt (.acpmux-md-field) had the engine's own scroller, which WebKit shows while the field
scrolls and fades out a moment later, so it flashed on every line typed. It now carries the
minimal scroller (MINIMAL_SCROLLER_ATTRIBUTE / MINIMAL_SCROLLER_CSS in webviews/src/scrollers.ts,
installed with the other shared scroller rules): a thin thumb in --cmux-scroller-thumb on no
track, drawn the whole time the draft overflows, its track inset from the card's rounded corners.
A draft that fits has no scrollbar.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15bf1-fdc7-79b0-b869-8ac78b0edd90&host=cosmic-gray
@teamleaderleo teamleaderleo added the risk:normal Risk tier (docs/ci/risk-tiers.md) label Oct 21, 2026
@cursor

cursor Bot commented Oct 21, 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.

@github-actions

github-actions Bot commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

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

Review e762574: 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=pr23854 -f ref=cmux/composer-persistent-scrollbar -f platform=macos -f backend_mode=local

Gallery before/after for e762574: 16 states rendered, 2 images differ, 1515 more touched states not rendered. Images are in the run's artifact, not on this public PR.

gh run download 39713019336 -R manaflow-ai/cmux -n gallery-advisory-23854-e762574b894c6aa764de169cac2969ae32c31362 (then read gallery-review.json)

States
State Theme Status Diff Picked by
agent-pane.composer/new-chat Apple System Colors Light unchanged 0% own MarkdownField.tsx
agent-pane.composer/new-chat Apple System Colors unchanged 0% own MarkdownField.tsx
agent-pane.composer/side-session Apple System Colors Light unchanged 0% own MarkdownField.tsx
agent-pane.composer/side-session Apple System Colors unchanged 0% own MarkdownField.tsx
agent-pane.composer/new-chat-suggest-open Apple System Colors Light unchanged 0% own MarkdownField.tsx
agent-pane.composer/new-chat-suggest-open Apple System Colors unchanged 0% own MarkdownField.tsx
agent-pane.composer/new-chat-suggest-failing Apple System Colors Light unchanged 0% own MarkdownField.tsx
agent-pane.composer/new-chat-suggest-failing Apple System Colors unchanged 0% own MarkdownField.tsx
agent-pane.composer/new-chat-suggest-draft Apple System Colors Light unchanged 0% own MarkdownField.tsx
agent-pane.composer/new-chat-suggest-draft Apple System Colors unchanged 0% own MarkdownField.tsx
agent-pane.composer/new-chat-reasoning Apple System Colors Light unchanged 0% own MarkdownField.tsx
agent-pane.composer/new-chat-reasoning Apple System Colors unchanged 0% own MarkdownField.tsx
agent-pane.composer/agent-home Apple System Colors Light unchanged 0% own MarkdownField.tsx
agent-pane.composer/agent-home Apple System Colors unchanged 0% own MarkdownField.tsx
agent-pane.composer/agent-home-path Apple System Colors Light changed 0% own MarkdownField.tsx
agent-pane.composer/agent-home-path Apple System Colors changed 0% own MarkdownField.tsx
agent-pane.composer-context/closed Apple System Colors Light unchanged 0% own composerLocation.css
agent-pane.composer-context/closed Apple System Colors unchanged 0% own composerLocation.css
agent-pane.composer-context/folder-menu Apple System Colors Light unchanged 0% own composerLocation.css
agent-pane.composer-context/folder-menu Apple System Colors unchanged 0% own composerLocation.css
agent-pane.composer-context/folder-favicons Apple System Colors Light unchanged 0% own composerLocation.css
agent-pane.composer-context/folder-favicons Apple System Colors unchanged 0% own composerLocation.css
agent-pane.composer-context/duplicate-worktrees Apple System Colors Light unchanged 0% own composerLocation.css
agent-pane.composer-context/duplicate-worktrees Apple System Colors unchanged 0% own composerLocation.css
agent-pane.composer-context/duplicate-search Apple System Colors Light unchanged 0% own composerLocation.css
agent-pane.composer-context/duplicate-search Apple System Colors unchanged 0% own composerLocation.css
agent-pane.composer-context/repo-worktrees Apple System Colors Light unchanged 0% own composerLocation.css
agent-pane.composer-context/repo-worktrees Apple System Colors unchanged 0% own composerLocation.css
agent-pane.composer-context/repo-worktrees-open Apple System Colors Light unchanged 0% own composerLocation.css
agent-pane.composer-context/repo-worktrees-open Apple System Colors unchanged 0% own composerLocation.css
agent-pane.composer-context/repo-worktrees-search Apple System Colors Light unchanged 0% own composerLocation.css
agent-pane.composer-context/repo-worktrees-search Apple System Colors unchanged 0% own composerLocation.css

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

Probably yours: web / react-apps-check (1) failed: a Python test failed, ERROR: test_real_vp_formats_an_edited_webviews_file (__main__.FormatPostEditTests.test_real_vp_forma....

CI failed on e762574b89 (run 39713019418 attempt 1): 1 code, 1 unknown.

Job Verdict Why
web / react-apps-check (1) code a Python test failed
web / react-apps-check unknown no known signature; failed step: Check webview test shards
Matched log lines
web / react-apps-check (1): ERROR: test_real_vp_formats_an_edited_webviews_file (__main__.FormatPostEditTests.test_real_vp_formats_an_edited_webviews_file)

Not re-run automatically: web / react-apps-check (1), 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: cmux-next checks (god files, concurrency, crash safety, l10n); NEW: red check: Tier routing is not red on the base 10b4591; do not merge until green; see lane-rules
red: web / Web status; NEW: green on the base 10b4591; do not merge until green; see lane-rules
red: web / react-apps-check; no finished base run on 10b4591 to compare; do not merge until green; see lane-rules
red: web / react-apps-check (1); no finished base run on 10b4591 to compare; do not merge until green; see lane-rules

Tour of e762574b89 (run): no media. The tour did not run: only webview code changed (5 path(s)), which the gallery advisory run checks in Linux Chromium on the pull request (its artifact holds any captures); add the media-tour-mac label, then re-add media-tour, to tour it on a Mac.

@blacksmith-sh

blacksmith-sh Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

Found 17 test failures on Blacksmith runners:

Failures

Test View Logs
/tmp/tmphovi2mcn/summary-missing.json (live):/summary-missing.json (live): View Logs
/tmp/tmpp3gggc_t/summary-fail.json (live):/summary-fail.json (live): View Logs
[new_workspaces] debug.new_workspace timed 0 of 50 new workspace rows/
[new_workspaces] debug.new_workspace timed 0 of 50 new workspace rows
View Logs
[new_workspaces] the window draws no frames/[new_workspaces] the window draws no frames View Logs
[tabs] debug.tab_switch timed 0 of 40 switches/
[tabs] debug.tab_switch timed 0 of 40 switches
View Logs
[tabs] the window draws no frames/[tabs] the window draws no frames View Logs
cmux-next-ios-kit.yml runs macOS jobs on pull requests but a new push does not cancel t
he previous run; key the concurrency group on the pull request and set cancel-in-progre
ss for its pull request events/
cmux-next-ios-kit.yml runs macOS jobs on pull requests but a new push does not cancel t
he previous run; key the concurrency group on the pull request and set cancel-in-progre
ss for its pull request events
View Logs
convention violations found (ERROR lines above)./
convention violations found (ERROR lines above).
View Logs
nightly cmux-tui resolve/nightly cmux-tui resolve View Logs
test_actual_workflow_commands_leave_failed_build_receipts_in_upload_directory (main
.SwiftPMBuildMetricsTests.test_actual_workflow_commands_leave_failed_build_receipts_in_
upload_directory)/
test_actual_workflow_commands_leave_failed_build_receipts_in_upload_directory (main
.SwiftPMBuildMetricsTests.test_actual_workflow_commands_leave_failed_build_receipts_in_
upload_directory)
View Logs

...and 7 more test failures. View all on Blacksmith: run 39713019329, run 39713019369

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

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

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

@teamleaderleo

teamleaderleo commented Oct 21, 2026 •

Copy link
Copy Markdown
Collaborator Author

Owned by orphan-sweep on air-blue · session

teamleaderleo and others added 2 commits October 21, 2026 17:47
…ft never rewraps

The minimal scroller is a classic WebKit scrollbar, which takes layout width. When a draft first
overflowed, its lane appeared and the text rewrapped (composer-draft-wrap at 300 px: 8 lines
became 9, the caret left the view). The minimal scroller now keeps its lane (scrollbar-gutter:
stable) and the composer takes it out of its right padding, in both looks, so the draft keeps
base's width whether or not it overflows. The lane stays empty while the draft fits.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15cfc-663f-7650-b9f7-64d198c6b88b&host=Air-Blue
@cursor

cursor Bot commented Oct 22, 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 (subagent, correctness first): SHIP at ee2217d

Independent review subagent (fresh context, read-only) at the exact head. No correctness findings. Non-blocking follow-ups, not fixed here:

  1. The Home composer (webviews/src/pages/home-channels/styles.css:521) now keeps the thumb and reserves the 8 px lane, so its text area is 8 px narrower (noted in the PR body).
  2. The placeholder's right: inset (markdownField.css ~:91, composerLocation.css ~:1168) does not subtract --cmux-scroller-size, so the placeholder truncates 8 px early.
  3. --acpmux-md-scrollbar-lane could be var(--cmux-scroller-size, 8px) instead of a separate 8px.
  4. A stale "overlay scrollbar's narrow lane" comment in markdownField.css.
  5. scrollbar-gutter needs WebKit from about Safari 18.2; check it against the minimum macOS.
  6. The right-to-left side (the lane and padding are physical right).
  7. The test's thumb() helper samples a column 3 px left of the lane.

Fleet compile-check at this head: passed (job 5471b4b64609c29da955208c).

teamleaderleo and others added 2 commits October 21, 2026 19:01
…croll (WebKit ignores scrollbar-gutter)

composer-draft-wrap still failed in WebKit at 300 px after the gutter fix: WebKit ignores
scrollbar-gutter on a box with a custom ::-webkit-scrollbar (measured with Playwright WebKit 26.5:
client width 215 px while the content fits, 207 px once it overflows), so the lane still appeared
on overflow and the draft rewrapped. overflow-y: scroll reserves it in both engines; the track is
transparent and a box with nothing to scroll draws no thumb (0 thumb pixels fitting, 76 overflowing,
in WebKit and Chromium). scrollers.ts is the scrollbar guard's allowed home for this rule.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15cfc-663f-7650-b9f7-64d198c6b88b&host=Air-Blue
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (subagent, correctness first): SHIP at e762574

Independent review subagent (fresh context, read-only) at the exact head. No correctness findings.

What changed since the SHIP at ee2217d: GitHub update-branch merges of feat-cmux-next (9735061, 05f3595; base only, PR diff unchanged), and e762574, which reserves the composer's thin scrollbar lane with overflow-y: scroll in place of scrollbar-gutter: stable. WebKit ignores scrollbar-gutter on a custom ::-webkit-scrollbar: measured in Playwright WebKit 26.5, client width was 215 px fitting and 207 px overflowing, so a draft rewrapped as it started to scroll. That broke composer-draft-wrap.test.ts (WebKit, 300 px) in CI. The track is transparent, and a box with nothing to scroll draws no thumb: 0 thumb pixels fitting and 76 overflowing, in WebKit and Chromium. With the change, composer-draft-wrap passes 32/32.

Non-blocking follow-ups, not fixed here:

  1. The Home composer (pages/home-channels/styles.css:518, .hc-composer-field padding: 8px 12px) keeps its 12 px right padding on top of the 8 px lane, so its text column is 8 px narrower. Fix: padding-right 12 px minus --cmux-scroller-size.
  2. --acpmux-md-scrollbar-lane: 8px (markdownField.css:27) could be var(--cmux-scroller-size, 8px).
  3. The placeholder's right: inset does not subtract the lane, so it truncates 8 px early. A stale "overlay scrollbar's narrow lane" comment remains, and the right-to-left side is unhandled.

Fleet compile-check at this head: passed (job 5d15e498461abc5d4d66aa7a). Reds at this head that also fail on base 80d19e4: gallery health composer#steer-read-hover (#24000 fixes it), the fast-gates web lint (test/subagent-stopped-after-cancel.test.ts formatting), release-notary, cmux-next checks, and the CI guard group (cmux-next-ios-kit / media / web-bundle guards).

@teamleaderleo
teamleaderleo merged commit 9239b22 into feat-cmux-next Oct 22, 2026
@teamleaderleo
teamleaderleo deleted the cmux/composer-persistent-scrollbar branch October 22, 2026 03:13
@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

teamleaderleo added a commit that referenced this pull request Nov 2, 2026
…ws, even under the scrollbar fade (#32112)

* test(composer): the draft's thumb stays at rest under the scrollbar fade too

Leo-ask: ask-c8936f0e52
Agent-Session: https://cmux.com/deeplink/agent?id=aid-591ebe5be3c52ce16103

* cmux NEXT composer: the scrollbar fade passes the composer by; its thumb stays while the draft overflows

Leo 2026-10-21: "STOP HIDING THEN SHOWING THEN HIDING THE SCROLLBAR. IF THERE ARE THINGS TO
SCROLL, JUST KEEP THE SCROLLBAR IN THE COMPOSER, LIKE CLAUDE DOES." #23854 built that, but the
agent pane's scrollbar fade (on by default since 2026-10-23) also faded the composer's thumb at
rest. The fade now covers the transcript only.

Leo-ask: ask-c8936f0e52
Agent-Session: https://cmux.com/deeplink/agent?id=aid-591ebe5be3c52ce16103

* Composer: the minimal scroller sets its own thumb ink

Leo-ask: c-c8936f0e52

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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