cmux-cloud-vm

Contributors

GitHub-linked commit authors for this SKILL.md at the saved revision. Co-authors and history before file renames are not included.

File history ↗

Route work to cmux Cloud machines from the plain `cmux vm` CLI (alias `cmux cloud`): route/run/agent pick a machine, `vm tree` and `surface ls` catalog This Mac and cloud surfaces, and open, exec, transfer, workspace, terminal, port, checkpoint, and domain operations share the same app paths. Use when an agent should run builds, tests, servers, desktop/browser tasks, or another agent on a cloud machine, or when the user says "cloud machine", "cloud VM", "run it in the cloud", "cmux vm", or "cmux cloud".

skills/cmux-cloud-vm/SKILL.md

Download bundle ↓
main · 6f118af5 bundle filesScanned 2026-09-15

references/sidebar-parity.md

3,639 tokens · o200k_base · 13,841 bytes

Sidebar ↔ CLI parity (1:1)

Every verb in the Cloud sidebar has a CLI verb that goes through the same socket method and the same app code path (SurfaceCatalog, the machine's CmuxTuiSurfaceProvider). An agent can do anything a person can do from the sidebar, and a sidebar action never does something the CLI cannot. Ids come from cmux vm tree --json / cmux surface ls --json (<machine>/<kind>/<key>, ws_…, term_…).

Sidebar (human)CLI (agent)Socket methodVerified
Machines panel + / palette "New Cloud Machine…" (name, Base size; Create closes the sheet and the create runs in the background)cmux vm new [--desktop|--base] [--size 4g|8g|16g|24g|32g|64g] [--name <label>] [--focus false] [--detach] [--json] — the sheet passes --focus false; vm ls --jsonlimits.memoryOptionsMb supplies its choicesvm.create✅ the pending row in the tree ("Creating…", then failure with Retry / Show Error / Dismiss) is MachineCreateCoordinator; --detach is the agent's way to get the same non-blocking outcome without a workspace
Open Base / Set Up Base (first setup closes its sheet immediately and continues in the background)cmux vm base open [--desktop|--base] [--focus false] — the sheet passes --focus falsevm.base_open✅ pending row reads "Setting up Base…"
Control bar › Open Cloud Agent (Claude/Codex/OpenCode)cmux vm prompt --open <agent>vm.cloud_agent_open✅ installs the bundled cmux-cloud skill file (~/.config/cmux/skills/cmux-cloud.md), opens a local agent terminal with the kickoff prompt
Control bar › Copy Cloud Promptcmux vm promptvm.cloud_prompt✅ prints the same prompt (skill path on stderr) — bootstraps ANY agent/harness
Machine row › Open Shell / clickcmux surface new-terminal --machine <m> (into the current workspace, like the row) · cmux vm open <m> [--workspace <ref>] (a shell, its own workspace by default)vm.terminal_new / workspace.cloud_vm_terminal_ready
Machine row › New Workspace, Workspaces +cmux vm workspace new <m> [--name n]vm.workspace_new
Machine row › Open Desktop, VNC Displays › Open Desktop, screen row click (one row per screen, display:1, …)cmux vm open <m>:desktop / cmux surface open <m>/display/display:1vm.desktop_open / surface.project
Machine row › Open Full cmux-tui Clientcmux vm tui <m>(pane command)
Machine row › Refresh, any group › Refreshcmux vm tree --refresh / cmux surface ls --refreshvm.tree {refresh}
Machine row › Rename…cmux vm rename <m> <label>vm.rename
Machine row › Statuscmux vm status <m> (+ vm stats)vm.status / vm.stats
Machine row › Checkpoint (only when capabilities.snapshot)cmux vm snapshot <m> [--name n]vm.snapshot✅ hidden on providers that cannot; vm ls --jsoncapabilities
Machine row › Fork (only when capabilities.fork)cmux vm fork <m> [--name n]vm.fork✅ hidden on providers that cannot
Machine row › Delete…cmux vm rm <m>vm.destroy
Terminals / Workspaces group › New Terminalcmux surface new-terminal --machine <m> [-- <cmd>]vm.terminal_new
Workspace row › New Terminal Herecmux surface new-terminal --machine <m> --remote-workspace <ws>vm.terminal_new {workspace_id}
Workspace row › Go to Workspace (the open verb's label once the workspace is showing locally), click, Returncmux workspace select <local-id> (the local workspace from vm tree --json projections)workspace.select✅ one open verb; never opens a second copy
Workspace row › Open Workspace (not open yet), click, Returncmux vm workspace open <m> <ws> — every member of the workspace (terminals, browsers, pinned displays) as its own local workspacevm.workspace_open✅ resolved exactly like the row (ws_… id or an unambiguous name; every view counted, so a terminal viewed in two workspaces opens from both); an empty workspace opens nothing (D9) — the CLI says so and names cmux vm open <m>/<ws> — and with the machine screen's geometry: split directions, divider ratios and the tabs of each pane come from the daemon's LayoutDocument (screens[].layout), so what the agent arranged in the cloud is what appears; a workspace with no layout falls back to one pane per terminal (right/down alternation)
(no menu verb — one terminal, not the whole workspace)cmux vm open <m>/<ws> — the workspace's focused/first live terminal, or a new shell in it when nothing is runningsurface.project / surface.new_terminal✅ same id-or-unambiguous-name resolution; this is the verb that creates in an empty workspace
(no menu verb — drop onto the current pane)cmux vm workspace open <m> <ws> --here [--workspace <local>]vm.workspace_open {here}
(no menu verb — CLI placement only)cmux vm workspace open <m> <ws> --tabs [--pane <p>]vm.workspace_open {here, placement: tab}
Drag a workspace row onto a pane edgecmux vm workspace open <m> <ws> --pane <p> --left|--right|--up|--downvm.workspace_open {here, pane_id, direction}
Workspace row › Close Workspace…, hover × (confirms when it has terminals)cmux vm workspace rm <m> <ws>vm.workspace_delete✅ same CloudTreeNodeActions.deleteWorkspaceAndTerminals: kills every terminal viewed there, then closes it — a closed workspace never leaves stray pool rows
(no menu verb — CLI only)cmux vm workspace close <m> <ws>vm.workspace_close✅ the protocol's keep-terminals close: they keep running (only terminal close kills) and, their workspace being gone, show in Terminals greyed as "detached"
Workspace row › Rename…cmux vm workspace rename <m> <ws> <name>vm.workspace_rename✅ same SurfaceCatalog machine-scoped rename lane
Terminal row / tab view › Rename…cmux vm tab rename <m> <tab> <name> or cmux vm terminal rename <m> <term> <name> ("" clears the custom label)vm.tab_rename / vm.terminal_rename✅ exact placement or explicit all-views fan-out through SurfaceCatalog
Workspace or item row › Pin / Unpin, Move Up / Move Down, drag between siblingscmux vm tree --sidebar list, then cmux vm tree --sidebar pin|unpin|up|down <node-id> or before|after <node-id> <target-id>vm.tree {sidebar: true, action, node_id?, target_id?}The catalog's organization store owns Mac-local persistent order and pins. Row IDs come from --sidebar list; moves stay within one group and pin section and do not mutate daemon layouts or sessions.
Workspace row › Copy Workspace IDcmux vm tree --json (remote_workspace.id)vm.tree
Terminal / browser / display row click, Opencmux surface open <resource> (reuses an open pane) / cmux vm open <m>/<ws>/<term>surface.project
Row › Open in New Tabcmux surface open <resource> --pane <p> --tabsurface.project {placement: tab}
Row › Open in New Pane (a second pane)cmux surface open <resource> --newsurface.project {reuse: false}
Drag a row onto a pane edgecmux surface open <resource> --pane <p> --left|…surface.project {pane_id, direction}
Terminal row › Kill Terminal…, hover ×cmux vm terminal close <m> <term>vm.terminal_close✅ also closes every local pane showing it
Terminals › detached row (greyed, "detached": still running, no tab on the machine shows it, so it is in no workspace folder); click re-attaches it in a pane, right-click › Kill Terminal…cmux vm tree lists it in the final terminals/ section, under its (detached — …) subgroup (remote_views: [] in --json), cmux surface open <m>/terminal/<term> / cmux vm terminal close <m> <term>surface.project / vm.terminal_close
Row › Copy Surface ID / Copy Portcmux surface ls --json (id, port)surface.ls
Port row (when shown) clickcmux vm open <m>:port/<n> / cmux vm open <m> <n> [--print]vm.port_open
(no menu verb — the workspace's shape as data)cmux vm layout export <m> <ws>vm.exec → in-VM cmux layout export✅ the same LayoutDocument the row renders, in the cmux new-workspace --layout / cmux layout get schema
(no menu verb — an agent builds the workspace the row will open)cmux vm layout apply <m> <file> [--name n] [--open]vm.exec → in-VM cmux layout apply, then vm.workspace_open for --open✅ builds panes/splits/tabs on the machine; --open is exactly the row click
(no menu verb — project secrets)cmux vm env set|ls|rm <m> …vm.exec → in-VM cmux env✅ machine-local, sourced by every shell cmux starts
(no menu verb — CLI only)cmux vm pause <m> / cmux vm resume <m>vm.pause / vm.resume✅ parks and wakes a machine; the sidebar shows the state
(no menu verb — agent-only)cmux vm terminal wait-exit|output <m> <term> …vm.terminal_wait_exit / vm.terminal_output✅ exit code and full output stream, headless

Rules that keep it 1:1:

  • One machine, many workspaces; four groups. A machine is the big box; its cmux-tui workspaces are rows under it, never machines of their own. Under a connected machine, in this order: Workspaces (always its own row — with one workspace, with none, a "No workspaces yet" line under it — so its +, cmux vm workspace new, is one click away; a workspace row shows its own name, never a folded "Workspaces / name" breadcrumb, and lists exactly its layout: the terminals with a tab in it, its browsers, its screen), Ports, VNC Displays (one row per screen), and last, its own section, Terminals (every terminal resource the machine owns, one row per identity, badge = daemon tabs, detached ones greyed; always present so its + is New Terminal, "No terminals yet" under it when empty). cmux vm tree prints the same sequence — workspaces, ports, one row per VNC display, then the final terminals/ section (with its detached subgroup); the Terminals section is the sidebar's flat index of what those lines already name. A daemon browser with neither a workspace tab nor a port has no group of its own.
  • A mirrored local workspace edits its machine workspace. A local workspace bound to a machine workspace (vm workspace open, workspace.cloud_vm_bind) is that workspace's view: moving a pane into it re-parents the tab (tab.move; a pool terminal gets a tab with terminal project), closing a terminal pane in it closes the tab (tab.close: the terminal detaches, only terminal close kills), and closing the local workspace (⌘⇧W, window close) leaves the machine workspace untouched. Viewer panes in unbound workspaces never touch the layout (CloudPlacementCoordinator).
  • A workspace folder is its layout. A terminal whose tab in the workspace closed (or whose workspace closed with vm workspace close) has left the workspace: no row lingers under it. It keeps running on the machine, so the Terminals group still lists it, greyed as "detached", where a click re-attaches it and Kill Terminal… ends it. Exited records with stale unresolved tab ids remain ordinary exited rows, not detached ones.
  • A sidebar verb is implemented as a closure in CloudTreeNodeActions that calls the catalog/provider; the matching socket handler in SurfaceSocketCommands calls the same catalog/provider method. Adding a sidebar verb without a socket method is a parity bug.
  • --focus false means the same on vm new, vm base open, and vm open: open the surface where it belongs, never select its workspace or move keyboard focus out of the workspace the person is in (a pane is still focused when its workspace is the one already on screen). The New Machine / Set Up Base sheets always create this way; the success notification's click goes to the new workspace.
  • Placement flags mean the same everywhere: --pane <p> + side = split that pane on that side; --tab / --tabs = tabs in that pane; nothing = the focused pane of the current (or --workspace) local workspace; --new = never reuse a pane that already shows the surface.
  • Ports are a first-class group in the tree when a machine exposes listening ports; the CLI and sidebar use the same port-open path. A canonical browser/port:<n> resource stays in the owning machine's Ports group even when the daemon also reports it inside a cloud workspace, where the workspace pointer uses the same resource id.
  • Agent-only primitives (cmux vm terminal send|read|waitvm.terminal_write|read|wait, plus exec, push, pull, route, run, agent, layout export|apply, env) have no sidebar verb by design: a person does those things by typing into a pane or by arranging panes. They still go through the machine's CmuxTuiSurfaceProvider, so what an agent types headlessly shows up in every pane projecting that terminal.

Existing machine-to-machine links are agent-only: the source machine's in-VM cmux vm shim uses the remote-daemon verbs without a control-plane credential. This build cannot create new peer grants; the old vm link enrollment broker is not part of the trusted private-network listener flow. Inside a machine the shim also speaks the Mac's own spellings for its local session (cmux send-key, cmux terminal send|read|wait, cmux new-workspace, cmux layout …, cmux env …, cmux tree), so an agent in the cloud drives its machine — and, through a link, a peer machine — with the verbs it already knows from the Mac.

Referenced from SKILL.md
Source excerpt starting at line 133.
`cmux vm workspace new|open|rename|close|rm` and `cmux vm terminal close|send|read|wait` are the machine's cmux-tui session verbs; ids come from `cmux vm tree`. `workspace rm` is the sidebar's "Close Workspace…" (kills the workspace's terminals); `workspace close` is CLI-only and keeps them running in the Terminals pool. Every sidebar action has a CLI verb over the same socket method — [references/sidebar-parity.md](references/sidebar-parity.md).
Source excerpt starting at line 198.
| [references/commands.md](references/commands.md) | Every verb, alias, flag, `--json` shape, exit code, socket method, and the sidebar action it mirrors — plus the "In flight" list of verbs that exist only in open PRs || [references/sidebar-parity.md](references/sidebar-parity.md) | Every Cloud-sidebar action and the CLI verb that does the same thing (1:1) || [references/agent-workflows.md](references/agent-workflows.md) | Recipes: cloud dev box, routed agents, headless terminal loops, parallel forks, desktop/browser tasks, showing the human |
Source excerpt starting at line 444.
| [references/commands.md](references/commands.md) | Exhaustive `cmux vm` command list with examples || [references/sidebar-parity.md](references/sidebar-parity.md) | Every Cloud-sidebar action and the CLI verb that does the same thing (1:1) || [references/agent-workflows.md](references/agent-workflows.md) | Recipes: cloud dev box, routed agents, parallel forks, desktop/browser tasks, showing the human |