cmux NEXT Cloud: Run New Workspaces in Cloud — each new workspace gets its own Freestyle VM (Fixes #26062)

Merged
AU
5d ago
+55323-53801

Fixes https://github.com/manaflow-ai/cmux/issues/26062

What

A Cloud toggle for cmux NEXT, function first (UI polish later):

  • Settings > Machines > Cloud Workspaces > Run New Workspaces in Cloud (cloud.newWorkspacesInCloud, off by default). It is a plain toggle setting, so it is also in the palette's Toggle Setting and in cmux.json.
  • New Cloud Workspaces Start In (cloud.newWorkspaceFolder): inherit (default) or empty.
  • When the toggle is on, a person's New Workspace (Cmd-N, the sidebar's +) does not open on this Mac. It runs the existing New Cloud Workspace flow with a new Freestyle machine for every workspace. The window shows the progress steps at once, and a failure stays with Retry.
    • inherit: the git working copy around the focused terminal's or chat's folder is copied with cmux link sync push (the same transport Move to Cloud uses), under the machine's ~/work. If the image refuses that folder it falls back to /root/work. The workspace's terminal opens in the person's folder on the machine, and the workspace takes the project's name.
    • empty, or no folder, or a home folder (never copied): the workspace opens in the machine's own home, from the image's working snapshot.
  • Agent chats started in that workspace run on its machine (existing cmux NEXT behavior for Cloud workspaces).
  • Scripts, the CLI and MCP (cmux workspace new), and any invocation that names --machine, keep their current behavior. Only a person's gesture follows the toggle.

Research: how ChatGPT Work / Codex cloud run tasks

OpenAI documents Work's policy, not its mechanics. Its security page says Work "can reuse an environment across tasks or replace it while preserving eligible state" (Work cloud security). The concrete mechanics below come from Codex Cloud, the closest documented product:

TopicChatGPT Work / Codex CloudThis PR
StartEach task gets its own isolated VM, booted from a published environment snapshot. Setup scripts run once; dependency caches are kept (cloud environments).One new Freestyle machine per new workspace, from the cmux image.
ChoiceA per-task Local / Cloud selector at creation ("Work in → This computer / Cloud"; Work's composer toggle). A task cannot switch mid-turn (modes, cloud-local access).One remembered toggle for new workspaces. The agent composer's existing environment picker remains the per-chat choice.
Files inA git clone of the selected GitHub repo. Local files and uncommitted changes are not sent (modes).Goes further: the local working copy, including uncommitted files, is synced (inherit), or nothing is synced (empty).
Files outDiff review, then a PR or codex apply (git apply; fails cleanly on conflict) (CLI).Existing Bring Back Local (cmux link sync pull, which reports conflicts) and the Cloud diff viewer (open PR https://github.com/manaflow-ai/cmux/pull/25696).
ResumeA task's VM state, including uncommitted work and installed tools, can be resumed for 7 days.Existing idle auto-pause, with resume on attach (Freestyle pause keeps memory).
Network / secretsPer-environment internet policy through a proxy. Secrets reach the agent only as proxy placeholders.Not in this PR. The Freestyle firewall and secrets rows are tracked in plans/cmux-next/freestyle-parity.md.
Feels localOne thread on every device; keeps running while the laptop sleeps.Same workspace and terminal UI as a local one, opened in the person's folder. The machine keeps running when the Mac sleeps.

Gaps left for follow-ups:

  • Prebuilt per-project environment snapshots with setup scripts, so a second workspace on the same repo does not sync and install again.
  • A per-workspace Local / Cloud choice on the New Tab page and in the composer.
  • A network policy per environment.
  • Proxy-held secrets.

Where the code lives

  • CmuxNextSettings/CloudNewWorkspaceSetting.swift: the two keys, their Settings rows (Machines page, "Cloud Workspaces"), privacy-refused for agents.
  • CmuxNextCloud/Move/CloudNewWorkspacePlan.swift: the decision (person only; no --machine/command; never a home folder) and the folder copy over cmux link sync push, with the ~/work → /root/work fallback.
  • CmuxNextApp/Handlers/CloudHandlers+Account.swift startNewWorkspaceInCloud: runs the New Cloud Workspace flow with a new machine whose open copies the folder and creates the workspace with its terminal there. CloudMachineCreation keeps that open so Retry repeats the copy.
  • No App growth (CmuxNext rule): CloudVmHostStore (Foundation + CmuxNextCloud only) moves to CmuxNextCloud unchanged apart from public, App −74 source lines.
  • Cmd-N stays local while Cloud is signed out or unavailable. An app that can't copy (no bundled CLI, or the opt-in app-server link) starts the machine empty instead of failing after it exists.

Tests

  • CmuxNextAppTests/CloudNewWorkspaceTests: the decision against real cmux.json values and a real git folder on disk (off by default; on copies the whole working copy and opens the nested folder; empty; a home folder is never copied; scripts, --machine and a command are not rerouted; an app that can't copy starts empty), and the copy's work-root fallback, stop on a real refusal and the outdated-machine case, with a stand-in for cmux link sync push.
  • CmuxNextSettingsTests/CloudNewWorkspaceSettingTests: parsing, defaults, the toggle on the Settings page and in the palette, agents refused.
  • Existing suites rerun for the touched code: CloudVmHostTests, SettingsPageSectionsTests, SettingsSchemaExportTests.

Observed / Not run

  • Display run at the current head e00f45e1e0f5 (added by the ready-queue unblocker): compile-check 300826d8c0eb1fe660435d17 (CmuxNext with test targets, app, cmux-tui: passed), then fleet step a7db046948c6f3ca2395a28b on a gui-session-v1 worker (cmux8s-Mac-mini) in cmux's console session, CMUX_TEST_REQUIRE_GUI=1 (a skip fails the step): CloudNewWorkspaceTests, CloudNewWorkspaceEntryTests, CloudNewWorkspaceLateStartTests, CloudNewWorkspaceSettingTests, CreationInputHoldTests and CmdNThenNewTerminalTabTests: all 6 suites passed, 30 tests, exit 0.
  • Current published head: a4e2b9b40ae45cd350bed6ee6faef01856cf6eed, normally merged with latest fetched base f06d9bd0736cc1af17a455eed1da63153ee7dead. GitHub reports MERGEABLE and zero unresolved review threads. The remote head was checked immediately before the plain push. Manual and hook prepush gates, the scoped web-lint wrapper, and syntax verification of all 18 changed Swift files passed. No builds or tests ran on the local Mac.
  • Exact-head fleet job 4de25f3cff892ca14fe0b6e4 compiled package/test targets and passed all 20 selected filters, with 153 reported Swift Testing tests and no failures (some filters overlap). This includes the Cloud/settings/late-reply coverage below plus CmdNThenNewTerminalTabTests and CreationInputHoldTests for the incoming base integration. The job exited 0 and confirmed workspace cleanup.
  • Caller-attribution red/green: CloudNewWorkspaceEntryTests at b62559281f5c250704627076f06bbbb789b47e58 (fleet 9f074c4e5cd57b551d01cafa) compiled and executed seven tests, failing only the four intended line-95 assertions for socket, app, agent and terminal callers claiming origin=user; exit 1, cleanup confirmed. The same filter passed all seven tests and all four parameter cases on the current head. The repair uses the shared ActionInvocation.isPersonsOwnRun predicate so these callers keep their requested route.
  • The late-reply repair uses the shared WorkspaceCreation.create / firstTerminal paths. CloudNewWorkspaceLateStartTests exercises the actual stored toggle opener over the JSON-lines transport, requiring one workspace, one terminal, stable IDs across retry, and no cleanup close. Canonical red-before at 969a0c69f0a54a157624e171b23313c3627fef79 (fleet 9965fe37e9fe81696e414ac8, exit 1, cleanup confirmed) executed one test and failed four intended assertions. It passed in the preceding 18-filter run and is selected again on the current head.
  • Canonical settings regeneration: fleet job 4713e214e53f8a26b315dbf9 at e0e3fac4670f41cadd10f05c89fef4e7226ec238 compiled package/test targets and passed all 4 managed-preference and 6 schema-export tests, then returned artifact SHA-256 9bb05acf2b62ec0dc2fa4bcf76dda10f00c78ea629c5bb82def61709aa0f8bc7. The unedited complete web reference was applied; the bot-owned defaults snapshot was excluded. The generation inputs are semantically unchanged at the current head. Independent byte and semantic audits confirm all 606 schema rows, 536 web-reference rows and 599 MDM properties from the current base are preserved, with only the two Cloud settings added. The four native exports also match the prior CI-generated artifact 13065934303.
  • Fresh independent correctness-first SHIP review covers the complete current-head diff, incoming base integrations, defaults, canonical exports, localization and executed red/green evidence. The review found and this head fixes the attributed-user-origin route. The two earlier human findings are also fixed: no window creates no Cloud machine, and local fallback displays its reason.
  • The current Windows check is a base finding: unchanged cmux-tui sources fail on libc::kill / libc::SIGKILL in meta_save.rs:273. An unrelated branch reproduces both errors. Matching logs and base attribution. The defaults guard passed on attempt 3, accepting the exact-head SHIP receipt after its installation API permission lookup recovered from the rate limit.
  • Localization audit: all 1,492 Settings and 89 Cloud base entries preserved; seven Settings keys and two Cloud keys added across 21 locales. English/Japanese are translated; other locales retain needs_review. No full strict localization audit is claimed.

Focused commands, with exact failing and passing commit references where available above:

cmux-ci run --class light --script scripts/ci/package-test-lane.sh \
  --arg=suite --arg=Packages/macOS/CmuxNext --arg=CloudNewWorkspaceLateStartTests \
  --ref <exact-sha> --key pr26078-<before-or-after>-<sha8> \
  --env CMUX_CI_XCODE_APP=/Applications/Xcode_26.6.app

cmux-ci run --class light --script scripts/ci/package-test-lane.sh \
  --arg=suite --arg=Packages/macOS/CmuxNext --arg=CloudNewWorkspaceEntryTests \
  --ref <exact-sha> --key pr26078-origin-<before-or-after>-<sha8> \
  --env CMUX_CI_XCODE_APP=/Applications/Xcode_26.6.app

The 18-filter selection is CloudNewWorkspaceLateStartTests, CreateTerminalLateStartTests, WorkspaceWithTerminalLateCreateTests, CloudNewWorkspaceTests, CloudNewWorkspaceEntryTests, CloudNewWorkspaceSettingTests, CloudWorkspaceSetupLifecycleTests, CloudSignedOutCreationContinuationTests, CloudVmHostTests, SettingsPageSectionsTests, CloudSignInRecoveryTests, CloudMachineChangeStateTests, CloudMachineChangesPollingTests, CloudStartChatMachineTests, AgentPaneCloudStartTests, AgentPaneNewChatsInSettingTests, ManagedPreferencesManifestTests and SettingsSchemaExportTests.

Not run: live signed-in Cloud creation/folder sync, a new tagged app, a current native capture, optimized Xcode Release compilation, or input-to-frame measurements. Package compilation does not establish optimized Xcode Release coverage. The historical capture below shows the toggle-off workspace view, not the new Settings rows or signed-in creation. No skipped test is claimed as coverage.

Performance

No perf numbers: verification covered opt-in Cloud workspace routing, generated settings, and late-reply correctness. Input-to-frame and live provisioning latency were not measured, so this PR makes no measured latency claim.

Changelog

Added: Run New Workspaces in Cloud (Settings > Machines) gives each new workspace its own Cloud machine, starting in a copy of your current folder or in an empty folder.

Capture

Existing real-app after image from 296d7f0115cc95695c5406e59cd3da3d4adbffff (core tour run); subsequent repair merged the base and refreshed generated exports. This image shows the default-off workspace view, not a signed-in Cloud create or the new Settings rows.

Default-off workspace after image

Viewed after image: yes
Visual verdict: The captured default-off layout is clear enough to sit beside ChatGPT or Claude, with readable navigation and no clipped controls.

🤖 Generated with Claude Code


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