Repository navigation
docs: gh-merge-green is optional on feat-cmux-next (no bead) - #20567
Merged
Merged
Conversation
A plain gh pr merge on the exact head is fine under the branch's rules; the batch queue's own --land still uses the helper. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configuration
You can disable this status message by setting the Use the checkbox below for a quick retry:
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. Comment |
Collaborator
Author
|
Bead |
teamleaderleo
added a commit
that referenced
this pull request
Oct 14, 2026
…s picked (cx-uq9xi) (#20506) * free tier: the local relay owns the device lease; the cmux NEXT app is its App Attest provider; freeModel.enabled (cx-ds09i) Relay (cmux-coderouter free_tier.rs): attest_provider on the admin socket, peer-checked (same user; a Team-signed build: the cmux app that contains the relay, cmux-link app_caller), production origin only in release apps (staging and the dev Worker only in DEV builds), one provider and one request at a time. The relay builds the client data hash from the server challenge, keeps the free token in memory only (never in status or logs), drops it when the provider ends, when the setting turns off or an account signs in (also for a lease in flight), and starts a lease only at the first signed-out data-plane request (20 s, in its own task). App Attest refuses a second attestation of a key in a later launch, so a new month takes a fresh key. The account bearer wins. App: Packages/Shared/CmuxAppAttest (DeviceAttesting, AppleDeviceAttest, KeychainAttestKeyStore); FreeTierAttestProvider (CmuxNextAgentPane) answers only purpose cmux.free-tier.v1 over a 32-byte hash on an AcpmuxCheckedLine connection, one keychain item per bundle id; AppServices+FreeTier follows freeModel.enabled (default on, MDM lock, agents refused: privacy) and the sign-in (a restoring session counts as signed in). Behavior tests: acpmux/tests/router_free_tier.rs (real relay, admin socket, stand-in app and API; 7 tests, Linux rbx and hosted macOS 38362901804). Red check of the in-flight race at a3b1066ba9c7 recorded on cx-ds09i. scripts/cmux-next/free-tier-attest-e2e.sh: T1/T2 on a real Mac. Security review hq-84: APPROVE at 8b1c3f861a1e. * settings: tip catalog with the four freeModel strings (21 locales); exports reset to the tip before regeneration (cx-ds09i) * test(cmux-tui): Chief registry behavior tests at the socket and the CLI (red) (cx-ebm.60.1, cx-ebm.60.2) The person makes, edits and deletes Chiefs with cmux chief new|list|edit|delete; a Chief on its own bound connection changes its own picture and only the fields its self_edit lists; another agent is refused. Red: the daemon has no chief.list/get/create/update/delete/avatar.* operations yet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(cmux-tui): the daemon's Chief registry and cmux chief new|list|edit|delete (cx-ebm.60.1, cx-ebm.60.2, cx-ebm.60.3) Multiple Chiefs per Chief home (Lawrence 2026-10-14: "create new chiefs too with specific roles, names, ... profile pics (chiefs need to be able to do it themselves too), personality, system prompt, tools"). Daemon: chief_registry.rs owns chiefs.sqlite3 in the session state directory. A record has id (= the conversation participant id; agent_mux is the default Chief, written on first open; new ones agent_<26 base32>), display_name, role, personality, instructions (system prompt additions), avatar (PNG/JPEG/GIF/WebP <= 1 MiB, bytes by SHA-256, collected when no record names them), tools (closed catalog), harnesses, engine, self_edit, is_default, rev. Deleted ids stay as tombstones. Idempotency ledger per caller. cmux.protocol/2: chief.list, chief.get, chief.avatar.get (read); chief.create, chief.update, chief.delete, chief.avatar.set (mutation). Callers: the owner (Unix, no link peer, user_local) and the Chiefs (a connection bound with conversation-bind to a live record's id). A Chief reads every record and changes only its own self_edit fields (default: avatar); tools, harnesses, engine, self_edit, create and delete are the owner's; anything else is chief_self_edit_denied before any write. Pages, WebSocket, relayed and remote connections and non-Chief agents get origin.forbidden. Not MCP tools. CLI: cmux chief list | new --name N [profile] | edit CHIEF [profile] [--clear-avatar] | delete CHIEF, CHIEF an id or a unique name, --json. schemas/chief-profile/tool.json: the Chief's self-edit tool (profile) for the brain (wired in cx-ebm.60.5 after the per-build Chief home lands). Catalog: 271 operations (84 read, 168 mutation). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * app: AcpmuxEnvironment.resolve for the free-tier provider (the tip removed AgentTabPaneSource.paneEnvironment) (cx-ds09i) * settings: regenerated settings schema and MDM exports for freeModel.enabled on the tip (cx-ds09i; export-settings cmux-ci step 02f78faaf8d0) * webviews: settings strings for freeModel on the tip (cx-ds09i) * fix(cmux-tui): Chief registry ops are chief.profile.*; review fixes (cx-ebm.60.1, cx-ebm.60.2) Review (correctness subagent, 2026-10-14): - The cloud catalog already has chief.list/create/update with another shape; the app platform merges both catalogs by name with the local op winning, so equal names hid the cloud ops. The daemon ops are now chief.profile.list/get/create/update/delete/avatar.set/avatar.get; the generated app-host types keep the cloud chief.* ops. - idempotency.conflict names the committed operation; the ledger keeps the newest 256 keys per caller. - harness, model and effort are single-line. - CLI: "needs a newer daemon" only when the first chief.profile.list call is refused as unknown; a value error prints the daemon's reason. The picture is checked for 1 MiB before any write; when the picture write fails after the create or edit committed, the CLI says what committed. edit with no change, and --clear-avatar outside edit, are usage errors. - The spec states the trust limit (a Chief turn with a shell is the same OS user; the self_edit rule guards the model); hardening is cx-ebm.60.9. - Generated: app-host d.ts/ops/scopes and the AppPlatform scopes copy. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * style(cmux-tui): rustfmt the Chief registry files (cx-ebm.60.1) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * style(cmux-tui): mod order for rustfmt (cx-ebm.60.1) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * cmux-next: the typeahead GUI gate in the repo (cx-wb5.78): typeahead-gate.sh runs split, newterm, split with a slow host, new-tab and cold new-tab proofs on the GUI host and fails on a lost key; typeahead-compare.py counts keys sent by terminal id; creation-hold-proof.py is superseded (named in the gate header) * app: the free-tier composition moves to CmuxNextAgentPane (FreeTierAttestStarter); CmuxNextApp keeps a two-line hook (cx-ds09i; CmuxNextApp size cap) * app: one-line free-tier hook; FreeTierAttestStarter owns its task for the app's life (cx-ds09i; CmuxNextApp size cap) * +1 cx-ds09i launch hook, +1 tip drift from another lane; chief go * free tier: keep the tip's ghostty pointer (cb1ef7091cde, #20024; a stale submodule checkout had moved it back); signed-in fallback true when the services are gone (cx-ds09i move-check) * free tier: ci-target-graph.json and the workspace file are the tip's plus only the CmuxAppAttest lines (cx-ds09i final check: a stale regeneration had dropped CmuxNextBrowserHistory, CmuxNextCLIInstall, CmuxNextNowPlaying and two CmuxNextCompat test edges) * settings: regenerated settings schema and MDM exports on the merged tip ae657738afc2 (cx-ds09i; export-settings cmux-ci step 788077f4a088) * webviews: settings strings for freeModel on the merged tip (cx-ds09i) * chore(cmux-app-host): regenerate the app catalog after the tip merge (cx-ebm.60.1) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * acpmux: a Windows client whose daemon lost the start lock waits for the winner's socket; fixes the Windows start code of landings 2/3 (2f063f889c, 1fdb2a766b) (cx-ncc.54) two_starts_at_once_share_one_daemon failed on the hosted Windows runner (cmux-tui full run 38352677155): the losing start's client connected once before the winning daemon had bound its socket ("read the owner: The system cannot find the file specified"). It passed on run 38352027335 (same start code), so it is a race in the Windows start that landings 2 and 3 put on feat-cmux-next, not in the agent job change. Now, when the started daemon exits without a readiness line, the client waits (within the same start budget) while another daemon holds daemon.lock and the socket file is missing. The probe takes daemon.lock for an instant when it is free (Windows cannot test a LockFileEx lock without taking it); the risk is written in a code comment. The change is in daemon/windows.rs; daemon.rs does not grow. * acpmux: owner-only files and folders on Windows (cx-ncc.54) What is mode 0600 / 0700 and a uid + mode check on Unix is an access list on Windows (src/owner_only.rs): - Written files are created (CreateFileW, CREATE_NEW, no reparse-point follow) with a protected DACL that grants only our token user, our user as owner: write_atomic (config.json and every file written through it: handoffs, the registry cache, harness profiles), the LocalApp and peer token files, private agent files, preset system prompts. daemon.log is opened that way and narrowed if a wider one exists. - Folders made here inherit the same list (0700 on create): harness_admin, handoffs, the registry cache, `cmux harness add` and `harness registry`, the doctor's temporary folder. ensure_private_dir (the run folder of the token files) makes or checks one and refuses a wider folder, as on Unix. narrow_to_owner replaces a wider list on config.json. - Profile reads (user and folder profiles): a file another user can change is refused, as `mode & 022` or a foreign uid is on Unix. "Another user" is the owner, or a SID granted write, delete or ACL rights, other than our user, SYSTEM, Administrators or OWNER RIGHTS (they can change any file, as root can); deny and inherit-only entries grant nothing; no DACL grants everyone. The diagnostic names the SID and gives the icacls fix. Not in this landing: the Computer Use endpoint check (cua_v2, with its socket), router routes (the router landing) and the remote-floor file identity checks. Behavior tests (tests/windows_daemon.rs; green on the Windows Server 2022 VM): after `acpmux daemon start`, config.json, daemon.log, run\, run\localapp.token and run\peer.token are owner-only (the SDK's owner-only check); `acpmux harness add` writes an owner-only profile that `harness list` loads, and after `icacls /grant Everyone:(M)` the list refuses it with "another user (S-1-1-0) can change this file" and the fix. * acpmux: Windows owner-only review fixes (cx-ncc.54) - daemon.log is opened shared for read, write and delete, as std opens are: a running daemon holds it as stdout and stderr, and a second start (two clients at once) must still open it; with read-only sharing it failed with a sharing violation. - daemon.log must be the file itself, not a link: the access list checks and the narrowing go by path. - write_atomic removes a temporary file a crashed process left under a reused pid, then creates it again (CREATE_NEW refused it). Behavior test: two acpmux daemon start at once on a new home both succeed and name the same daemon (green on the Windows VM). * acpmux: the Windows narrow_to_owner body moves to owner_only.rs, so daemon.rs does not grow (cx-ncc.54) daemon.rs is over the Rust god-file budget on feat-cmux-next (not in the baseline), and the CI god-file check fails any growth. The Windows narrow_to_owner (an existing file or folder that is not owner-only gets the owner-only access list; a failure is logged) is now owner_only::narrow, imported under the old name. No behavior change. Base reds: exact base 7b86415e2d82 (cmux-tui full run 38529816383). The gate excludes a red job only when that run has the same job red with the same error lines; expected from the earlier base 12b1e29b82d9 (run 38357900702): "valgrind-leak-check (startup)" and "valgrind-leak-check" ("cmux_tui-f9329b8abfb86495 does not contain exact test config::tests::ghostty_config_files::load_uses_file_ghostty_defaults_without_invoking_external_resolver"; valgrind 0 errors). This stack changes only cmux-tui/crates/acpmux. The first commit of this landing is the Windows start-race fix for landings 2/3 (2f063f889c, 1fdb2a766b). Linux tests (chief decision 2026-10-14, cx-f4thx): this landing changes no Linux-compiled line (every hunk is cfg(windows) code or under it). Its gate accepts a red "test (linux)" only when the only failing test is router_lifetime::a_kept_agent_keeps_its_router_and_the_next_daemon_adopts_it, a feat-cmux-next flake ("agent response channel dropped" on the first prompt; Freestyle loops: 4/120 on aebcd4572fc6, 2/40 on this stack; its cause, a double host adoption, is fixed by cx-f4thx 7b86415e2d82). darwin, windows, the Linux build and clippy must be green. * acpmux: red test, a direct agent's moved-out helper outlives the model probe and a kill (cx-n3uid) Behavior test at the daemon socket (real acpmux binary, agent hosts off): the fake harness starts a setsid helper on session/new. _acpmux/models {refresh:true} waits for the model probes; every probe helper must be gone within 10 s. A direct session agent stopped with _acpmux/kill must take its helper too. ChildAgent::kill/terminate end the harness with killpg only, so both helpers run on with ppid 1. * acpmux: ending a direct agent ends what its harness moved out of its group (cx-n3uid) The model probe (probe_one, at each daemon start, config reload and models --refresh) and a direct session agent (agent hosts off) end the harness through ChildAgent::kill/terminate: killpg only. A helper the harness moved into its own session (setsid, Node detached:true) missed the group signal and ran on with ppid 1. As the pool does for a SIGKILLed host (cx-7gs9r, terminate_unadoptable): take the processes under the harness by pid and start time (agent_host::tree::descendants) while the harness is not reaped, signal the group, then SIGKILL the ones still running (kill_still_running). Both ps reads run off the runtime. Unix only. harness_helpers.rs: red before (both helpers ran on after 10 s), green after (rbx). * acpmux: review follow-ups, name what the direct-agent tree end does not reach; the helper test cleans up on failure (cx-n3uid) * acpmux: red test: with nothing picked a new chat starts on the harness's own config (cx-uq9xi) Codex's config.toml model and model_reasoning_effort, and Claude Code's settings.json model (an alias resolved to the catalog id), come before the catalog default; the person's pick still wins; a config that does not parse, or names a model the catalog does not list, falls back to the catalog. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * acpmux: a new chat with nothing picked starts on the harness's own config (cx-uq9xi) Leo 2026-10-14: the composer's starting model and effort are the last pick, else what the harness's own config chooses, else the catalog default. start_defaults now reads Codex's config.toml (`model`, `model_reasoning_effort`, the active `[profiles.<profile>]` first) and Claude Code's settings.json `model` (harness_config.rs), between the saved pick and the catalog. A config model counts only when the catalog lists it (an alias names its id) and a config effort only when it fits the running model; a file that is missing or does not parse chooses nothing. `_acpmux/harnesses` reports the new source as "harness". The start_defaults test homes give each fake its own config folder, so the machine's ~/.codex and ~/.claude never leak in. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * CmuxNext: chrome fonts are nil-checked; a nil font no longer aborts keycap drawing (no bead) nxtip3-v1 (772b6ea30a5b) aborted at 01:42 in PaletteKeycapsView.capWidth: NSString.size(withAttributes:) -> CoreText TAttributes::ApplyFont -> -[NSDictionary initWithDictionary:copyItems:] "attempt to insert nil object from objects[0]". Cause: Typography.shortcut (NSFont.monospacedSystemFont(ofSize:weight:), imported non-optional) returned nil on the main thread. Swift kept the null NSFont in [.font: ...]; CoreText found no font, copied the attributes to apply its default, and the copy hit the nil. Reproduced on cmux-lawrence-2 (macOS 27.0.1): a nil font in the attributes gives the same exception and frames; a nil foreground color does not abort. Ruled out: the size (NaN, 0, negative and infinite sizes all return a font there), the weight, and a call off the main thread (the faulting thread is the main queue). The laptop log has no fontd or CoreText error and no jetsam before the crash; why AppKit returned nil is not visible. Fix: CheckedFont tests each AppKit font for null (an optional bit cast in a non-inlined function, which -O does not fold) and falls back to the system font, then CoreText Helvetica, then the last font that resolved, with a fault log. Every Typography font (body, caption, header, search, shortcut, title, subtitle) goes through it, so the palette keycaps, the which-key overlay and every other Typography caller measure and draw with a non-null font; ShortcutHintChipView and the braille spinner font too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(cmux-next): one shared native popup row; page menus and the Extensions menu draw their rows with it (cx-jpi3o, REUSE.md slice 2) PopupRowView (CmuxNextDesign/Overlay) owns what every native popup row shares: the leading column, title and subtitle, a trailing view, the gray highlight in the popup row radius, press fill, gray focus ring, hover tracking, release-inside click, Return/Enter/Space and the accessibility press. WebPopupRows stacks PopupRowViews (the page keeps the one highlight); ExtensionMenuRowView is a PopupRowView with the system menu font and colors. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * free tier part 2: settings sources and exports equal the tip (landed in part 1, 7bd91dc3129c) (cx-ds09i) * chore(next): PR autofix at 73b393e337d9 - regenerated schemas/defaults/cmux-next.json Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38542400367 * chore(app-platform): sync the AppPlatform scopes copy after the tip merge (cx-ebm.60.1) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Channels view: connect with no credential when the page's origin already authorized the person A plain-browser Channels page whose daemon endpoint is its own origin first asks `GET /auth/session`. When that server answers {"authorized": true} (a relay that identified the person, for example by a private-network identity, and attaches the daemon credential upstream itself), the page connects with the new `{ origin: true }` auth: no preamble, no form, and the browser never holds the credential. Any other answer (a 404 from a daemon that serves the page itself included) shows the credential form as before; a refused origin connection falls back to the form too. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Channels view: origin auth comments (review) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * acpmux: behavior test, a new chat starts in full access; the person's switch back is saved; every chat gets the cmux MCP server (red) (cx-wx93i) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * acpmux: new chats start in the harness's full-access mode; the person can switch back and the pick is saved; every agent chat gets the cmux MCP server (cx-wx93i) Lawrence 2026-10-14: "give every agent chat the cmux MCP tools by default, but by default all chats should be in skip permission mode, that user can switch back". - hub/start_mode.rs: once the harness is up, acpmux sets the start mode with session/set_mode (soft, like the start model): the person's saved pick (config.json defaults.<profile>.mode), else acpmux config.json defaultPermissionMode, else the cmux setting agents.defaultPermissionMode (fullAccess | standard | ask), else full access: Claude Code bypassPermissions, the Codex bridge agent-full-access (approval never + danger-full-access), or a harness's yolo/full-access mode. Not for Web (remote-origin) chats, presets, folder profiles, adopted chats, or a profile that pins its mode in argv. - A mode pick from the person's app pane (session/set_mode or the mode config option) is saved; Plan is a toggle and is not saved; a pick equal to what the setting gives removes the saved mode. Only the person may clear a saved mode (_acpmux/defaults clear), as for a stored policy. - claude_stdio: offers bypassPermissions ("Full access") and launches Claude Code with --allow-dangerously-skip-permissions when it accepts it (not root, or IS_SANDBOX=1); remote chains strip the flag. - agent_tools: the cmux MCP server (cmux mcp serve) is on for every agent chat unless the settings file says mcp.enabled false; the settings file is now the app's cmux-next.json (user_settings.rs), not classic cmux.json. - cmux mcp serve: on when CMUX_AGENT_SESSION is set and mcp.enabled is not set; any other client still needs mcp.enabled true. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * review: popup row title end yields in a narrow row; 12 pt before a shortcut; a disabled row's check mark is quiet (cx-jpi3o) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * ci-guards: keep the step name "Run agent-chat tests" (cx-eczvt) Main sync merge 3bf71fdcda1e brought back main's "Run agent-chat unit tests"; feat-cmux-next renamed it after the unit-test deletion (cx-034r, cx-ys07v). test_ci_guard_workflow_structure and test_ci_change_areas now name the same step. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat(cmux-next): Page Info on the shared native popup host; its rows on the shared popup row (cx-x9o52, REUSE.md slice 3) PageInfoPanel is a NativePopupPanel: placement through PopupPlacement, the host's grow/shrink motion and dismiss rules (click outside with the omnibar button kept open, Escape, key loss, app inactive, window move/resize/close). The hand placement, PopupFade and the mouse-down reopen guard go. The card no longer draws its own shadow band (PopupHostView draws the one popup shadow). PageInfoRowView is a PopupRowView. NativePopupPanel joins the child-window allow list (the bookmark bubble tripped it in DEBUG). PageInfoMotionTests (a unit test of PopupFade on PageInfoPanel) is deleted under the no-unit-test rule; the live check covers the bubble. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(cmux-next): a new bookmark's name follows the page title that arrives after the star (bookmark bubble) The star saves the bookmark at once, often before the page has a title, so the bubble showed an empty name. While the bubble shows, the page title (observed) fills the name until the user edits it; close saves it as before. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * test: bookmark bubble live check covers the late page title, Page Info on the shared host (captures) and a real click on the star (--real-click) (cx-x9o52) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * review: Page Info rows keep their inset before the accessory (cx-x9o52) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * cmux-tui: the documented customize template installs as is in a real daemon (cx-swovq.1) Behavior test through the daemon socket: the docs/cmux-next/sidebar-customization folder, copied unchanged into the customize folder, is listed installed, enabled and sandboxed with its workspace:read grant. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * CmuxNext: Codex-like status icons by default, plus static status glyphs (#20410) * test(cmux-next): static status glyphs are apart by shape, crisp, still and theme-colored Red: there is no static status set and no ui.status-glyphs contact sheet yet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * CmuxNext: static status glyphs for the Static status mode Leo 2026-10-14: six custom static glyphs for op-next-motion's Static status mode (Reduce Motion): a hollow ring (idle), a half-filled ring (working), an empty speech bubble (waiting on you), a shield (needs permission or a sign-in), a check disc (done) and a ! diamond (error). Told apart by shape alone at 10 pt, tinted by their theme role, never animated. One source, schemas/status-glyphs/static-status.json: a 20-unit master (10 pt at 2x) and 10 px pixel art for 1x. gen-status-glyphs.py writes the Swift StaticStatusGlyph (CGPaths) and the web statusGlyphs.generated.ts (SVG paths); --check runs in bun run check. StatusMark.vector draws a glyph, StatusIconSet.still (Static) maps every state to them, and StaticStatusGlyph(state)?.plan is the hook for the Static setting. The gallery sheet ui.status-glyphs shows each live, in a row, and its 1x and 2x pixels, plain and on a wallpaper. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(cmux-next): status glyphs at 2x probe their straight edges A share-of-soft-pixels cap cannot tell a curve from blur (a ring half a pixel off reads the same), and the idle ring's 63% tripped it. At 2x the test now probes pixels on each glyph's straight edges, which are whole only when the drawing sits on the pixel grid; half a pixel off, every glyph leaves some half covered. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * CmuxNext: the Static set keeps a known-progress ring Review: StatusIconSet.still drew the working glyph for an agent that reports progress, dropping how far along it is. That ring never moves, so the Static set keeps it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test: Codex-like status set draws grey work, blue done, red error Red: StatusIconSet has no codex case, there is no spinner or unread tint, and the web sheet has no codex glyphs (shieldLine, info, dot). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat: Codex-like status icon set A Debug set for the status indicators that follows Codex's sidebar: Lawrence's shared spinner re-tinted to the foreground at 66% (a still ring under Reduce Motion or Static), Codex's blue (#3982F5) done dot, muted line bubble and shield for waiting, and a red line i for error. The schema gains a codex set that the generator emits for the web copy, and the gallery sheet gains codex variants. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test: Codex-like still loader stays a stopped arc Red: with motion off, the Codex-like set turned every arc into the still work ring, so a busy page or command loader read as agent work. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: Codex-like still ring only for agent work Only working without progress becomes the still ring when nothing animates; a busy loader keeps its stopped arc. The glyph generator now checks that every set picks a glyph for every state from its own set or the static set. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: Codex blue as a theme token; document the idle/info 2x floor Codex's blue moves to --cmux-status-unread in webviews/src/theme, so the generated glyph table holds no blue literal (check-system-blue). At 2x the still work ring and the error ring differ only by the i, 16 whole pixels, and they differ in color too; the test says so. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test: the Codex-like status icons are the default set Red: the default is still symbols. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat: Codex-like status icons are the default Leo 2026-10-14, a team decision: the grey spinner (a still ring under Reduce Motion), Codex's blue done dot, muted line glyphs and a red line i for errors, for everyone. Symbols, Static and the other sets stay as Debug alternates. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: Codex blue as a theme constant, not a page stylesheet color A literal color in a page stylesheet trips the theme-colors ratchet, so the blue moves to STATUS_UNREAD in webviews/src/theme/statusColors.ts and the generator writes it as the fallback of --cmux-status-unread. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore(next): PR autofix at a8608cf74601 - vp fmt webviews/src/agent-session/acpmux/modelPickerLayout.ts Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38521104749 * test: the status glyph and count badge center on the row's middle, one line or two Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: the status glyph centers on the row's middle beside the badge; a 6 pt done dot The glyph sat on the title's capitals, so on a two-line row it rode above the count badge (Leo 2026-10-14: "why is it superscript?"). It now centers on the line the badge and the other trailing marks share. The Codex-like done dot grows from 4 pt to 6 pt ("too tiny"). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test: a status glyph at 3x or 5x draws the master, not the 1x pixel art blown up Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: only a 10 px status glyph takes the 1x pixel art; 3x and 5x draw the master Review on #20410: the odd-multiple-of-10 rule sent 30 and 50 px glyphs to the 10-unit art, blown up in coarse blocks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: cmux-autofix[bot] <cmux-autofix[bot]@users.noreply.github.com> * cmux-next: pin CEF cef-154.0.28-cmux.25 (cmux.24 + WebAuthn hybrid fix with a PIN key attached; fork API 23) (cx-d0d.97) * cmux-next: remote browser host linked against CEF cmux.25 (step beeef9df6b98) (cx-d0d.97) * passkeys-roaming-e2e: --typing smoke with trusted key events (cx-d0d.97) * passkeys-matrix-e2e: a timed-out addVirtualAuthenticator reply counts as sent (the socket deadline is now 6 s) (cx-d0d.97) * chrome-promos-live: ignore Chromium's status bubble (<= 30 pt at the page window's bottom-left), logged; any other new window still fails (cx-d0d.97) * passkeys matrix + promo check review fixes: unconfirmed authenticator rows that pass without one are NOTE; promo count uses only new windows (cx-d0d.97) * CmuxNext: no gray ring trails a split (#20500) * CmuxNext: test that a split's focus ring lands on the new pane in the apply that mounts it (red) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * CmuxNext: no gray ring trails a split The split's daemon tree mounted the new pane and the layout view drew the focus ring around the old pane at its new frame; the focus coordinator landed focus on the new pane in the same apply, but the view mirrored it only on its observation's next turn. Sync the view again after the topology so the frame rings the pane focus landed on. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * CmuxNext: one line for the split focus sync (app size cap) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * CmuxNext: split focus ring test compiles (closure, not a key path, in #expect) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore(next): PR autofix at 44de1da3d855 - regenerated schemas/defaults/cmux-next.json Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38532789052 * chore(next): PR autofix at c7d76dbf2fb3 - regenerated schemas/defaults/cmux-next.json Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38541548095 --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: cmux-autofix[bot] <cmux-autofix[bot]@users.noreply.github.com> * cmux-next: tabs take the max width while the strip has room Lawrence 2026-10-14 asked for max width: "default widths for new tabs still have the same max width and try to grow as much as possible (ofc it can shrink tho)". This reverses the fit-to-title rule from 7f9fc1ed53f2 (merged into feat-cmux-next with 3ef63bc02144; that titlebar commit carries Lawrence's name as author but was hq-1d's worker change). Every unpinned tab takes the max width (Metrics.tabMaxWidth) while the strip has room; a crowded strip shrinks all tabs evenly down to the minimum, then scrolls. The tabs.minFitTabWidth tunable, TabLayoutItem.naturalWidth, TabStripMetrics.naturalTabWidth and the title measurement in TabStripView+Layout go with it. That measurement ran NSString.size for every tab title on every layoutItems call, on the main thread, also during strip springs; it no longer runs. Separators, the traffic-light center line, the + position and the reserved close-button room are unchanged. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * cmux-next: debug.pane_chrome reports each tab's slot tab_slots ([x, width] per tab in strip content points) and tab_available, so a proof can read the tab width rule without pixels. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * free tier: a Keychain error never mints a new App Attest key; no key-id read where App Attest cannot work (cx-5bxp7 P3-A, P3-B) AttestKeyStore load/save/delete throw on a store error (load: nil only for errSecItemNotFound). The provider answers failed when the key id cannot be read or saved, so it never generates or attests a new key then (a new key spends the device's monthly grant), and it saves a new key id before attesting it. The register line skips the Keychain read when App Attest is not supported (no prompt in an ad-hoc DEV build). * acpmux start mode: review fixes (cx-wx93i) - Settings file read as JSONC like the app (comments, trailing commas); a file acpmux cannot read or parse, or an unknown value, gives the harness's own mode, never full access. Classic cmux.json only when cmux-next.json does not exist. The setting is resolved before the config write lock. - A remote chain never starts Claude in bypassPermissions (a transfer keeps the mode): the spawn mode and args fall back to default. - A handoff target starts in full access only from a full-access source and never with narrower. - A profile with its own skip flag keeps its mode on respawn; config reload picks up defaultPermissionMode; acpmux reads mcp.enabled only nested, as the CLI does. - Tests: the fake Claude refuses bypassPermissions without the launch flag; the settings-file test is its own binary (it sets CMUX_NEXT_CONFIG_FILE) and covers JSONC, no key, an unparseable file and an unknown value. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * cmux-next: Ctrl and Option holds show their shortcut hints too; hint chips are Liquid Glass in the theme's tint (cx-w9f3s) Lawrence 2026-10-14: "we need cmd hold tab to work for hold ctrl as well, maybe option if there are relevant shortcuts, we also need it to be liquid glassy". - A hold arms on any set of Cmd, Ctrl and Option (with or without Shift), not only bare Cmd or Ctrl. The overlay shows each target's binding from the resolved table (keybindings.json and cmux.json overrides included) whose modifiers contain the held set; a hold with no matching binding shows no chip. Same 300 ms delay, key-down suppression and placement. - ShortcutHintChipView: a full Liquid Glass capsule (GlassPanelView -> NSGlassEffectView) tinted with the theme's glass tint, text in the theme's primary text color. macOS 14/15: the same panel's blur, tint and hairline. Reduce Transparency: the theme's opaque popup surface, a device-pixel hairline and the soft shadow. - debug.shortcut_hints takes opt, shift and +-joined sets (ctrl+opt). CmuxNextApp line count unchanged (113450). * cmux-next: hold hints review fixes: only Cmd/Ctrl chords get a chip, a click suppresses, stronger chip tint (cx-w9f3s) Review of d77c9ec3f078 (P2s): a chip only for bindings KeyRouter runs (KeyRouter.isChord: a pure-Option binding types a character); a mouse-down while a modifier is held hides and suppresses the hints like a key-down (Option-click / Option-drag in a terminal); the chip's glass tint is the theme tint at 1.5x alpha so 10 pt text keeps its contrast over bright content. P3s: no double Borders.color, no continuous curve against a circular shadow path, debug release only alone. plans/cmux-next/keybindings.md describes the Cmd/Ctrl/Option holds and the glass chip. CmuxNextApp line count unchanged (113450). * review: Page Info keeps its side on a new page; any NativePopupPanel passes the child-window policy; the bookmark name follows only the bookmarked URL's title; live check presses the star once (cx-x9o52) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * free tier e2e runner: never kill; the app quits through its control socket (action.run quitEndSessions, peer-checked), the daemon by acpmux daemon shutdown (cx-ds09i T1/T2) * New Tab: never block launch on a slow WebKit setup (#20484) * test: launch prewarm does not wait for a stalled WebKit NewTabSparePool.makeSpare becomes a seam (no behavior change) so the test puts a WebKit that blocks for 2 s in its place. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: the New Tab spare never makes a web view before WebKit's setup answers Launch no longer makes the spare. prewarm() asks the sandbox broker off the main thread (WebKitSetupGate, 2 s timeout); the first spare follows the first window's first frame once it answered, and a spare that held the main thread over 1 s marks WebKit slow for the run. A wedged sandboxd (cua-2: WKWebView load blocked >10 s in sandbox_extension_issue) gets no spare. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * backend: behavior test for a Chief brain on Durable Objects answering in Cloud conversations (red) The owner turns the chief's brain on over HTTP; a person writes in the chief's DM and in a channel over POST /v1/ops; the chief answers as itself (typing, then the message, on a member's socket), in the channel message's thread, with a run reference whose run and steps only members read. Fails before the brain exists (the routes answer 404). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * backend: ChiefBrainDO, a Chief that answers in Cloud conversations on pi-durable with OptChat memory One ChiefBrainDO per chief (agent id): the optchat-lab impl/pi-durable turn loop ported into the API Worker (agents SDK PiHarness, pi-durable, the OptChat Rust core as wasm over DO SQLite, background compactor, one fresh pi session per turn). - MuxDO forwards each committed mux.wake (DM, mention, reply, wake_policy all) to the brain where CHIEF_BRAIN_ENABLED is 1 (staging, development; not production). - The brain pulls the conversation's new messages as the chief, runs one turn per conversation batch, and posts one message.send as the chief (in a channel, in the thread of the message it answers) with a work part naming the run; NO_REPLY posts nothing; then mux.ack. A refused post (loop guard agent_rate) retries under a new key; no answer retries under the same key. - Realtime: ConversationDO.agentFrame sends the chief's typing (same gate as a socket) and conversation-run-changed frames (TRAJECTORIES Run/Step JSON) to member sockets, never stored. - HTTP: GET/PUT /v1/chiefs/<agent>/brain (owner: enabled, model, role, personality, instructions), GET /v1/chiefs/<agent>/runs[?conversation=] and /runs/<run> (members only). - Model: fake by default; Workers AI through the Worker's AI binding where CHIEF_BRAIN_MODEL names one (staging: @cf/moonshotai/kimi-k2.7-code). The team subrouter is tailnet-only. - DO migration v15 (ChiefBrainDO). firstName moves to its own file (ConversationDO size limit). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * backend: Chief brain review fixes: one memory per conversation, live-chief and placement checks, bounded turns Review (subagent, REVISE) findings fixed: - P0: one OptChat memory for every conversation could carry one conversation's messages into another's reply and run steps. Now one brain per conversation (ChiefBrainDO name <agent>/<conversation>); the chief's settings object (name <agent>) holds the owner's settings. - P1: every turn and post asks the settings object: enabled, the chief record live (archived chiefs stop at once) and not placed on a paired server, under a daily turn limit (CHIEF_BRAIN_DAILY_TURNS, default 300). MuxDO forwards only for brain cloud. - P1: the reply answers the newest woken message (rows carry woke), not the newest message. - P1: the compactor wait is bounded (60 s, then the view as it is); a turn stops after 10 min. - P2: post retries reschedule through the job outcome; no concurrent post of one run; a drain that ends re-checks the queue; the test fires the brain's alarm. - P3: run reads need ?conversation= and check membership before touching a brain; NO_REPLY match ignores punctuation and case; replies are clipped under the text limit. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * backend: Chief brain: a transient owner-record error retries later instead of skipping; a failing drain backs off Re-review (APPROVE) follow-ups 1 and 2: owner.unreachable leaves the woken messages queued and schedules a drain job; a drain that threw schedules its next try instead of looping at once. Reply helpers move to brain-text.ts (size limit). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(cmux-next): macOS 27 base reds: CLI parity person-only refusal, cancelled load keeps the new address (#20373) * test(cmux-next): a New Tab load that cancels a loading page shows no preview of it (red) Replays WebKit's callbacks in the order the macOS 27 lane hit (NewTabHoverPreviewTests:50 on #20342): the New Tab address arrives, then the cancellation of the load it replaced puts the old address back. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cmux-next): a cancelled load keeps the address of the load that replaced it When a new load replaced one still provisional, WebKit reports the new address first (the URL KVO, or the old load's late start reading webView.url) and then the old load's cancellation. The state machine reverted the address to the last committed one on that cancellation, so until the new load started the tab showed the old address: the hover card pictured the old page over the New Tab page (NewTabHoverPreviewTests:50 on the macOS 27 lane) and the omnibar flickered back. A cancellation whose failing URL is not the address shown now keeps it, and never restores the old error page. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(cmux-next): CLI parity expects the person-only refusal browserProfile.delete is person-only since 596dd7a (cx-dwg.10): it keeps its CLI verb but the control socket refuses every run. CLISurfaceParityTests:48 still expected the run to reach its handler. A person-only action now has to answer exactly the person-only refusal (code unavailable, the personOnly reason) and run nothing; every other CLI action still has to run its own handler. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cmux-next): keep a replaced load's address by its start, not its failing URL Review: comparing the cancellation's failing URL with the address shown broke CEF, where the start carries the URL cmux asked for and the failing URL is Chromium's (after a redirect): a redirected load aborted as a download kept its address over the committed page. The address now stays only when it moved off the cancelled load's own start/redirect address, which in CEF it never does before commit. WebKit can also report an old load's start after a newer one was asked for, reading the newer address; the tab now tells the state machine which navigation it asked for last (`requested`), and the start of an older one is ignored, so its cancellation changes nothing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cmux-next): drop the requested-navigation rule; test the real order Re-review: the late-start order cannot revert in practice (the New Tab URL KVO arrives first while nothing is provisional and moves the committed address too), so the test half for it could not fail, and ignoring an older start could leave a real load untracked when the newer request is refused by policy. Removed both. The test now commits a page first, so the cancellation would put that page back on the base. A cancellation WebKit already moved back to the committed page is not a replacement, so a cancelled retry still shows its error page. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore(next): PR autofix at c26ac6910070 - regenerated schemas/defaults/cmux-next.json Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38530564433 * chore(next): PR autofix at b55536721932 - regenerated schemas/defaults/cmux-next.json Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38542307133 --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: cmux-autofix[bot] <cmux-autofix[bot]@users.noreply.github.com> * optchat-chief: Chiefs react to other Chiefs, with a per-thread loop guard In local side conversations another Chief's message now wakes a Chief (never its own; agents that are not Chiefs still never do). The loop guard is computed from the conversation itself, so every host and a page agree with no shared state: - cmux_chief::rules::chief_streak: consecutive Chief messages at a thread's tail (or the top level) since a person wrote; at CHIEF_TURN_BUDGET (6) no Chief answers a Chief there until a person posts. - cmux_chief::rules::owner_agent_streak mirrors the owner's own guard (MAX_AGENT_TURNS agent messages per conversation): a Chief stays quiet instead of running a turn whose reply the owner would refuse. That guard is lower than 6 today, so it is the one that stops Chiefs first. - Both are taken at the newest message read, and a pause is logged ("Chiefs paused ..."). Side messages now carry the author's name in their label on the local source, the Channels prompt says acks need nothing (NO_REPLY), and only a person answers a pending approval. WakeRule replaces wakes_as' loose arguments; wakes() is unchanged. Test: channels_daemon.rs two_chiefs_wake_each_other_stop_at_the_budget_and _a_person_resumes_them, two real brains on a real headless daemon. Red with Chief wakes off (the Chiefs never reach the budget), green with them (twice). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * optchat-chief: loop guard review fixes - the thread streak follows the thread a reply goes into (a top-level message's own thread), and retracted Chief messages still count; - the owner-streak mirror stops only at a known person's text, skips authors who left, and resets at an answered question, as the owner does; - side labels say whether the author is a person, a Chief or an agent. Not done (P2 test gap): a behavior case where the 6-message thread budget, not the owner's 4-per-conversation guard, stops the Chiefs. Any person's text that resets the owner's streak also wakes the Chiefs in its own thread, so with the owner guard as it is the thread budget cannot bind first. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * cmux-next groups: a right-click on a group header or tab group chip opens the group editor Lawrence 2026-10-14: "im talking about the rename + color things ... looks like the image in chrome, we had it at some point". The editor bubble (name field, color dots, group rows; cx-rcby, 3ca7be38252e) is still there, but #19019 (31db8ce85faf) pointed the header's more button and its right-click at the plain menu. #20442 put the more button back on the editor; this puts the right-click back too, and does the same for a tab group chip, whose right-click showed the app's menu (the editor opened only on a press and hold). The full menu stays one row away (More Group Actions… in the sidebar editor) and on Option-right-click of a tab group chip. scripts/cmux-next/group-editor-live.py proves it with real right-clicks (cua-driver): the editor opens with its name field, color dots and rows, a typed name with Return renames the group, Escape closes it. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * cmux-tui: socket test for a workspace move during New Workspace losing tab identity (cx-95uaf) The app's New Workspace: create-workspace, then the first terminal with a reserved terminal id, while the app places the listed workspace with move-workspace. A debug-only gate (CMUX_TUI_TEST_CREATE_BIND_GATE, scoped to one workspace key) holds that create between its surface insert and its pane binding until the move is done. Fails on this commit: the create reports 'tab slot N has no durable identity' and later closes fail the same way. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * cmux-tui: a created tab keeps its durable identity until it is placed (cx-95uaf) State::rebuild_resource_indexes rebuilt tab identity only from the tabs the workspace/screen walk reached. A created terminal is inserted (its identity registered) before it is bound to a pane, and a move-workspace (or any other index rebuild) in that window dropped the identity. The binding then placed a slot with no durable identity, the create failed ('tab slot N has no durable identity'), and every later full projection (close-workspace too) failed the same way. On the app this was the second New Workspace: the sidebar places the listed workspace while its first terminal is still being created. - Placing a live surface in a pane registers the identity it was created with when the topology has none (State::register_placed_tab_identity) at every terminal placement site: hosted bind, local create, effect tabs and panes. - The rebuild carries the identity of a live surface that is in no pane. - A placed slot whose record is missing takes its live surface's identity (State::tab_identity_of) in the full rebuild and in the scoped reindex, so one lost record cannot wedge later mutations. A slot with neither still fails loudly. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Channels view in the app: the page may play video from the daemon's loopback listener (PageCSP media-src) The Channels page plays a video attachment from the daemon's own GET /attachments/<token> (ws-attachments-v1). The app's page scheme sent no media-src, so the web view blocked it. PageCSP gains media sources; the home-channels descriptor allows http://127.0.0.1:* (the daemon listener). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * group-editor-live: find the group by its member row, the tab chip by the strip, the rename by the reopened editor Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * group-editor-live: real window-server right-click first, the in-app event path as fallback; strip rects are arrays Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * cmux-next tab groups: the group editor's More row shows the group's full menu under the chip (review P2) A right-click on a tab group chip now opens the editor, whose rows are New Tab, Ungroup, Close, Move to New Window and Save. The rest of the group's menu (icon, moves to a split, column or workspace, collapse, configured rows) stays one row away: More (the strip's existing paneToolbar.more string, 21 locales) pops the same menu under the chip, as the sidebar editor's More Group Actions row does. Option-right-click still shows it directly. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * cmux NEXT: Ghostty unfocused-split-opacity and unfocused-split-fill dim unfocused panes (cx-6so.35) (#20533) * test(cmux-next): Ghostty unfocused-split keys dim unfocused panes (red, cx-6so.35) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * cmux-next: honor Ghostty unfocused-split-opacity and unfocused-split-fill (cx-6so.35) The Ghostty config's unfocused-split-opacity dims every unfocused pane by 1 - value while a screen has more than one pane, over the unfocused-split-fill color (the theme background when unset), as Ghostty.app draws over an unfocused split. cmux loads unfocused-split-opacity = 1 before the user's files, so nothing dims unless the config sets it. Both keys leave GhosttyKeySupport.unsupported, so Settings' diagnostics stop listing them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore(next): PR autofix at 918e7d3d8115 - regenerated schemas/defaults/cmux-next.json Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38541840504 --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: cmux-autofix[bot] <cmux-autofix[bot]@users.noreply.github.com> * cmux-tui: behavior test, a large legacy registry gets no full VACUUM while its owner serves (cx-4bd8m) Red commit: drives the owner binary on a registry in the shape a build without journal maintenance leaves (auto_vacuum off, no marker). Adds a debug-only CMUX_TUI_TEST_JOURNAL_MAINTENANCE_INTERVAL_MS override. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * ci(nightly): signed app downloadable before the notarization wait (#20551) * test(nightly): require a signed app artifact before the notarization wait Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci(nightly): upload the signed app before the notarization wait Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore(next): PR autofix at 3dd82a78f6aa - regenerated schemas/defaults/cmux-next.json Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38546488020 * ci(nightly): signed-app upload never blocks notarization; only the import pause skips it Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: cmux-autofix[bot] <cmux-autofix[bot]@users.noreply.github.com> * docs: gh-merge-green is optional on feat-cmux-next (#20567) A plain gh pr merge on the exact head is fine under the branch's rules; the batch queue's own --land still uses the helper. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * cmux-tui: no full VACUUM of a large legacy registry while its owner serves (cx-4bd8m) Austin's cmux NEXT registry grew to 10.7 GB in 8.5 h under a build without journal maintenance (auto_vacuum off, 4.47M journal rows). The maintenance worker's first step converts such a registry with PRAGMA auto_vacuum= INCREMENTAL; VACUUM; while it holds the registry: on that file every client of the owner would read "not connected" for minutes after the next update. Convert only while live data is at most 64 MiB. Above it the conversion is deferred (one diagnostic per owner); sealing still runs and deletes archived rows, and SQLite reuses their pages, so the file stops growing once sealing keeps up. It does not shrink: sealed segments stay in the registry, so giving the free pages back needs a compaction that does not hold the registry (follow-up bead). Debug-only overrides for the interval and the bound keep the behavior test small. Red/green: legacy_registry_maintenance. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * cmux-next: a local merge commit reuses the fetched same-tree acpmux (#20534) * test: a local merge commit reuses the fetched same-tree acpmux (red) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: a local merge commit reuses the fetched same-tree acpmux reload.sh on a developer Mac stopped with "no cached acpmux" for any commit no workflow published (a local integration of feat-cmux-next and PRs), even though the tree fetch had just put that tree's checksum-verified acpmux in place. build-acpmux.sh now seeds its commit cache from it when it has every requested architecture. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore(next): PR autofix at 7be0d24457e0 - regenerated schemas/defaults/cmux-next.json Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38542356066 --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: cmux-autofix[bot] <cmux-autofix[bot]@users.noreply.github.com> * webviews: popups draw one hairline, not two (#20461) * webviews: test that every popup draws one hairline edge Red: --acpmux-popup-elevation stacks a composer-edge hairline on the one already in --ui-popup-shadow. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * webviews: popups draw one hairline, not two --acpmux-popup-elevation stacked a 0.5px composer-edge hairline on the hairline already in --ui-popup-shadow. It now is the shared popup shadow, so every menu and popover has one edge. Increase Contrast colors that one edge in the popup's ink, which the composer-edge hairline did before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore(next): PR autofix at 1cc661608ff2 - vp fmt webviews/src/agent-session/acpmux/modelPickerLayout.ts Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38520503432 * webviews: test that popups draw no border over the hairline and clear it under borders none Red: the pages' .ui-popup and the chat find bar draw a border over the --ui-popup-shadow hairline, and appearance.borders none leaves the hairline drawn. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * webviews: one rim on page popups and the find bar; borders none clears it The pages' .ui-popup drew a 1px border over the --ui-popup-shadow hairline; it now draws no border. The chat find bar keeps its border (its focus cue) and casts --ui-popup-drop, the shadow without the hairline. appearance.borders none sets --ui-popup-edge transparent. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * webviews: format modelPickerLayout.ts (base fmt red) Keeps cmux-autofix's vp fmt of the base file, which the base merge replaced with the unformatted copy; react-apps-check fails on it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * webviews: the Channels palette draws one rim; test follows the summary card Red after the base merge: the new Channels palette (.lg-palette, ledger.css) drew a 1px border over the --ui-popup-shadow hairline, and the summary popover became .acpmux-summary-card. The palette now draws no border. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore(next): PR autofix at 54dd59d45f3d - regenerated schemas/defaults/cmux-next.json Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38543983469 --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: cmux-autofix[bot] <cmux-autofix[bot]@users.noreply.github.com> * cmux-next: name the owner of ControlWorkspaceInfoCache's publish hop (clears the concurrency red) (#20485) * fix: clear two feat-cmux-next check reds tree-publish-v2's stub uploader takes --conflict-exit-code, which the tree publisher now passes (af8b68ebc8f9e). PaneAnimationsSetting carries the namespace-type justification its ratcheted sibling settings have. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: keep PaneAnimationsSetting internal to CmuxNextSettings Nothing outside the module uses it, so it needs no namespace-type allow. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore(next): PR autofix at c2bdb982abed - regenerated schemas/defaults/cmux-next.json Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38530638157 * fix: name the owner of ControlWorkspaceInfoCache's publish hop check-concurrency flags the unowned Task d0a62bef9b28c added; it is a one-shot main-actor hop that holds the cache weakly. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore(next): PR autofix at 7cf07e3731b0 - regenerated schemas/defaults/cmux-next.json Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38544346314 --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: cmux-autofix[bot] <cmux-autofix[bot]@users.noreply.github.com> * CmuxNext: one-line sidebar rows by default; notification text in the hover card (#20483) * test: a notified compact row stays one line; its text reads in the hover card Leo 2026-10-14: "why is it even 2 lines in the first place?" Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: compact sidebar rows are one line by default; the notification text moves to the hover card sidebar.workspaceRow.notification is now off by default (Leo 2026-10-14). #19862 turned it on for classic parity; the setting stays as an opt-in. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore: regenerate the settings schema hash for the notification default Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore: regenerate the settings schema hash on the merged base Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore: take base's settings exports after the base merge (regenerated next) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore: regenerate the settings exports on the merged base Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore: refresh the defaults snapshot on the merged base Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs: the hover card template lists the notification fact; comments say where the text shows Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Lawrence Chen <54008264+lawrencecchen@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: cmux-autofix[bot] <cmux-autofix[bot]@users.noreply.github.com> Co-authored-by: safe-push <safe-push@cmux.local>
teamleaderleo
added a commit
that referenced
this pull request
Oct 14, 2026
…nce, failed with why, lost) (#20362) * test(acpmux): every session summary carries its lane (cx-v9k2f) Working since its turn started, input, idle since its last turn ended, failed with the error text (a restart's outcome_unknown included), lost; peer sessions too. Red: summaries have no lane yet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(acpmux): every session summary carries its lane (cx-v9k2f) lane = {state, since, error}, decided once next to indicator from the summary's own fields, for local and peer sessions (re-decided when a peer goes unreachable): working since its turn started, input, idle since its last turn ended, failed with that turn's error text, lost. A restart's outcome_unknown now records lastTurn, so that session reads failed with why, not idle. The restart test moves to its own file (hub_integration.rs was at its size cap). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(acpmux): review follow-ups for the session lane (cx-v9k2f) Waiting reads inputSince (when the session began waiting), so a draft save, a later record or a second ask no longer moves it. A session lost mid-turn is lost since it went, without the previous turn's error. outcome_unknown records lastTurn before its record goes out, as every turn end does, and lastTurn keeps detail. An idle session with turns but no lastTurn falls back to updatedAt. The schema documents lane and inputSince; the restart test module sits in order. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore(next): PR autofix at 5099ccd - cargo clippy --fix cmux-tui/crates/acpmux/src/hub/turns.rs - cargo clippy --fix cmux-tui/crates/acpmux/src/hub/views.rs Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38495693983 * acpmux: lastTurn keys live beside the lane (turns.rs does not grow) (cx-v9k2f) Adding `detail` wrapped the key list and grew hub/turns.rs to 1064 lines, which the god-file check refuses (1062 on base, over the 1000 limit). The list becomes views::LAST_TURN_KEYS, so turns.rs stays at 1062. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * cmux-next: the typeahead GUI gate in the repo (cx-wb5.78): typeahead-gate.sh runs split, newterm, split with a slow host, new-tab and cold new-tab proofs on the GUI host and fails on a lost key; typeahead-compare.py counts keys sent by terminal id; creation-hold-proof.py is superseded (named in the gate header) * acpmux: behavior test, a new chat starts in full access; the person's switch back is saved; every chat gets the cmux MCP server (red) (cx-wx93i) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * acpmux: new chats start in the harness's full-access mode; the person can switch back and the pick is saved; every agent chat gets the cmux MCP server (cx-wx93i) Lawrence 2026-10-14: "give every agent chat the cmux MCP tools by default, but by default all chats should be in skip permission mode, that user can switch back". - hub/start_mode.rs: once the harness is up, acpmux sets the start mode with session/set_mode (soft, like the start model): the person's saved pick (config.json defaults.<profile>.mode), else acpmux config.json defaultPermissionMode, else the cmux setting agents.defaultPermissionMode (fullAccess | standard | ask), else full access: Claude Code bypassPermissions, the Codex bridge agent-full-access (approval never + danger-full-access), or a harness's yolo/full-access mode. Not for Web (remote-origin) chats, presets, folder profiles, adopted chats, or a profile that pins its mode in argv. - A mode pick from the person's app pane (session/set_mode or the mode config option) is saved; Plan is a toggle and is not saved; a pick equal to what the setting gives removes the saved mode. Only the person may clear a saved mode (_acpmux/defaults clear), as for a stored policy. - claude_stdio: offers bypassPermissions ("Full access") and launches Claude Code with --allow-dangerously-skip-permissions when it accepts it (not root, or IS_SANDBOX=1); remote chains strip the flag. - agent_tools: the cmux MCP server (cmux mcp serve) is on for every agent chat unless the settings file says mcp.enabled false; the settings file is now the app's cmux-next.json (user_settings.rs), not classic cmux.json. - cmux mcp serve: on when CMUX_AGENT_SESSION is set and mcp.enabled is not set; any other client still needs mcp.enabled true. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat(cmux-next): Page Info on the shared native popup host; its rows on the shared popup row (cx-x9o52, REUSE.md slice 3) PageInfoPanel is a NativePopupPanel: placement through PopupPlacement, the host's grow/shrink motion and dismiss rules (click outside with the omnibar button kept open, Escape, key loss, app inactive, window move/resize/close). The hand placement, PopupFade and the mouse-down reopen guard go. The card no longer draws its own shadow band (PopupHostView draws the one popup shadow). PageInfoRowView is a PopupRowView. NativePopupPanel joins the child-window allow list (the bookmark bubble tripped it in DEBUG). PageInfoMotionTests (a unit test of PopupFade on PageInfoPanel) is deleted under the no-unit-test rule; the live check covers the bubble. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(cmux-next): a new bookmark's name follows the page title that arrives after the star (bookmark bubble) The star saves the bookmark at once, often before the page has a title, so the bubble showed an empty name. While the bubble shows, the page title (observed) fills the name until the user edits it; close saves it as before. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * test: bookmark bubble live check covers the late page title, Page Info on the shared host (captures) and a real click on the star (--real-click) (cx-x9o52) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * review: Page Info rows keep their inset before the accessory (cx-x9o52) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * cmux-next: pin CEF cef-154.0.28-cmux.25 (cmux.24 + WebAuthn hybrid fix with a PIN key attached; fork API 23) (cx-d0d.97) * cmux-next: remote browser host linked against CEF cmux.25 (step beeef9df6b98) (cx-d0d.97) * passkeys-roaming-e2e: --typing smoke with trusted key events (cx-d0d.97) * passkeys-matrix-e2e: a timed-out addVirtualAuthenticator reply counts as sent (the socket deadline is now 6 s) (cx-d0d.97) * chrome-promos-live: ignore Chromium's status bubble (<= 30 pt at the page window's bottom-left), logged; any other new window still fails (cx-d0d.97) * passkeys matrix + promo check review fixes: unconfirmed authenticator rows that pass without one are NOTE; promo count uses only new windows (cx-d0d.97) * free tier: a Keychain error never mints a new App Attest key; no key-id read where App Attest cannot work (cx-5bxp7 P3-A, P3-B) AttestKeyStore load/save/delete throw on a store error (load: nil only for errSecItemNotFound). The provider answers failed when the key id cannot be read or saved, so it never generates or attests a new key then (a new key spends the device's monthly grant), and it saves a new key id before attesting it. The register line skips the Keychain read when App Attest is not supported (no prompt in an ad-hoc DEV build). * acpmux start mode: review fixes (cx-wx93i) - Settings file read as JSONC like the app (comments, trailing commas); a file acpmux cannot read or parse, or an unknown value, gives the harness's own mode, never full access. Classic cmux.json only when cmux-next.json does not exist. The setting is resolved before the config write lock. - A remote chain never starts Claude in bypassPermissions (a transfer keeps the mode): the spawn mode and args fall back to default. - A handoff target starts in full access only from a full-access source and never with narrower. - A profile with its own skip flag keeps its mode on respawn; config reload picks up defaultPermissionMode; acpmux reads mcp.enabled only nested, as the CLI does. - Tests: the fake Claude refuses bypassPermissions without the launch flag; the settings-file test is its own binary (it sets CMUX_NEXT_CONFIG_FILE) and covers JSONC, no key, an unparseable file and an unknown value. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * cmux-next: Ctrl and Option holds show their shortcut hints too; hint chips are Liquid Glass in the theme's tint (cx-w9f3s) Lawrence 2026-10-14: "we need cmd hold tab to work for hold ctrl as well, maybe option if there are relevant shortcuts, we also need it to be liquid glassy". - A hold arms on any set of Cmd, Ctrl and Option (with or without Shift), not only bare Cmd or Ctrl. The overlay shows each target's binding from the resolved table (keybindings.json and cmux.json overrides included) whose modifiers contain the held set; a hold with no matching binding shows no chip. Same 300 ms delay, key-down suppression and placement. - ShortcutHintChipView: a full Liquid Glass capsule (GlassPanelView -> NSGlassEffectView) tinted with the theme's glass tint, text in the theme's primary text color. macOS 14/15: the same panel's blur, tint and hairline. Reduce Transparency: the theme's opaque popup surface, a device-pixel hairline and the soft shadow. - debug.shortcut_hints takes opt, shift and +-joined sets (ctrl+opt). CmuxNextApp line count unchanged (113450). * cmux-next: hold hints review fixes: only Cmd/Ctrl chords get a chip, a click suppresses, stronger chip tint (cx-w9f3s) Review of d77c9ec (P2s): a chip only for bindings KeyRouter runs (KeyRouter.isChord: a pure-Option binding types a character); a mouse-down while a modifier is held hides and suppresses the hints like a key-down (Option-click / Option-drag in a terminal); the chip's glass tint is the theme tint at 1.5x alpha so 10 pt text keeps its contrast over bright content. P3s: no double Borders.color, no continuous curve against a circular shadow path, debug release only alone. plans/cmux-next/keybindings.md describes the Cmd/Ctrl/Option holds and the glass chip. CmuxNextApp line count unchanged (113450). * review: Page Info keeps its side on a new page; any NativePopupPanel passes the child-window policy; the bookmark name follows only the bookmarked URL's title; live check presses the star once (cx-x9o52) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * free tier e2e runner: never kill; the app quits through its control socket (action.run quitEndSessions, peer-checked), the daemon by acpmux daemon shutdown (cx-ds09i T1/T2) * cmux-next groups: a right-click on a group header or tab group chip opens the group editor Lawrence 2026-10-14: "im talking about the rename + color things ... looks like the image in chrome, we had it at some point". The editor bubble (name field, color dots, group rows; cx-rcby, 3ca7be3) is still there, but #19019 (31db8ce) pointed the header's more button and its right-click at the plain menu. #20442 put the more button back on the editor; this puts the right-click back too, and does the same for a tab group chip, whose right-click showed the app's menu (the editor opened only on a press and hold). The full menu stays one row away (More Group Actions… in the sidebar editor) and on Option-right-click of a tab group chip. scripts/cmux-next/group-editor-live.py proves it with real right-clicks (cua-driver): the editor opens with its name field, color dots and rows, a typed name with Return renames the group, Escape closes it. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Channels view in the app: the page may play video from the daemon's loopback listener (PageCSP media-src) The Channels page plays a video attachment from the daemon's own GET /attachments/<token> (ws-attachments-v1). The app's page scheme sent no media-src, so the web view blocked it. PageCSP gains media sources; the home-channels descriptor allows http://127.0.0.1:* (the daemon listener). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * group-editor-live: find the group by its member row, the tab chip by the strip, the rename by the reopened editor Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * group-editor-live: real window-server right-click first, the in-app event path as fallback; strip rects are arrays Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * cmux-next tab groups: the group editor's More row shows the group's full menu under the chip (review P2) A right-click on a tab group chip now opens the editor, whose rows are New Tab, Ungroup, Close, Move to New Window and Save. The rest of the group's menu (icon, moves to a split, column or workspace, collapse, configured rows) stays one row away: More (the strip's existing paneToolbar.more string, 21 locales) pops the same menu under the chip, as the sidebar editor's More Group Actions row does. Option-right-click still shows it directly. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * cmux-tui: behavior test, a large legacy registry gets no full VACUUM while its owner serves (cx-4bd8m) Red commit: drives the owner binary on a registry in the shape a build without journal maintenance leaves (auto_vacuum off, no marker). Adds a debug-only CMUX_TUI_TEST_JOURNAL_MAINTENANCE_INTERVAL_MS override. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * docs: gh-merge-green is optional on feat-cmux-next (#20567) A plain gh pr merge on the exact head is fine under the branch's rules; the batch queue's own --land still uses the helper. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * cmux-tui: no full VACUUM of a large legacy registry while its owner serves (cx-4bd8m) Austin's cmux NEXT registry grew to 10.7 GB in 8.5 h under a build without journal maintenance (auto_vacuum off, 4.47M journal rows). The maintenance worker's first step converts such a registry with PRAGMA auto_vacuum= INCREMENTAL; VACUUM; while it holds the registry: on that file every client of the owner would read "not connected" for minutes after the next update. Convert only while live data is at most 64 MiB. Above it the conversion is deferred (one diagnostic per owner); sealing still runs and deletes archived rows, and SQLite reuses their pages, so the file stops growing once sealing keeps up. It does not shrink: sealed segments stay in the registry, so giving the free pages back needs a compaction that does not hold the registry (follow-up bead). Debug-only overrides for the interval and the bound keep the behavior test small. Red/green: legacy_registry_maintenance. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * cmux-next: a local merge commit reuses the fetched same-tree acpmux (#20534) * test: a local merge commit reuses the fetched same-tree acpmux (red) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: a local merge commit reuses the fetched same-tree acpmux reload.sh on a developer Mac stopped with "no cached acpmux" for any commit no workflow published (a local integration of feat-cmux-next and PRs), even though the tree fetch had just put that tree's checksum-verified acpmux in place. build-acpmux.sh now seeds its commit cache from it when it has every requested architecture. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore(next): PR autofix at 7be0d24 - regenerated schemas/defaults/cmux-next.json Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38542356066 --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: cmux-autofix[bot] <cmux-autofix[bot]@users.noreply.github.com> * webviews: popups draw one hairline, not two (#20461) * webviews: test that every popup draws one hairline edge Red: --acpmux-popup-elevation stacks a composer-edge hairline on the one already in --ui-popup-shadow. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * webviews: popups draw one hairline, not two --acpmux-popup-elevation stacked a 0.5px composer-edge hairline on the hairline already in --ui-popup-shadow. It now is the shared popup shadow, so every menu and popover has one edge. Increase Contrast colors that one edge in the popup's ink, which the composer-edge hairline did before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore(next): PR autofix at 1cc6616 - vp fmt webviews/src/agent-session/acpmux/modelPickerLayout.ts Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38520503432 * webviews: test that popups draw no border over the hairline and clear it under borders none Red: the pages' .ui-popup and the chat find bar draw a border over the --ui-popup-shadow hairline, and appearance.borders none leaves the hairline drawn. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * webviews: one rim on page popups and the find bar; borders none clears it The pages' .ui-popup drew a 1px border over the --ui-popup-shadow hairline; it now draws no border. The chat find bar keeps its border (its focus cue) and casts --ui-popup-drop, the shadow without the hairline. appearance.borders none sets --ui-popup-edge transparent. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * webviews: format modelPickerLayout.ts (base fmt red) Keeps cmux-autofix's vp fmt of the base file, which the base merge replaced with the unformatted copy; react-apps-check fails on it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * webviews: the Channels palette draws one rim; test follows the summary card Red after the base merge: the new Channels palette (.lg-palette, ledger.css) drew a 1px border over the --ui-popup-shadow hairline, and the summary popover became .acpmux-summary-card. The palette now draws no border. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore(next): PR autofix at 54dd59d - regenerated schemas/defaults/cmux-next.json Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38543983469 --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: cmux-autofix[bot] <cmux-autofix[bot]@users.noreply.github.com> * cmux-next: name the owner of ControlWorkspaceInfoCache's publish hop (clears the concurrency red) (#20485) * fix: clear two feat-cmux-next check reds tree-publish-v2's stub uploader takes --conflict-exit-code, which the tree publisher now passes (af8b68e). PaneAnimationsSetting carries the namespace-type justification its ratcheted sibling settings have. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: keep PaneAnimationsSetting internal to CmuxNextSettings Nothing outside the module uses it, so it needs no namespace-type allow. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore(next): PR autofix at c2bdb98 - regenerated schemas/defaults/cmux-next.json Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38530638157 * fix: name the owner of ControlWorkspaceInfoCache's publish hop check-concurrency flags the unowned Task d0a62be added; it is a one-shot main-actor hop that holds the cache weakly. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore(next): PR autofix at 7cf07e3 - regenerated schemas/defaults/cmux-next.json Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38544346314 --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: cmux-autofix[bot] <cmux-autofix[bot]@users.noreply.github.com> * CmuxNext: one-line sidebar rows by default; notification text in the hover card (#20483) * test: a notified compact row stays one line; its text reads in the hover card Leo 2026-10-14: "why is it even 2 lines in the first place?" Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: compact sidebar rows are one line by default; the notification text moves to the hover card sidebar.workspaceRow.notification is now off by default (Leo 2026-10-14). #19862 turned it on for classic parity; the setting stays as an opt-in. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore: regenerate the settings schema hash for the notification default Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore: regenerate the settings schema hash on the merged base Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore: take base's settings exports after the base merge (regenerated next) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore: regenerate the settings exports on the merged base Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore: refresh the defaults snapshot on the merged base Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs: the hover card template lists the notification fact; comments say where the text shows Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: cmux-autofix[bot] <cmux-autofix[bot]@users.noreply.github.com> Co-authored-by: Lawrence Chen <54008264+lawrencecchen@users.noreply.github.com> Co-authored-by: safe-push <safe-push@cmux.local>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Lawrence and Leo:
gh-merge-greenis optional on feat-cmux-next, and nothing should tell agents to use it. A plaingh pr merge --squash --match-head-commit <sha>under the branch's rules is fine. The helper's fast gate is in #20566 (main, where the helper lives).docs/ci/cmux-next-batch.md: by hand, the owner lands a validated PR with a plain merge or the optional helper. Only the queue's own--landuses gh-merge-green.scripts/ci/next_batch.py: the green receipt now says "land it yourself on this receipt (gh pr merge --squash --match-head-commit; gh-merge-green is optional)".Verification:
python3 tests/test_next_batch.pypasses (it asserts "land it yourself" in the receipt).Changelog
none
🤖 Generated with Claude Code
Need help on this PR? Tag
@codesmith-botwith what you need.Summary by cubic
Clarifies that
gh-merge-greenis optional onfeat-cmux-nextand that nothing should tell agents to use it. A plaingh pr merge --squash --match-head-commit <sha>is fine under the branch's rules.docs/ci/cmux-next-batch.mdso only the queue's own--landusesgh-merge-green; owners land validated PRs with a plain merge.scripts/ci/next_batch.pyto say "land it yourself on this receipt" and note thatgh-merge-greenis optional.Written for commit 1b5f222. Summary will update on new commits.