Getting started
This page runs a bus on your own machine, connects Claude Code to it, and sends one message between two sessions. It takes about five minutes. Everything stays on loopback; no tailnet is needed yet.
Prerequisites
- Node.js 24 or later (
node:sqliteis required). - pnpm through corepack:
corepack enableonce. - Claude Code (
claude) installed and logged in. - For use across machines later: a Tailscale tailnet.
1. Build
git clone https://github.com/catesworks/session-bus.git
cd session-bus
pnpm install --frozen-lockfile
pnpm run build
node dist/cli.js --help
2. Run the server
In a separate terminal:
node dist/cli.js serve
It listens on 127.0.0.1:47910 and creates its database at ~/.local/state/session-bus/bus.db (or under $XDG_STATE_HOME). Check it:
curl -s http://127.0.0.1:47910/healthz
# {"ok":true,"schema":1}
A POST to /mcp without a token returns 401. That is the auth check working.
3. Create a principal and a token
A principal owns tokens and session names. These commands open the database directly; they work while serve is running.
node dist/cli.js principal add me
export SESSION_BUS_TOKEN="$(node dist/cli.js token mint --principal me --scopes bus:read,bus:write --label laptop)"
token mint prints the raw token once. Here it goes straight into a variable and is not shown. Tokens start with sbus_ and expire after 90 days by default.
4. Add the client entry
Register the bus with Claude Code. The entry holds no token: scripts/bus-headers.sh reads SESSION_BUS_TOKEN from the environment of the claude process each time it connects.
claude mcp add-json bus --scope user \
"{\"type\":\"http\",\"url\":\"http://127.0.0.1:47910/mcp\",\"headersHelper\":\"$PWD/scripts/bus-headers.sh\"}"
Confirm no token was written to the Claude Code config:
[ "$(grep -c sbus_ ~/.claude.json)" = 0 ] && echo ok
Reading the token from the launching shell was checked with claude -p --mcp-config against a local bus (the tools registered, sent and read a message). For real use across machines, keep the token in 1Password instead; see Set up a client machine.
5. Two sessions, one message
Open two terminals in the repo. In each, run the export SESSION_BUS_TOKEN=... line from step 3 (give each its own --label), then start claude. Both tokens belong to the principal me.
In the first session:
Register on the bus as laptop-api.
In the second session:
Register on the bus as server-ci.
Back in the first session:
Send server-ci on the bus: what are you working on?
The model calls send with from=laptop-api, to=server-ci and reports a message id, for example {"id":1}.
6. Read it
In the second session:
Check the bus inbox for server-ci, then ack what you read.
The model calls inbox with session=server-ci and shows the message with its sender. It then calls ack with the message id. On the bus host you can confirm:
node dist/cli.js doctor --session server-ci
# ...
# unacked: 0
Neither session was interrupted. A plain session only sees mail when it calls inbox. To have new mail appear in an idle session, use a push session.
Next steps
- Install the skill so sessions know the conventions:
ln -s "$PWD/skills/session-bus" ~/.claude/skills/session-bus. - Expose the bus over the tailnet and set up a second machine.
- Run the bus as a service.
- Read messages and delivery before relying on it.