pointers, not copies
high
4m
unread
normal
21m
read
low
1h
resolved
accepted, 1 recipient, 1 pointerexit 0
message relay / local
When several long-running sessions work on the same thing, they have to tell each other what changed. relay2 is the channel underneath that: a session decides what to say and to whom, and everything after that point, transport, validation, routing, retries, receipts, backpressure, escalation and search, is ordinary software that never calls a model.
pointers, not copies
high
4m
unread
normal
21m
read
low
1h
resolved
accepted, 1 recipient, 1 pointerexit 0
relay2 send --to ROLE validates the address before it writes, so a name nobody owns is refused in front of the sender who can fix it.
One canonical copy under messages/originals/. Six recipients get six pointers, not six copies of a 20 KB body.
The watcher coalesces: one ping per recipient per cycle, capped at three lines, and it announces less as a queue gets deeper.
relay2 metrics reports bytes carried against bytes opened, so a long report nobody read is visible as one.
Written and tested on macOS; the design is POSIX and the one platform assumption is an atomic rename within a single filesystem. A relay root on a network mount is outside what the tests cover, and the documentation says so rather than leaving you to find out.
command surface
One Python package on your machine and one long-lived process, the watcher. No daemon manager, no service file, no database server, no account and no network access after it is installed.
A message moves through created, accepted, delivered, notified, read, acknowledged, resolved, archived. They are kept apart on purpose: a session can read something without taking responsibility for it, and take responsibility long before it has finished.
The SLA clock starts at accepted, never at the ping. That is the one decision worth reading twice. A clock that starts at the ping cannot start at all for a recipient that was not running, so its messages can never escalate while every instrument reports healthy.
relay2 digest --since 15mcounts, threads, open requestsBackpressure is computed from the queue rather than declared by the recipient: normal, busy at six unread, congested at fifteen, critical at forty, offline. Durable delivery is never rate limited. Only the noise is.
relay2 metrics --since 24hcarried versus opened, and never openedbefore you install
Stated here rather than discovered later. The last item is the one that decides whether this tool is for you at all: it is a channel between processes on one machine, and it announces nothing until you give it something that can announce.
It is not a transport. It never opens a socket, never talks to a terminal and never raises a window. Announcing is one configured argv with the role and the text substituted, passed as separate arguments and never interpolated into a shell string, because a subject is sender-controlled data. It ships empty, and messages still arrive; they are just never announced.
It is not a chat system. A message is an event with a lifecycle, written once and never mutated. Nothing here renders a conversation or holds a session open.
It calls no model. Routing, projection, backpressure, digests, the SLA clock and escalation are arithmetic over an index. The numbers are already in the database, and spending a model call to recover them from prose is the waste this exists to remove.
It does not know who your roles are. The three config files ship as a worked example with placeholder roles and routing rules. Nothing in the code knows any of those strings. Replace them with yours.
./install.sh --uninstallremoves the launcher, leaves your messagesinstall
The installer checks for Python 3.9 or newer, builds a private Python environment under ~/.relay2 with pyyaml in it, and puts a small relay2 launcher in your local bin directory. The launcher points back into the unpacked folder, so leave it where you put it. It is fifty-six lines. Read it first, and read the accept pipeline it runs; that is why both are served as plain text here.
Then set your own role, start one watcher, and replace the three example config files. Uninstall with the same script and the uninstall flag: it removes the launcher and the private environment and leaves every message you have.
$ curl -fsSLO https://auto.relay70.dev/relay2/relay2.tar.gz && tar -xzf relay2.tar.gz && cd relay2 && ./install.sh
Download the archive
Read the accept pipeline
Read the installer
Report a problem