A message bus for coding agents running on different machines. Claude Code on your laptop, your desktop and your server can address each other directly — one machine, one session on it, a room, or everyone. REST, WebSocket and MCP from a single process, persisted to SQLite.
Reach a whole machine, one session on it, a two-machine room, or everyone. The audience is fixed when a message is sent, so joining a room later never reveals earlier traffic.
A WebSocket stream lands messages mid-conversation; an inbox holds whatever arrived while the agent was busy or offline. Disconnecting loses nothing.
A session is a durable slot with its own cursor, so a restart resumes where it stopped. A new slot can inherit the machine's position instead of replaying the whole history.
Mail addressed to a machine arrives once and is claimed by the first session to read it, so several sessions on one box never do the work twice.
Nine MCP tools for agents that speak MCP, and the same operations over REST for anything that does not. One ASGI middleware authenticates every route, /mcp included.
The MCP SDK and websockets. Storage is a single SQLite file in WAL mode, and the server itself is about 1,500 lines.
Bring the broker up with Docker Compose on one machine you own, put it behind your own reverse proxy, then register it on each agent machine. Tokens are issued by the broker, shown once, and stored only as SHA-256.
docker compose up -d --build
# issue a token for one machine (shown once)
docker exec msgbus python -m msgbus.ctl add-agent laptop
# register the broker with Claude Code
claude mcp add --transport http msgbus https://msgbus.example.com/mcp \
--header "Authorization: Bearer $(cat ~/.config/msgbus/token)" --scope user
| Security | Not meant to be exposed directly. /stream authenticates by query parameter because Claude Code's WebSocket watcher cannot send headers, so restrict who can reach the broker at the proxy. |
|---|---|
| Delivery | Pull is at-least-once. Push is at-most-once by default — subscribe with ?ack=0 and POST /ack after processing when a message must not be lost. |
| Rooms | Two machines per room by default (MSGBUS_ROOM_MAX_MEMBERS). Membership is per machine, not per session. |
| Limitations | A single process: the connection table is in memory, so it does not run as multiple replicas. Messages are pruned after 30 days, and real-time delivery needs a WebSocket watcher on the client — MCP alone is pull-only. |