Documentation · v0.2 · powered by FalkorDB
/.relay docs
/.relay is the coordination layer for AI coding agents. Claude Code, Cursor, Copilot, Codex and Antigravity all write to the same files and none of them know the others exist. /.relay gives them one shared lock table, a dependency-aware view of the blast radius, live patch sync across every machine on the team, and a FalkorDB memory graph that tells every agent who is doing what, and why.
Everything on this page runs on your own hardware. There is no hosted backend and no account server — one person on the team runs relay serve and that machine is the server. The memory graph is optional: one FalkorDB container on the host (or a hosted FalkorDB), and teammates read it through the room.
- 12 agents · 12 blind writers · conflicts discovered at merge
+ 12 agents · 1 lock table · conflicts prevented at the edit
What is in here
| If you want to… | Go to |
|---|---|
| Install the CLI and run it for the first time | Installation → Quickstart |
| Turn on the memory graph (FalkorDB) | Set it up → relay graph commands |
| Set relay up on a second or new PC | A new PC |
| Understand what a lock actually guards | Core concepts |
| Look up a command and its flags | CLI reference |
| Wire a specific agent into the claim/release cycle | Agent hooks |
| Read room context from an MCP client | MCP server |
| Fix an empty board or a broken room | Troubleshooting |
Reading order matters less than you would think — the quickstart is four commands. If you are impatient, jump to Quickstart · Host and come back for the concepts once something is locked.
Get started
Installation
/.relay is a Node CLI plus a local API and the Mission Control board. It is published on npm as relaybrain, with Mission Control prebuilt inside the package.
Requirements
| Status | What | Why |
|---|---|---|
| Required | Node.js 20+, npm | Runs the CLI, the API, and Mission Control |
| Required | git | relay clone shells out to it |
| Optional | gh CLI | Fastest path for relay login |
| Optional | Docker (Desktop on Windows/macOS, engine on Linux) | Runs FalkorDB for the memory graph on the host. Skip it with a hosted FalkorDB, or as a room guest |
| Optional | A tunnel: Cloudflare (no account), ngrok, or Tailscale | Only needed for cross-machine rooms |
| Not needed | A hosted backend, an account, a database on guest machines | Coordination state lives in files on your disk |
Install the CLI
$ npm install -g relaybrain # puts `relay` (and `relaybrain`) on your PATH
Or from source, if you want to hack on relay itself:
$ git clone https://github.com/prakrititz/relayBrain
$ cd relayBrain
$ npm install # deps for the CLI, API and Mission Control
$ npm link # puts `relay` on your PATH
Confirm the binary resolves:
$ relay help
Relay — Version control for AI agents
relay login Sign in with GitHub (uses gh CLI, or device flow if GITHUB_CLIENT_ID is set)
relay logout Clear the local session
relay whoami Show the signed-in GitHub user
relay clone <url> [dir] git clone + register workspace + install agent hooks
relay add <path> Attach an existing local repo
relay init [path] Wire hooks, MCP, and relay-os instructions (default: cwd)
relay serve Start the API and Mission Control on 127.0.0.1:3001 (prebuilt UI, fast start)
relay serve --no-ui Start API + coordinator only
relay serve --dev Run Mission Control with next dev on :3002 (hot reload, slow first load)
relay push Send your dirty working-tree files to the shared room
relay pull Apply the host's current dirty files onto this clone
relay status Health check
relay mcp-url Print the MCP config for this room's shared context endpoint
relay doctor Why the Coordinator board is empty (run it on the machine that sees nothing)
relay graph <cmd> Memory graph (FalkorDB): up | enable [url] | disable | status | stats | rebuild [id|all]
npm install -g and npm link write to your global npm folder. If your Node install lives under a system path you may need elevated permissions, or an nvm/fnm-managed Node — which is the friendlier option. Install globally rather than with npx: agent hooks point at the installed files, so they need a stable path.
Get started
Quickstart · Host
The host is the machine that owns the lock table — and, with the memory graph on, the room's graph. Exactly one person on the team is the host; everyone else is a guest. A handful of commands and you are live.
Sign in with GitHub
Locks are attributed to a GitHub identity, so the board can say @pony holds this file rather than agent-4f2 holds this file.
$ relay login
This reuses the gh CLI session. If gh is not installed, set GITHUB_CLIENT_ID and /.relay falls back to the GitHub device flow.
Bring a repository under /.relay
Cloning through relay clones the repo, registers the workspace, and installs the claim/release hooks for every supported agent in one shot.
$ relay clone <repo-url> [dir]
Already have the repo on disk? Attach it in place instead — same hook install, no re-clone:
$ relay add /path/to/repo
Turn on the memory graph (optional)
Start Docker Desktop first, then:
$ relay graph up # FalkorDB in Docker on localhost:6379
$ relay graph enable # save the URL and switch relay onto the graph
No Docker? Use a hosted FalkorDB instead — see Set it up. Without a graph, everything else on this page still works.
Start the relay
$ relay serve # API + Mission Control → http://localhost:3001
$ relay serve --no-ui # API + coordinator only, no board
$ relay serve --dev # Mission Control with hot reload on :3002
Mission Control is served prebuilt from the API port, so it opens in well under a second. In a source checkout it is rebuilt once, only after the UI code changes. Old :3002 links redirect to :3001. Everything shuts down together on Ctrl-C.
Mint the invite link
Open localhost:3001 → Team → Share. Pick a tunnel — Cloudflare Quick Tunnel (no account), ngrok, Tailscale Funnel, or a custom URL — and /.relay hands you a link. That link, plus the member token baked into it, is the whole room.
Nothing else to remember. Once hooks are installed, agents claim and release locks on their own — no one on the team ever types a lock command.
Get started
Quickstart · Teammate
Guests run their own relay against their own filesystem. They do not share a working tree with the host — they share a lock table and a patch stream.
$ npm install -g relaybrain # the relay CLI
$ relay login # their own GitHub identity
$ relay clone <same-repo-url> # their own clone
$ relay serve # their own local relay
# then: Mission Control → Team → Join, paste the host's invite link
$ relay pull # take the host's current working state
From that point on, the two machines see one lock table. A claim on the guest's machine is arbitrated against the host over the tunnel, and the board mirrors the host's locks back down.
Guests don't need FalkorDB or Docker. Their Memory Graph tab and their agents' graph tools are answered by the host's graph through the room.
| Role | Owns | Board is fed by |
|---|---|---|
| Host | The canonical lock table | Its own local table |
| Guest | Its own clone and agents | The lock mirror polling the host |
If the host's tunnel dies, locks still arbitrate correctly on the machines that can reach it — the board is what degrades first. relay doctor walks that chain and names the broken link.
Get started
Your first coordinated write
Open your agent as you normally would and ask it to edit a file. Nothing about your workflow changes — the hooks fire underneath.
lock table — 4 held
├── src/auth/session.ts # @pony · claude · write
├── src/api/routes.ts # @unnath · cursor · write
├── lib/db/client.ts # @arjun · codex · write
└── ui/Header.tsx # @pony · copilot · write
└── dep-blocked: ui/Nav.tsx, ui/Layout.tsx
Now have a second agent try the same file. Instead of a silent overwrite discovered three hours later at the merge, the write is refused at the edit and the agent is told who holds it.
Confirm the whole chain is healthy at any time:
$ relay doctor
Memory graph
The memory graph
A lock stops two agents writing one file. It doesn't tell the blocked agent what the other one is doing, what was decided, or which prompt made the code look this way. With the memory graph on, /.relay writes every agent session, prompt, edit, block and decision — across every agent and every teammate — into one FalkorDB graph, and hands it back to agents before and during their work.
| What you get | How |
|---|---|
| Context at the conflict | A denied lock quotes what the holder is working on, so the blocked agent can pick other work instead of retrying blindly |
| Context before acting | relay_session_brief briefs any agent on the files it is about to touch: who is in them now, past blocks, decisions, recent prompts, who to ask |
| Every change explained | Each edit is linked to the user request behind it, inferred from the transcript — no agent has to report anything |
| Graph algorithms as tools | PageRank over co-edited files finds the hotspots; every answer ships the Cypher that produced it |
| One brain per room | The host's graph answers for every teammate; guests need no database |
Context at the moment of conflict
File `src/auth.ts` is locked by Claude Code:DESK:52b2…. Pick a different task.
They're working on: "switch the login flow to JWT tokens" (2 min ago).
The holder's intent comes from an in-process cache filled on ingest (and refilled from the graph after a restart), so the lock path never waits on the database. If FalkorDB is down, locks keep working exactly as before.
What's in the graph
(Person)-[:RUNS]->(Agent)-[:RAN]->(Session)-[:HAS_TURN]->(Turn)
└─[:MADE]->(Edit)-[:MODIFIED]->(File)
(Edit)-[:PROMPTED_BY {via}]->(Turn {role:user}) the inferred "why"
(Edit)-[:EXPLAINED_BY]->(Turn {role:assistant})
(Session)-[:HELD {count}]->(File) lock claims
(Contention)-[:ON]->(File), -[:HELD_BY]->(Session), -[:WANTED_BY]->(Session)
(Overlap)-[:ON]->(File), -[:BETWEEN]->(Edit)×2 two agents, same file, minutes apart
(Decision|Task)-[:ABOUT]->(File), -[:DURING]->(Session)
(File)-[:CO_EDITED {weight}]->(File) → PageRank, communities
| Source | Becomes |
|---|---|
| Agent transcripts (Claude Code, Cursor, Codex, Copilot, Antigravity) | Person, Agent, Session, Turn, Edit, and the prompt links |
| Every lock claim and block | HELD counts and a Contention per block |
| Room teammates' snapshots | Their sessions and edits, in the host's graph |
relay_report_decision / relay_update_task | Decision and Task nodes tied to files and sessions |
| Analytics job (debounced) | Overlap, CO_EDITED, file rank and community |
Every edit is linked to the last meaningful user request in the same session. Filler like "continue", "yes" or "hi" is skipped and kept on the edge as via. On real multi-agent history, 100% of transcript edits get a prompt link.
Memory graph
Set it up
Only the host runs a graph. The same commands work on Windows, macOS and Linux, with no environment variables.
Start FalkorDB
With Docker Desktop running:
$ relay graph up
FalkorDB is up on falkor://127.0.0.1:6379 (browser UI: http://localhost:3010).
Next: relay graph enable
This runs the falkordb/falkordb container: the database on 6379, FalkorDB's own browser on localhost:3010, and data in a named Docker volume that survives restarts.
Turn the graph on
$ relay graph enable # local Docker
$ relay graph enable falkor://default:PASSWORD@HOST:PORT # hosted FalkorDB
$ relay graph enable falkors://default:PASSWORD@HOST:PORT # hosted, TLS
Connected to falkor://127.0.0.1:6379 (2 graph(s)).
relay serve: memory graph is on.
Saved to ~/.relay/falkor.json.
enable checks that the database answers, saves the URL to ~/.relay/falkor.json (readable only by you), and switches a running relay serve on immediately. You only do this once per machine. You can also click Enable in Mission Control's Memory Graph tab.
Refresh agent configs (existing workspaces only)
$ relay init # in each repo you set up before the graph, then restart your agents
This teaches each agent's MCP entry its own name and the new tools. Repos added with relay clone / relay add after this release are already wired.
Start relay and check it
$ relay serve
$ relay graph status
config: falkor://127.0.0.1:6379 (from file)
file: ~/.relay/falkor.json
relay: graph running, connected
proj_45dbc0415beb: last ingest 18/10/2026, 3:44:08 pm
db: reachable, 3 graph(s)
Bring in history you already have (optional)
$ relay graph rebuild # every project
$ relay graph rebuild <id> # one project (ids: curl http://127.0.0.1:3001/api/projects)
New activity is ingested automatically whenever an agent turn ends. Want something to look at right away? relay graph seed fills a realistic five-agent demo graph in its own sandbox.
Memory graph
A new PC
Pick the row that matches what this machine will be. Your own agents' chats always load from this machine's transcripts, graph or not.
| This machine is… | Do this | Docker? |
|---|---|---|
| A teammate joining a room | npm i -g relaybrain → relay serve → Team → Join with the host's invite. The graph is the host's, read over the room | No |
| The host, with Docker | relay graph up → relay graph enable → relay serve | Yes |
| The host, without Docker | Create a free instance on FalkorDB Cloud, copy its host, port and password, then relay graph enable falkor://default:PASSWORD@HOST:PORT → relay serve | No |
$ npm install -g relaybrain
$ relay login
$ relay clone <repo-url>
$ relay graph up && relay graph enable # or: relay graph enable falkor://…cloud URL…
$ relay serve # → http://localhost:3001
Opened your editor on a folder above the repo (a monorepo root, a hackathon folder)? That's fine: /.relay also picks up Claude sessions started in parent folders, as long as they touch files inside the repo.
Memory graph
relay graph commands
Every subcommand accepts --help.
relay graph upStart FalkorDB in Docker
Starts the container from docker-compose.falkor.yml. Fails with a clear message if Docker isn't running.
$ relay graph uprelay graph enable [url]Save the URL and switch relay on
Default URL is falkor://localhost:6379. Accepts falkor://, falkors:// (TLS), redis:// and rediss://, with optional user:password@.
$ relay graph enable
$ relay graph enable falkor://default:s3cret@r-6jissuruar.instance-xyz.falkordb.cloud:6379relay graph statusConfig, connection, ingest state
Shows where the URL came from (from file or from env), whether relay is connected, when each project was last ingested, and whether the database is reachable. Says NEEDS REBUILD if an update changed how history is stored.
$ relay graph statusrelay graph stats [id|all]Node and edge counts per project
$ relay graph statsrelayBrain (proj_relay) -> graph relay_proj_relay
nodes: Edit:317 Turn:271 File:77 Agent:1 Person:1 Meta:1 Session:1
edges: PROMPTED_BY:317 BY:317 EXPLAINED_BY:317 MODIFIED:317 MADE:317 HAS_TURN:271 TOUCHED:77
turns: 271/271 with text (2026-10-16 .. 2026-10-18)
schema: v1 (ingest v6), migrations: 001_meta_versions_v6relay graph rebuild [id|all]Rebuild from relay history
Re-projects a project's history into its graph. Safe to run any time; writes are idempotent.
$ relay graph rebuild
$ relay graph rebuild proj_45dbc0415bebrelay graph seed [id]Seed a 5-agent demo graph
Fills a realistic coordination graph — five agents, overlaps, blocks, decisions — for demos and for exploring the Memory Graph tab. It goes into its own sandbox graph (demo_<projectId>), never into your real project's graph; Mission Control's Memory Graph tab can switch between the two.
$ relay graph seed # sandbox for your first project
$ relay graph seed proj_45dbc0 # sandbox for a specific projectrelay graph disableTurn the graph off
Takes effect on the next relay serve. Your data stays in FalkorDB; enable picks it back up.
$ relay graph disableMemory graph
Queries & agent tools
Agents reach the graph through two MCP tools. Both are read-only and work for room guests too.
| Tool | What it does |
|---|---|
relay_session_brief | Call before editing unfamiliar files (paths). Returns who is editing them now and why, past blocks, decisions, the prompts behind recent changes, who to ask, and related files |
relay_graph_query | Runs one of the named queries below and returns rows plus the exact Cypher used |
Named queries
| Query | Answers | Args |
|---|---|---|
file_story | Every change to a file, newest first, with the prompt that caused it | path |
who_to_ask | People (and their agents) who know a file best, by recency and volume | path |
contention_trace | Why agents were blocked: who held the file, what they were doing, who wanted it | path (optional) |
search_memory | Full-text search across every agent conversation | q |
agent_activity | What an agent or person has been working on, session by session | agent / person |
hotspots | Files where coordination matters most: PageRank over co-edits, plus overlaps and blocks | — |
decision_trace | Decisions about a file (or all), who made them and in which session | path (optional) |
overlaps | Places where two different agents changed the same file within minutes | — |
session_brief | The brief behind relay_session_brief | paths |
overview | Counts by node label and relationship type | — |
The same queries are on the HTTP API, so you can script them:
$ curl -s http://127.0.0.1:3001/api/graph/queries
$ curl -s "http://127.0.0.1:3001/api/graph/query/file_story?path=src/auth.ts"
$ curl -s "http://127.0.0.1:3001/api/graph/query/search_memory?q=jwt"
Or ask in plain words inside any agent: "call relay_session_brief for src/auth.ts", or "use relay_graph_query hotspots". In Mission Control, the Memory Graph tab lets you click a file to see its agents, sessions, prompts, blocks and decisions, open the Cypher behind any panel, and search every conversation.
Memory graph
Graph troubleshooting
| Symptom | Cause and fix |
|---|---|
relay graph up: Docker is not running (Windows: failed to connect to the docker API at npipe:…) | Start Docker Desktop, wait until it says running, run relay graph up again — or use FalkorDB Cloud |
| Port 6379 already in use | Often a local Redis. Change the host port in docker-compose.falkor.yml to "6380:6379", then relay graph enable falkor://localhost:6380 |
| FalkorDB unreachable (retrying) | The container stopped (docker ps). relay graph up; relay reconnects by itself within ~30 s |
| Memory Graph tab: not enabled on this relay | Click Enable, or relay graph enable |
| Guest: room host unreachable | The host's tunnel is down or relay isn't running there. The host re-shares from Team |
| Graph is empty | Ingest runs when an agent turn ends. For older history, relay graph rebuild. To just look around, relay graph seed |
| Claude chats missing | Run one agent turn, then Sync in Mission Control. Sessions opened in the repo or any folder above it that touch the repo are picked up |
relay graph status shows NEEDS REBUILD | An update changed how history is stored: relay graph rebuild |
RELAY_FALKOR_URL seems ignored, or wins over enable | The env var beats the saved file. relay graph status shows which is in use |
More detail — persistence, recovery after a hard shutdown, the full design — is in docs/MEMORY-GRAPH.md ↗.
Core concepts
File locking
Every agent write goes through a claim/release cycle against a shared, TTL-based lock table. A pre-tool hook fires before the agent touches a file and claims it. A post-tool hook fires after and releases it. If another agent holds the file, the claim fails and the write never lands.
agent wants to write src/auth/session.ts
│
├─ pre-tool hook ──► POST /api/locks/claim
│ ├─ free? → granted, TTL starts
│ ├─ held by other? → REFUSED (+ holder identity)
│ └─ dep-affected? → REFUSED (+ blast radius)
│
├─ the edit runs
│
└─ post-tool hook ─► POST /api/locks/release
└─ change fans out as a patch to the room
Locks are TTL-based and auto-expire, so a crashed agent or a killed terminal cannot wedge a file permanently. Hooks call the host directly over HTTP — arbitration never depends on the board being up.
Core concepts
Dependency-graph locking
Files do not exist independently. Editing one module can break a dozen importers, so path-exact locking is not enough. /.relay parses imports with tree-sitter and asks the real question: does this change affect a file another agent is working on? — not merely is this exact path locked?
Agents stay parallel wherever the graph says they are independent. The blast radius is what gets serialized.
Languages parsed
| Family | Languages |
|---|---|
| Web | TypeScript, JavaScript |
| Systems | Go, Rust, C, C++ |
| JVM / .NET | Java, C# |
| Scripting | Python, PHP, Ruby |
The graph is rebuilt from the working tree, not from a hosted index. A file in a language outside this list still locks exactly — it just does not contribute edges to the blast radius.
Core concepts
Rooms & the host model
A room is one host machine plus the guests connected to it. There is no cloud component: relay serve binds the API to 127.0.0.1:3001, and sharing means opening a tunnel (Cloudflare, ngrok or Tailscale) straight to that laptop. With the memory graph on, the host's FalkorDB is the room's brain: guests' graph queries are forwarded to it.
Cursor ──┐ pre-tool hook: claim
Claude ──┤ post-tool hook: release ┌──────────────┐
Copilot ─┼──► lock table ◄── dep graph ──│ relay serve │──► Mission Control
Codex ───┤ ▲ │ (your host) │ ▲
Antigravity ┘ │ └──────┬───────┘ │
│ cloudflare / ngrok │ │
teammate's relay ◄──── patches ─────┴──────────────────┘
| Layer | Who runs it | What it guards |
|---|---|---|
| Claim / release | pre- and post-tool hooks | Exclusive write access to a file |
| Dependency graph | tree-sitter import scan | Files affected by the edit |
| Room | relay serve + a tunnel | One shared lock table across machines |
| Patches | relay push / relay pull | Working-tree state without full copies |
| Board | Mission Control (:3001) | Who holds what, right now |
| Memory graph | FalkorDB on the host (optional) | Who did what, and why — for every agent |
Room state is written to room.json and carries the role (host or guest), the tunnel URL, the host project id, and a member token for invite-only rooms.
Core concepts
Patch sync
Your teammate has their own filesystem, their own environment, and their own agents. /.relay does not copy projects around — it propagates patches of the dirty working tree, so both clones converge on the same uncommitted state without anyone committing.
$ relay push # send your dirty working-tree files to the room
$ relay pull # apply the host's current dirty files onto this clone
push 3 file(s)
src/auth/session.ts
src/api/routes.ts
lib/db/client.ts
Both commands are thin clients over the local API — if the relay is not running you get offline — run relay serve and a non-zero exit code, which makes them safe to use in scripts.
Reference
CLI reference
Every command /.relay ships. Expand one for usage, output, and the failure modes worth knowing.
Identity
relay loginSign in with GitHub
Reads the existing gh CLI session and stores a local /.relay session. Locks and board entries are attributed to this identity.
$ relay loginsigned in as Krishna V (@pony) via GitHub CLINo gh installed? Set GITHUB_CLIENT_ID (and GITHUB_CLIENT_SECRET) and the command falls back to the GitHub device flow, printing a verification URL and a one-time code. You can also sign in from Mission Control with Continue with GitHub.
relay whoamiShow the signed-in user
$ relay whoamiKrishna V (@pony)
project prj_8f31a2Exits non-zero with not signed in — run relay login when there is no session.
relay logoutClear the local session
$ relay logoutRemoves the stored session only. Your gh credentials are untouched.
Workspaces
relay clone <url> [dir]Clone + register + install hooks
Three steps in one: git clone, register the workspace as a /.relay project, and install pre-tool, post-tool, pre-read and stop hooks for every supported agent.
$ relay clone https://github.com/acme/api-server
$ relay clone https://github.com/acme/api-server ./apicloned https://github.com/acme/api-server
workspace /Users/pony/code/api-server
registered api-server (prj_8f31a2)relay add <path>Attach an existing local repo
Same registration and hook install as clone, without touching git. Use this for a repo you already have on disk.
$ relay add ~/code/api-serveradded /Users/pony/code/api-server as api-serverRuntime
relay serveStart the API and Mission Control
Boots the coordination API on 127.0.0.1:3001 and serves the prebuilt Mission Control from the same port. In a source checkout the UI is rebuilt once, only after its code changes; :3002 redirects to :3001. Everything shuts down together on Ctrl-C, including child process trees on Windows.
$ relay serve # API + Mission Control on :3001
$ relay serve --no-ui # API + coordinator only
$ relay serve --dev # Mission Control via next dev on :3002
$ relay serve --port 4001 # move the API off 3001
| Flag | Effect |
|---|---|
--no-ui | Skip Mission Control; run the API and coordinator only |
--dev | Run Mission Control with next dev on RELAY_UI_PORT (hot reload; slow first page load). Source checkouts only |
--port <n> | API port (overrides RELAY_PORT, default 3001) |
With --dev, the board port comes from RELAY_UI_PORT (default 3002). If next is missing you will get Mission Control is not installed — run npm install.
relay statusHealth check as JSON
Prints the raw /api/health payload — room, role, host, and ports.
$ relay status{
"ok": true,
"port": 3001,
"room": {
"role": "host",
"url": "https://a1b2c3.ngrok-free.app",
"hostProjectId": "prj_8f31a2",
"hostProjectName": "api-server",
"hostWorkspacePath": "/Users/pony/code/api-server"
}
}
Exits non-zero with offline — run relay serve when no local API answers.
Sync
relay pushSend dirty files to the room
$ relay pushpush 2 file(s)
src/api/routes.ts
lib/db/client.tsPrints push: nothing to push when the working tree is clean.
relay pullApply the host's working state
$ relay pullpull 3 file(s)
src/auth/session.ts
src/api/routes.ts
ui/Header.tsxPatches land on your clone — no whole-project copy, no commit required on either side.
Diagnostics & integration
relay doctorExplain an empty Coordinator board
Locks and the board are separate subsystems — hooks arbitrate straight against the host over HTTP, while the board is fed by a lock mirror and SSE. That makes "locking works but I see nothing" a normal and otherwise invisible failure. doctor walks that exact chain and names the broken link.
$ relay doctor
$ relay doctor --port 4001relay doctor — room + Coordinator board
ok local API on http://127.0.0.1:3001
ok room joined as guest -> https://a1b2c3.ngrok-free.app
ok mirroring host project prj_8f31a2
ok host answers through the tunnel
ok host reports 4 lock(s) for the shared project
board would render 4 lock(s):
3 mirrored from the room, 1 claimed on this machine
src/auth/session.ts @pony write
Run it on the machine that sees nothing — not on the host.
relay mcp-urlPrint the room's MCP config
Emits a ready-to-paste mcpServers block pointing at this room's shared-context endpoint. See MCP server.
$ relay mcp-urlExits non-zero with a hint when you are not in a room — locally your agents already reach relay over stdio, so there is nothing to configure.
relay helpFull command list
$ relay help
$ relay -h
$ relay --helpCheat sheet
| Command | Description |
|---|---|
relay login | GitHub identity via gh, or device flow with GITHUB_CLIENT_ID |
relay logout | Clear the local session |
relay whoami | Show the signed-in GitHub user and active project |
relay clone <url> [dir] | git clone + register workspace + install agent hooks |
relay add <path> | Attach an existing local repo |
relay init [path] | Re-wire hooks, MCP and agent instructions in a repo |
relay serve | API + Mission Control on 127.0.0.1:3001 |
relay serve --dev | Mission Control with hot reload on :3002 |
relay serve --no-ui | API + coordinator only |
relay push | Send your dirty working-tree files to the room |
relay pull | Apply the host's current dirty files onto this clone |
relay status | Health check (room, role, host, ports) |
relay mcp-url | Print the MCP config for this room's shared-context endpoint |
relay doctor | Diagnose an empty Coordinator board |
relay graph up | Start FalkorDB in Docker |
relay graph enable [url] | Save the FalkorDB URL and switch relay onto the graph |
relay graph status | Config, connection and per-project ingest state |
relay graph stats [id|all] | Node and edge counts per project |
relay graph rebuild [id|all] | Rebuild a graph from relay history |
relay graph seed [id] | Seed a five-agent demo graph |
relay graph disable | Turn the graph off (next relay serve) |
Reference
Agent hooks
relay clone and relay add install four hooks into your project: pre-tool (claim), post-tool (release), pre-read, and stop. They are written into each agent's own config format, so every tool participates without a plugin.
| Agent | Config file | Write tools intercepted |
|---|---|---|
| Claude Code | .claude/settings.json | Edit, Write, NotebookEdit |
| Cursor | .cursor/hooks.json | Write, Edit, Delete |
| Codex | .codex/hooks.json | apply_patch, Edit, Write |
| Copilot CLI | .github/hooks/relay-os.json | edit, create |
| Antigravity | .agents/hooks.json | write_to_file, replace_file_content, multi_replace_file_content |
Verifying the install
$ ls -a .claude .cursor .codex .agents .github/hooks
The hook files are committed alongside the repo, so a teammate who clones it normally still gets the claim/release wiring — they only need their own relay serve running for it to have something to talk to.
Reference
MCP server
Any MCP client can read the room's shared context — even on a machine with no relay installed. Print the config and paste it into your agent:
$ relay mcp-url
{
"mcpServers": {
"relay-room": {
"type": "http",
"url": "https://a1b2c3.ngrok-free.app/mcp",
"headers": {
"ngrok-skip-browser-warning": "relay",
"x-relay-room-token": "rmt_9f81…"
}
}
}
}
The room endpoint is read-only for anyone off the host machine. Coordination tools that mutate state — relay_claim_file, relay_release_file, relay_status — run against each member's own local relay.
Tools exposed
| Tool | Purpose |
|---|---|
relay_claim_file | Acquire an exclusive write lock before editing |
relay_release_file | Release the lock after editing |
relay_status | View the full lock table |
relay_get_conflicts | Overlapping edits in the last 5 minutes |
relay_get_recent_changes | Recent code_edit events |
relay_get_chat_history | Unified agent chat across every room member |
relay_report_change | Push a code-change event |
relay_report_decision / relay_get_decisions | Append / read decisions |
relay_update_task / relay_get_active_tasks | Append / read tasks |
relay_get_project_context | Full JSON project context |
relay_sync | Re-read agent transcripts into unified history |
relay_room_brief | Teammate activity: peer chat, edits, tool activity, live locks |
relay_get_collision_stats | Lifetime counts of collisions relay prevented |
relay_session_brief | Memory-graph brief for files you are about to edit — see Queries & agent tools |
relay_graph_query | Run a named memory-graph query; returns rows and the Cypher |
If you are a guest and no member token is on file, re-join with the invite link — the host may have made the room invite-only.
Reference
Mission Control
One board for every agent on every machine. Started by relay serve, running on your own hardware, with no hosted account behind it.
| Surface | URL |
|---|---|
| Dashboard | http://localhost:3001 |
| Memory Graph tab | http://localhost:3001/?tab=graph |
| FalkorDB browser | http://localhost:3010 (with relay graph up) |
| API health | http://127.0.0.1:3001/api/health |
Panels
| Panel | What it shows |
|---|---|
| File locks | Who holds what file, right now, with agent and mode |
| Lock graph | The dependency blast radius as a live canvas |
| Code edits | Recent code_edit events across the room |
| Agent chat | Unified session history from every agent on every machine |
| Activity timeline | Claims, releases, pushes and pulls in order |
| Team & presence | Who is online, plus Share and Join for the room |
| Conflict notices | Overlapping edits surfaced within seconds |
| Memory Graph | Click a file for its agents, sessions, prompts, blocks and decisions; hotspots; search; the Cypher behind every panel |
Reference
HTTP API
The CLI is a thin client over a local HTTP API. Anything the CLI does, you can script.
| Endpoint | Method | Purpose |
|---|---|---|
/api/health | GET | Liveness, port, room role and host details |
/api/locks | GET | The lock table this machine would render |
/api/locks?projectId=… | GET | Locks for one shared project (used across the tunnel) |
/api/push | POST | Send dirty working-tree files to the room |
/api/pull | POST | Apply the host's dirty files onto this clone |
/mcp | HTTP | Read-only room context for MCP clients |
/api/graph/queries | GET | Names of the memory-graph queries |
/api/graph/query/:name | GET / POST | Run a named query; guests are answered by the host's graph |
/api/graph/health | GET | Whether the memory graph is on and connected |
$ curl -s http://127.0.0.1:3001/api/health
$ curl -s http://127.0.0.1:3001/api/locks
$ curl -s -X POST http://127.0.0.1:3001/api/push -d '{}'
Requests that cross the tunnel to a host carry two headers: ngrok-skip-browser-warning: relay and, in invite-only rooms, x-relay-room-token.
Reference
Configuration
Environment variables
| Variable | Default | What it controls |
|---|---|---|
RELAY_PORT | 3001 | Coordination API port |
RELAY_UI_PORT | 3002 | Mission Control port for relay serve --dev; otherwise it redirects to the API port |
RELAY_UI_ORIGIN | the UI's origin | Origin the API accepts board requests from (CORS) |
RELAY_FALKOR_URL | from ~/.relay/falkor.json | falkor://[user:pass@]host:port; overrides the saved URL |
RELAY_FALKOR_DISABLED | 0 | 1 = graph off, whatever is saved |
RELAY_FALKOR_TEXT | 1 | 0 = metadata-only graph (no chat text or diffs) |
RELAY_FALKOR_TEXT_DAYS | 90 | Chat text and diffs older than this are cleared; nodes and edges stay |
RELAY_PUBLIC_READONLY | 0 | 1 = hosted demo: remote callers may only read |
GITHUB_CLIENT_ID | — | Enables the device-flow login fallback |
GITHUB_CLIENT_SECRET | — | Pairs with the client id for Mission Control sign-in |
$ export RELAY_PORT=4001
$ relay serve # API + Mission Control on :4001
Where state lives
Coordination state is files on your own disk. The memory graph, when on, lives in FalkorDB.
| File | Holds |
|---|---|
room.json | Role, tunnel URL, host project id and name, member token |
| Session store | The GitHub identity from relay login |
| Project registry | Workspaces registered by relay clone / relay add |
| Hook configs | Per-agent files listed under Agent hooks |
~/.relay/falkor.json | The saved FalkorDB URL from relay graph enable |
| Docker volume (FalkorDB) | The memory graph itself, snapshotted to disk; survives restarts |
Bundled dependencies
| Area | Packages |
|---|---|
| API & coordination | express, cors, ws |
| Dependency graph | @vscode/tree-sitter-wasm |
| Memory graph | falkordb (client) |
| Mission Control | next, react |
Operations
Troubleshooting
Start here, always:
$ relay doctor # run it on the machine that sees nothing
The board is empty but locking works
Expected, and the single most common report. Hooks claim straight against the host over HTTP; the board is fed by a separate lock mirror. If the mirror is not committing its polls, locks stay correct while the board stays blank.
BROKE the host holds locks but this machine mirrors none of them.
Locks still arbitrate correctly (hooks call the host directly); it is only
the board that is fed by the mirror. Restart `relay serve` here.
Common failures
| Symptom | Cause | Fix |
|---|---|---|
offline — run relay serve |
No local API on the expected port | Start relay serve, or match RELAY_PORT |
no local API on http://127.0.0.1:3001 |
Same, seen from doctor |
Run relay serve on this machine |
room.json has no hostProjectId |
Joined without a complete invite | Re-join with the host's invite link |
cannot reach the host |
Tunnel down or rotated | Host re-shares; /.relay looks up the current tunnel and reconnects |
host refused /api/locks |
Missing member token in an invite-only room | Re-join with the invite link to store the token |
Mission Control is not installed |
next not present in node_modules |
npm install at the repo root |
Install GitHub CLI and run: gh auth login |
No gh session and no GITHUB_CLIENT_ID |
Install gh, or set the client id for device flow |
| No agent ever claims a lock | Hooks not installed in that workspace | Run relay add <path> on the repo |
Port already in use
$ relay serve --port 4001 # API + Mission Control on :4001
$ RELAY_UI_PORT=4002 relay serve --dev # if :3002 is taken in dev mode
An empty board with nothing locked anywhere is correct. Have someone start an agent edit and run relay doctor again before assuming something is broken.
Operations
FAQ
Do I need an account?
No. relay login reads a GitHub identity so locks can be attributed to a person, but there is no /.relay account server, no sign-up, and no hosted state.
Do I need FalkorDB?
No. Locking, patch sync and Mission Control work without it. The memory graph is an add-on, and only the host runs it — room guests read the host's graph. No Docker? Use a hosted FalkorDB. See A new PC.
Does this replace Git?
No — it sits under it. Git coordinates humans committing minutes apart. /.relay coordinates agents editing the same files right now. You still branch, commit and merge exactly as before.
What happens if the host goes offline?
Guests keep their own local relay and their own clone. Claims that need the host will fail loudly rather than silently succeed, and the board falls back to local locks until the tunnel is back.
My language is not in the dependency-graph list.
File locking still works exactly the same — every write is claimed and released. Only the blast-radius edges are missing, so /.relay will not know that editing your file affects someone else's.
What is next?
- Git worktree isolation — every agent in its own workspace off the same repository, free to experiment and test independently, integrated back into main when the work is ready.
- Richer conflict resolution on top of the existing OT / patch layer.