Skip to content

cloud: let Cloud VMs notify the owning Mac over the private network - #11641

Closed
lawrencecchen wants to merge 4 commits into
mainfrom
feat-vm-host-listener
Closed

lawrencecchen wants to merge 4 commits into
mainfrom
feat-vm-host-listener

Conversation

@lawrencecchen

@lawrencecchen lawrencecchen commented Sep 2, 2026 •

Copy link
Copy Markdown
Contributor

Machines have no public ports and no path back to the Mac, so agent hooks inside a Cloud VM never reached the Mac's notifications. This adds the reverse path over the WireGuard private network the Mac already joins (cmux vpn up, #11602), with no new Freestyle feature and no public listener.

Mac side. Off by default; Settings > Cloud "Notifications from machines" or cmux vpn notifications on. While on, signed in, tunnel up, and at least one machine owned, the app binds TCP on its tunnel addresses only (never a wildcard), so the port disappears with the utun. Each request must come from the network CIDRs, carry the per-machine token the Mac minted, use one of the notification/status verbs in VMHostAccessPolicy.allowedMethods, and name only workspaces bound to that machine. Same wire protocol as the local control socket, different gate (TerminalController+VMHostClient.swift).

Machine side. On link connect the Mac writes /etc/cmux/host.env (endpoint, token, bound workspace) and puts a journal hook on the daemon over the link. The hook runs cmux-tui host-forward per agent.* event, which maps the event to workspace.status.set and notification.create on the Mac. Exit 1 = Mac unreachable, dispatcher retries. Turning the feature off rewrites the env file with an empty endpoint.

Tests: VMHostAccessPolicyTests, VMHostListenerCoordinatorTests (Swift Testing), host_forward unit tests in cmux-tui (9 pass on a Blacksmith testbox, clippy clean for touched files).

Not covered: OSC 9 notifications from guest processes, surface-level verbs, and an offline Mac. See docs/cloud-cmux-tui-daemon.md.


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.


Summary by cubic

Lets Cloud VMs notify the owning Mac over the private WireGuard network, so VM agent notifications and status reach the Mac. Previously machines had no public ports and no path back; the Mac now listens only on its tunnel addresses, and the feature is off by default (Settings > Cloud or cmux vpn notifications on).

  • Listener runs only while enabled, signed in, tunnel up, and the account owns at least one machine.
  • Enabling refreshes the machine inventory, and missing tunnel network metadata self-heals by re-asking the control plane once per tunnel-up episode, writing only network.json.
  • An unreachable Cloud service now surfaces as cloud_unreachable with the error text in the CLI and vm.host_status, instead of a misleading "not signed in"; cancelled fetches stay silent, and until the first fetch lands the status reads "still checking".
  • Requests must come from network CIDRs, carry a per-machine token, use allow-listed verbs, and target only workspaces bound to that machine.
  • Each linked machine gets /etc/cmux/host.env and a journal hook that runs cmux-tui host-forward, mapping agent.* events to workspace.status.set and notification.create; turning the feature off rewrites the env file with an empty endpoint.
  • Not covered: OSC 9 notifications from guest processes, surface-level verbs, and an offline Mac.

Written for commit 0ba128c. Summary will update on new commits.

Review in cubic

@vercel

vercel Bot commented Sep 2, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
cmux166 Canceled Canceled Sep 3, 2026 10:12am UTC
cmux41 Canceled Canceled Sep 3, 2026 10:12am UTC

@coderabbitai

coderabbitai Bot commented Sep 2, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

Next included review available in 1 minute.

Check out review usage here.

View limit details

Limit 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.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Team

Run ID: e6081d70-c8da-4433-ac7c-0ad623c03c67

📥 Commits

Reviewing files that changed from the base of the PR and between f277fe6 and 0ba128c.

📒 Files selected for processing (33)
  • CLI/CMUXCLI+VPN.swift
  • CLI/cmux.swift
  • Packages/macOS/CmuxSettings/Sources/CmuxSettings/Keys/CloudMachinesCatalogSection.swift
  • Packages/macOS/CmuxSettings/Sources/CmuxSettings/Keys/SettingCatalog.swift
  • Packages/macOS/CmuxSettingsUI/Sources/CmuxSettingsUI/Navigation/CuratedSettingEntry+Default.swift
  • Packages/macOS/CmuxSettingsUI/Sources/CmuxSettingsUI/Scene/SettingsWindowScene.swift
  • Packages/macOS/CmuxSettingsUI/Sources/CmuxSettingsUI/Sections/CloudMachinesSection.swift
  • Resources/Localizable.xcstrings
  • Sources/AppDelegate+CloudVMWorkspaces.swift
  • Sources/AppDelegate.swift
  • Sources/Cloud/CloudMachineLinkManager.swift
  • Sources/Cloud/CloudTuiCommandLine.swift
  • Sources/Cloud/MachinesPanelViewModel.swift
  • Sources/Cloud/VMClientSocketCommands.swift
  • Sources/Cloud/VMHostAccessPolicy.swift
  • Sources/Cloud/VMHostForwardHook.swift
  • Sources/Cloud/VMHostListener.swift
  • Sources/Cloud/VMHostListenerCoordinator.swift
  • Sources/Cloud/VMHostTokenStore.swift
  • Sources/Cloud/VMTunnelManager.swift
  • Sources/TerminalController+RemoteRelayAuthorization.swift
  • Sources/TerminalController+VMHostClient.swift
  • Sources/TerminalController+WorkspaceCreate.swift
  • Sources/TerminalController.swift
  • cmux-tui/crates/cmux-tui/src/cli.rs
  • cmux-tui/crates/cmux-tui/src/cli/command.rs
  • cmux-tui/crates/cmux-tui/src/host_forward.rs
  • cmux-tui/crates/cmux-tui/src/main.rs
  • cmux.xcodeproj/project.pbxproj
  • cmuxTests/VMHostAccessPolicyTests.swift
  • cmuxTests/VMHostListenerCoordinatorTests.swift
  • cmuxTests/VMTunnelManagerTests.swift
  • docs/cloud-cmux-tui-daemon.md

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

The Mac listens on its WireGuard tunnel addresses only (VMHostListener),
gated by a per-machine token, the VPC CIDRs, and an allow-list of
notification and status verbs scoped to workspaces bound to the machine
(VMHostAccessPolicy, TerminalController+VMHostClient). Off by default;
Settings > Cloud and 'cmux vpn notifications on' turn it on.

While listening, each linked machine receives /etc/cmux/host.env
(endpoint, token, bound workspace) and a journal hook on its cmux-tui
daemon that runs 'cmux-tui host-forward' per agent.* event. The guest
command turns the event into workspace.status.set and
notification.create on the Mac.
…n enable

A Mac enrolled before network.json existed never listened
(network_metadata_missing) until the user re-ran 'cmux vpn up' with sudo.
The coordinator now re-asks the control plane once per tunnel-up episode
through the idempotent enrollment call and writes only network.json, config
untouched. Turning the feature on also refreshes the machine inventory so a
stale 'not signed in' clears without another surface refreshing it.
Tests import CmuxControlSocket for ControlRequest.
Until the first inventory fetch succeeds the coordinator only guesses at
sign-in; a backend that cannot be reached now surfaces as cloud_unreachable
with the client's error text, in the CLI and in vm.host_status.
…loud

Turning the feature on schedules a fresh inventory fetch, which cancels the
one in flight; the cancellation surfaced as 'cancelled' and flipped the
status to cloud_unreachable. Cancelled fetches now stay silent, and until
the first fetch lands the status says it is still checking instead of
guessing 'not signed in'.
@lawrencecchen

Copy link
Copy Markdown
Contributor Author

Superseded. The design inverted: the Mac dials the VM over the existing state feed, and the VM's cmux-tui daemon owns notifications with per-client read state. Part 1 is #12108 (daemon side); the macOS consumer follows as part 2 and will be linked here.

@lawrencecchen

Copy link
Copy Markdown
Contributor Author

Part 2 (macOS consumer): #12112

This branch was successfully deployed

2 active deployments
Preview – cmux166 — 0ba128c0 Deployed Sep 3, 2026 by vercel[bot]
Preview – cmux41 — 0ba128c0 Deployed Sep 3, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant