Install dev-mux
"Install" means something different for each role. Pick your role first, then follow the platform steps for that role. With the managed product the hub is provisioned for you — there is nothing to install for the hub role.
Which role am I installing?
- Spoke — a machine that runs your coding agents. Install the
devtooling here. Floor:bash3.2+,tmux,git. - Device — a machine you drive the fleet *from* (laptop, phone, tablet). Use the browser Command Center, the native iPhone app, or the optional
devfterminal client.
If you are unsure: the box where your code and your agents live is a spoke; the box in your hands is a device.
Before you install
The hub reaches your spokes over Tailscale, a private network. Follow the Tailscale setup guide for that connection. A browser can reach a managed hub's public Command Center at https://<your-hub>.dev-mux.com/cc/; Cloudflare sign-in and DevMux device enrollment are separate steps. Native apps and terminal clients need the connection address supplied by your hub owner. A private tailnet address also requires Tailscale on the device.
Install a spoke
A spoke runs the single-file dev script. It needs no heavy dependencies — no databases, no tokens, no secrets. The public one-line bootstrap installs dev, wires the current codebase's hooks, creates a minimal runnable .dev/session.conf when one is absent (and preserves an existing one), and registers the spoke with your hub:
curl -fsSL https://dev-mux.com/install | bash
Answer the prompts for the existing absolute codebase path, its session name, and your hub. After bootstrap reaches done:, local installation and wiring are complete. When you supplied a hub, the adopt path also reports registration accepted; if you left the hub blank, no registration was attempted. The completion output does not claim that the poller or Cockpit can already see the spoke. Verify the finished path explicitly:
dev onboard-check "$PWD" --hub <your-hub-url>
REPO_ROOT="$PWD" dev ls
REPO_ROOT="$PWD" dev up
Then confirm the live session appears in Cockpit. Install your coding agent (for example, Claude Code) before relying on agent-activity reporting. If bootstrap reports a failed hook, config, or registration step, use the manual recovery in Add spokes; do not repeat those commands after a successful run.
Spoke on a Raspberry Pi or cloud VM
The same public one-liner works on a Raspberry Pi, a GCP/AWS/Azure VM, or any Linux box. The floor is identical: bash, tmux, git. No native code runs on a spoke.
Spoke on macOS (Apple Silicon)
A Mac works as a spoke; the hub drives its tmux exactly like a Linux box. One thing to clear on Apple Silicon: Homebrew is not on the non-interactive PATH that a remote command runs under, so surface dev and tmux on a system path:
sudo ln -sf ~/.local/bin/dev /usr/local/bin/dev
sudo ln -sf "$(command -v tmux)" /usr/local/bin/tmux
Keep the spoke's repo on the internal disk (not an external volume) so macOS file permissions do not block the remote session.
Install a device
For the browser Command Center, open your hub's /cc/ address and use the device enrollment link supplied by your owner. No terminal-client installation is required. For an optional desktop terminal client, install devf:
curl -fsSL https://dev-mux.com/dl/install.sh | bash -s -- --role device
export DEV_HUB=<your-hub-host>
<your-hub-host> is your hub's Tailscale name (for example hub.tailnet-XXXX.ts.net). Then run the onboarding helper for your platform, for example devf onboard mac.
Windows (WSL2)
tmux and the dev-mux core run under WSL2 on Windows. The PowerShell installer sets up WSL2, installs the tool inside it, and recommends WezTerm:
./install.ps1 -Role device -Hub <your-hub-host> # or -Role spoke
Then drive the fleet from WezTerm into WSL with devf.
iPhone
The native DevMux iPhone app is a SwiftUI fleet client with a terminal, files, screenshots and session controls. It communicates with the hub over HTTPS/WSS, not SSH. You do not install the spoke tooling or devf on your phone.
- Ask your hub owner for the currently supported app build and installation invitation. TestFlight distribution requires an invitation; an App Store submission does not mean a public listing is available. Use only the distribution link supplied for your build.
- In your cockpit, open Settings and add a device. Choose Show QR code for the iPhone app, or Copy iPhone app link and send the link to your phone privately. The link works once and expires after 15 minutes. This makes the phone one of your own devices, the same as a second browser: no terminal on the hub is needed, and you never copy the hub operator token or a credential from another device.
- Open DevMux. Scan the QR code with the iPhone Camera and tap Open in dev-mux, or paste the link into the onboarding screen and tap join this hub. A link opened from another app asks you to confirm the hub's name before anything is redeemed; a pasted link joins the address inside it, so check that it is your hub's. The credential is stored in Keychain. A hub behind Cloudflare Access, which is how hosted hubs are fronted today, cannot be joined from the app yet: a browser's Cloudflare sign-in does not sign the native app in. The cockpit offers no app link or QR for such a hub, and if a link reaches one anyway the app says the hub is behind a sign-in page it cannot complete and changes nothing. Open the cockpit in Safari on the phone instead, or join over the hub's private (Tailscale) address if it has one. Do not disable the hub's access controls.
- Confirm your codebases load, open a session, and verify its identity before typing.
Sign out is in Settings. It revokes this phone on the hub and removes its notifications, then returns the app to onboarding. The app counts a sign-out as done only when the hub itself confirms it; a redirect to a sign-in page, or any reply that is not the hub's, leaves the phone connected and says nothing was revoked. If an owner removes the phone in the cockpit, the app returns to onboarding by itself the next time it checks. A hub that is merely restarting, throttling or unreachable never counts as a removal. If the hub cannot be reached, Sign out offers to remove the hub from this phone only. That first asks the hub to switch off this phone's notifications and tells you whether it did; the hub still lists the device until it is revoked in the cockpit. If this is the hub's only owner device, the hub keeps its link active (revoking it would leave nobody able to manage the hub), so the phone can only forget it, and coming back needs a new link.
If your hub runs on your own machine, the older route still works: devf enroll ios <device-name> mints a scoped grant that you paste under Connect with a hub address and token instead. A pasted grant cannot receive push notifications, and Sign out cannot revoke a pasted operator token. A pasted grant is also the only way to use the voice (liaison) command plane today: it is tied to an agent grant and its enrolled device key, and a phone joined with a device link (a seat) is not accepted there. If you rely on voice, keep the grant connection on that phone.
Push notifications and Live Activities are disabled unless your build is provisioned for them. Enabling iOS notification permission alone does not enable them. They require an app build with the push entitlement, APNs configuration on the hub, and real-device delivery verification. A phone joined with a device link registers for alerts as its own device; if the hub refuses that registration, Settings says so instead of leaving push silently dead.
If the app says unauthorized, ask the owner to check or replace this phone's grant. If it says unreachable, check the supplied address and your network/Tailscale connection. Do not interpret either message as an empty fleet.
An SSH client remains an optional alternative for terminal-only use with a reachable hub; it is not the native app's installation path:
ssh <your-hub-host>
devf next so
Sessions remain in tmux on the machine where they run; disconnecting a client does not end that work. This is tmux-backed sessions with automatic reconnect, not a special always-on tunnel.
What connects to what
- A device connects to the hub (you drive from here).
- The hub connects to each spoke over Tailscale (this is the reach your hub needs).
- Sessions live in
tmuxon their execution machine (a spoke, or the hub for hub-local work), so clients are free to disconnect and reconnect.
Every convenience tier — cockpit, phone, glasses — is additive. The fleet is fully drivable from the smallest tier alone.
Next steps
- Set up Tailscale so your hub can reach your spokes.
- Add spokes to register machines into your fleet.
- Troubleshooting if a spoke does not show up.