Repository navigation
cmux NEXT agent chat: a relaunch never draws a black picture of a see-through page - #29058
Conversation
…the quit saved --record-launch SECONDS passes the app's own launch recorder to every restore relaunch and archives the frames (--launch-frames), so a black first frame is something a fleet run can count. Each restore line also names the saved pictures (AgentPaneLaunchImages) the relaunch could draw. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…-through page Leo, 2026-10-26: "on restarting after an update/maybe in general, we dont wanna see a black background on the agent chat." The agent chat shows in Chromium by default. Its saved picture (the next launchs first frame, and a released pages frame when it is built again) is a Chromium JPEG, which has no alpha: over a glass, frosted or see-through window, or a background image, the page is clear and those pixels came out black. The relaunch drew that black picture until the live page painted. A picture that cannot keep clear pixels is now saved only when the page sits on an opaque color; otherwise the pane shows its loading state on the window backdrop. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
cmux status (one comment, edited in place; each line is updated by the job that owns it) Review App of this head (app.zip, kept 1 day)
Default changesThis pull request changes 5 defaults at
Signed off on this commit by Merge receipt: merged as Regenerate the snapshot with Shipped in:
|
|
Owned by an agent session · session |
… paints Review findings at 2a00805: the colors were read outside the view's theme scope, so a workspace's own picture or glass was missed and its Chromium picture still saved black; and a page with its own opaque surface background (appearance.surfaces) has a clear under-page color, so its safe picture was dropped. The decision now reads, in the view's scope, the background the page itself paints (WebTheme.pageBackground, the one source of --cmux-surface-background). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rawn Review follow-up at c81be33: the first launch after an update reads the pictures the previous version saved at quit, so a Chromium JPEG of a see-through page still drew black once. The same rule now holds when a saved picture is drawn (AgentPaneView.pictureCoversPage, in the pane's scope): one with no alpha only over a page that paints opaque. The chat-open bench reads the saved pictures from the build's real Application Support folder. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ch frames land Review follow-ups at 611fb43: a tab its launch defers draws its saved picture before its view exists, so the picture was never checked there. With no view, a picture with no alpha now covers only when both agent surfaces would paint opaque in the pane's scope. The chat-open bench makes the launch recorder's folder (the app writes no frames into a missing one) and reports the archive path make_archive actually wrote. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review at dbde555: requiring both surfaces opaque for a tab with no view yet dropped an opaque chat's valid picture (the New Tab surface is clear by default), and take() had already consumed it. The tab's record says whether it is a New Tab page (AgentTabStore.isNewTabPage) before its view exists, so the picture is judged against that one surface. The chat-open bench waits for the launch recorder's frames.json (bounded) instead of a guessed delay. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ck-launch-image # Conflicts: # Packages/macOS/CmuxNext/Sources/CmuxNextAgentPane/AgentPaneView+PageImage.swift
|
Found 1 test failure on Blacksmith runners: Failure
|
|
Review (codex gpt-6-astra high via router-review): SHIP at 1964f05 Delta review of the merge of feat-cmux-next (hand-resolved conflict in AgentPaneView+PageImage.swift) over a600db2..1964f05: no findings. Earlier P2 follow-ups stand (tag substring match in the bench; a JPEG saved over a clear page drawn if the window turned opaque before relaunch). At this head: compile-check --app passed; PageImageBackgroundTests, AgentPaneColdChatRevealTests, WebThemeTests passed. |
|
Review (next-review patch-id; carried): SHIP at 2bc4838 The independent SHIP at 1964f05 carries to this head: the PR's own change ( |
|
Review (codex gpt-6.1-sol xhigh via router-review): SHIP at 2bc4838 Review of the PR diff at the head after cmux-bot's clean base merge (diff unchanged apart from line offsets). compile-check --app passed at this head. Follow-ups (filed as issues):
|
A newer verdict blocks 6baf6eb (no independent SHIP at the head).
|
Review (next-review patch-id; carried): SHIP at 6baf6eb The independent SHIP at 5812769 carries to this head: the PR's own change ( |
|
Review (next-review patch-id; carried): SHIP at 1977a24 The independent SHIP at 5812769 carries to this head: the PR's own change ( |
…loud and CmuxNextAgentPane (app_lines) (#29883) * base red: move #29532's and #29058's CmuxNextApp lines into CmuxNextCloud and CmuxNextAgentPane app_lines rose +5 (28ab7d2, #29532) and +6 (aaa050d, #29058). This moves pure parts of the same code to the owning packages, with no behavior change: - CmuxNextCloud: CloudMachine.startChatPlanEntry(connected:chats:) (a listed machine as cmux link start-chat plan reads it) and Collection<CloudMachine>.keptForPin(listed:) (#29532's stored list). - CmuxNextAgentPane: AgentPaneLaunchImages.takeCovering(...), the take plus #29058's savedPictureCovers rule. CmuxNextApp -16 lines. CloudStartChatMachineTests call the new API and cover the plan entry. * AgentPaneLaunchImagesAlphaTests: takeCovering hands a saved picture with clear pixels out once
|
Review (subagent claude-opus-5-5 medium, post-merge): SHIP at 5a52092 This PR merged with no review at its head, so this is an after-the-fact review. No blocking findings. Follow-ups:
|
![Fix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/fix-with-codesmith-light-3x.png)
Leo, 2026-10-26: "also as for loading in stuff, on restarting after an update/maybe in general, we dont wanna see a black background on the agent chat. idk why it's black. chromium not loading fast enough? idk, the sidebar loads in the background/theming pretty quick. feels weird."
Leo, 2026-10-27: "Okay, well, what about in terms of when you just restart and update the app? There's still that black screen and what not in the agent chat area."
Why it was black
The agent chat shows in Chromium by default (
agent.chromiumis on). At quit, each shown chat saves a picture of its page, and the next launch draws that picture as the pane's first frame until the live page paints (AgentPaneLaunchImages). A released page that is built again draws its picture the same way (AgentPageHibernation).A Chromium picture is a JPEG (
Page.captureScreenshot), which has no alpha. In a glass, frosted or see-through window, or over a background image, the page is clear, and those clear pixels come out black.PageImageBackground.fillonly flattens over an opaque color, so the relaunch drew that black picture for as long as the page took to paint again. The sidebar has no saved picture: it draws the theme and backdrop from its first frame, which is why only the chat looked black.The New Tab cover already refuses a Chromium picture for this reason (
PageWebView.snapshotKeepsClearAreas, #24692). The launch and hibernation pictures did not.What changes
AgentPaneView.pageImage()returns nil when the picture can't keep clear pixels and the page paints no opaque background of its own. It reads that background in the pane's own theme scope (performWithTheme, so a workspace's own picture or glass counts) fromWebTheme.pageBackground, the one source of--cmux-surface-background. With no picture, the pane shows its loading state on the window's own backdrop (the theme and glass the sidebar shows), and the page fades in over that.drawLastPageapplies the same rule before drawing one (AgentPaneView.savedPictureCovers), using the tab's record (isNewTabPage) for a tab its launch defers, which has no view yet.appearance.surfacesbackground, the page paints opaque, so a JPEG has no clear pixels to lose. That picture still saves and draws as before, and the relaunch keeps its instant first frame.snapshotKeepsClearAreas), so they are unchanged in every window.PageImageBackground.cover/coversare the one rule. The tests cover each case.--record-launch SECONDS(the app's own launch recorder on each restore relaunch, frames archived) and--backdrop. Each restore line also names the saved pictures the relaunch could draw. That turns "no black frame" into something a fleet run can check.No timers, observers or animation loops are added. No default changes. Nothing is removed.
Not in this PR
Risk
Low. The change is in what the quit saves, never in what a live page draws. In a translucent window with Chromium, a relaunch now shows the loading state (backdrop plus a delayed spinner) instead of a black picture, until the page paints. Opaque windows and WebKit pages are unchanged.
Validation
compile-check --app) passed at the fix commit.compile-check --apppassed at 313130b.PageImageBackgroundTests,AgentPaneColdChatRevealTests,WebThemeTests: all passed.Relaunch on a fleet Mac, frosted window, Chromium chat
scripts/measure/chat-open.sh --cases=sidebar,restore --conditions=idle --runs=2 --backdrop=frosted, same worker class (aws-m4pro, Mac16,11). Before: this PR's bench on base (03c7706). After: dbde555; the commit after it changes only the deferred-tab path and the bench's wait. The app's own chat-open trace records, frame by frame, which surface the pane showed. A flash is a return to an empty surface after content.tab_…@1x.jpg(Chromium JPEG)tab_…@1x.jpgThe restore case counted 2 flashes before and 0 after.
Performance
No screenshots: the app's launch recorder (
--record-launch) wrote no frames on these display-less fleet workers (an empty archive both times), and a capture tour can't relaunch the app. The frame-by-frame evidence is the trace above.Follow-ups (review, P2)
tags/chatopenalso matchestags/chatopen2).🤖 Generated with Claude Code
Agent session: agent session