Skip to content

cmux NEXT Cloud: cmux cloud start-session, start an agent on a machine (2/2) - #25319

Merged
teamleaderleo merged 43 commits into
feat-cmux-nextfrom
p0-machines/ergo-cloud-start-session
Oct 26, 2026
Merged

teamleaderleo merged 43 commits into
feat-cmux-nextfrom
p0-machines/ergo-cloud-start-session

Conversation

@teamleaderleo

@teamleaderleo teamleaderleo commented Oct 26, 2026 •

Copy link
Copy Markdown
Collaborator

Audit group §2d (p0-machines): start a VM from an ACP chat. This is part 2 of 2. Part 1, #25414 (landed), holds the agent ask card and the runs registry (CloudStartSessionAsks.swift) with their tests and strings.

Lawrence: "start new VMs from acp chat", with "decouple persistence of acp trajectories from the VM itself, in case the VM is resuming".
Leo: "so chieff related stuff we dont need to worry too much about but ergo of commands and docs and error/hint messages we do need ... anyways those are just quite a few things that we already kinda own/should prob own"

What changes

One explicit call:

cmux cloud start-session --target machine:<id> --agent claude [--cwd /home/cmux/work]
cmux cloud start-session --name dev --agent codex          # take machine "dev", or create it

It answers {machine_id, session_id, host}, plus machine_name, target, agent, and the chat's workspace_id, surface_id and tab_id.

  1. It takes the machine (by --target, else the one named --name, else it creates that machine) and connects. A paused machine resumes.
  2. It opens a chat tab on the machine's store (host registry:<id>) in the machine's first workspace.
  3. It starts the session in that machine's own acpmux through agent-session-start, the same keyed start a new remote chat's first send uses (AgentTabRemoteHost.startNow reuses keyedStart).

The person sees the chat in the machine's workspace.

Running it again. A run that answers pending (a new machine can take minutes) keeps going. The same command again joins it, or picks up its end once. A run whose caller already got its answer is not kept, so the next run starts a new session.

An agent's run asks first. A run from the cmux MCP server (or nested inside one: the outer run's origin decides), or from a shell naming its chat, puts a card in the agent's own chat: "The agent asks to start a claude session on Cloud machine dev", with Start and Not now. It follows cloud move's agent ask (CloudMoveAsks). Only Start creates or starts anything, and then as the person's run. Nobody answering within 2 minutes is a refusal that says so. The chat may be local or on a Cloud machine (an agent started by this verb can start another).

--name never makes a second machine. It needs a list the server answered within 15 s for the user and team signed in now (CloudService.hasCurrentList(within:)), and reads one if not. A failed or superseded read, or another team's list, refuses: a machine of that name may exist, check cmux cloud list-machines, then run the same command again. Two runs naming the same new machine share one create.

Per account. A run carries the user and team signed in when it was asked, and checks it (and cancellation) before every step that changes anything and after every wait: the list read, the create (before the new machine joins this Mac's list or connects: CloudService.createMachine's proceed), the resume or connect, the first-workspace fallback (CloudHandlers.terminalAnchor's proceed, right before it creates one), the tab, and each keyed restart and start try (AgentTabRemoteHost.startNow's proceed). After the start the session exists, so the result reports it, but nothing is shown on screen if the account changed meanwhile. A --target must be in the machine list read for the account signed in now (hasLoadedCurrentMachines): after a team switch, the previous team's machines stay in the store until that list lands, and a target among them refuses, saying to check cmux cloud list-machines. A team switch or sign-out while a card is open or a start is going on stops the run with a refusal that says so and gives the command. Runs and creations are also keyed by that account, so another account's ask never joins or takes them, and a sign-out or user change (CloudService.dropAllMachines) cancels and forgets them.

Why a new verb, not cloud move --new-session

  • cloud move moves an existing local chat: it syncs its folder and moves its session and history. Its target is a tab.
  • Starting a session targets a machine and has nothing to move. A --new-session flag would make one verb take two target kinds, with half its flags (--path, update/retry) meaningless in one mode.
  • web/app/api/vm/[id]/acpmux/keyed-start doesn't start a session. It only restarts the machine's acpmux with the person's key (for approvals), and the app already calls it through restartWithApprovals when a start needs that.

So the verb starts the session the way the app already does, through agent-session-start on the machine's daemon, and keyed-start is reached only through that approvals path.

Persistence (hq#4381)

  • Nothing here waits on a client snapshot. Create and resume wait only for the machine's daemon and store id, as cloud move does.
  • cmux-tui/crates/acpmux/src on current base has no peer_snapshot or similar hook. I grepped peer_snapshot, client_snapshot and PeerSnapshot.
  • So no hook is called. Once it lands, the place to call it is CloudStartSession.run right after startNow answers. The session id is known there, and a comment marks the spot. I did not make up a hook name.

Errors

Every failure names the machine and the agent and gives a CLI command, for example:

  • "Machine dev started but its agent didn't (The agent service on dev did not start). Run cmux cloud start-session --target machine:vm-x --agent claude again."
  • A missing folder says to pass --cwd.
  • A machine that doesn't connect points at cmux cloud machine-status.
  • A script run with no machine says how to name one.
  • Closing the new chat's tab before its agent started (while the store creates it, or while its start runs) says the tab closed (not that the account changed) and gives the command to run again.
  • A step that failed because the run was cancelled or the account ended says that, never that the machine didn't connect or the agent didn't start.
  • An agent outside a chat, a card that can't show, Not now, or no answer each name the machine and agent and give the full command to run again, every argument shell-quoted (for example cmux cloud start-session --name 'my dev' --agent claude).

Strings are in new tables (CloudSessionActions.xcstrings, CloudSessions.xcstrings) in all 21 languages the l10n gate requires. They don't touch Cloud.xcstrings.

Capture

No capture: the capture build of this head (fleet job aa9ed4b4719fad6af2a2921b, and the earlier 336a287df6bad0203956cb94) fails before the app builds, because the fleet's Linux pool has bun 1.4.2 and webviews needs 1.4.4 or newer. The card is the existing agent tool card (AgentPaneToolCard, as cloud move shows it) with this verb's text; the DEBUG scene cloud-start-session-ask (cmux-ci capture <sha> --state scene:cloud-start-session-ask) shows it once the pool is updated.

Timers and loops

The card's deadline and account watch, the caller deadline, the runs registry and CloudService's account observer are in #25414. This PR adds:

  • Tab listed: a one-shot 10 s wait for the machine's tree to list the new tab (CloudMove.holds, an observation raced with one sleep; the group is cancelled when either side wins). A tab not listed in time refuses.
  • Test bound: the card test's two stream waits race a one-shot 10 s sleep in a task group, cancelled when either side wins.
  • Machine up: the 180 s connect wait, the same CloudMove.holds.
  • Answer bound: the run answers pending: true 10 s before action.run's 200 s person deadline (CloudStartSessionRuns.answer), with text giving the same command to run again. The work keeps going until the start succeeds or fails, or the account ends.
  • No loops or observers outlive the run.

Size

1624 added lines over the ~800 cap:

  • 546 are the two translation tables (16 app keys, plus the action title and description, in 21 languages).
  • 450 are tests.
  • 73 are the regenerated exports and docs.
  • 555 are code: the start path (CloudStartSession.swift), its strings, the catalog entry, the account guards in AgentTabRemoteHost, CloudService and CloudHandlers, and one-line registrations.

This is already the second half of a split (the coordinator asked for it after nine rounds); the start path, its strings and its tests can't land apart without leaving a verb with no strings or no tests.

Tests

CloudStartSessionTests (the card and the runs registry are tested in #25414):

  • the descriptor is a CLI verb and an MCP tool that waits for the person
  • argument parsing, with a bad --agent and a bad --cwd refused
  • a script run with no machine
  • an agent outside a chat refused before any card shows
  • a sign-out or team switch while the agent's card asks refuses its run and clears the card (its stream waits end after 10 s)
  • closing the new chat's tab after Start says the tab closed and gives the command, both while the store creates it and while its start runs; a cancelled run stays cancelled
  • a step that failed after cancellation or an account change says so
  • a sign-out or team switch during a keyed start stops it before the next restart or start try, with and without the keyed reason; the same account runs both and reports the start
  • the retry command keeps the machine name one shell word
  • an agent's chat on a Cloud machine is found
  • --name with no machine list read (no sign-in) refuses, creates nothing, and gives the commands to check and rerun
  • only a fresh list of this account is current (old, never loaded, another team's)
  • a --target outside the list of the account signed in now starts nothing and says so
  • a run asked in another account starts nothing and says so; the account check refuses a change and stops a cancelled run
  • a nested run of an MCP run asks like an agent
  • the command to run again keeps every argument, quoted
  • the pending answer through the deadline race carries pending: true
  • the description
  • refusal mapping, including the folder cases
  • every hint is a CLI-offered verb

Agent session: Air-Blue

🤖 Generated with Claude Code

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Owned by an agent session · session

@github-actions

github-actions Bot commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

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

Review d2b5272: HQ feed card · gallery before/after runs · checks

App of this head (app.zip, kept 1 day)

gh workflow run reload-build.yml -R manaflow-ai/cmux --ref feat-cmux-next -f tag=pr25319 -f ref=p0-machines/ergo-cloud-start-session -f platform=macos -f backend_mode=local

Seen on other PRs too (likely flaky): next-docs.test.ts also failed on other PRs before this one; check whether it is this PR's before re-running.

CI failed on d2b52723a3 (run 40331846440 attempt 1): 1 code.

Job Verdict Why
web / Web tests (2/4) code a web test failed

Failures:

  • seen on other PRs next-docs.test.ts cmux-next docs > the CLI and MCP reference is fresh against the action catalog: failed (job)

A web test can import code this PR changes without being one of its files: python3 scripts/ci/web_test_verdict.py --pr 25319 --file web/tests/next-docs.test.ts checks its import graph (on Linux, in a sandbox) and its failures on other branches.

Matched log lines
web / Web tests (2/4): (fail) cmux-next docs > the CLI and MCP reference is fresh against the action catalog [2.50ms]

Not re-run automatically: web / Web tests (2/4) is not a machine failure.

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

red: web / Web status; NEW: green on the base d1c305f; do not merge until green; see lane-rules
red: web / Web tests (2/4); no finished base run on d1c305f to compare; do not merge until green; see lane-rules

CI fast guards failed on 93c9145a3b (https://github.com/manaflow-ai/cmux/actions/runs/40314726918). It does not block the merge; a red guard merged into main breaks it for every open PR.
The log named no failed step; see the run.

Agents: python3 scripts/ci/guard_attribution.py fix applies the mechanical fixes locally.

@github-actions github-actions Bot added the risk:normal Risk tier (docs/ci/risk-tiers.md) label Oct 26, 2026
@blacksmith-sh

This comment has been minimized.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

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

teamleaderleo and others added 3 commits October 25, 2026 21:46
…gent's chat

`cmux cloud start-session --target machine:<id> | --name <name> --agent <harness> [--cwd <folder>]`
takes the machine (or creates the named one), connects, opens a chat tab on its store and starts
the session in that machine's acpmux through agent-session-start (the keyed start a page's first
send uses). It answers machine_id, session_id and host. An agent's run asks the person with a
card in its own chat first (Start, Not now), like an agent's Move to Cloud.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-4ba8980ae4e8eecb82d6
…e a card that can't show

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-4ba8980ae4e8eecb82d6
…ending run's end is handed to the same command; name create failures

Review fixes:
- The ask owns its chat's card, by token, until its run ends; a second ask is refused.
- Runs are joined by what they ask for. A run that outlasted its caller's answer is kept (at most 10 min and 32 runs, pruned when a run starts, no timer) for the same command's next run.
- A machine that can't be created says so, with the command.
- The --cwd hint gives the full command.
- The action carries a description, as #25254 added.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-4ba8980ae4e8eecb82d6
@teamleaderleo
teamleaderleo force-pushed the p0-machines/ergo-cloud-start-session branch from 7867074 to 8fae4c3 Compare October 26, 2026 04:53
…ng; quote the retry name; a capture scene of the ask card

Review fixes:
- CloudStartSessionRuns runs each caller's answer race itself. A run that ends with a caller waiting is dropped. One that every caller left is kept for the next same ask, handed out once, and expires for that same key too.
- Tests use explicit signals (an injected wait, a card-shown stream) instead of yield counts.
- The create-failure retry command quotes the machine name as one shell word.
- DEBUG scene cloud-start-session-ask: the real ask card in the showcase chat.

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

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

@blacksmith-sh

This comment has been minimized.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

cmux-next fast gates / post cmux-next/fast-gates is red on 15 of 18 fresh feat-cmux-next PR heads in the last 2:00:00, so it is most likely a base red, not this PR's. The base-reds lane has it; a base merge picks up the fix once it lands.

…achine's chat may ask; the keep limit holds when runs end together

Review fixes:
- The production pending answer carries pending: true (with a test through the race).
- Agents in a chat on any machine's store are found.
- Kept runs are trimmed when a run is kept, not only when one starts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-4ba8980ae4e8eecb82d6
… reads a fresh machine list and creates once per name; refusals repeat the full command

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

Copy link
Copy Markdown
Collaborator Author

high-signal review link / link is red on 14 of 18 fresh feat-cmux-next PR heads in the last 2:00:00, so it is most likely a base red, not this PR's. The base-reds lane has it; a base merge picks up the fix once it lands.

Base's exports predate its auto-archive actions; these are the export
script's output for this tree.

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

Copy link
Copy Markdown
Collaborator Author

cmux-next / cmux-next checks (god files, concurrency, crash safety, l10n) › Script tests (pin-cmux-tui, embed-cef, ensure-cef store) is red on 7 of 11 fresh feat-cmux-next PR heads in the last 2:00:00, so it is most likely a base red, not this PR's. The base-reds lane has it; a base merge picks up the fix once it lands.

@cursor

cursor Bot commented Oct 26, 2026

Copy link
Copy Markdown

Bugbot needs on-demand usage enabled

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

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

teamleaderleo and others added 3 commits October 26, 2026 04:21
@teamleaderleo
teamleaderleo changed the base branch from p0-machines/ergo-cloud-start-session-asks to feat-cmux-next October 26, 2026 11:58
…/ergo-cloud-start-session

# Conflicts:
#	Packages/macOS/CmuxNext/Sources/CmuxNextApp/Cloud/CloudService.swift
#	Packages/macOS/CmuxNext/Sources/CmuxNextApp/Cloud/CloudStartSessionStrings.swift
#	Packages/macOS/CmuxNext/Sources/CmuxNextApp/Resources/CloudSessions.xcstrings
@cursor

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

…ument Agent in de and fr

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-4ba8980ae4e8eecb82d6
…lish, instead of an allowlist entry

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-4ba8980ae4e8eecb82d6
…/ergo-cloud-start-session

# Conflicts:
#	Packages/macOS/CmuxNext/Sources/CmuxNextApp/Cloud/CloudService.swift
@teamleaderleo
teamleaderleo merged commit e22f938 into feat-cmux-next Oct 26, 2026
174 of 180 checks passed
@teamleaderleo
teamleaderleo deleted the p0-machines/ergo-cloud-start-session branch October 26, 2026 14:05
@github-actions

github-actions Bot commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

This branch had an error being deployed

2 failed and 2 inactive deployments
artifacts — d2b52723 Deployed Oct 26, 2026 by teamleaderleo via publish to R2 #57636
sentry-dsyms — d2b52723 Deployed Oct 26, 2026 by teamleaderleo via upload cmux-tui dSYMs to Sentry #57636
ci-routing-agent — d2b52723 Deployed Oct 26, 2026 by teamleaderleo via namespace autofix #3395
cmux-tui-merge-tree — d2b52723 Deployed Oct 26, 2026 by teamleaderleo via publish the merge tree #6527
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk:normal Risk tier (docs/ci/risk-tiers.md)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant