GitHub - phyra-research/roamux: Run AI coding agents on your own machines. Control them from anywhere.

GitHub

8 min read Original article ↗

Run AI coding agents on your own machines. Control them from anywhere.

Your computer stays the execution host — the agent, your repo, shell, files, git state, credentials, and model access never leave it. A phone or browser signs in and steers the agent live.

Quick start · How it works · Contributing · Architecture

License: MIT TypeScript Runtime: Bun


What it is

roamux is a remote control plane for AI coding agents running on machines you own. Install a small host daemon on any computer; it dials out to the cloud and lets your authenticated devices watch and steer its agents. From your phone you can:

  • see your connected machines and their live agent sessions,
  • start a new session (pick a machine, a project, and an agent) and send tasks,
  • watch activity stream in real time,
  • approve or deny the agent's permission requests,
  • stop a run, and review the files it changed.

Your code never leaves your machine. The cloud routes structured control messages and stores only metadata (labels and ids) — never your files, paths, credentials, or model keys.

Supported agents (bring your own): OpenCode, Claude Code, and Codex. roamux does not implement its own agent — it drives yours through a swappable HarnessAdapter.

Prerequisites

roamux drives an agent you already run locally — it does not ship or proxy a model. So before you start, install and sign in to one of the supported agent CLIs on the machine you want to control (this is where your model access and auth live — nothing leaves the box):

Agent Install Sign in
OpenCode curl -fsSL https://opencode.ai/install | bash opencode auth login
Claude Code curl -fsSL https://claude.ai/install.sh | bash claude (run once, complete the login)
Codex npm install -g @openai/codex codex login

You only need one. If the agent isn't installed or signed in, roamux host refuses to start and prints the exact commands to fix it.

Quick start

On the machine you want to control (macOS or Linux):

# 1. Install the host CLI
curl -fsSL https://remote.phyra.ai/install.sh | sh

# 2. Link it to your account (opens a code — approve it in your browser)
roamux login

# 3. Start it in the project you want the agent to work on, picking the agent.
#    AGENT_ADAPTER defaults to `opencode` — set it for Claude Code or Codex.
cd ~/your/project
AGENT_ADAPTER=claude-code roamux host      # or opencode | codex

Then open the web app on your phone or browser, sign in, pick your machine → New Session → choose the project + agent + a task → Start, and watch it run.

A host serves one agent — whichever AGENT_ADAPTER you launched it with. To offer several, run one host per agent.

File edits: the agent auto-accepts file edits so it can actually do the work (it still won't run destructive shell commands unattended). Point it at a project you're comfortable letting it change — a git repo is ideal.

Keep it running in the background (survives closing the terminal / logout): roamux service install

CLI

Command What it does
roamux login Link this machine to your account (device authorization)
roamux host Start the host daemon and serve your agents
roamux service install Install the host as a background service (launchd / systemd)
roamux service status / uninstall Manage the background service
roamux help · roamux version Usage / version

Configure via env: AGENT_ADAPTER=opencode|claude-code|codex picks the agent (default opencode), DEFAULT_PROJECT_PATH=<dir> sets the project (default: the current directory), HOST_NAME=<name> labels the machine.

How it works

Phone / Browser ─▶ roamux Cloud (web + API)        your machine
      │                 │  auth · host & session registry     host daemon ─▶ agent ─▶ model
      │                 │  mints scoped realtime tokens              ▲
      └─────────────── realtime transport (Ably) ─────────────────────┘   (host dials OUT)

Three boundaries carry the whole design:

  • Protocol (packages/protocol) — every message on the wire is a versioned, Zod-validated envelope. No raw internal objects, ever.
  • Transport — how bytes move, behind one interface: a local WebSocket relay for development, and Ably in production. Swappable.
  • HarnessAdapter (packages/agent-adapters) — how a runtime is driven. Agent-specific code lives only inside its adapter; the rest of the system speaks one normalized event vocabulary.

Security invariants (enforced in code and tests):

  • the agent runtime binds to localhost only;
  • the host dials out — nothing local is exposed via an inbound port;
  • routing is authenticated and scoped per user, so one account can never reach another's machines;
  • there is no arbitrary remote shell — clients send a small set of explicit, validated commands, never shell strings or filesystem paths;
  • repos, credentials, env vars, and model keys never cross the wire.

Full write-ups, with diagrams, in docs/architecture.md (the as-built local slice) and docs/beta-architecture.md (the multi-host, hosted design of record).

Use it from an AI client (MCP)

Besides the web app, roamux exposes its control surface as an MCP server — so you can drive your hosts straight from an MCP-capable chat client (Claude desktop/mobile, ChatGPT, …). The chat app becomes the UI; roamux routes the commands to the agent running on your machine. It's additive — the web app is unchanged, and an MCP client can do only what a browser session can (the same small, validated command set).

Claude / ChatGPT ──▶ https://remote.phyra.ai/api/mcp ──▶ Ably ──▶ your host ──▶ agent
     (MCP client)         (roamux MCP server, OAuth)        (scoped per user)

Step by step

Before you start: you need a roamux account and a host already linked and running — do the Quick start first (roamux login + roamux host). Sign in to the MCP client with the same account that linked the host, or the client will see none of your machines.

1. Get your host id. Easiest: just ask the client "list my roamux hosts" — the roamux_list_hosts tool returns each machine's id + status. (Or copy it from your machines list at remote.phyra.ai.)

2. Add roamux as a connector in your client:

  • Claude (Settings → Connectors → Add custom connector):
    • URL: https://remote.phyra.ai/api/mcp
    • Save. Claude opens a sign-in window — log in with the same roamux (GitHub) account as your host. No keys to paste.
  • ChatGPT (Settings → Connectors → Create / add MCP server):
    • URL: https://remote.phyra.ai/api/mcp, auth: OAuth → sign in.
  • Any other MCP client: add a remote/HTTP MCP server at that URL; it auto-discovers the OAuth flow.

3. Chat to drive your agent. In a new conversation, try — pasting your real host id:

Using roamux, list the projects on host <your-host-id>.

then:

Start a claude-code session on that host in the roamux-demo project, and have it
create a file hello.txt that says "hello from Claude". Then show me the activity.

The agent runs on your machine and writes the file there — you're steering it from the chat app. Follow up with "what's the latest activity?" to watch a long run, or "stop that session" to halt it.

Nothing came back / "no projects"? Almost always an account mismatch — the client is signed into a different roamux account than the one that linked the host. Confirm the host appears in your machines list at remote.phyra.ai under the same account you used in the client, and that the host is running.

The tools

Tool Does
roamux_list_hosts your linked machines + their ids/status (remote server only)
roamux_list_sessions sessions on a host
roamux_list_projects approved projects + installed agents (valid start_session inputs)
roamux_start_session start a session for a project + agent
roamux_send_prompt send an instruction to a session
roamux_get_activity poll a session's recent activity
roamux_stop_session stop a session
roamux_respond_permission allow/deny a permission the agent is waiting on

There is no generic "run anything" tool — the surface mirrors roamux's closed command set. A local stdio variant (for Claude Desktop on the same machine) also ships; see apps/mcp/README.md. Self-hosting the remote server: see DEPLOY.md + apps/mcp/REMOTE-DESIGN.md.

Repository layout

apps/
  host/    the daemon + `roamux` CLI. Runs on the user's machine, dials out,
           owns sessions. Compiles to a single binary.
  relay/   local-dev WebSocket router (not used in production — Ably replaces it).
  web/     Next.js — the mobile-first control UI + API + auth. Deploys to Vercel.
packages/
  protocol/        Zod envelopes, commands/events, the Transport interface, channels.
  agent-adapters/  HarnessAdapter + OpenCode / Claude Code / Codex + a mock for tests.
  db/              Postgres schema, migration runner, typed repositories.
docs/              architecture and design docs.

Development

You do not need any cloud accounts to develop. The fastest path:

bun install
bun run dev        # relay + host (mock agent) + web at http://localhost:3000

Full guide — local database, real agents, running the test suite — in CONTRIBUTING.md. Before opening a PR:

bun run check      # typecheck + lint + tests — must be green

Tech stack

TypeScript (strict) · Bun · Next.js · Zod · Ably (realtime) · Supabase (Postgres + auth) · deployed on Vercel.

Contributing

Contributions are welcome. Start with CONTRIBUTING.md for setup, and CLAUDE.md (aliased AGENTS.md) for the working agreement every contributor — human or AI coding agent — follows. Keep bun run check green and never weaken a security invariant silently.

License

MIT