Chief: use the user's Cloud machines, and offer cmux Pro when a create needs it

Merged
AU
10d ago
+26402-22025

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 and Cloud machines. A shipped chief-cloud-machines skill (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 own cmux (cmux cloud exec), and drive its Linux desktop with cua-driver, pulling screenshots back with cloud file-read. The skill forbids building tunnels, bridges or local ports, and says older notes that do are out of date.
  • cmux Pro. A create refusal that names cmux Pro (upgradeRequired on /api/vm, or the app server's plan_required) is a typed CloudAPIError.planRequired, and the person sees one "Cloud machines need cmux Pro" dialog whoever asked (click, CLI, Chief).
  • Open Desktop (cmux cloud open-desktop --target machine:<id>, palette and the machine menu's Connection submenu): the machine's noVNC page in a Chromium tab at http://<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.
  • Tunnel hardening (VPN parity, plans/cmux-next/cloud-tunnel-protection.md). wg hub --client-token-stdin serves 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 a 127.0.0.1:16901 bridge; the two hubs knocked each other off and the desktop's mouse froze. Classic's cmux vpn up Network Extension is not ported (a product decision; see the note). The one tokenless lane is port 22, for base's cmux wg dial ssh route (cloud enroll-machine).
  • Development-build viewers (the remote view pane is DEBUG-only): --viewer native, the app's VNC client over RFB-in-WebSocket (WebSocketRFBTransport) on the same tunnel; --viewer rd, Lawrence's cmux-rd host (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

  • Fleet Swift suites at 5777e8c1 (step 23952-cloud-5777e8c1, all 9 green): CloudHubLoopbackTests, CloudLinkReconnectingTests, CloudAPIClientPlanRequiredTests, CloudCreationProOfferTests, CloudCLITargetTests, ActionSurfaceParityTests, ActionSurfaceExportTests, RemoteViewTabPolicyTests, RemoteViewVNCTests. CmuxVNC WebSocketTransportTests and EndToEndTests green (step d0261167).
  • Rust on rbx at 6a36de6c: cmux-remote wireguard_hub_e2e 3/3 (a tokenless and a forged client are refused at the real hub), socks 4/4, cmux-tui hub/stdin flags 6/6, optchat-chief all green.
  • Dev build 23952-chief-cloud-machines (jobs 1aceaabc at 5f8b8bbc and the 5777e8c1 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

  • Not observed: a --viewer rd frame 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 native was not seen streaming on a VM.
  • Not run: the Chief first-turn cost guard.

No capture: the visible changes are a standard CmuxDialogSpec dialog (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


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with 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.

  • Ships a chief-cloud-machines skill and one prompt line: find machines with cmux cloud list-machines, create with cmux cloud new-machine (the app's Create card still asks the person), run commands and the machine's own cmux via cmux cloud exec, and drive the Linux desktop with cua-driver. The desktop helper makes its folder with exec (cloud file-mkdir makes 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's paid-plans skill: a checkout (a billing checkout link) 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).
  • New Open Desktop action (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 default web viewer loads the machine's noVNC page in a cmux browser tab; --viewer native and --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 Rust cmux-rd host (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). A via=cloud record 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 by cloud enroll-machine) reaches port 22, which authenticates both ends itself, and lets a same-user program with the user's ssh key carry ssh -L to the machine's loopback services.
  • A create refusal that names cmux Pro is now a typed CloudAPIError.planRequired: upgradeRequired on /api/vm with no other plan named (not a credits top-up), or the app server's plan_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 code cloud.plan.required and 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.
  • The shipped skill list now holds five in install order, cmux-adoption and paid-plans beside the new skill.

Testing

  • CloudAPIClientPlanRequiredTests stubs the server's own free-plan 402 body and checks .planRequired; a Pro budget naming Max and a paid plan's limit stay .http.
  • CloudCreationProOfferTests checks the flow offers Pro once for a Pro refusal or the app-server plan_required, never for an ordinary refusal or an agent's create.
  • CloudHubLoopbackTests checks 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).
  • WebSocketTransportTests checks 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.
  • Rust wireguard_hub_e2e checks that a tokenless and a forged client are refused and ssh's tokenless exception works.
  • The desktop loop was walked on a dev Cloud machine through the tagged build's CLI: diagnostics, exec, the machine's own cmux, the helper install, launching Chrome, a click that navigated, and the screenshot round trip.
  • The shipped-skill test now expects the new skill; not run yet are the full CmuxNext and optchat-chief suites and the tagged dogfood.