CLI reference
The CLI is dist/cli.js after pnpm run build. Run it as node dist/cli.js <command>, or as session-bus <command> after npm link in the repo.
All commands except channel work on the database at BUS_DB (default ${XDG_STATE_HOME:-$HOME/.local/state}/session-bus/bus.db) and create its directory if needed. Run them on the bus host.
Exit codes (all commands)
| Code | Meaning |
|---|---|
| 0 | Success. |
| 1 | Error. One line on stderr: session-bus: <message>. |
| 2 | Usage error (the usage text is printed on stderr), or a refused configuration (see each command). |
| 3 | A lock is held by another process. |
| 4 | channel only: the session name is owned by another principal. |
serve
session-bus serve
Runs the HTTP MCP bus. Reads BUS_HOST (default 127.0.0.1), BUS_PORT (default 47910), BUS_DB, BUS_LOG_LEVEL (info or debug). Logs to stderr. Stops cleanly on SIGTERM or SIGINT.
| Exit | Cause |
|---|---|
| 2 | refusing to bind <host> (bind guard), or invalid BUS_PORT |
| 3 | serve already running (pid N): another serve or a restore holds <BUS_DB>.lock |
| 1 | cannot listen on <host>:<port>: ... |
principal
session-bus principal add <id>
session-bus principal disable <id>
add fails (exit 1) if the id exists. disable makes every token of the principal invalid; it is idempotent.
token
session-bus token mint --principal <id> --scopes bus:read,bus:write [--label <text>] [--ttl-days N]
session-bus token list
session-bus token revoke <id>
mintprints the raw token (prefixsbus_) once on stdout.--ttl-daysis 1 to 90; the default is 90.--principaland--scopesare required.listprints a tab-separated table:id label creator_id scopes created_at expires_at revoked_at last_used_at. It never prints a token or a hash.revoketakes the token id fromlist.
session release
session-bus session release <name>
Deletes the session and its unacked mail. Use it to free a name held by another principal or to clear a full inbox. An invalid name exits 1.
doctor
session-bus doctor [--session <name>] [--rotate-instance]
Prints:
db: <path>
schema: 1
bus_instance_id: <uuid>
sessions: <count>
unacked: <count>
oldest_unacked_age_s: <seconds or ->
last_seen: <ISO time or ->
With --session, unacked, oldest_unacked_age_s and last_seen are for that session; an unknown session exits 1 (no such session <name>). --rotate-instance gives the database a new bus_instance_id; push shims then reset their cursor and push unacked mail again.
backup
session-bus backup <path>
Writes a consistent single-file copy with VACUUM INTO. Safe while serve runs. The copy gets a fresh bus_instance_id. Fails with output file already exists if <path> exists.
restore
session-bus restore <backup>
Replaces the live database with a backup. Stop serve first. Exits 3 with bus.db locked by pid N; stop serve first while anything holds the lock. There is no --force. See Backup and restore.
channel
session-bus channel [--session <name>] [--allow-from <principal,...>]
The stdio push shim. Claude Code starts it from the bus-push MCP entry; you do not run it by hand. Reads BUS_URL, SESSION_BUS_NAME, SESSION_BUS_TOKEN_CMD or SESSION_BUS_TOKEN, SESSION_BUS_TOKEN_CMD_TIMEOUT_MS, BUS_POLL_MS, XDG_STATE_HOME.
| Output (stderr) | Exit |
|---|---|
session-bus: no session name; push idle | none: idles, exits 0 when stdin closes |
session-bus: invalid session name "<value>"; push idle | none: idles, exits 0 when stdin closes |
BUS_URL must be a base URL ... | 2 |
SESSION_BUS_TOKEN_CMD failed | 2 |
no token; set SESSION_BUS_TOKEN_CMD or SESSION_BUS_TOKEN | 2 |
token rejected (401); fix the token and restart claude | 2 |
token lacks scope (403); mint with bus:read,bus:write | 2 |
session <name> already has a running shim (pid N) | 3 |
session name <name> is owned by another principal | 4 |
bus error (...); retrying in N ms | none: retries with backoff, max 60 s |
unregister skipped (...) | exit code unchanged |
On a clean exit (stdin closed, SIGTERM, SIGINT) a named shim that registered calls unregister for its session, capped at 3 s. See Push and pull.
--help
session-bus --help (or -h, help, or no arguments) prints the usage text and exits 0.