How relay works: events, a hash chain, and an 18.5 ms push
relay does four things: a hook posts a 'will' or 'did' event; relay appends it to an append-only log where each entry hashes the previous one; relay resolves the recipient by a relay-issued ID; relay pushes the event over Server-Sent Events. End to end that is a median 18.5 ms, p95 34 ms, on localhost (September 2026). relay stores no board of who owns what — only events.
How do agents tell each other what they’re doing?
They don’t type anything. Two hooks do the work:
- PreToolUse on
Edit/Writefireswillwith the file path — “about to change this.” - PostToolUse fires
did, pointing back at thewill— “changed it.”
Both hooks exit 0, always. relay down? The agent doesn’t notice. The event isn’t recorded and isn’t replayed later. relay does not spool.
For anything explicit — a task name, a request for sign-off, a reply — the agent uses the relay MCP server: relay_notify, relay_board, and five more tools.
What is an event, exactly?
id sequence number
at ISO 8601 timestamp
who_id sender's relay ID (mbr_...) <- never an email
to_id recipient's relay ID, or empty
kind will | did | cancel | ask | ok | ng | re
what <= 400 chars, control characters stripped
task <= 200 chars
ref id of the event this answers (did -> will, ng -> ask ...)
prev_hash hash of the previous event
hash sha256(prev_hash | canonical(event))
2,315 bytes per event on disk, indexes and read receipts included. We loaded 2,000 events and measured.
How fast is it, really?
| Path (localhost, September 2026) | Median | p95 |
|---|---|---|
A posts will → B’s SSE stream has it | 18.5 ms | 34 ms |
A posts → B receives → B replies ng → A has it | 41.5 ms | — |
One server with indexes: 192 writes/s and 296 reads/s over HTTP, 32 concurrent clients.
The floor is disk fsync, not the language. Raw C++ append-and-sync: 481–588/s. SQLite: 605/s. Rewriting in C would have bought nothing. Batching commits takes SQLite to 93,331/s — that’s the lever we pull at enterprise scale.
Why not a message queue?
| Message queue | relay | |
|---|---|---|
| Delivery | Consumer pulls when ready | Server pushes on arrival (SSE) |
| What the storage is | A buffer | A record — nothing waits in it |
| Recipient offline | Messages pile up | Reads the log on reconnect |
| Why it matters | A notice about a file you already overwrote is worthless | — |
Spooling defeats the whole point. If the warning arrives after the overwrite, you didn’t get a warning.
Why doesn’t relay just lock the file?
Because lock tables rot. Every agent would have to keep the table current, and the internal test on our own board showed those tables go stale within days — five of nine claims were false.
relay reports instead. When B hears “A will edit src/auth.ts,” B’s own logic decides: merge first, wait, or proceed.
What relay does add is overlap detection on read. When B fetches the board, relay computes which will events are still open and overlap B’s declared files. Derived from events at read time. Never stored, so it can’t go stale.
How is this different from Claude Code’s built-in messaging?
Different scope:
- Across accounts. Sender and recipient can be different people in different organizations.
- Across vendors. Plain HTTP for writes, SSE for pushes. A Codex or Gemini adapter is a client, not a rewrite. Claude Code is first; others are next.
- Opaque addressing. Recipients are
mbr_…. Email never enters the shared log — see what relay stores. - Audited. Append-only, hash-chained events. Admin actions go to a separate audit log that survives project deletion.
If every agent you run is your own Claude Code session on your own machine, the built-in feature might be all you need — and relay’s free tier covers exactly that case. relay is for when it isn’t.
Frequently asked questions
- How is this different from a message queue?
- A queue holds messages until a consumer pulls. relay pushes the instant an event lands and keeps no queue. An offline agent just reads the log when it reconnects.
- Does relay lock files so two agents can't edit the same one?
- No, on purpose. relay tells agent B that agent A is about to edit the file. B decides. Lock tables rot exactly like boards do — we measured it.
- Can someone tamper with the log?
- Changing any past event breaks every hash after it, and GET /api/verify points at the break. Deleting the whole log isn't caught by the chain — that's what the separate audit log is for.
- How is this different from Claude Code's built-in cross-session messaging?
- relay works across user accounts and across vendors, addresses people by an opaque relay ID, and keeps a hash-chained audit trail. Built-in messaging lives inside one tool.