Skip to content

cmux-next: a pending new chat's mode chip names the mode it starts in - #20650

Merged
teamleaderleo merged 32 commits into
feat-cmux-nextfrom
leo-start-mode-chip
Oct 15, 2026
Merged

teamleaderleo merged 32 commits into
feat-cmux-nextfrom
leo-start-mode-chip

Conversation

@teamleaderleo

@teamleaderleo teamleaderleo commented Oct 14, 2026 •

Copy link
Copy Markdown
Collaborator

Part of cx-wx93i.

A new chat that hasn't started yet (pending until its first prompt) showed the mode the harness's last chat reported, not the mode acpmux will start it in. After the person picked Normal in one pane, a new chat in another pane still read "Full access", and the chip flipped after the first prompt.

acpmux is the only source of truth; the pane no longer mirrors its rules.

acpmux

  • New read-only _acpmux/start_mode {harness?, preset?, cwd?}. It returns {harness, modeId, name, level, source} for a plain new chat. modeId is null when session/new would set no mode: a preset, folder-profile or argv-pinned profile, a level that keeps the harness's own mode, or modes not known yet (no chat of that harness in this daemon, and not acpmux's own Claude backend).
  • One rule set: session/new and the answer both decide with start_mode::mode_eligible, start_level and mode_for. The answer waits for startup, as session/new does.
  • A Web or Peer connection gets the all-null answer before any cwd, preset or harness resolution.
  • Local watchers get _acpmux/start_mode_changed {} (sent on the existing watcher harness feed, marked, so hub/mod.rs and server/mod.rs do not grow) in two cases: when a pick saves a new level, and when a config reload changes defaultPermissionMode or lastPermissionMode. A change to the cmux settings file sends no notice; the pane asks again when shown or focused.

Pane

  • startMode.ts keeps acpmux's last answer per harness and folder, never a chat's mode. A pending chat (harness switch or New Tab) draws the kept answer on its first frame, then asks again on mount.
  • It also asks again on _acpmux/start_mode_changed, after this pane's own successful pick, and when the pane is shown or focused.
  • No answer, or an older acpmux, shows "Mode".
  • A pick made during the switch still wins.
  • A chat on another machine (peer, cloud, remote connection) shows "Mode" until its session reports.
  • The access menu value no longer falls back to the first mode, so the first mode can be picked.
  • The base's remembered last-chat mode chip (cx-uq9xi: a full-access chat's access chip shows its warning from the first frame #20579) gives way to the kept acpmux answer; its warning treatment on the first frame stays.

Relay authorization

_acpmux/start_mode is added only to the agent-pane relay (policy.json / AcpmuxPaneMethods: params harness, cwd; preset and _meta are stripped). It is not added to RemoteRelayCommandPolicy, so cmux ssh relays still deny it.

  • Command or content execution: none. It reads config.json and the settings file and resolves a profile; it spawns nothing, writes nothing and opens no content.
  • Unowned objects: it takes no session, surface or workspace ID, so no ID scoping applies. It reads the connection's own daemon state and is never forwarded to a peer (peer_forward.rs exclusion).
  • Local-state exposure: the app pane (LocalApp) gets the start level and its source (pick/config/settings/default), derived from lastPermissionMode/defaultPermissionMode, which the user's own pane already controls. Web and Peer connections get the null answer before any cwd, preset or harness resolution, so they learn nothing about this Mac's files or settings.
  • Notice: _acpmux/start_mode_changed carries no data and goes only to watching local connections, never Web or Peer.
  • Path check: the pane's cwd goes through the host path check.
  • Policy cases: pane-policy cases cover the allow case, the stripped params, the forward-mark refusal and the path check.

Test

  • acpmux, tests/start_mode.rs and tests/start_mode_settings.rs (start_mode_answer_*, through the protocol handler):

    • A fresh config answers bypassPermissions. After a pick of default it answers default, and session/new starts there.
    • Picks in a preset chat or a Web chat leave the answer unchanged.
    • A saved pick notifies local watchers, not Web watchers, and Plan sends nothing.
    • A Web caller with a cwd under a folder profile gets the plain null answer.
    • A folder profile and an argv-pinned profile answer null. Codex with no chat answers the level with no mode id.
    • The settings file answers with source settings.
    • Red (hosted Linux, fb99d29): harness acme is a folder profile (<path>); a Web or peer connection cannot start it and the local watcher is told. The earlier test commit b0b3782 was red with Method not found: _acpmux/start_mode.
    • Green on cfbfee5 (hosted Linux and macOS, lint green): all six start_mode_answer_* tests ... ok.
  • Pane policy (hosted, merged head e40e709): full_check_order ... ok (44 cases, Linux; the macOS runner refused with "a fleet build is waiting for the host") and the_allowlist_is_what_the_page_sends ... ok (Linux and macOS). The Swift relay parity test has no target in this repo, so it was not run.

  • Browser, test/agent-pane-start-mode-chip.test.ts (two panes, stub acpmux):

    • A pick in pane A shows Normal on pane B's new chat. Red on the merge-base: Received "Full access".
    • A null answer shows "Mode". Red on the earlier pane-side mirror: Received "Normal".
    • A pending chat opened first follows a pick made later, before any send. Red before the fix: waitForFunction: Timeout 10000ms exceeded.
    • All pass with the fix.
  • jsdom, test/access-chip-pending-warning.test.tsx:

    • The kept answer draws the warning chip on the first frame.
    • A wrong kept answer is corrected by acpmux's answer.
    • No answer names no mode.
    • Before the fix all three failed because the cache API did not exist.
  • Another folder's answer (review fix, 178c78a): a folder acpmux has not answered for yet borrows the harness's latest answer from any folder, but only to hold the access chip's place on the first frame. The chip reads "Mode" with no unrestricted warning until this folder's answer arrives, because a folder profile or preset may start the chat in a different mode. applySwitch sets currentModeId from this folder's own answer only.

    • Red on d726b09 (bun test test/access-chip-pending-warning.test.tsx, 3 pass 2 fail): Expected: not "Bypass permissions" for the first-frame chip, and applySwitch ... currentModeId Received: "bypassPermissions".
    • Green on 178c78a: the same command passes 5 of 5. Also green: test/new-tab-composer-first-frame.test.tsx (its borrowed first frame now expects "Mode" in place of the other folder's "Ask before edits"; chips, order and the settled chips are unchanged), CMUX_BROWSER_TESTS=1 test/agent-pane-start-mode-chip.test.ts (3/3) and composer-location-strip.test.ts -t "effort and access" (1/1). No new strings: it reuses picker.mode.

Captures

Real cmux NEXT, tagged DEV builds on macOS 27: before = merge base 1cb7e587bffe (bundled acpmux same tree), after = PR head 178c78ad3950 (bundled acpmux with _acpmux/start_mode). Fresh acpmux home per build; Claude Code through acpmux. A new chat stays pending while its folder's trust question is open, which is how these hold a chat before session/new. Host name blanked. Stills are the agent page's own WebKit snapshot on a flat background (the app's window snapshot draws the light window material as grey); clips are window recordings in dark.

1. A new chat after a pick of Normal in another chat (cx-wx93i). Before: the not-yet-started chat in a new folder reads Full access, then flips to Normal when it starts. After: it reads Normal from the start.

new chat chip, light
new chat chip, dark

Before (base), 12 s: new chat in beta reads Full access; Trust starts it and the chip flips to Normal.

s1 before

Full quality: s1-before.mp4

After (PR), 12 s: the same steps; Normal throughout.

s1 after

Full quality: s1-after.mp4

2. After only: the first frame in a folder acpmux has not answered yet. The chip holds its place as "Mode" for one or a few frames (22 ms for beta, about 120 ms for gamma), then shows acpmux's answer.

first frames

10x slower: gamma (Normal) to a new chat in beta: Mode for one frame, then Normal.

s2 after 10x slower

Full quality: s2-after-first-frame-10x-slower.mp4

3. A pick in one chat and a second, pending chat. Left: a new chat waiting on its trust question. Right: a started chat where Normal is picked. Before: the left chip stays Full access. After: it follows to Normal.

pick updates pending, light
pick updates pending, dark

Before (base), 7 s: the right chat goes to Normal; the left pending chat keeps Full access.

s3 before

Full quality: s3-before.mp4

After (PR), 7 s: the left pending chat changes to Normal right after the pick.

s3 after

Full quality: s3-after.mp4

Changelog

  • Fixed: a new agent chat's mode chip shows the mode it will actually start in, not the previous chat's mode.

🤖 Generated with Claude Code

teamleaderleo and others added 3 commits October 14, 2026 07:09
Fails on base: after Normal is picked in one pane, a new chat in another
pane that acpmux has not started yet shows Full access.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…n (cx-wx93i)

A chat acpmux has not started yet drew its access chip from the mode the
harness's last attached chat reported (any pane), or the label the last
chat showed. acpmux starts a new chat in the level of the person's latest
pick (hub/start_mode.rs), so the chip said Full access for a chat that
then started asking.

The harness profiles now keep the mode a chat acpmux just started
reported (startMode) and the level of the latest mode pick a local pane
made; a pending chat shows the pick's mode when newer, mapped onto the
harness's own ids as acpmux maps it, else the last start mode, else no
mode at all. Profiles re-read storage another pane changed.

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

coderabbitai Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration
  • Configuration used: Repository: manaflow-ai/cmux/.coderabbit.yaml
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: 27281135-d2be-41dd-a99c-769830d868f5

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

all web/size checks green

@github-actions

github-actions Bot commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

Not verified: macOS jobs did not run: compile and app tests were skipped on e6568638bd; ci-status is green without them.

CI passes on e6568638bd (run 38693325574 attempt 1).
macOS jobs did not run: compile and app tests were skipped: Fast static checks skipped (the macos job needs both to succeed). Re-run CI once they pass, before merging.

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

@github-actions

github-actions Bot commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

CI fast guards passes on f7aa29d91a (https://github.com/manaflow-ai/cmux/actions/runs/38685070620). This covers only the fast guards, not CI: CI's result is the ci-status check, and the CI failure attribution comment names any failing test.

teamleaderleo and others added 2 commits October 14, 2026 07:18
Importing a type from "bun" pulls Bun's ImportMeta.hot into every
source file, which broke the dev-host HMR callbacks' types.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
_acpmux/start_mode names the mode a plain new chat on a harness starts in,
and a session/new then starts there: full access from config, then Normal
after a pick in a chat. Picks in a preset's chat or a Web chat change
nothing, and a Web connection gets no prediction for its own chats.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@teamleaderleo
teamleaderleo temporarily deployed to cmux-tui-merge-tree October 14, 2026 14:22 — with GitHub Actions Inactive
teamleaderleo and others added 4 commits October 14, 2026 07:25
…, cx-wx93i)

The pane mirrored acpmux's start-mode rules and could not see what they
depend on: preset, folder-profile and remote-origin chats, profiles that
pin a mode in argv, the defaultPermissionMode setting and webAskingModes.
acpmux now answers it: `_acpmux/start_mode {harness?, preset?, cwd?}`
returns `{harness, modeId, name, level, source}` for a plain new chat, or
modeId null when session/new would set no mode.

One rule set: session/new and the answer both decide with
`start_mode::mode_eligible` (lifecycle.rs used to inline it),
`start_level` (latest pick, else config.json, else the setting) and
`mode_for`. The harness's modes come from its newest chat in this daemon,
else acpmux's own Claude backend list; unknown modes answer null. Read
only: no config write, no spawn.

Origin: a connection gets the answer for its own context, as
`_acpmux/prewarm` and session/new take `remote` from the connection. A
Web or Peer connection's session/new sets no start mode, so it is
answered modeId null rather than refused; the answer reveals only the
level and mode id, which the same caller's next chat would show anyway.
Answered locally, never forwarded to a peer. No person or approval gate
changes.

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

The stand-in acpmux answers `_acpmux/start_mode`: the latest pick's mode,
or null for a profile that pins its mode. After Normal is picked in pane A,
pane B's new chat shows Normal; when acpmux would set no mode, the chip
names none ("Mode"), even after a pick.

Red: on the merge-base the first case shows "Full access" (the last chat's
mode); on the pane-side mirror the second shows "Normal" (it guessed a
pick acpmux does not take).

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

The pane no longer mirrors acpmux's start-mode rules. When a pending new
chat is created, the pane asks acpmux `_acpmux/start_mode` for its harness
and folder and names that mode; until the answer comes, or when acpmux
sets none or predates the method, the chip names no mode ("Mode").

- harnessSwitch: the switch asks through its port before session/new and
  sets the pending chat's currentModeId from the answer; a pick made
  during the switch still wins, and the session's own report replaces it.
- ComposerPickers: the New Tab PendingChip asks the same (useStartMode,
  startMode.ts) when no modes are known. The access menu's value no
  longer falls back to the first mode, so the first mode can be picked
  while the trigger shows "Mode".
- Deleted: the pick recording in App.tsx, harnessProfiles' pick storage,
  level tables, startMode/startedAt/family fields and its per-read
  localStorage reload (harnessProfiles.ts is as on the base again).
- The pane relay allows `_acpmux/start_mode {harness, cwd}` (policy.json,
  AcpmuxPaneMethods.swift): read only, no gesture.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- vp fmt webviews/src/pages/home-channels/AttachmentViews.tsx
- vp fmt webviews/src/pages/home-channels/Composer.tsx
- vp fmt webviews/src/pages/home-channels/HomeChannelsPage.tsx
- vp fmt webviews/src/pages/home-channels/attachmentService.ts
- vp fmt webviews/src/pages/home-channels/icons.tsx

Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38580001182
teamleaderleo and others added 2 commits October 14, 2026 08:03
A remote chain runs Claude Code only inside the macOS sandbox, so on Linux
the Web Claude chat was refused before the case reached its point.

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

github-actions Bot commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

Gallery

Review in feed

216 states changed: agent-pane.artifact-panel/closed, agent-pane.artifact-panel/markdown, agent-pane.artifact-panel/html, agent-pane.transcript/long-code, pages.settings/browser-group-8, ... · 52 broken states · 124 play checks failed

Diff page and renders (the run's gallery-pr artifact)

State Before · after
agent-pane.artifact-panel/closed (Apple System Colors, chromium)
agent-pane.artifact-panel/markdown (Apple System Colors, chromium)
agent-pane.artifact-panel/html (Apple System Colors, chromium)
agent-pane.transcript/long-code (Apple System Colors Light, chromium)
pages.settings/browser-group-8 (Apple System Colors, webkit)
pages.settings/general-group-2 (Apple System Colors Light, webkit)

209 more on the diff page.

Live preview (follows this branch; start it with scripts/gallery-live.sh up <branch> from an hq checkout):

  • agent-pane.artifact-panel/closed: /wt/leo-start-mode-chip/?entry=agent-pane.artifact-panel#/agent-pane.artifact-panel/closed
  • agent-pane.artifact-panel/markdown: /wt/leo-start-mode-chip/?entry=agent-pane.artifact-panel#/agent-pane.artifact-panel/markdown
  • agent-pane.artifact-panel/html: /wt/leo-start-mode-chip/?entry=agent-pane.artifact-panel#/agent-pane.artifact-panel/html
  • agent-pane.transcript/long-code: /wt/leo-start-mode-chip/?entry=agent-pane.transcript#/agent-pane.transcript/long-code
  • pages.settings/browser-group-8: /wt/leo-start-mode-chip/?entry=pages.settings#/pages.settings/browser-group-8
  • pages.settings/general-group-2: /wt/leo-start-mode-chip/?entry=pages.settings#/pages.settings/general-group-2
  • 127 more on the diff page

Play checks failed (0 px anchor movement, 0 layout shift, no frame over 33 ms unless the entry gives a reason):

  • agent-pane.artifact-panel/markdown (Apple System Colors, chromium): play: no element for button "Open preview"
  • agent-pane.artifact-panel/html (Apple System Colors, chromium): play: no element for button "Open preview"
  • agent-pane.artifact-panel/html (Apple System Colors Light, chromium): play: no element for button "Open preview"
  • agent-pane.dictation/hide (Apple System Colors Light, chromium): play: no element for menuitem "Hide Dictation Button"
  • agent-pane.dictation/hide (Apple System Colors Light, chromium): play: no element for menuitem "Hide Dictation Button"
  • agent-pane.dictation/hide (Apple System Colors, chromium): play: no element for menuitem "Hide Dictation Button"
  • 654 more on the diff page

639 nondeterministic states differed from a second render of the same head (a clock or fixture leak) and are not counted as changes.

7105 unchanged · base 1cb7e58 · head 178c78a

github-actions Bot added a commit that referenced this pull request Oct 14, 2026
github-actions Bot added a commit that referenced this pull request Oct 14, 2026
github-actions Bot added a commit that referenced this pull request Oct 14, 2026
github-actions Bot added a commit that referenced this pull request Oct 14, 2026
github-actions Bot added a commit that referenced this pull request Oct 14, 2026
github-actions Bot added a commit that referenced this pull request Oct 14, 2026
github-actions Bot added a commit that referenced this pull request Oct 14, 2026
github-actions Bot added a commit that referenced this pull request Oct 14, 2026
github-actions Bot added a commit that referenced this pull request Oct 14, 2026
github-actions Bot added a commit that referenced this pull request Oct 14, 2026
github-actions Bot added a commit that referenced this pull request Oct 14, 2026
github-actions Bot added a commit that referenced this pull request Oct 14, 2026
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@cursor

cursor Bot commented Oct 15, 2026

Copy link
Copy Markdown

Bugbot needs on-demand usage enabled

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

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

… mode

Red on 4ae6985: the pending access chip names another folder's
Bypass permissions (with its warning) on the first frame, and applySwitch
sets it as the switching chat's currentModeId.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@teamleaderleo
teamleaderleo temporarily deployed to cmux-tui-merge-tree October 15, 2026 03:23 — with GitHub Actions Inactive
cachedStartMode marks an answer borrowed from another folder (acpmux has
not answered for this one yet). The pending access chip draws it as the
neutral "Mode" label (existing picker.mode string, no new strings), with
no unrestricted warning, so it never names a mode a folder profile or
preset may not start the chat in. applySwitch and askStartMode use only
this folder's own answer.

new-tab-composer-first-frame: the borrowed first frame now labels the
access chip "Mode" instead of the other folder's "Ask before edits";
the chips, their order and the settled chips after the report are
asserted as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@teamleaderleo
teamleaderleo temporarily deployed to cmux-tui-merge-tree October 15, 2026 03:27 — with GitHub Actions Inactive
teamleaderleo and others added 2 commits October 14, 2026 21:28
Keeps both sides in harness_admin.rs (watch_note and restart_harness's
id_set) and ComposerPickers.tsx (base's effortShown and Ultracode; the
PR's start-mode access chip, so the last chat's mode is no longer kept).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…in the protocol registry

check:browser-lanes requires warmViteServer once a test's Vite listens.
Base's protocol registry (#20576) must name every rpc::method constant:
_acpmux/start_mode and _acpmux/start_mode_changed join it, the IR, and
the generated web method list.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@teamleaderleo
teamleaderleo temporarily deployed to cmux-tui-merge-tree October 15, 2026 04:29 — with GitHub Actions Inactive
@blacksmith-sh

This comment has been minimized.

Keeps both pane methods: the PR's _acpmux/start_mode and base's
_acpmux/subagent_stop, in AcpmuxPaneMethods.swift and policy.json.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@teamleaderleo
teamleaderleo temporarily deployed to cmux-tui-merge-tree October 15, 2026 06:29 — with GitHub Actions Inactive
@teamleaderleo
teamleaderleo temporarily deployed to cmux-tui-merge-tree October 15, 2026 06:30 — with GitHub Actions Inactive
@teamleaderleo
teamleaderleo temporarily deployed to cmux-tui-merge-tree October 15, 2026 06:32 — with GitHub Actions Inactive
@teamleaderleo
teamleaderleo temporarily deployed to cmux-tui-merge-tree October 15, 2026 06:35 — with GitHub Actions Inactive
@teamleaderleo
teamleaderleo merged commit 0882c70 into feat-cmux-next Oct 15, 2026
97 of 99 checks passed
@blacksmith-sh

blacksmith-sh Bot commented Oct 15, 2026

Copy link
Copy Markdown

Found 1 test failure on Blacksmith runners:

Failure

Test View Logs
convention violations found (ERROR lines above)./
convention violations found (ERROR lines above).
View Logs

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

This branch was previously deployed

2 inactive (1 outdated) deployments
cmux-tui-merge-tree — e6568638 Deployed Oct 15, 2026 by teamleaderleo via publish the merge tree #1283
artifacts — f7aa29d9 Deployed Oct 15, 2026 by teamleaderleo via publish tree-addressed cmux-tui #16199
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant