{"slug": "one-inbox-for-every-claude-code-session-on-every-machine", "title": "One inbox for every Claude Code session on every machine", "summary": "A developer built sessionhub, an open-source (MIT) Go binary with a SQLite database that acts as a registry and unified inbox for every Claude Code session across multiple machines. The tool uses Claude Code hooks, an MCP server exposing report_progress and set_title, and an optional herdr plugin to track session status (live, blocked, stale, ended) and let users resume sessions or answer permission prompts remotely, including from a phone. Clients fail open with two-second network timeouts and a local write queue so Claude Code and herdr never stall when the hub is unreachable.", "body_md": "On a normal day I have somewhere between five and fifteen Claude Code sessions running. Some are on my laptop, some on a desktop, a few on a home server that never sleeps. They run inside [herdr](https://herdr.dev), an agent-aware terminal multiplexer, and I attach to them over SSH from whatever I'm holding at the time, which is often a phone.\n\nThat setup works well until you step away. Then three questions start nagging:\n\nNone of the tools I already had answered all three. So I built a small thing that does. It's called **sessionhub**, it's open source (MIT), and this post is about why it exists, how it works, and how you can run it.\n\nI want to be fair to the tools I use every day, because they're good at what they do:\n\nWhat was missing wasn't another terminal. It was a **registry**: one place that knows every session on every machine, what each one is working on in plain words, and what each one needs from me.\n\nsessionhub is one static Go binary with a SQLite database. The same binary is the server and every client. You run the server on one always-on machine and \"join\" each machine that runs Claude Code.\n\nFrom there:\n\n`live`, `blocked`, `stale`, or `ended`.` sessionhub resume <id>` focuses the pane, restarts the session, or prints the exact `ssh` command for the machine it's on. Or turn on Remote Control and continue in the Claude app.\nHere's the inbox on a phone, with a session asking to run `npm install`:\n\n```\n{\n  \"hooks\": {\n    \"SessionStart\": [{\n      \"matcher\": \"*\",\n      \"hooks\": [\n        { \"type\": \"command\", \"command\": \"~/.local/bin/sessionhub hook session-start\", \"async\": true },\n        { \"type\": \"command\", \"command\": \"~/.local/bin/sessionhub hook context\", \"timeout\": 5 }\n      ]\n    }],\n    \"UserPromptSubmit\": [{ \"hooks\": [\n      { \"type\": \"command\", \"command\": \"~/.local/bin/sessionhub hook prompt\", \"async\": true },\n      { \"type\": \"command\", \"command\": \"~/.local/bin/sessionhub hook context\", \"timeout\": 5 }\n    ]}]\n  }\n}\n```\n\nThe `context` hook is synchronous on purpose: its output is how the standing rules reach the prompt. It reads a local copy of the rules and never touches the network, so a prompt never waits on the hub.\n\n**2. An MCP server.** `sessionhub mcp` gives each session `report_progress` and `set_title`. A short snippet in `~/.claude/CLAUDE.md` tells Claude when to use them:\n\n```\n## Reporting progress to sessionhub\n\n- Call `report_progress` when you finish a task, when you start a task that\n  will take a while, and when you are blocked waiting on me or on something\n  external. Fill `done`, `in_flight`, and `waiting_on` with short one-line items.\n- Call `set_title` once the session has a clear purpose, and again if the\n  purpose changes.\n```\n\nThat's what turns \"blocked\" into \"waiting on: permission to run npm install\".\n\n**3. A herdr plugin (optional).** If you use herdr, its plugin registers the sessions in your panes, ends them when the pane closes, and runs a small watcher. The watcher is what lets the hub *do* things on a machine: type a message, turn on Remote Control, move a session, or start a new one.\n\nA tool that watches your agents must never become the reason they stall. So every client fails open. Hooks always exit 0. Every network call has a two-second limit. If the server is down, writes go to a local queue (`~/.local/state/sessionhub/queue.jsonl`) and drain later. Claude Code and herdr never wait on sessionhub.\n\nMachines poll the server; the server never reaches into them. When you tap **Allow once** on your phone, the `PermissionRequest` hook on that machine is holding a long poll open, and it picks up your answer. When you start a new session, the machine's watcher is long-polling for work and claims the request. That keeps the firewall story simple: the only open port is the hub's.\n\nThe CLI is where I spend most of my time:\n\n``` bash\n$ sessionhub ls\nMACHINE  ID        TITLE                     STATUS   AGE  REPORT\ntower    e5b07a1c  postgres 16 upgrade plan  live     1s   doing: writing the rollback steps\nbluebox  c18e5f43  rewrite the quickstart    live     1s   waiting: your review of the wording\nbluebox  a72d4b90  dark mode for settings    blocked  1s   doing: settings page\ntower    3f9c1e27  fix CI token rotation     live     1s   doing: re-running the pipeline\n\n$ sessionhub inbox\nBlocked (1)\n  a72d4b90  dark mode for settings  bluebox  1s  asks to use Bash: npm install\n\nWaiting on you (1)\n  c18e5f43  rewrite the quickstart  bluebox  1s  your review of the wording\n```\n\n`sessionhub show` gives the full picture for one session, including its report history:\n\n``` bash\n$ sessionhub show a72d\ntitle:     dark mode for settings\nmachine:   bluebox\nstate:     blocked\nbranch:    dark-mode\nresume:    ssh -t bluebox '~/.local/bin/sessionhub resume a72d4b90-...'\n\nreports (1, newest first)\n    done        theme tokens\n    in flight   settings page\n    waiting on  permission to run npm install\n```\n\nA few more I use daily:\n\n```\nsessionhub approve a72d                          # allow that npm install once (asks first)\nsessionhub rules add \"Never push to main.\"       # every session sees it, on every prompt\nsessionhub send --machine tower -m \"Wrap up and report progress.\"\nsessionhub move c18e bluebox                     # conversation, branch and uncommitted changes\nsessionhub start tower --dir ~/Code/api -m \"Fix the flaky test in ci.yml\"\n```\n\nThat last one is the newest feature, and it's the one I wanted most. On the dashboard it's a **New session** button: pick a machine and a directory (it suggests the ones you've used), optionally type a first prompt, and you get an **Open in Claude** link a few seconds later:\n\nNow I can start work on my home server from a train.\n\nYou can run the server and a client on one machine to see what it does:\n\n```\n# Download a release (Linux or macOS, amd64 or arm64) into ~/.local/bin,\n# or build it:\ngo install github.com/abdallah/session-hub/cmd/sessionhub@latest\n\n# This machine holds the server:\nmkdir -p ~/.config/sessionhub\ninstall -m 600 /dev/null ~/.config/sessionhub/server.toml\nsessionhub server &\n\n# Join it: creates a token, installs the hooks and the MCP server.\nsessionhub join localhost --name \"$(hostname -s)\"\n\n# Start claude anywhere, send a prompt, then:\nsessionhub ls\nsessionhub login --name my-phone   # a one-time sign-in link for the dashboard\n```\n\nFor more machines, run the server on an always-on box (there's a systemd unit and a `docker-compose.yml`), put it behind a tunnel or reverse proxy, and `sessionhub join` each machine. The [self-hosting guide](https://github.com/abdallah/session-hub/blob/main/docs/self-hosting.md) walks through it.\n\nBe honest with yourself about what this server can do. A machine token or a signed-in browser can approve tool calls, add rules that every session reads, type messages into sessions, and start new ones. That's the point of the tool, and it also means **a leaked credential can get Claude to run commands on your machines.**\n\nSo: keep the server on a private network if you can, use HTTPS if you expose it, turn on the Telegram alerts (they also fire whenever someone adds a rule), and use the per-machine opt-outs (`remote_permissions = false`, `remote_start = false`) on machines you want to keep hands-off. [SECURITY.md](https://github.com/abdallah/session-hub/blob/main/SECURITY.md) has a table of what each credential can do.\n\nI built sessionhub with Claude Code itself, which turned out to be a good test of the tool and of the process.\n\nEvery feature started as a short spec, then a plan broken into tasks, and each task had to meet a written definition of done before it counted. Two rules from that list did most of the work:\n\n`testdata/`, never from memory. The spec said it bluntly: verify against `--help` and the docs, and quote what you found.\nThe early plan was to host it on Cloud Run. An always-on instance came out at about $45–50 a month, so it moved to a systemd user service on a home server behind a Cloudflare Tunnel, which costs nothing extra.\n\nsessionhub is a personal, single-user tool: one person, their machines, no accounts or teams. That's deliberate, and I don't plan to change it. Things I do want:\n\nIf you run more than a couple of Claude Code sessions across more than one machine, I'd love to hear whether this matches your workflow, and where it doesn't.\n\n**Repo:** [https://github.com/abdallah/session-hub](https://github.com/abdallah/session-hub) (MIT, Linux and macOS binaries on the releases page)", "url": "https://wpnews.pro/news/one-inbox-for-every-claude-code-session-on-every-machine", "canonical_source": "https://dev.to/abdallah/one-inbox-for-every-claude-code-session-on-every-machine-2en4", "published_at": "2026-10-04 10:40:28+00:00", "updated_at": "2026-10-04 10:42:33.709039+00:00", "lang": "en", "topics": ["ai-agents", "developer-tools", "ai-tools", "agent-protocols", "mlops"], "entities": ["Claude Code", "sessionhub", "herdr", "Anthropic", "MCP", "Go", "SQLite"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/one-inbox-for-every-claude-code-session-on-every-machine", "markdown": "https://wpnews.pro/news/one-inbox-for-every-claude-code-session-on-every-machine.md", "text": "https://wpnews.pro/news/one-inbox-for-every-claude-code-session-on-every-machine.txt", "jsonld": "https://wpnews.pro/news/one-inbox-for-every-claude-code-session-on-every-machine.jsonld"}}