Cloud link service desktop: the machine creator's view of its agent display

Merged
TE
1d ago
+777-58

Link service desktop: the owner's view of a Cloud machine's agent display (cmux.rd/1), carried over the existing Native link. Part of the Cloud desktop end-to-end build (W1 #36433 host on the socket, W3 #36416 image units).

Leo, 2026-11-05: "Also go check in on the state of affairs of screen sharing remotely on these machines, like the cloud machines, because there was so much VNC work. But it's also like, I feel like it wasn't really linked up end to end here, and we have an opportunity quite soon to start doing that. [...] And then it became AI computer use!!"
Leo, on cmux#36080: "is that really necessary? can't you both do it at the same time?"
Leo: "don't stick it into dev. Put it into prod".

Who may reach desktop

Only the machine's creator, through their own install, on a machine that serves a desktop. Four checks, each enough on its own:

  1. Mint (cloud.machine.link_token, cmux-platform companion PR): desktop only when the caller created the machine (an install principal, never an agent token or a teammate, whatever the team's cloud.connectServices says) and the machine is Native with daemon capability link-desktop-v1. connect_info never lists desktop (older clients parse that list strictly), so the mint is its only authority.
  2. TeamDO dial authority (cloud-native-dial.ts): desktop passes only when CloudDO names the caller as desktop_owner; it needs no VM firewall port (it rides the link stream). The recheck after signing applies the same rule.
  3. Receiving policy (cloud-vm-receiver-peers.ts): desktop is added only to the creator's own (non-server) peers, and only when CloudDO says the machine serves it.
  4. Receiver (cmux-link NativeTokenVerifier): a desktop stream needs a token naming desktop and vmk: owner, and a policy peer that lists desktop. A policy renewal that drops it ends a live desktop stream.

The capability gate matters: a receiver before this PR refuses a whole receiving policy that names an unknown service (cmux-host receiver.rs peer validation), so the platform must never list desktop for an older image. cmux-host advertises link-desktop-v1 in its bind and status daemon block only when the image installed /etc/systemd/system/cmux-agent-rd.socket (a recorded daemon.json never decides it).

No backend env flag: the gate is the machine's own record (its daemon capabilities, set by bind and status reports), per machine and never per provider.

What changes

  • Protocol: LinkService gains desktop (max 3), CloudVmReceiverPeer.services too; CLOUD_DESKTOP_CAPABILITY = "link-desktop-v1". Catalog, TS client and Rust wire regenerated with catalog:export, catalog:client, catalog:rust (fleet), not by hand.
  • cmux-link: Service::Desktop; one cloud_services rule for tokens and policy peers (1 to 3 of daemon/ssh/desktop, unique; never owner_session); desktop requires an owner token.
  • cmux-host: maps the wire desktop to Service::Desktop, accepts it in policy validation, advertises link-desktop-v1 from the image's socket unit.
  • Receiving dispatch (cmux-tui link/host_inbound.rs): an admitted desktop stream connects /run/cmux-rd/desktop.sock and splices bytes; a missing or refusing socket closes the stream with the refusal line reason: DesktopUnavailable, check: desktop_unavailable.
  • Dialer: cmux link dial --service desktop; the Cloud broker accepts up to three services; a desktop dial skips the connect_info list check (the mint decides). Help text and spec/cli.md updated.

Where the boundary is (and what the socket mode is for)

The receiver that admits link streams is not root: cmux-host.service is User=root (web/scripts/cmux-vm-image/host-agent.ts), but cmux link __receive-vm is a child of the session daemon (link/daemon_entry.rs -> native_supervision.rs), which the root host starts as the work user cmux (cmux-host linux/spawn.rs select_layout + daemon_command setuid). The image also gives cmux ALL=(ALL) NOPASSWD:ALL (web/services/vms/images/workUser.ts:52), and the agent display :99 itself runs as cmux, so the agent can already see and drive it directly.

So the image's desktop socket is SocketGroup=cmux, 0660 (W3 #36416), with the rd host's --peer-uid the cmux uid (W1 #36433), and this dispatch connects it directly. A root-only socket the receiver cannot reach would keep the desktop off production and protect nothing. The boundary against other people is the link admission above (one-time, owner-only token; creator-only peer service; capability gate). A root-mediated open (root cmux-host passes the receiver a connected fd over root_bootstrap) becomes a follow-up only once agent sessions lose sudo, coordinated with the owner of #36176, which is reworking the same receiver code.

Tests

  • cmux-link: native_token_receiver_admits_desktop_only_for_an_owner_token_and_a_desktop_peer (owner admitted once; team/kindless token, daemon/ssh-only peer, cross-service, repeated and owner_session lists refused, no jti spent on refusal); native_receiving_policy_accepts_desktop_and_refuses_invalid_service_lists; native_receiver_desktop_stream_ends_when_the_policy_drops_desktop; dial hello wire shape.
  • cmux-host: vm_receiver_client_read_maps_a_desktop_peer_service (plus refusal of duplicates, desktop+daemon without ssh, unknown); the_desktop_capability_follows_the_images_socket_unit.
  • cmux-tui: a_valid_desktop_hello_reaches_the_desktop_socket_and_splices_bytes, a_desktop_hello_on_a_machine_without_the_socket_is_refused_as_desktop_unavailable; dial CLI and broker cases.
  • Backend: cloud-native-dial.test.ts "the desktop link service" (creator with desktop owner admitted, no port needed; refused without a desktop, to another member, to an agent token and a service key; recheck fails when the owner changes); owner-network-rpcs.test.ts (creator's peer gets desktop only with the flag; another member's never; desktop needs no port).

Verification (fleet)

  • catalog:export, catalog:client, catalog:rust run on the fleet; bun run catalog:check clean (222 cloud ops).
  • Backend: vitest on cloud-native-dial, owner-network-rpcs, cloud-connect, cloud-link-install-kinds and cloud-bind-vectors: 5 files, 69 tests passed.
  • cargo fmt --all --check clean; cargo clippy -p cmux-link -p cmux-host -p cmux-tui --all-targets -D warnings clean.
  • cargo test -p cmux-link: all suites pass (113 tests); cargo test -p cmux-host --lib cloud::: 166 passed; cargo test -p cmux-tui --lib link::: 265 passed, including both desktop dispatch tests.

Changelog

Added: cmux link dial --service desktop reaches a Cloud machine's agent display for the machine's creator, on machines whose image serves it.

Deploy

cmux-platform companion: manaflow-ai/cmux-platform#865

  • cmux-platform (the live cloud.machine.link_token mint and cloud.vm.network_policy): manaflow-ai/cmux-platform#865 re-vendors this PR's protocol at the merged commit; its ci.yml deploys development, staging and production on push to its main.
  • cmux-api TeamDO (cloud-native-dial.ts, cloud-vm-receiver-peers.ts): backend.yml deploys development and staging on push to feat-cmux-next, production on target=promote (HQ skills/infra/cloud-api-promote). Until then the platform's desktop_owner/desktop fields are ignored and desktop is refused: safe in any order.
  • VM side (receiver, capability, dispatch) ships with the next image pin of cmux-tui; until a machine reports link-desktop-v1, nothing grants desktop to it.

Agent session: agent session

🤖 Generated with Claude Code


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


Summary by cubic

Adds desktop as a Cloud link service so a machine's creator can reach its agent display over the link, restricted end to end to their own identity and to machines that serve it.

Access control

  • The token mint, TeamDO dial authority, receiving peer list, and receiver each require the caller to be the machine's creator; desktop is never listed in connect_info, so the mint is its only authority.
  • The machine's image must install the desktop socket unit (cmux-agent-rd.socket) before the daemon advertises link-desktop-v1; the capability gate is per machine, never per provider.
  • A policy renewal that drops desktop ends a live desktop stream, and a desktop token requires vmk: owner.

Dispatch

  • An admitted desktop stream connects /run/cmux-rd/desktop.sock and splices bytes; a missing or refusing socket closes the stream with desktop_unavailable.
  • cmux link dial --service desktop is now accepted, and the cloud broker accepts up to three services (daemon, ssh, desktop).