Repository navigation
Chief: use the user's Cloud machines, and offer cmux Pro when a create needs it - #23952
Conversation
…e needs it Chief gets a shipped `chief-cloud-machines` skill and one prompt line: it finds the user's Cloud machines with `cmux machine list`, creates one with `cmux cloud new-machine` (the app's Create card still asks the person), runs commands and the machine's own `cmux` through `cmux cloud exec`, and drives the desktop with cua-driver (one helper step per exec, the screenshot pulled back with `cloud file-read`). The loop is the one verified on classic Chief (b7284a8), moved to cmux next's Cloud actions. A create the plan does not include (`upgradeRequired` on the /api/vm refusal, or the app server's plan_required) is now a typed `CloudAPIError.planRequired`, and the creation flow shows the person one "Upgrade to cmux Pro" dialog whoever asked (a click, the CLI or Chief); Upgrade opens the pricing page. A paid plan's ordinary limit stays a plain HTTP refusal. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
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)
Not verified: macOS jobs did not run: compile and app tests were skipped on CI passes on Written by web and size checks: green |
|
Found 5 test failures on Blacksmith runners: Failures
|
- Chief lists machines with `cmux cloud diagnostics` (every Cloud machine, paused ones too, by the Cloud id `--target` takes); `--target` also takes the `machine_…` id `cmux machine list` prints for a connected one. - The Pro offer is only for a refusal that names Pro (`upgradeRequired` with no other `upgradePlanId`, not a credits top-up): a Pro user's budget that names Max stays an ordinary error. The dialog's body is the server's localized reason, Upgrade opens its cmux.com link, one offer shows at a time, and a failed open is logged. - The skill reads fields under `.result`, runs the machine's own cmux with HOME=/home/cmux, creates the log directory before a detached job, and notes that a --command cannot start with `--`. - CloudCreationProOfferTests: the flow offers Pro once for a Pro refusal or the app server's plan_required, never for an ordinary refusal. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review and verificationThe review is a correctness-first subagent review, run twice: on First pass (
|
|
Bead |
Conflicts: the shipped Chief skill list (optchat-chief src/skills.rs and tests/auth_escalation_brain.rs) now holds the base's cmux-adoption and paid-plans beside chief-cloud-machines, five in install order. chief-cloud-machines defers to the base's paid-plans skill: after a create refused for cmux Pro, the app's Upgrade dialog is the offer, and Chief starts a checkout only when the user asks or no dialog could show. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Walking the skill on a dev Cloud machine found that `cloud file-mkdir` makes a root-owned folder (the Cloud file API runs as root) the cmux-user cua-driver daemon cannot write its screenshot into, and that cua-driver exits 0 on "Capture error: Permission denied". The skill now makes the folder with exec (the machine's cmux user), and the helper removes the old screenshot and fails when no new one was saved. Verified on the dev backend machine through the tagged build's CLI: cloud diagnostics, exec, the machine's own cmux (workspace and terminal list), the helper install, launch_app (Chrome on example.com), a background click that navigated to iana.org, and the screenshot round trip (1440x900 PNG). Also from review: the app server's plan_required shows the dialog's own localized copy, the diagnostics jq tolerates an empty report, and the skill says an "unverifiable" click is checked by title or screenshot. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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. |
…ext-chief-cloud-vms
A Chief subagent showed a machine's desktop by starting a second cmux-tui wg hub on the app's WireGuard config and a local port bridge to its noVNC. The second hub on one key fought the app's own link (the desktop reconnected whenever the app touched the machine), and the bridge gave the machine's unprotected VNC to every program on the Mac. The skill now forbids both and sends screenshots until cmux has a live view. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nnel cmux Classic shows a Cloud machine's desktop in a cmux browser pane whose traffic goes through the app's userspace WireGuard tunnel. cmux next had no way in, so a Chief subagent improvised a second `cmux-tui wg hub` on the app's key and a local port bridge to noVNC: it reconnected whenever the app touched the machine (two hubs on one key) and handed the machine's unauthenticated VNC to every program on the Mac. Open Desktop (`cloud open-desktop`, palette and the machine's menu) opens a "<machine> Desktop" workspace on this Mac whose Chromium tab loads the machine's noVNC (6901 on its loopback). Its pane is marked as that machine's before the tab loads, so remote localhost routes it: the peer-checked proxy (only cmux's own Chromium) opens the stream with the new HubLoopbackOpener, SOCKS5 over the app's CloudTunnelHub socket (the tunnel enrolled for this Mac with POST /api/vm/tunnel) to the machine's private address. No port opens on the Mac. A Cloud machine whose cmux-tui predates the loopback forward takes the same route for its own tabs. Chief's skill uses Open Desktop to show a desktop and still forbids any hub, tunnel or bridge of its own. CloudHubLoopbackTests: a stand-in hub checks the SOCKS5 CONNECT to the machine's address and port, echoes bytes through the tunnel, a hub refusal is refused, and a non-loopback host never dials. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…losure crashed the compiler's diagnostics) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review of ba13b9b: the pane mark lived only in memory, keyed by a daemon pane handle that does not survive a daemon restart, so a relaunched desktop tab loaded this Mac's 127.0.0.1:6901 and a reused handle could send an unrelated local tab to the Cloud machine. The desktop page's URL now names its machine, `http://<machine id>.cloud-desktop.localhost:6901/vnc.html`: a name under `.localhost`, loopback by the remote-localhost rule. Remote localhost routes that URL to the machine over the app's tunnel whatever pane or daemon holds it, through relaunches, moves and hibernation; no state. - configureBrowser no longer turns a nil configuration (a blocked proxied tab, a route that cannot start) into the default store: the page stays blank (TabContentCache.chromiumConfiguration), never on this Mac's localhost. - The hub route is Open Desktop's only; Cloud machines whose cmux-tui lacks the loopback forward keep "update machine" for their own tabs. - HubLoopbackOpener: one deadline over the whole open, and the SOCKS5 reply is read by its ATYP (IPv4, IPv6 or a name) so none of it reaches the page. - Copy says "no TCP port opens on this Mac"; skills/cmux-cloud-vm lists `cloud open-desktop`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review of b00c7ea: pasting or following an Open Desktop URL in a tab of this Mac loaded this Mac's port 6901 (the profile store had no guard) while the badge named the Cloud machine. The shim's store guard gets mode 3, any URL but an Open Desktop page (`*.cloud-desktop.localhost`), and this Mac's tabs take it instead of "any". Such a navigation is cancelled and reported as rerouteStore, and the page comes back in the machine's store over the app's tunnel. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…a later shadowing let made the bind closure capture it before its declaration) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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. |
…efaults to the main actor, so its accept thread tripped the runtime isolation check) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… of rerouting forever The shim's IsCloudDesktopHost refuses any *.cloud-desktop.localhost page in the ordinary store (exceptCloudDesktop). Swift's routing is stricter (one DNS label, this Mac's tabs only), so for a host it could not route (a_b., x.y., a trailing dot, or a remote tab whose localhost is this Mac on purpose) it chose that same store, the guard fired on the new browser's first load and TabContentCache.reroute rebuilt it again, endlessly; a web page could trigger it. RemoteLocalhostStorePlan.blank: such an address gets no page. isCloudDesktop now drops a trailing dot like the shim, so the two agree. Regression: CloudHubLoopbackTests.aDesktopAddressThatCannotRouteOpensBlankNotAReroute (red at c3da2a8: no .blank; green on this commit, fleet run below). Found by the independent review of 0263369. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ext-chief-cloud-vms # Conflicts: # Packages/macOS/CmuxNext/Sources/CmuxNextApp/Cloud/CloudMachineCreateFlow.swift
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. |
|
Review of 0263369 (independent subagent, correctness first): FIX, with one blocker.
Lows (not fixed here, none blocking):
Re-review of 61265ff: SHIP at 61265ff. It checked every Chromium configuration path: creation, reroute, hibernated wake, duplicate, history, popups and ChromiumNewTabNow. Each ends blank or in the right store, and the Swift and shim host checks now agree. Then I merged origin/feat-cmux-next (8711a8c), giving head ea69bc6. The one conflict was |
…o card feat-cmux-next made the upgrade card person-only; this PR's planRequired hook still opened the Pro dialog for a Chief or CLI create the server refused (app-server mode, or before the plan limits load). Fails until the fix: CloudCreationFlow has no startedByPerson. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
feat-cmux-next made the upgrade card person-only ("the person is not
prompted on every agent request"), but this PR's planRequired hook still
opened the Pro dialog for a Chief or CLI create the server refused (always
in app-server mode, where no limits gate first; in legacy mode before the
limits load). CloudCreationFlow.startedByPerson now gates the hook; the
agent still gets cloud.plan.required with the plan and offers the checkout.
Regression: CloudCreationProOfferTests.anAgentsServerRefusedCreateOffersNothing
(red at d0a17c7: no startedByPerson; green here, fleet run below).
Found by the independent review of ea69bc6.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Review (claude subagent, independent): SHIP at 8f8e081 Review history
Lows (follow-ups, not blocking)
Checks on 8f8e081
Not run: a live Open Desktop |
…ext-chief-cloud-vms Base's `cloud enroll-machine` reaches a machine's ssh through the app's WireGuard hub with `cmux wg dial --hub`, a separate process without the hub's per-launch token. The hub now admits a tokenless client for port 22 only (wireguard_hub::OPEN_PORTS): ssh authenticates both ends itself, and every other port (noVNC, desktop hosts, dev servers, daemon links) still needs the token. socks::server_greet returns a Greeting (Refused, Authenticated, Open) so the hub can narrow an Open client. Conflicts kept both sides: CloudTunnelHub (base's restart watch and hub symlink, this PR's in-memory key and token); CloudMachineLink (vm-kind args plus the token on stdin); CloudMachineCreation and CloudHandlers+Account (base's bootstrap hook, this PR's Pro offer gated on startedByPerson); CloudLinkReconnectingTests (both sides' tests); cmux-tui/spec/cli.md (wg hub flags plus wg dial). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review of b909146: the lane lets a same-user program that can use this Mac's ssh key ssh -L to an enrolled machine's loopback services; say so, and name the narrowing options for 13742. cli.md names the lane. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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. |
feat-cmux-next added CloudAPIError.code (a2f2…, Sandboxed sends) after this PR added .planRequired; the merge compiled only on the fleet build, which failed with "switch must be exhaustive" (job a0fbe73ed6b0). The code is plan_required, as the runs control error answers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Review (claude subagent, independent): SHIP at 0f7afcc What changed since 8f8e081
Reviews
Checks on 0f7afcc
Not run: a live |
…ext-chief-cloud-vms
Default changesThis pull request changes 7 defaults at
Needs a review. It passes with an independent review receipt on this commit: a comment or review whose first line is Merge receipt: merged as Regenerate the snapshot with |
|
The feat-cmux-next push run https://github.com/manaflow-ai/cmux/actions/runs/40626998043 at 0341883 failed: cmux-next generated files. |
|
The feat-cmux-next push run https://github.com/manaflow-ai/cmux/actions/runs/40626020108 at 0ab915d failed: cmux-next checks (god files, concurrency, crash safety, l10n), cmux-next generated files. |
|
The feat-cmux-next push run https://github.com/manaflow-ai/cmux/actions/runs/40627558915 at 47b4dbb failed: cmux-next checks (god files, concurrency, crash safety, l10n), cmux-next generated files. |
|
The feat-cmux-next push run https://github.com/manaflow-ai/cmux/actions/runs/40628944074 at 18af98c failed: cmux-next generated files. |
|
Review (claude subagent, independent): SHIP at 3634d90 This head
Review findings
Checks on 3634d90
Not run: a live |
|
Shipped in:
|
|
Shipped in:
|
![Fix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/fix-with-codesmith-light-3x.png)
Summary
Chief can use the user's cmux Cloud machines from the Mac through the cmux CLI, the app shows a machine's desktop over its own Cloud tunnel, and the tunnel only serves cmux's own processes.
Size: one integration PR by request (the Chief skill, Pro gating, the hub token and Open Desktop share the Cloud tunnel and land together); most of the diff is tests, localization and the design note.
chief-cloud-machinesskill (and one prompt line): list machines (cmux cloud list-machines), create one (cmux cloud new-machine, the Create card still asks the person), run commands and the machine's owncmux(cmux cloud exec), and drive its Linux desktop withcua-driver, pulling screenshots back withcloud file-read. The skill forbids building tunnels, bridges or local ports, and says older notes that do are out of date.upgradeRequiredon/api/vm, or the app server'splan_required) is a typedCloudAPIError.planRequired, and the person sees one "Cloud machines need cmux Pro" dialog whoever asked (click, CLI, Chief).cmux cloud open-desktop --target machine:<id>, palette and the machine menu's Connection submenu): the machine's noVNC page in a Chromium tab athttp://<machine>.cloud-desktop.localhost:6901/….RemoteLocalhostProxy(peer-checked) routes that address by its URL to the machine's private address over the app's WireGuard hub, so no port opens on this Mac; the shim store guard reroutes a desktop URL typed into another tab, and WebKit refuses one.wg hub --client-token-stdinserves only SOCKS5 clients that present a per-launch token (RFC 1929, constant-time compare); link sidecars get it on stdin (remote connect --wireguard-hub-token-stdin). The hub's config (--config -) and the WireGuard key never touch disk: the key is made per app launch and held in memory, each start enrolls its public key and the server rotates the device's peer. Found live: a Chief subagent had copied the key file into a second hub and a127.0.0.1:16901bridge; the two hubs knocked each other off and the desktop's mouse froze. Classic'scmux vpn upNetwork Extension is not ported (a product decision; see the note). The one tokenless lane is port 22, for base'scmux wg dialssh route (cloud enroll-machine).--viewer native, the app's VNC client over RFB-in-WebSocket (WebSocketRFBTransport) on the same tunnel;--viewer rd, Lawrence'scmux-rdhost (H.264 via Cisco's OpenH264, XTest input) over the machine's daemon link (loopback-forward-v1). The rd host is not in the VM image yet.Testing
cmux-remotewireguard_hub_e2e 3/3 (a tokenless and a forged client are refused at the real hub), socks 4/4,cmux-tuihub/stdin flags 6/6, optchat-chief all green.23952-chief-cloud-machines(jobs 1aceaabc at 5f8b8bb and the 5777e8c build) dogfooded on a Freestyle machine: Chief creates and drives a machine; Open Desktop connects through the tunnel; the page moved the VM's pointer to the aimed pixel (xdotool reported 359,222 for 25% of 1440x900); with the key in memory a Chief subagent's attempt at its own SOCKS bridge was refused ("the app's hub refuses no-auth SOCKS").Observed / Not run
--viewer rdframe on screen (the host runs on one hand-set-up machine; one live Connect ended with the app exiting and no crash report, under investigation).--viewer nativewas not seen streaming on a VM.No capture: the visible changes are a standard
CmuxDialogSpecdialog (Pro) and an Open Desktop workspace that needs a signed-in Cloud account with a running machine; the capture minis have neither, so a real capture cannot show them. The dogfood above is on a live machine.Changelog
Added: Chief can create and use your cmux Cloud machines, including their desktop; Open Desktop shows a machine's screen over the app's own Cloud tunnel; a Cloud create on a plan without Cloud offers cmux Pro.
🤖 Generated with Claude Code
Need help on this PR? Tag
@codesmith-botwith what you need.Summary by cubic
Chief can now create and use the user's cmux Cloud machines from the Mac through the cmux CLI, and a Cloud create on a plan without Cloud offers an Upgrade to cmux Pro dialog instead of a bare refusal.
chief-cloud-machinesskill and one prompt line: find machines withcmux cloud list-machines, create withcmux cloud new-machine(the app's Create card still asks the person), run commands and the machine's owncmuxviacmux cloud exec, and drive the Linux desktop withcua-driver. The desktop helper makes its folder with exec (cloud file-mkdirmakes a root-owned folder the daemon cannot write) and fails when no screenshot was saved. After a create refused for cmux Pro, the skill defers to the base'spaid-plansskill: a checkout (abilling checkoutlink) starts only when the user asks or no dialog could show. The skill forbids its own tunnel or port bridge (a second hub on the app's key knocks the app's link off the machine; a local port hands the machine's unprotected VNC to every program on this Mac).cloud open-desktop, palette and machine menu) shows a machine's desktop over the app's own WireGuard tunnel: SOCKS5 on the Cloud hub socket to the machine's private address, with no port opened on this Mac and only cmux's own Chromium allowed through. The defaultwebviewer loads the machine's noVNC page in a cmux browser tab;--viewer nativeand--viewer rd(both DEBUG-only, refused without the remote view pane) show it in the app's own pane — native through RFB inside websockify's WebSocket on the machine's 6901, rd through the machine's Rustcmux-rdhost (H.264) on its private address — with no sign-in sheet and no listener on this Mac; a reader drains the tunnel as it comes, so a burst never drops the session. The pane's card names the machine, says "Connecting through your Cloud tunnel," keeps its session for two minutes after a hidden tab, and reconnects by itself after a lost path (1 s up to 10). Avia=cloudrecord connects for a person's open within 15 seconds and asks first otherwise. The desktop route serves only this Mac's tabs (a remote workspace's tab never dials this Mac's hub), and the page's URL names its machine, so remote localhost routes it by URL through relaunches, moves and hibernation with no stored state; following that URL in any other tab of this Mac reroutes to the machine's store over the app's tunnel (a shim guard keeps the page out of this Mac's store; WebKit tabs cancel the URL, which would load this Mac's loopback), and a route that cannot start leaves the page blank, never this Mac's localhost. The badge matches the machine without case. The hub now requires a per-launch token of every client — one per app launch, made in memory so a restarted hub keeps its running links (SOCKS5 username/password, constant-time compare) — and reads its config on stdin, an earlier build's file copy removed, so the private key never lands on disk and another program of this user that finds the socket gets nothing. The one tokenless exception is ssh:cmux wg dial(used bycloud enroll-machine) reaches port 22, which authenticates both ends itself, and lets a same-user program with the user's ssh key carryssh -Lto the machine's loopback services.CloudAPIError.planRequired:upgradeRequiredon/api/vmwith no other plan named (not a credits top-up), or the app server'splan_required, which shows the dialog's own localized copy instead of the server's English text. Only a person's own create shows the dialog, whose body is the server's reason; Upgrade opens the refusal's cmux.com link and one offer shows at a time. A CLI or Chief create gets no dialog: its answer has codecloud.plan.requiredand ends with(plan: …), and Chief offers the checkout. Refusals naming another plan (Max) stay plain HTTP, and a free-plan gate refusal maps to a Pro refusal already marked offered.cmux-adoptionandpaid-plansbeside the new skill.Testing
CloudAPIClientPlanRequiredTestsstubs the server's own free-plan 402 body and checks.planRequired; a Pro budget naming Max and a paid plan's limit stay.http.CloudCreationProOfferTestschecks the flow offers Pro once for a Pro refusal or the app-serverplan_required, never for an ordinary refusal or an agent's create.CloudHubLoopbackTestschecks the SOCKS5 CONNECT to the machine's address and port, the client token (a wrong token gets an auth failure), byte echoing, a refused or non-loopback connection, and an unroutable desktop address opening blank, not a reroute loop (the stand-in hub now runs off the main actor).WebSocketTransportTestschecks the native viewer's RFB-over-WebSocket stream under a time limit: masked client frames, split server frames, a ping, and a refused or wrong handshake.wireguard_hub_e2echecks that a tokenless and a forged client are refused and ssh's tokenless exception works.Written for commit 3634d90. Summary will update on new commits.