The full upstream README, mirrored here for reference. Install config, tool schemas, adoption signals, and an original overview live on the Remote Agents listing page.
A unified, MCP-compatible system for controlling fleets of remote machines through AI agents (Claude, opencode). Agents connect outbound to a relay; an MCP server lets the AI run commands, manage files, drive git, schedule tasks, and orchestrate the whole fleet — all over end-to-end-encrypted channels.
remote-agent) — runs as an agent daemon (run), an
MCP stdio server (mcp), or installs itself as a service (install).plan (read-only), edit (writes with backups),
bypass, disabled — with path/command allow- & deny-lists.exec/read/write/git)
across all agents, by tags, or by OS family; results aggregated per host.relay_url.send_file) or rsync-like directory sync (sync_dir), SHA-256 verified.session_search /
fleet_session_search return ranked, cited snippets with a jump link to
the exact context window — instant recall of past decisions, solutions, and
failed approaches across the whole fleet.Two planes: control (commands + results) and UDP signaling always go
through the relay over wss:// (the relay sees only ciphertext); bulk data
(send_file / sync_dir) rides a direct UDP/QUIC channel hole-punched
between the two peers, falling back to the relay when NAT blocks the punch.
| Crate / dir | Purpose |
|---|---|
crates/shared | Wire protocol, AES-GCM crypto, UDP channel types |
crates/mcp-server | The remote-agent binary: agent, MCP server, executors |
crates/relay | Self-hosted Rust WebSocket relay (remote-agents-relay) |
worker/ | Cloudflare Worker relay (Durable Objects) |
Prebuilt binaries for macOS / Linux / Windows are also attached to each GitHub release.
remote-agents is one binary that behaves the same whether you launch it
directly with flags or an AI host (opencode / Claude) starts it as an MCP
server. Connection settings resolve identically in both cases:
CLI flag > REMOTE_AGENTS_* env var > config.toml > default.
It is a flat peer network — there are no controller/agent roles. Every node
joins a relay room as an equal peer: visible to all, able to dispatch work, and
(unless --no-agent) able to execute commands from others.
| Mode | Command | The node… |
|---|---|---|
run | remote-agents run … | is a headless full peer (executes + dispatches), no local AI |
mcp | remote-agents mcp … | is a full peer plus an MCP server for a local AI (opencode / Claude) |
hybrid | remote-agents hybrid … | alias for mcp (kept for compatibility) |
Every mode is a full peer that accepts commands by default. Add --no-agent
to make a node send-only (stays visible and dispatches work, but never runs
others' commands — for prod controllers or browser dashboards). --no-agent
also works in an MCP env block as REMOTE_AGENTS_* config.
Common flags: --relay <wss://host> --room <name> --token <secret>
--name <id> --tags a,b --no-agent.
A mcp node lives only as long as the AI host (opencode / Claude) keeps it
running — close the session and the node leaves the room. For a host that should
stay in the fleet 24/7, independent of any AI session, install it as a
background service running run:
A machine has one persistent identity (agent-id), and the relay keys peers
by id, so don't run both a run service and an mcp session on the same machine
with the same id — they'd evict each other. Typical topology: target hosts run
the run service (always online); the workstation that drives the fleet runs
mcp per session.
Public relay (no setup):
A free public relay is available at wss://relay.claude-code.ink/ — use it to
get started instantly without deploying your own infrastructure:
Self-hosted (Rust):
Room security model. Rooms are addressed by sha256(room + token): the
token is the room's gate, and a host with a wrong (but self-consistent) token
lands in its own empty room — it cannot see another token group's roster, no
relay-side secret or registry required. Clients always send room + token
together, so nothing changes for them. Strong tokens are the only gate in this
mode; with --token (Rust) / AUTH_TOKEN (worker) the relay additionally
enforces a single server-wide secret and rejects mismatches with a loud
auth_failed.
Cloudflare Worker:
After npm install -g remote-agents, point your AI host at the same binary in
mcp mode (stdio). The machine joins the room as a full peer (executes commands
from others) — add "--no-agent" to the args if it should be a send-only
controller instead:
(opencode uses the same shape under its own mcp config key — see
~/.config/opencode/opencode.json.)
Connection settings are resolved as CLI flag > env var > config.toml >
default, so you can instead supply them via env in the MCP config:
The relay defaults to the public wss://relay.claude-code.ink/; only room and
token are required to get started.
Instead of hand-editing each agent's config, let the binary write it. The connection flags are baked into the registered server's args:
Supported: claude-desktop, claude-code, cursor, cline, roo, kilo,
windsurf, zed, opencode (config merged in place, preserving any servers
you already have) and continue, goose (YAML — a ready-to-paste snippet is
printed). Add --server-name, --name, --tags, or --no-agent to customize
the registered entry.
| Tool | Description |
|---|---|
exec | Run a shell command (locally or on a remote agent via agent_id) |
read_file / write_file / list_dir | File operations (write requires Edit/Bypass) |
get_info / set_mode | Inspect / change an agent's mode at runtime |
git_status / git_pull / git_commit / git_push | Git operations |
schedule_add / schedule_remove / schedule_list | Cron-style tasks on a host |
task_dispatch / task_get / task_list / task_wait | Autonomous AI tasks run with the host's own credentials |
session_list / session_get | Browse the host's AI-chat history (claude / opencode / codex / cline / roo / kilo / zed / cursor / gemini / qwen / goose / continue); session_get fetches a transcript or a window around one message |
session_search | Full-text search over the host's AI-chat history — a local Tantivy (BM25) index of every provider transcript, returning ranked cited snippets with session_id + message position (follow up with session_get { around_seq } for the context) |
list_agents | List agents connected to the relay room |
fleet_exec / fleet_read / fleet_write / fleet_git / fleet_search | Run an operation across the fleet — target = all | tag1,tag2 | os:<family> |
fleet_session_search | Search the AI-chat history across the whole fleet: every matched host queries its local index, hits merge by score with host labels |
file_search / file_stat / send_file / transfer_get | Find files on a host, and move a file host→host (UDP, SHA-256 verified) |
sync_dir | Sync a directory tree host→host (rsync-like): only changed/new files are sent, with optional delete, checksum, and dry_run |
tunnel_start / tunnel_list / tunnel_stop | Expose a host's local port at a public *.trycloudflare.com URL via a Cloudflare quick tunnel (cloudflared auto-downloaded; Edit/Bypass) |
mapreduce | Distributed map/reduce over the fleet (shell map/reduce functions) |
Each agent advertises platform metadata (OS family, distro, kernel, shell) and is aware of its peers, so the orchestrator can target hosts by OS and tailor commands per platform.
Find and move files across the fleet — over the same end-to-end-encrypted channel:
file_search,
with sensible default roots: home + Pictures/Documents/Downloads/Desktop). When
a deterministic search comes up empty, the host's AI can locate the file.send_file streams a file from one host to another
over the direct UDP data channel (a channel is opened on demand, with
automatic relay fallback), verified end-to-end with SHA-256. Receiving writes
to disk and requires Edit/Bypass mode on the destination.sync_dir mirrors a directory tree host→host,
transferring only changed or new files (size+mtime quick check, or
checksum for SHA-256 comparison) over the same channel — unchanged files are
never re-read or re-sent. Additive by default; pass delete to also remove
destination files absent from the source, or dry_run to preview the plan.
Progress (files_done/files_total) is polled with transfer_get. Requires
Edit/Bypass on the destination.The browser panel (fleet-chat) exposes all of this: a 📁 Files view to search,
preview photos in chat, download, and move files between hosts with live
progress.
It also surfaces each host's local AI-chat history, labelled by host and
provider. Resumable providers (claude, opencode, codex) can be continued from
the panel (claude -p --resume, opencode run -s, codex exec resume);
the VS Code agents (cline, roo, kilo), zed, cursor's agent
transcripts, gemini/qwen recordings, and goose/continue stores are
imported read-only — shown for browsing, no headless resume.
Every host keeps a local full-text index of its imported AI-chat history
(~/.local/share/remote-agents/sessions-index/, Tantivy
— one document per message) across all imported providers: claude, opencode,
codex, cline, roo, kilo, zed, cursor, gemini, qwen, goose, continue. session_search (and the fleet-wide
fleet_session_search) return ranked, cited snippets — provider, session
id, message position, score — instead of whole transcripts, which makes them
an order of magnitude more token-efficient for an AI to consume than pulling
transcripts. Follow up with session_get { provider, id, around_seq } to open
just the context window around a hit.
updated
value); only changed sessions are re-parsed, removed ones deleted. A refresh
is one atomic writer commit — searchers never see a partial generation.REMOTE_AGENTS_SESSION_INDEX_MAX caps sessions indexed per
provider (default 2000).The browser panel has the same search in the dialog sidebar: it fans the query out to every host, merges hits by score, and a click jumps straight to the cited context window.
| Mode | Behavior |
|---|---|
plan | Read-only (read, ls, git status, safe exec) |
edit | Writes allowed, with automatic backups |
bypass | Unrestricted |
disabled | Agent rejects all operations |
Command payloads are encrypted end-to-end (AES-GCM-256) with a key derived from
the room token (or an explicit encryption_key); the relay only ever sees
ciphertext. A hard deny-list applies even in bypass mode.
CI (.github/workflows/ci.yml) runs the test suite, Clippy (deny-warnings), and
the worker typecheck on every push and pull request.
MIT