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.

the shiftdiff
- 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 timeInstallation → Quickstart
Turn on the memory graph (FalkorDB)Set it up → relay graph commands
Set relay up on a second or new PCA new PC
Understand what a lock actually guardsCore concepts
Look up a command and its flagsCLI reference
Wire a specific agent into the claim/release cycleAgent hooks
Read room context from an MCP clientMCP server
Fix an empty board or a broken roomTroubleshooting
Note

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

StatusWhatWhy
RequiredNode.js 20+, npmRuns the CLI, the API, and Mission Control
Requiredgitrelay clone shells out to it
Optionalgh CLIFastest path for relay login
OptionalDocker (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
OptionalA tunnel: Cloudflare (no account), ngrok, or TailscaleOnly needed for cross-machine rooms
Not neededA hosted backend, an account, a database on guest machinesCoordination state lives in files on your disk

Install the CLI

from npm (recommended)bash
$ npm install -g relaybrain   # puts `relay` (and `relaybrain`) on your PATH

Or from source, if you want to hack on relay itself:

from sourcebash
$ 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:

terminalbash
$ relay help
outputconsole
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]
Heads up

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.

Tip

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.

teammatebash
$ 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.

RoleOwnsBoard is fed by
HostThe canonical lock tableIts own local table
GuestIts own clone and agentsThe lock mirror polling the host
Warning

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.

relay statusconsole
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 getHow
Context at the conflictA denied lock quotes what the holder is working on, so the blocked agent can pick other work instead of retrying blindly
Context before actingrelay_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 explainedEach edit is linked to the user request behind it, inferred from the transcript — no agent has to report anything
Graph algorithms as toolsPageRank over co-edited files finds the hotspots; every answer ships the Cypher that produced it
One brain per roomThe host's graph answers for every teammate; guests need no database

Context at the moment of conflict

pre-tool hook · deniedconsole
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

graph modelcypher
(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
SourceBecomes
Agent transcripts (Claude Code, Cursor, Codex, Copilot, Antigravity)Person, Agent, Session, Turn, Edit, and the prompt links
Every lock claim and blockHELD counts and a Contention per block
Room teammates' snapshotsTheir sessions and edits, in the host's graph
relay_report_decision / relay_update_taskDecision and Task nodes tied to files and sessions
Analytics job (debounced)Overlap, CO_EDITED, file rank and community
How the "why" works

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 thisDocker?
A teammate joining a roomnpm i -g relaybrain → relay serve → Team → Join with the host's invite. The graph is the host's, read over the roomNo
The host, with Dockerrelay graph up → relay graph enable → relay serveYes
The host, without DockerCreate a free instance on FalkorDB Cloud, copy its host, port and password, then relay graph enable falkor://default:PASSWORD@HOST:PORT → relay serveNo
new host, from zerobash
$ 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
Tip

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 up
relay 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:6379
relay 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 status
relay graph stats [id|all]Node and edge counts per project
$ relay graph stats
relayBrain (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_v6
relay 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_45dbc0415beb
relay 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 project
relay graph disableTurn the graph off

Takes effect on the next relay serve. Your data stays in FalkorDB; enable picks it back up.

$ relay graph disable

Memory graph

Queries & agent tools

Agents reach the graph through two MCP tools. Both are read-only and work for room guests too.

ToolWhat it does
relay_session_briefCall 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_queryRuns one of the named queries below and returns rows plus the exact Cypher used

Named queries

QueryAnswersArgs
file_storyEvery change to a file, newest first, with the prompt that caused itpath
who_to_askPeople (and their agents) who know a file best, by recency and volumepath
contention_traceWhy agents were blocked: who held the file, what they were doing, who wanted itpath (optional)
search_memoryFull-text search across every agent conversationq
agent_activityWhat an agent or person has been working on, session by sessionagent / person
hotspotsFiles where coordination matters most: PageRank over co-edits, plus overlaps and blocks—
decision_traceDecisions about a file (or all), who made them and in which sessionpath (optional)
overlapsPlaces where two different agents changed the same file within minutes—
session_briefThe brief behind relay_session_briefpaths
overviewCounts by node label and relationship type—

The same queries are on the HTTP API, so you can script them:

scripting the graphbash
$ 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

SymptomCause 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 useOften 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 relayClick Enable, or relay graph enable
Guest: room host unreachableThe host's tunnel is down or relay isn't running there. The host re-shares from Team
Graph is emptyIngest runs when an agent turn ends. For older history, relay graph rebuild. To just look around, relay graph seed
Claude chats missingRun 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 REBUILDAn update changed how history is stored: relay graph rebuild
RELAY_FALKOR_URL seems ignored, or wins over enableThe 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.

write lifecycletext
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

FamilyLanguages
WebTypeScript, JavaScript
SystemsGo, Rust, C, C++
JVM / .NETJava, C#
ScriptingPython, PHP, Ruby
Note

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.

topologytext
  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 ─────┴──────────────────┘
LayerWho runs itWhat it guards
Claim / releasepre- and post-tool hooksExclusive write access to a file
Dependency graphtree-sitter import scanFiles affected by the edit
Roomrelay serve + a tunnelOne shared lock table across machines
Patchesrelay push / relay pullWorking-tree state without full copies
BoardMission Control (:3001)Who holds what, right now
Memory graphFalkorDB 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.

terminalbash
$ relay push     # send your dirty working-tree files to the room
$ relay pull     # apply the host's current dirty files onto this clone
outputconsole
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 login
signed in as Krishna V (@pony) via GitHub CLI

No 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 whoami
Krishna V (@pony)
project prj_8f31a2

Exits non-zero with not signed in — run relay login when there is no session.

relay logoutClear the local session
$ relay logout

Removes 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 ./api
cloned 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-server
added /Users/pony/code/api-server as api-server

Runtime

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
FlagEffect
--no-uiSkip Mission Control; run the API and coordinator only
--devRun 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 push
push 2 file(s)
  src/api/routes.ts
  lib/db/client.ts

Prints push: nothing to push when the working tree is clean.

relay pullApply the host's working state
$ relay pull
pull 3 file(s)
  src/auth/session.ts
  src/api/routes.ts
  ui/Header.tsx

Patches 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 4001
healthy guestconsole
relay 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-url

Exits 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 --help

Cheat sheet

CommandDescription
relay loginGitHub identity via gh, or device flow with GITHUB_CLIENT_ID
relay logoutClear the local session
relay whoamiShow 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 serveAPI + Mission Control on 127.0.0.1:3001
relay serve --devMission Control with hot reload on :3002
relay serve --no-uiAPI + coordinator only
relay pushSend your dirty working-tree files to the room
relay pullApply the host's current dirty files onto this clone
relay statusHealth check (room, role, host, ports)
relay mcp-urlPrint the MCP config for this room's shared-context endpoint
relay doctorDiagnose an empty Coordinator board
relay graph upStart FalkorDB in Docker
relay graph enable [url]Save the FalkorDB URL and switch relay onto the graph
relay graph statusConfig, 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 disableTurn 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.

AgentConfig fileWrite tools intercepted
Claude Code.claude/settings.jsonEdit, Write, NotebookEdit
Cursor.cursor/hooks.jsonWrite, Edit, Delete
Codex.codex/hooks.jsonapply_patch, Edit, Write
Copilot CLI.github/hooks/relay-os.jsonedit, create
Antigravity.agents/hooks.jsonwrite_to_file, replace_file_content, multi_replace_file_content

Verifying the install

$ ls -a .claude .cursor .codex .agents .github/hooks
Note

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
mcp configjson
{
  "mcpServers": {
    "relay-room": {
      "type": "http",
      "url": "https://a1b2c3.ngrok-free.app/mcp",
      "headers": {
        "ngrok-skip-browser-warning": "relay",
        "x-relay-room-token": "rmt_9f81…"
      }
    }
  }
}
Scope

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

ToolPurpose
relay_claim_fileAcquire an exclusive write lock before editing
relay_release_fileRelease the lock after editing
relay_statusView the full lock table
relay_get_conflictsOverlapping edits in the last 5 minutes
relay_get_recent_changesRecent code_edit events
relay_get_chat_historyUnified agent chat across every room member
relay_report_changePush a code-change event
relay_report_decision / relay_get_decisionsAppend / read decisions
relay_update_task / relay_get_active_tasksAppend / read tasks
relay_get_project_contextFull JSON project context
relay_syncRe-read agent transcripts into unified history
relay_room_briefTeammate activity: peer chat, edits, tool activity, live locks
relay_get_collision_statsLifetime counts of collisions relay prevented
relay_session_briefMemory-graph brief for files you are about to edit — see Queries & agent tools
relay_graph_queryRun 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.

SurfaceURL
Dashboardhttp://localhost:3001
Memory Graph tabhttp://localhost:3001/?tab=graph
FalkorDB browserhttp://localhost:3010 (with relay graph up)
API healthhttp://127.0.0.1:3001/api/health

Panels

PanelWhat it shows
File locksWho holds what file, right now, with agent and mode
Lock graphThe dependency blast radius as a live canvas
Code editsRecent code_edit events across the room
Agent chatUnified session history from every agent on every machine
Activity timelineClaims, releases, pushes and pulls in order
Team & presenceWho is online, plus Share and Join for the room
Conflict noticesOverlapping edits surfaced within seconds
Memory GraphClick 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.

EndpointMethodPurpose
/api/healthGETLiveness, port, room role and host details
/api/locksGETThe lock table this machine would render
/api/locks?projectId=…GETLocks for one shared project (used across the tunnel)
/api/pushPOSTSend dirty working-tree files to the room
/api/pullPOSTApply the host's dirty files onto this clone
/mcpHTTPRead-only room context for MCP clients
/api/graph/queriesGETNames of the memory-graph queries
/api/graph/query/:nameGET / POSTRun a named query; guests are answered by the host's graph
/api/graph/healthGETWhether the memory graph is on and connected
scripting the APIbash
$ 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

VariableDefaultWhat it controls
RELAY_PORT3001Coordination API port
RELAY_UI_PORT3002Mission Control port for relay serve --dev; otherwise it redirects to the API port
RELAY_UI_ORIGINthe UI's originOrigin the API accepts board requests from (CORS)
RELAY_FALKOR_URLfrom ~/.relay/falkor.jsonfalkor://[user:pass@]host:port; overrides the saved URL
RELAY_FALKOR_DISABLED01 = graph off, whatever is saved
RELAY_FALKOR_TEXT10 = metadata-only graph (no chat text or diffs)
RELAY_FALKOR_TEXT_DAYS90Chat text and diffs older than this are cleared; nodes and edges stay
RELAY_PUBLIC_READONLY01 = 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
moving off the default portsbash
$ 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.

FileHolds
room.jsonRole, tunnel URL, host project id and name, member token
Session storeThe GitHub identity from relay login
Project registryWorkspaces registered by relay clone / relay add
Hook configsPer-agent files listed under Agent hooks
~/.relay/falkor.jsonThe saved FalkorDB URL from relay graph enable
Docker volume (FalkorDB)The memory graph itself, snapshotted to disk; survives restarts

Bundled dependencies

AreaPackages
API & coordinationexpress, cors, ws
Dependency graph@vscode/tree-sitter-wasm
Memory graphfalkordb (client)
Mission Controlnext, 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

SymptomCauseFix
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
Tip

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.