Repository navigation
cmux-next: open a remote machine's agent chat as a sidebar workspace (agent-session-adopt) - #22871
teamleaderleo wants to merge 34 commits into
Conversation
…uses peers, the Chief and team VMs Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15ba7-3152-78b2-bfdf-bb6eb0d5a053&host=cosmic-gray
|
owner: 01a15ba7-3152-78b2-bfdf-bb6eb0d5a053 |
…pmux to a tab of its store Same gates as agent-session-start (trusted local client, host gate, unbound tab of this store); the session must be this machine's own (no peer mirror, no Home Chief). A non-asking session is adopted on allowed hosts and the answer says asking: false for the app's bypass badge. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15ba7-3152-78b2-bfdf-bb6eb0d5a053&host=cosmic-gray
|
Bead |
|
cmux status (one comment, edited in place; each line is updated by the job that owns it) Review App of this head (app.zip, kept 1 day)
Passes: CI passes on CI passes on Written by red: cmux-next checks (god files, concurrency, crash safety, l10n); NEW:
Tour of |
…rkspace, with a bypass warning agent.openSessionWorkspace with a host that names a remote machine (cmux agent open huge-blue/NAME) creates the workspace on that machine's daemon and binds its agent tab to the session through agent-session-adopt; a refused adopt closes the workspace. A chat whose mode does not ask before acting puts a 'Bypass: acts without asking' warning first on its row, which no row setting hides. mirroredPane and AgentTabRemoteClient move out of CmuxNextApp (Bridge, AgentPane) to keep the App target flat. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15ba7-3152-78b2-bfdf-bb6eb0d5a053&host=cosmic-gray
This comment has been minimized.
This comment has been minimized.
…nt reads them off the main actor) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15ba7-3152-78b2-bfdf-bb6eb0d5a053&host=cosmic-gray
…ch reply and follows changes Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15ba7-3152-78b2-bfdf-bb6eb0d5a053&host=cosmic-gray
…rries it and pushes changes Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15ba7-3152-78b2-bfdf-bb6eb0d5a053&host=cosmic-gray
…t NAME --group G joins that machine's group The badge comes from the adopt answer, one agent-session-mode read per bound tab at each connect, the attach reply and its agent-session-mode pushes, so a relaunch, a mode change or a chat an agent adopted there all show. A reporter's entry under the reserved key is dropped. remoteDaemon(named:) is nil for an ambiguous name; adopt refusals say what happened. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15ba7-3152-78b2-bfdf-bb6eb0d5a053&host=cosmic-gray
…ng none is refused before the workspace is made Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
…takes Data) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15ba7-3152-78b2-bfdf-bb6eb0d5a053&host=cosmic-gray
Bugbot needs on-demand usage enabledBugbot 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. |
…uses Data) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15ba7-3152-78b2-bfdf-bb6eb0d5a053&host=cosmic-gray
Bugbot needs on-demand usage enabledBugbot 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. |
…fer the nested closure) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15ba7-3152-78b2-bfdf-bb6eb0d5a053&host=cosmic-gray
Codex review (xhigh) of b10a581: the adopt creates the terminal and the agent tab before agent-session-adopt runs, and base's half-created close only closes an empty workspace (ifEmpty), so a refused adopt left the workspace, its terminal and an unbound tab on the other machine. Red until the fix. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16040-fd0b-7dd0-9487-1a3a198d9f5c&host=cosmic-gray
The adopt makes the workspace, its terminal and the agent tab before agent-session-adopt runs. On a refusal, base's half-created close (ifEmpty) refused with workspace_not_empty, so the workspace, terminal and unbound tab stayed on the other machine. A refused adopt (AgentSessionAttachError: nothing was bound) now closes that workspace outright, kept out of Recently Closed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16040-fd0b-7dd0-9487-1a3a198d9f5c&host=cosmic-gray
|
|
|
|
… request survives a late reply Codex review (xhigh) of 3e53b9c: only a refusal closed the workspace. A timeout, closed connection or malformed reply from agent-session-adopt, or a failed agent-tab request, left the workspace with its terminal and a bound or unbound tab. The adopt's workspace now closes on any failure after its terminal (closing only detaches a bound session), and the agent tab is sent with DaemonConnection.retryingLateReplies under its fixed mutation id, so a late commit replays instead of failing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16040-fd0b-7dd0-9487-1a3a198d9f5c&host=cosmic-gray
Bugbot needs on-demand usage enabledBugbot 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. |
|
|
|
|
|
|
… and leaves no repair claim Codex review (xhigh) of f070600. The cleanup moves into AgentSessionWorkspace.closeFailedAdopt unchanged (the captured connection), so aFailedAdoptsWorkspaceClosesOnceTheMachineReconnects is red: with the link down the close fails at once and the workspace stays. The refused-adopt test also checks that the key is not left settling in EmptyWorkspaceRepair. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16040-fd0b-7dd0-9487-1a3a198d9f5c&host=cosmic-gray
…nder the repair's claim Codex review (xhigh) of f070600: - The cleanup ran on the connection captured at the start. When the other machine's link dropped mid-adopt, the close failed on that dead connection and the workspace stayed. closeFailedAdopt now closes through DaemonService.failureOnceConnected: at once when the link is up, else once it is up again, unless the machine leaves the app. - The tab and the adopt ran after WorkspaceCreation had released the key to EmptyWorkspaceRepair as awaitingPane, so a workspace closed before a pane snapshot left the key settling for good. The whole create (workspace, terminal, tab, adopt) now runs under repair.populating with withTerminal, so a failure leaves the key closing (cleared when it is gone), and a close that fails releases it with closeFailed, as WorkspaceCreation does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16040-fd0b-7dd0-9487-1a3a198d9f5c&host=cosmic-gray
… and closes its terminal; mode re-read ordering Codex review (xhigh) of 92bc138: - The failed adopt's close waited for one connect only, so a link that dropped again under close-workspace left the workspace. closeFailedAdopt now loops: wait (observation) for a live link, send the close, and send it again after a lost link or reply (closeRetries: notConnected, connectionClosed, daemonShutdown, connectFailed, timedOut); a daemon answer or the machine leaving the app ends it. - The close passed no terminals, so a daemon without batch-close-v1 removed the workspace and kept its PTY. The terminal made for the adopt is now closed with it. - agent_session_stream reread_mode: the worker released mode_reading with a plain store, so it and a concurrent mode event could miss each other (store buffering on weak memory) and drop the last mode change. It now releases with swap(AcqRel), which reads the event's swap and sees its mode_again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16040-fd0b-7dd0-9487-1a3a198d9f5c&host=cosmic-gray
Bugbot needs on-demand usage enabledBugbot 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. |
…kes its key as closing AgentSessionAdoptNoPageTests at ef650fa (step 2b66681c1a9e754dfdadb1ae): the refused adopt's key stayed settling in EmptyWorkspaceRepair. The close ran inside repair.populating, so the store could drop the workspace before finishPopulating marked the key .closing; storeDidChange clears .closing only for an absent key on a later change, and none came. withTerminal now only notes that the workspace may exist; the close runs after populating has failed, and a close that fails releases the key with endClosing. The test waits (bounded) for the repair too, since it observes the store after the store applies the drop. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16040-fd0b-7dd0-9487-1a3a198d9f5c&host=cosmic-gray
Codex review (xhigh) of f5d3758: a daemon that stayed live but kept timing out on close-workspace made the close loop retry at once, forever, so the action never returned and the key never left closing. A late reply is now asked again only within the late-reply budget (retryingLateReplies), and a timeout past it ends the close. A link loss is retried only on a new connection (the observation waits for a live connection other than the one that dropped), so every pass needs a reconnect. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16040-fd0b-7dd0-9487-1a3a198d9f5c&host=cosmic-gray
|
Closing the umbrella. p0-machines adopted it after its lane died. The split went this way:
|
Summary
Open a chat that already runs on another machine (cmux16, huge-blue; for example one
cmux agent open huge-blue/NAMEstarted) as a sidebar workspace bound to that machine's daemon.agent-session-adopt {surface, session}(agent-session-adopt-v1). It binds a session of this machine's own acpmux to an unbound agent tab of this store.agent-session-start(a trusted local non-remote client, the host gate that refuses team VMs and unverified Cloud VMs, and a tab of this store with no session yet).agent_session.unknown_sessionany id that this machine's_acpmux/sessionsdoes not list as its own: a peer's mirrored chat, the Home Chief's, or an unknown id.{surface, session, conversation, family, mode, asking}.Risk: high. This adds a new socket verb that binds sessions and lets a non-asking session open on a trusted host.
Takes back #23163: nothing is taken back. This PR moves
AgentTabRemoteClient(with #23163'schildren()) unchanged fromCmuxNextApp/AgentTabRemoteHost.swifttoCmuxNextAgentPane/AgentTabRemoteClient.swift, so the agent pane can use it.Changelog
Added: open an agent chat running on another machine as a sidebar workspace.
Observed / Not run
No capture: the only new visual is the "Bypass" warning on the row of a chat adopted from another machine's acpmux. A capture mini has no second machine with a running non-asking chat to adopt, so no tour reaches it.
AgentBypassBadgeTestscovers the row content.Head
211a40356ce919dea9a7771a2dc2498b1a3bdff8: two fixes, test first.cmux agent open S --host <machine>took the adopt path, which skipped thecanHostChatcheck that the local open makes. In a build with no agent page it made a workspace on that machine and bound the session into a tab that could not show it. Adopt and open now share one check (requireChatPage), which refuses before any workspace is made. A Debug-onlyCMUX_NEXT_AGENT_PANE_NONE=1makes the agent tabs resolve no page, so a test can run as such a build.Command:
cmux-ci run --class light --script scripts/ci/package-test-lane.sh --arg=suite --arg=Packages/macOS/CmuxNext --arg=AgentSessionAdoptNoPageTests,AgentBypassBadgeTests --env CMUX_CI_XCODE_APP=/Applications/Xcode_26.6.app5d87ec570ee584bf138073cc77723011cfce9ad7, job22e656453201c8696521bccd:anotherMachinesChatIsRefusedWithoutTheAgentPageAndMakesNoWorkspacefailed with no refusal, a started work item ("The agent service on Move VM did not start.") and a workspace made on the other machine.anAdoptsOwnRefusalsSayWhatHappenedfailed because the text said "session name". (An earlier run atb5122f739d9a, job3da86b8af641d14e631e6cdf, showed that the fleet's test build carries the bundled page, which is why the seam was added.)211a40356ce9, jobb7ffea143d44bd85549928fe: both suites passed, 7 of 7 tests, none skipped.cmux-ci compile-check --appon211a40356ce9, jobfaa4a6d49cb59a9e93882737: ok.cmux-tui spec inventory / clippy (changed cmux-tui packages)(run 39630147344) is red only on two "redundant clone" errors atcmux-tui-core/src/server/rows_tests.rs:373and:416. This PR does not touch that file. It is a base red, fixed on base by rows_tests: drop two redundant clones (clippy base red) #23557.Head
169626f5634d10b51b859852f46fcb31b85da827: one merge offeat-cmux-nexte323f77325da, then a test-only fix.Merge conflicts, with both sides kept:
AgentSessionWorkspace: the remote adopt path plus acpmux new: one launcher for agents (worktree, prompt file, report-to, sidebar group, reuse) #22809'sgroupargument, which now also goes to the local open. The listed-key reuse now applies to adopt too. Base'sDaemonStore.firstPane(mirroring:)replaces this branch's duplicatemirroredPane(of:)in AgentSessionWorkspace, CloudMove and CloudBringBack, and the duplicate file is deleted.AgentTabRemoteClient: this branch moved it toCmuxNextAgentPane. It now carries cmux-next: wire explicit read-only remote agent observation #21258's observemodeandisReadOnly, and cmux NEXT: show and open a Cloud VM chat's child chats #23163'schildren().AgentSessionAttachClient: attach sendsmode.command(attach or observe) withmode_eventsand the bypass notes. The private mode read is renamedchatMode()so it does not clash with themodeproperty. Adopt is refused in observe mode.DaemonEndpointcapability list:agentSessionAdoptplus base's observe, children, cloudAttachments and cloudSelfHost.agent_session_attach/agent_session_stream: the adopt and children modules, the mode-read fields and the children set. Asession_changedof the session or of a followed descendant streams. Only the session's own mode change re-reads its mode.Fleet, on the merged head
e0f0a4808e44unless noted:cmux-ci compile-check --app, job9f4181e7d0cd8737d040c953: ok (app compiled and linked).99113f1332b59dff06e1a59f(the fleet coalesced the per-suite keysr22871-<Suite>-e0f0a4808e44into one build): passed for AgentBypassBadgeTests (6), AgentTabHostRefusalTests (4), AgentSessionAttachClientObserverTests (2), RemoteChildSessionsTests (4), RemoteAcpmuxObserverTests (1), CloudMoveTests and CloudBringBackTests (12).test agent_session, step7ad611affb284732b92a9baf: red. 15agent_session_attach_testsfailed because the attach's new mode read (_acpmux/web_modes) went unanswered by the tests' fake acpmux and showed up as the next frame. Fixed in169626f5634d: the fake answers the read and skips it like the watch.test agent_sessionon169626f5634d, step9cec0891204f1fa16b33ef79: 94 of 96 passed, including every adopt, start, attach, observe and children test. Two did not pass:terminal_respawn::a_respawned_terminal_resumes_its_agent_sessionfails the same way on basee323f77325da(step9da1003cc84a96e2051d2360), so it is not this PR's.agent_input_hint::terminal_input_into_an_agent_suggests_agent_messagefailed in the full run and passed alone, so the gate marked it flaky.PR checks on
169626f5634d:cmux-next guards / defaults-snapshotis red at "Menu rows run registered actions" over FileExplorer files this PR does not touch. It fails the same way on the feat-cmux-next push run 39617831647, so it is a base red.pr-capture-checkfailed because the description had no capture line. The note above addresses it.Not run: no live adopt of a real remote chat end to end, and no capture.
Agent session: cosmic-gray
🤖 Generated with Claude Code
Need help on this PR? Tag
@codesmith-botwith what you need.Summary by cubic
Opens a chat that already runs on another machine's acpmux as a sidebar workspace bound to that machine's daemon, via the new
agent-session-adoptverb in the cmux-tui daemon and the cmux-next app.--host NAME --group Gopens into that machine's group of that name, joining any same-named group that can hold the row and making it when missing; a host that names none or more than one machine is refused before the workspace is made, and the refusal says why.feat-cmux-nextkeeps adopt and the base's observe, children, andgroupfeatures, reusing base'sAgentSessionWorkspace.joinfor the group (the branch's duplicateSidebarEdits.group/joinGroupare removed) and base'sis_chief; an adopt in observe mode is refused, and the attached client carries the observe mode and children support.agent-session-start), reportingasking: falsefor the app's bypass badge.agent-session-modeverb reads a bound tab's mode, the attach reply carries it, and an attachment withmode_eventshears pushes when the mode changes. Mode reads are bounded and run only while the connection serves them; a stale connection's read is dropped, and the re-read lock uses acquire-release ordering so a concurrent mode change is never lost.mirroredPaneandAgentTabRemoteClientintoCmuxNextBridgeandCmuxNextAgentPaneto keep the App target flat. Adopt shares the local open's agent-page check, so without the page it is refused before any workspace is made on the other machine; the unknown-session refusal names the exact session id.agent-session-adoptruns, and a timeout, closed connection, malformed reply, or failed agent-tab request would otherwise leave them on the other machine. The close retries through later drops until the daemon answers (or the machine leaves the app), re-asking a late reply only within the late-reply budget, retrying a lost link only on a new connection, and ending on a timeout past the budget so it always terminates; it closes the terminal too, so a daemon without batch-close-v1 does not keep the PTY. The whole create runs under the workspace-repair claim, the close runs only after that claim fails and releases the key withendClosing, so no key is left settling, and the tab request is sent under a fixed mutation id so a late reply replays.CMUX_NEXT_AGENT_PANE_NONEkey simulates a build without the page).Written for commit 80236be. Summary will update on new commits.