Skip to main content

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)​

CodeMeaning
0Success.
1Error. One line on stderr: session-bus: <message>.
2Usage error (the usage text is printed on stderr), or a refused configuration (see each command).
3A lock is held by another process.
4channel 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.

ExitCause
2refusing to bind <host> (bind guard), or invalid BUS_PORT
3serve already running (pid N): another serve or a restore holds <BUS_DB>.lock
1cannot 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>
  • mint prints the raw token (prefix sbus_) once on stdout. --ttl-days is 1 to 90; the default is 90. --principal and --scopes are required.
  • list prints 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.
  • revoke takes the token id from list.

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 idlenone: idles, exits 0 when stdin closes
session-bus: invalid session name "<value>"; push idlenone: idles, exits 0 when stdin closes
BUS_URL must be a base URL ...2
SESSION_BUS_TOKEN_CMD failed2
no token; set SESSION_BUS_TOKEN_CMD or SESSION_BUS_TOKEN2
token rejected (401); fix the token and restart claude2
token lacks scope (403); mint with bus:read,bus:write2
session <name> already has a running shim (pid N)3
session name <name> is owned by another principal4
bus error (...); retrying in N msnone: 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.