Relay IDE is an agentic development environment for running AI coding agents and terminals from a browser. A Relay hub hosts the web UI; local or remote nodes provide shells, agent CLIs, repo inventory, and tmux-backed session execution. Repos and worktrees are first-class development context, but they are optional bindings on sessions/tabs rather than the definition of a workspace.
Relay's current direction uses this IA vocabulary:
- View — a UI mode or surface.
- Workspace — a saved grouping/config layer for related projects, repos, defaults, and visual organization. It is not synonymous with one repo.
- Project — product/work scope, usually represented by issue/PR/docs context.
- Instance — a concrete local or remote node/repo/worktree occurrence.
- Bench — an arrangement of working surfaces.
- Tab — the leaf working surface: terminal, agent session, file/diff/html surface, PR view, or other active context.
The shipped app is mid-migration toward that vocabulary. Existing repo/worktree flows still matter; new docs and UI copy should describe them as optional context carried by a tab/session.
| Dependency | Why |
|---|---|
| Node.js 24+ | Runtime and build target |
| tmux | Required PTY/session substrate for interactive terminals and agents |
| Agent CLI such as Claude Code, Codex, OpenCode, Hermes | Relay launches configured agent frameworks from the node PATH |
GitHub CLI (gh) |
Optional; used by PR/CI surfaces when available |
| Tailscale | Optional but recommended for private phone/tablet access |
Install the published package:
npm install -g relay-ideStart the hub in the foreground:
relay-ideOr install/start the background service:
relay-ide --bg
# equivalent long form:
relay-ide hub installIf no PIN exists, Relay sets one before accepting traffic: foreground starts with a terminal prompt when stdin is a TTY, while background/non-TTY starts fall back to browser setup. Then open http://localhost:3456. To reset the PIN later, run this on the host from an interactive terminal:
relay-ide pin resetDo not expose Relay directly to the public internet. For phone/tablet use, prefer Tailscale and open http://<tailscale-ip>:3456 from another device on the same tailnet.
From a source checkout:
npm install
npm run devnpm run dev builds the TypeScript backend once, starts the backend as an isolated dev instance on 127.0.0.1:3457, and starts the Vite frontend on 127.0.0.1:5173. Open the Vite URL for frontend HMR; Vite proxies REST and WebSocket traffic to the real backend. Dev instances use separate config/tmux identity but still require the normal PIN/browser-session auth flow.
Useful split commands:
npm run dev:backend
npm run dev:viteWhen developing Relay from inside an already-running Relay instance, use the self-hosting wrapper so the child instance gets isolated config, ports, and tmux names:
npm run dev:selfSee docs/SELF_HOSTING.md for the self-hosting workflow.
The source-of-truth help lives in bin/relay-ide.ts and the built binary. Current command shape:
Usage: relay-ide [options]
relay-ide <command>
Commands:
dev [--self-host] Run backend + Vite frontend with HMR (source checkout)
update Update this single relay-ide package from npm
hub Run the Relay hub web server (same as bare relay-ide)
install Install/start the hub background service
uninstall Stop and remove the hub background service
status Show hub service status
logs Print platform log commands for the hub service
install Back-compat alias for relay-ide hub install
uninstall Back-compat alias for relay-ide hub uninstall
status Back-compat alias for relay-ide hub status
manifest Print local node capability manifest as JSON
node Manage relay-node pairing and diagnostics
status Show local node/service status
logs Print platform log commands
doctor --hub <url> Check hub reachability and local node capability
connect --hub <url> --pair-token <token>
Exchange a pair token and send one heartbeat
install --hub <url> --pair-token <token> [--service auto|manual|launchd|systemd-user|wsl-systemd|wsl-manual]
Pair the node, then install/start the local Relay-managed service when requested/available
link --hub <url> Open and hold the persistent /hub/node-link reverse WebSocket (foreground)
worktree Manage git worktrees (wraps git worktree)
add [path] [-b branch] [--yolo] Create worktree and launch Claude
remove <path> Forward to git worktree remove
list Forward to git worktree list
browser Open an HTML file in the remote viewer
<path> Path to HTML file
pin Manage authentication PIN
reset Reset the PIN (interactive, requires TTY)
Options:
--bg Shortcut: install and start as background service
--port <port> Override server port (default: 3456)
--host <host> Override bind address (default: 0.0.0.0)
--config <path> Path to config.json (default: ~/.config/relay-ide/config.json)
--compact With 'manifest': print compact JSON
--debug-log Enable SDK event debug logging to ~/.config/relay-ide/debug/
--yolo With 'worktree add': pass --dangerously-skip-permissions to Claude
--version, -v Show version
--help, -h Show this help
Global config is stored at ~/.config/relay-ide/config.json. Source dev defaults to a local dev config where the dev scripts set it explicitly.
Common fields:
| Field | Meaning |
|---|---|
host, port |
Hub bind address and port |
cookieTTL |
Auth cookie lifetime |
pinHash |
PIN verifier, created by the app or relay-ide pin reset |
repos |
Explicit repo paths known to the local node |
rootDirs |
Parent directories scanned for repos |
workspaces |
Saved workspace groupings: name, repo membership, order, color, settings |
defaultFramework |
Default agent framework id, for example claude, codex, opencode |
frameworks |
Built-in framework overrides or custom framework definitions |
claudeArgs |
Back-compat/default extra args still used by Claude-oriented flows |
updateChannel |
stable or nightly self-update channel |
github |
Optional GitHub integration settings |
Bare relay-ide and relay-ide hub run the hub web server. A node can pair with a hub, report its local capability manifest, and hold a reverse /hub/node-link WebSocket for routed work:
relay-ide manifest
relay-ide node doctor --hub http://hub.example:3456
relay-ide node connect --hub http://hub.example:3456 --pair-token <token>
relay-ide node link --hub http://hub.example:3456relay-ide node install pairs the node and installs/starts a Relay-managed service when the selected service mode supports it. Bootstrap diagnostics exist for pairing and local capability checks; do not assume every planned remote file/log capability is shipped unless the relevant doc and tests say so.
- Launch tmux-backed agent or terminal sessions from the browser.
- Built-in framework definitions exist for Claude Code, Codex, OpenCode, and Hermes; config can override or add frameworks.
- Session rows carry agent type, cwd/repo/worktree context when available, state, scrollback, and reconnect behavior.
worktree addremains a repo helper and currently launches Claude for the legacy fast path.
- Relay can scan configured roots and explicit repos.
- Git worktree management wraps
git worktreefor add/remove/list flows. - Repo identity and worktree inventory are a feature layer on top of the hub/node core; local paths are node-specific.
- Workspace groups organize repos/defaults/settings, but a Workspace is not the same thing as a repo.
- PR surfaces use
ghand/or GitHub integration state where configured. - GitHub webhooks can be managed through the app when OAuth/webhook config is available.
- Jira integration fields exist for org-dashboard/ticket mapping, but exact behavior should be verified against current integration docs/code before making product claims.
- Browser terminal rendering uses xterm.js; tmux owns process/session durability on the node.
- The frontend is React 19 with Zustand and TanStack Query.
- Vite HMR is available in source dev. Non-dev runtime serves
dist/frontend:npm startrebuilds before starting, but package/global runs (relay-ide) or directnode dist/server/index.jsuse the already-built bundle, so runnpm run buildafter frontend source edits when you are not using Vite HMR.
Install/start:
relay-ide --bg
# or
relay-ide hub installManage:
relay-ide hub status
relay-ide hub logs
relay-ide hub uninstallBack-compat aliases still work:
relay-ide status
relay-ide uninstallmacOS uses launchd. Linux uses user-level systemd where available.
Recommended path:
- Install Tailscale on the hub machine and the client device.
- Sign into the same tailnet.
- Run
tailscale ipon the hub machine. - Open
http://<tailscale-ip>:3456from the phone/tablet/laptop.
Cloudflare Tunnel and ngrok can work, but they place the hub behind a public ingress; use them only when you understand the exposure and PIN limitations.
Start with docs/README.md. It separates current source-of-truth docs from historical plans/spikes so stale implementation plans do not look like shipped behavior.
relay-ide/
├── bin/ CLI entry point
├── server/ Express hub, services, sessions, PTY, node-link, integrations
├── shared/ Shared protocol/types for frontend, server, and node surfaces
├── frontend/src/ React UI, state, hooks, API/WebSocket clients
├── docs/ Current docs plus historical plans/spikes
├── test/ Vitest tests
├── scripts/ Build/dev/postinstall helper scripts
├── dist/ Compiled output (gitignored)
└── package.json
npm test
npm run check
npm run buildUse targeted Vitest files for narrow changes when possible; run the broader gates before PR handoff when the change can affect build, types, lint, or runtime packaging.
Relay is tested on macOS and Linux. Windows is not currently tested; file watching, service management, and PTY spawning may behave differently.
MIT