Repository navigation
cmux Cloud: cmux-tui only machines, working create/attach/type/desktop, sized disks, provisioned images (master dogfood PR) - #10831
austinywang wants to merge 59 commits into
Conversation
Plan shape: the free plan now includes one full-size machine (24 GB default and cap — the free machine demos the product; the paywall is the window and the count, not the machine's usefulness) and Pro includes five machines (24 GB default, 32 GB cap). 24576 joins the memory picker options. All numbers stay env-overridable per plan. Free access window: a free-plan machine older than 5 days (CMUX_VM_FREE_ACCESS_WINDOW_DAYS, 0 disables) is preserved but unreachable — attach, ssh, exec, ports, and sessions fail with a 402 vm_access_requires_pro upgrade prompt, while list/status/rename/delete keep working so the machine stays visible and disposable. The gate keys on the caller's CURRENT plan, so upgrading unlocks existing machines immediately. Enforced in one place (requireAccessibleUserVm) that every access workflow shares; the five REST routes thread the caller's plan and map the typed error. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* machines: surface the free access window — countdown rows, locked rows, upgrade routing The list payload now carries freeAccessWindowDays (0 for paid plans) so clients render policy from the wire instead of hardcoding it. The Machines panel mirrors the backend's window math per row: free-plan machines show a days-left countdown in the subtitle, and a machine past the window renders locked — lock glyph in place of the activity dot, Locked in the subtitle, and double-click/context-menu routing to the shared Pro upgrade presenter instead of a doomed connect (the backend still enforces with 402s; the UI just stops walking into them). Rename/Status/Delete stay available on locked rows so the machine remains manageable and disposable. Strings localized en+ja; snapshot window math unit-tested against the backend's boundary behavior. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * machines: flip free-window rows at the boundary itself, not on a poll tick Review follow-up: the countdown/lock facet was only as fresh as the 45s list poll. Expiry is a known future timestamp the client can compute (createdAt + window), so the panel now arms a one-shot timer at exactly the next transition across the fleet — each day-boundary where the label decrements, and finally the expiry — and recomputes the facet locally with no network, re-arming for the next boundary. Rows flip at the moment the state changes; the slow poll is left covering only what genuinely needs the server (machines created or deleted elsewhere). The recompute happens above the lazy-list snapshot boundary, so the panel's snapshot rule (cmux#2586) holds. Boundary math unit-tested. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: cmux reload-cloud <cmux-reload-cloud@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…main After #10781, worktreeDeviceID/worktreeFileID were both defaulted at the declaration and assigned in the explicit init, which the current toolchain rejects ("immutable value may only be initialized once"). The init's parameter defaults keep the same call-site contract. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
vm run routes a command to a cloud machine without naming one: sticky per-directory binding, then an idle agent-pool machine, then a sleeper, then a freshly provisioned pool machine. push/pull move files over the exec channel (base64 chunks, SHA-256 verified, directories as tarballs); wait blocks until ready and optionally wakes the machine. The skill lets any coding agent drive machines from plain CLI. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… progress
Live dogfood on Blaxel: a 512 KiB chunk base64-encodes past Linux's 128 KiB
per-argument limit ("argument list too long"), macOS tar shipped ._* files
onto the machine, and chunk progress ran together when stderr was captured.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…el; review fixes - The router now only drafts machines it provisioned itself (ids recorded in ~/.cmuxterm/vm-run-pool.json at create time, pruned when machines vanish); a user machine renamed agent-pool is never used. Test covers the impostor. - Staging tarball is removed if reading it throws before the defer is armed. - Push/pull chunk progress is localized (cli.vm.push.progress, cli.vm.pull.progress). - vm --help, the usage contract, and the contract doc list open/ports/tools/ handoff/promote-template, which the dispatcher already handled. - Sticky-binding fixture uses a fixed instant, not the host clock. - Skill recipes: --sync runs inside the synced dir (no remote $PWD), port readiness poll instead of sleep, eligibility filter instead of .vms[0], background test exit status captured to a status file. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…recipes - updateVMRunPool does the read-modify-write under flock on a sibling lock file, so two routers provisioning at once both land in the store; covered by a two-process test against two mock sockets. - Dev-server recipe reuses a live server or starts one with a workspace pidfile and log; test recipe uses per-run log/status paths written atomically. - Document that --sync is additive. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…r and use unique run ids - updateVMRunPool/saveVMRunPool throw on lock or write failure and createPoolVM reports the machine it provisioned but could not record, instead of a silent unlocked update. - The dev-server recipe reuses a server only when the recorded pid is alive and owns :3000 (netstat -p), refuses to start a second server on a port someone else owns, and clears stale metadata. - Test-run ids come from uuidgen, not the epoch second. - Skill docs: cmux vm shell is a cmux-tui session now that machines run the cmux-tui remote daemon; agents keep working through vm run/exec. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…-remote (Phase 1) Implements the next open item of docs/cloud-cmux-tui-daemon.md (#10800): every Blaxel machine gets the pinned static-musl cmux-tui (CMUX_VM_BLAXEL_TUI_URL + _SHA256, verified in-VM, installed on the persistent home volume) running `server start --remote-ws` under the sandbox supervisor, with its own private preview. attach-endpoint accepts transport:"cmux-remote" and returns the tokenized /v1/link route plus a single-use enrollment invitation when the caller's device is not enrolled; a new cmux-remote/approve route approves the pending claim the control plane invited. Opt-in per deployment; no change for clients that do not ask. Measured on Blaxel: a WebSocket upgrade with the preview token as a query parameter completes on the raw <hash>.preview.bl.run host but is refused through the vm.cmux.sh custom domain, so the daemon preview is created unbranded. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- `cmux vm tui <id>` and, by default, `cmux vm shell <id>` (which the Machines panel launches) open a workspace whose pane runs the local cmux-tui client against the machine's authenticated /v1/link route; the hidden vm-tui-connect helper hands the terminal to the client and approves the device enrollment through the app socket, remembering the device fingerprint per machine. The websocket attach remains only for deployments without a cmux-tui pin. - Socket methods vm.cmux_remote_info / vm.cmux_remote_approve and the VMClient calls behind them; capabilities list updated. - With the pin configured, new Blaxel machines get cmux-tui only: no cmuxd-remote install or process; the sleep watcher counts cmux-tui's terminal children as work. - Client discovery probes candidates with `remote-probe --json` so the SSH-remote bootstrap's shell wrapper at ~/.cmux/bin/cmux is skipped. - Localized en+ja strings; help, usage contract and docs updated. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…d installs curl Found by creating a machine under the pin: a just-created sandbox 404s its API for a few seconds (the cmuxd path only survived because encoding the Go binary took that long), and a stock blaxel/base-image has no curl until the background provisioning adds it. The first write now retries until the API answers, and the installer adds curl via apk or falls back to busybox wget. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…es the client - The Blaxel driver resolves the daemon build from the artifacts manifest (rolling latest by default, CMUX_VM_CMUX_TUI_MANIFEST_URL to pin a commit, CMUX_VM_CMUX_TUI_ENABLED=0 as the kill switch); the sha256 comes from the manifest, never from env. An installed daemon that no longer matches the manifest is reinstalled on attach. The endpoint reports the daemon's build identity and remote protocol. - scripts/install-cmux-tui-client.sh bundles a universal, sha256-verified cmux-tui client into Contents/Resources/bin like the Ghostty helper; reload.sh, ci.yml and release.yml run it. The CLI looks there first and checks the client/daemon remote protocol before opening a pane, naming the stale side. - cmux-tui-artifacts.yml publishes on main pushes again so latest/ tracks main. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Hosted ingress in front of cmux Cloud machines (CloudFront on the branded vm.cmux.sh domain) refuses upgrades that omit User-Agent, and tungstenite sends none by default, so the daemon route had to fall back to the raw preview host. Direct dials now carry cmux-tui/<version>; no Origin is set because the daemon rejects browser-style upgrades. Unit test covers the header and that the endpoint query (route token, lane) survives. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…oud-dogfood-integration-3 # Conflicts: # web/app/api/vm/[id]/attach-endpoint/route.ts
…nto cloud-dogfood-integration-3 # Conflicts: # Resources/Localizable.xcstrings # cmux.xcodeproj/project.pbxproj # docs/cli-contract.md
Plan shape: the free plan now includes one full-size machine (24 GB default and cap — the free machine demos the product; the paywall is the window and the count, not the machine's usefulness) and Pro includes five machines (24 GB default, 32 GB cap). 24576 joins the memory picker options. All numbers stay env-overridable per plan. Free access window: a free-plan machine older than 5 days (CMUX_VM_FREE_ACCESS_WINDOW_DAYS, 0 disables) is preserved but unreachable — attach, ssh, exec, ports, and sessions fail with a 402 vm_access_requires_pro upgrade prompt, while list/status/rename/delete keep working so the machine stays visible and disposable. The gate keys on the caller's CURRENT plan, so upgrading unlocks existing machines immediately. Enforced in one place (requireAccessibleUserVm) that every access workflow shares; the five REST routes thread the caller's plan and map the typed error. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* machines: surface the free access window — countdown rows, locked rows, upgrade routing The list payload now carries freeAccessWindowDays (0 for paid plans) so clients render policy from the wire instead of hardcoding it. The Machines panel mirrors the backend's window math per row: free-plan machines show a days-left countdown in the subtitle, and a machine past the window renders locked — lock glyph in place of the activity dot, Locked in the subtitle, and double-click/context-menu routing to the shared Pro upgrade presenter instead of a doomed connect (the backend still enforces with 402s; the UI just stops walking into them). Rename/Status/Delete stay available on locked rows so the machine remains manageable and disposable. Strings localized en+ja; snapshot window math unit-tested against the backend's boundary behavior. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * machines: flip free-window rows at the boundary itself, not on a poll tick Review follow-up: the countdown/lock facet was only as fresh as the 45s list poll. Expiry is a known future timestamp the client can compute (createdAt + window), so the panel now arms a one-shot timer at exactly the next transition across the fleet — each day-boundary where the label decrements, and finally the expiry — and recomputes the facet locally with no network, re-arming for the next boundary. Rows flip at the moment the state changes; the slow poll is left covering only what genuinely needs the server (machines created or deleted elsewhere). The recompute happens above the lazy-list snapshot boundary, so the panel's snapshot rule (cmux#2586) holds. Boundary math unit-tested. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: cmux reload-cloud <cmux-reload-cloud@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…-remote (Phase 1) Implements the next open item of docs/cloud-cmux-tui-daemon.md (#10800): every Blaxel machine gets the pinned static-musl cmux-tui (CMUX_VM_BLAXEL_TUI_URL + _SHA256, verified in-VM, installed on the persistent home volume) running `server start --remote-ws` under the sandbox supervisor, with its own private preview. attach-endpoint accepts transport:"cmux-remote" and returns the tokenized /v1/link route plus a single-use enrollment invitation when the caller's device is not enrolled; a new cmux-remote/approve route approves the pending claim the control plane invited. Opt-in per deployment; no change for clients that do not ask. Measured on Blaxel: a WebSocket upgrade with the preview token as a query parameter completes on the raw <hash>.preview.bl.run host but is refused through the vm.cmux.sh custom domain, so the daemon preview is created unbranded. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- `cmux vm tui <id>` and, by default, `cmux vm shell <id>` (which the Machines panel launches) open a workspace whose pane runs the local cmux-tui client against the machine's authenticated /v1/link route; the hidden vm-tui-connect helper hands the terminal to the client and approves the device enrollment through the app socket, remembering the device fingerprint per machine. The websocket attach remains only for deployments without a cmux-tui pin. - Socket methods vm.cmux_remote_info / vm.cmux_remote_approve and the VMClient calls behind them; capabilities list updated. - With the pin configured, new Blaxel machines get cmux-tui only: no cmuxd-remote install or process; the sleep watcher counts cmux-tui's terminal children as work. - Client discovery probes candidates with `remote-probe --json` so the SSH-remote bootstrap's shell wrapper at ~/.cmux/bin/cmux is skipped. - Localized en+ja strings; help, usage contract and docs updated. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…d installs curl Found by creating a machine under the pin: a just-created sandbox 404s its API for a few seconds (the cmuxd path only survived because encoding the Go binary took that long), and a stock blaxel/base-image has no curl until the background provisioning adds it. The first write now retries until the API answers, and the installer adds curl via apk or falls back to busybox wget. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…es the client - The Blaxel driver resolves the daemon build from the artifacts manifest (rolling latest by default, CMUX_VM_CMUX_TUI_MANIFEST_URL to pin a commit, CMUX_VM_CMUX_TUI_ENABLED=0 as the kill switch); the sha256 comes from the manifest, never from env. An installed daemon that no longer matches the manifest is reinstalled on attach. The endpoint reports the daemon's build identity and remote protocol. - scripts/install-cmux-tui-client.sh bundles a universal, sha256-verified cmux-tui client into Contents/Resources/bin like the Ghostty helper; reload.sh, ci.yml and release.yml run it. The CLI looks there first and checks the client/daemon remote protocol before opening a pane, naming the stale side. - cmux-tui-artifacts.yml publishes on main pushes again so latest/ tracks main. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Hosted ingress in front of cmux Cloud machines (CloudFront on the branded vm.cmux.sh domain) refuses upgrades that omit User-Agent, and tungstenite sends none by default, so the daemon route had to fall back to the raw preview host. Direct dials now carry cmux-tui/<version>; no Origin is set because the daemon rejects browser-style upgrades. Unit test covers the header and that the endpoint query (route token, lane) survives. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… in the rebase The pre-rebase toolchain-fix commit had absorbed these cmux.swift hunks when it was amended, so dropping it in favor of main's #10820/#10822 dropped them too: the vm-tui-connect dispatch, tui in every vm usage string and the help block, and the internal access on applyWindowOrCallerContext / setTerminalForegroundProcessGroup that CMUXCLI+VMTui.swift needs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
openVmCmuxRemote and approveVmCmuxRemoteEnrollment resolve the machine through requireAccessibleUserVm with the caller's current plan, and both routes map VmFreeAccessExpiredError to the same 402 upgrade prompt the websocket attach uses, so a free machine past its window is locked on every transport. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Warning Review limit reachedNext included review available in 2 minutes. View limit detailsLimit details: You’ve used all 10 included reviews currently available. You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Review configuration: ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (89)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…ss expires The list payload carries a server-authoritative freeAccessExpiresAt per machine (and the earliest across them). The Machines panel meter uses singular/plural forms, and free plans get a banner under the control bar counting down the 7-day window (expires in 6d 23h / expires today / expired) that opens the existing Pro upgrade flow. cmux vm ls prints the same footer. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…inals, desktop, ports) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…kill teaches agents to route work to machines vm tree shows machines → cmux-tui workspaces → terminals (title, cwd, agent badge, open marker), desktop and ports; vm open addresses any node (<m>/<ws>/<term>, <m>:desktop, <m>:port/<n>) and keeps the <id> <port> form; vm route exposes the machine chooser vm run already uses; vm agent runs Claude Code / Codex / OpenCode / Pi inside the chosen machine's cmux-tui session as a new terminal that shows up in the tree. vm desktop and the shell's desktop split share one path (vm.desktop_open). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The Cloud tab is an NSOutlineView: machine → Workspaces (cmux-tui) → terminals (lifecycle, title, cwd, agent badge, open marker) → Desktop → Ports, with asleep/connecting/error placeholders, persisted expansion, keyboard navigation, per-node context menus, and a com.cmux.cloud-surface.transfer drag that drops a terminal, desktop or port as a pane at the drop position through the same CloudTreeServicing path the CLI uses. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…/terminal_open/terminal_new/desktop_open/port_open/link_socket The app keeps one headless 'remote connect --headless --json' link per awake machine (never waking a sleeping one), reads 'session current snapshot' and follows 'session current events' to build the Cloud tree, and opens a remote terminal locally as a pane running 'attach --terminal <id>'. Bindings between local surfaces and remote terminals make terminal_open reuse an open pane. Deleting a machine now closes its cmux-tui-bound workspace too. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…main-actor isolated Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…p await in the link manager Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This comment has been minimized.
This comment has been minimized.
Restored vm:<id> workspaces keep their WorkspaceCloudVMBinding so workspace(forCloudVMID:), the sidebar cloud button's Base reuse, and vm.terminal_open find the machine's workspace again after relaunch. Only the binding is persisted; the pane's one-shot link is not replayed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Three never-mutated vars and an unused optional binding in CLI/cmux.swift and TerminalController+MobileWorkspaceList.swift, plus the occlusion observer in GhosttyTerminalView calling a main-actor method from its main-queue closure. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…licit full-client attach vm new / base open / shell / fork / restore, the sidebar cloud button and the Machines panel now create a terminal in the machine's cmux-tui session through vm.terminal_new and show it as a single-terminal pane (attach --terminal), like an ssh session — no cmux-tui sidebar or tabs in the pane. vm tree renders link state (connecting / asleep / error) instead of hiding it behind '(none yet)'. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
CI baseline notes (so reviewers can tell this PR's failures from inherited ones): swift-package-tests — app-host unit tests — the four shards were red on every recent Everything this PR introduced that CI caught (missing |
A drag from the Cloud tree now carries the real Bonsplit destination (pane, orientation, insert-first → left/right/up/down, or tab index) through CloudTreeOpenTarget into the same surface.split / surface.create path every other pane drag uses, so dropping on the left edge splits left instead of always splitting right. vm.terminal_open/desktop_open/port_open accept pane_id/surface_id/direction/tab_index. Rows follow the Files sidebar: secondary/tertiary labels and template symbols, one status dot per machine, a single dim 'CPU · Mem · Disk' line instead of colored gauges. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
#10855 added terminal.output_read to spec/resource-operations-v2.json without bumping the frozen count in test_check_resource_api_boundary, so the cmux-tui SDKs and cmux-tui spec checks fail on every merge with main (125 != 124). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…n slot, chevron on the name line Every row lays out as (level+1)×16pt indent → 6pt → 16pt icon slot → 8pt → title, so glyphs form a column and rows without a chevron reserve its slot. Machine rows put the status dot in its own 10pt slot and top-align the disclosure with the name line instead of letting it float between the subtitle lines next to the dot. Trailing markers get a 10pt gap and an 8pt edge. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ts raw id Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Merged as part of #10887 (cloud-surfaces). |
Master PR for cmux Cloud dogfood: machines are cmux-tui only (cmuxd-remote removed from the Blaxel path), the create → attach → type → desktop flow works end to end, and the right sidebar gets a Finder-like Cloud tree (machines → workspaces → terminals / desktop / ports) that people drag into the main view and agents drive through
cmux vm tree/open/route/agent. Folds in the design doc from #10800 and the ancestry of #10812 / #10793 / #10758.What was broken (as dogfooded)
sha256sum -c -s;-sis BusyBox-only and GNU coreutils (the xfce-vnc desktop image) rejects it.vm new/vm base open/fork/restore/ the sidebar button / the Machines panel all went through the legacy cmuxd websocket PTY path; onlyvm shelltried cmux-tui.bl_preview_tokencookie is third-party inside a cross-site frame and WebKit drops it, so every asset and the websockify upgrade 401'd.*.preview.bl.runroutes for the daemon: the branded<machine>.vm.cmux.shingress refuses WebSocket upgrades without a User-Agent.Changes
Backend (
web/)CMUX_VM_BLAXEL_DAEMON_*, no legacy websocket attach, no kill switch. The bare branded host<machine>.vm.cmux.shbelongs to the cmux-tui preview; clients advertisingdirect-ws-user-agentget it, everyone else the raw preview.openAttachon Blaxel → 409vm_attach_transport_unsupportedpointing attransport: "cmux-remote"(/attach-endpointdefault branch and/sessions).instant = false, no nestedhtml/body.CMUX_VM_BLAXEL_HOME_VOLUME_MBstill pins./root, and the CUA driver (cua-computer-server).freeAccessExpiresAt(per machine + earliest).macOS app
com.cmux.cloud-surface.transferdrag that drops a terminal, desktop, or port as a pane at the drop position through the same pane-drop routing every other drag uses.cmux-tui remote connect --headlesslink per awake machine (never wakes a sleeping one),session current snapshot+session current eventsfeed the tree; a terminal opens locally as a plain terminal pane (attach --terminal <id>, no TUI chrome). Surface↔terminal bindings make reopen focus the existing pane.vm.tree,vm.terminal_open,vm.terminal_new,vm.desktop_open,vm.port_open,vm.link_socket— one shared path for the sidebar and the CLI.vm new/base open/fork/restore/shell, sidebar button, Machines panel) goes through one open path; the pane is a plain terminal on the machine;vm tui <id>is the explicit full-client attach.remote-probe --jsoncapabilities forwarded asclientCapabilities; workspaces carry a persisted cloud VM binding (workspace.cloud_vm_bind, saved in the session snapshot).vm ls: "N of 1 machine" on free plans and a "Free cloud access expires in …" indicator (7-day window) that opens the upgrade flow.CLI + agent skill
cmux vm tree [<machine>] [--json],cmux vm open <m>/<ws>/<term> | <m>:desktop | <m>:port/<n>(the<id> <port>form is unchanged),cmux vm route(the machine chooservm runalready uses, exposed),cmux vm agent --agent claude|codex|opencode|pi -- <prompt>(runs the agent inside the chosen machine's cmux-tui session as a new terminal that shows up in the tree).skills/cmux-cloud-vmrewritten: when to run in the cloud, how to pick a machine, run/watch/report back, what a machine contains, and how CodeRouter composes (credentials, not compute).cmux-tui (Rust)
remote-probe --jsonadvertisescapabilities: ["direct-ws-user-agent"].Dogfood
Tagged build
cloud-dogfood-integration-3(fleet-built, bundled cmux-tui client from the branch's artifacts) against the local web stack on :3777. Verified live: create (16 GB volume, provisioning log), brandedwss://<machine>.vm.cmux.shroutes,vm treeacross three machines (workspaces, a running Claude Code terminal, desktop, port 8000), a terminal opened from the tree as a plainvivid-gecko:~#pane, keystrokes delivered, noVNC desktop connected.Summary by CodeRabbit
New Features
Bug Fixes