Mika Kuns 462d6561e1 feat(plugin): per-session mailbox identity + mailbox-update command
The hook now derives a unique mailbox name from the session_id supplied
on hook stdin, so two parallel Claude Code sessions in the same project
get distinct mailboxes (e.g. `claude-a8b3c1d2`, `claude-d4e5f6a7`)
instead of colliding on a shared env value. An optional
CLAUDE_MAILBOX_NAME base prefix flavors the names as `<base>-<sid>`.

Adds:
- `claude-mailbox session-announce` subcommand for the new SessionStart
  hook, which prints the current session's mailbox name to context
- `/claude-mailbox:mailbox-update` slash command for `npm update` +
  daemon restart
- stdin parsing helpers (parseHookStdin, deriveSessionName) with unit
  tests; the doctor no longer needs a mandatory name prompt
2026-05-19 11:39:14 +02:00
2026-04-24 18:26:11 +02:00
2026-04-24 18:26:11 +02:00
2026-04-24 18:26:11 +02:00
2026-04-24 18:26:11 +02:00
2026-04-24 18:26:11 +02:00

ClaudeMailbox

A standalone MCP mail server that lets parallel Claude sessions coordinate with each other. Any Claude session (plain terminal, ClaudeDo worktree, anything that consumes .mcp.json) can send messages to a peer session's inbox, check for pending messages, and discover other active mailboxes.

Not a substitute for run_in_background: true — that handles single-session responsiveness. This handles session-to-session coordination.

Architecture

One long-running daemon binds HTTP on loopback, hosts the MCP server at /mcp and a small REST API at /v1/*, and persists state in a single SQLite file. Sessions declare themselves via an X-Mailbox header in their .mcp.json.

 session-backend                 session-frontend           external sender
 (X-Mailbox: backend)            (X-Mailbox: frontend)      (CLI / UI / hook)
        |                                |                          |
        |  HTTP                          |                          |
        +--------------+-----------------+--------------------------+
                       v
         claude-mailbox serve  (ASP.NET Core + Kestrel)
           /mcp      MCP tools
           /v1/*     REST for non-MCP senders
           /health
                       v
         ~/.claude-mailbox/mailbox.db  (SQLite WAL)

Install

The recommended path is the npm package — it works on Windows, macOS, and Linux.

# one-time per machine: point the @kuns scope at the public Gitea npm registry
npm config set @kuns:registry=https://git.kuns.dev/api/packages/releases/npm/

# install
npm install -g @kuns/claude-mailbox

Or use the bootstrap one-liner:

# Windows
irm https://git.kuns.dev/releases/ClaudeMailbox/raw/branch/main/install.ps1 | iex
# macOS / Linux
curl -fsSL https://git.kuns.dev/releases/ClaudeMailbox/raw/branch/main/install.sh | sh

macOS users can also install via Homebrew once the tap is published:

brew install kuns/tap/claude-mailbox

Autostart

claude-mailbox install-autostart            # per-user, no admin
claude-mailbox install-autostart --service  # Windows only: register as a Windows Service (admin)
claude-mailbox status                       # Running | Stopped | NotInstalled
claude-mailbox uninstall-autostart [--purge]
Platform Default mechanism --service mechanism
Windows Scheduled Task at logon (no admin) Windows Service (admin, via node-windows)
macOS launchd LaunchAgent in ~/Library/LaunchAgents/ n/a
Linux systemd --user unit in ~/.config/systemd/user/ n/a

Config precedence

CLI flag   >   mailbox.json   >   built-in defaults

mailbox.json is searched at ~/.claude-mailbox/mailbox.json (per-user), and on Windows additionally at %ProgramData%\ClaudeMailbox\mailbox.json (machine-wide, written by --service install). Pass --config <path> to override.

Defaults: port 47822, bind 127.0.0.1, database at ~/.claude-mailbox/mailbox.db.

Smoke test

claude-mailbox install-autostart
claude-mailbox status
curl http://127.0.0.1:47822/health
claude-mailbox uninstall-autostart --purge

Build the .NET binary (alternative)

The original .NET 8 implementation still lives in src/ClaudeMailbox/. Build a self-contained Windows exe with:

dotnet publish src/ClaudeMailbox -c Release -r win-x64 --self-contained -p:PublishSingleFile=true

Put the resulting claude-mailbox.exe on your PATH and use the legacy install-service verbs (Windows-only, admin shell):

claude-mailbox install-service [--port 47822] [--bind 127.0.0.1] [--db-path <path>]
claude-mailbox uninstall-service [--purge]

The .NET and Node builds are wire-compatible (same port, same X-Mailbox header, same MCP tool names, same SQLite schema), so a .mcp.json configured against one works against the other.

Use from Claude Code (plugin)

Easiest path — three prompts, all inside Claude Code:

/plugin marketplace add https://git.kuns.dev/releases/ClaudeMailbox
/plugin install claude-mailbox@claude-mailbox
/claude-mailbox:mailbox-doctor

The doctor command auto-installs the daemon binary via npm (asks first), registers autostart, optionally takes a base prefix (e.g. backend), and runs a smoke test. Subsequent slash commands:

  • /claude-mailbox:mailbox-status — read-only health check
  • /claude-mailbox:mailbox-update — pull the latest daemon version and restart

Each Claude session gets its own mailbox identity derived from the session's UUID — claude-a8b3c1d2 by default, or <base>-a8b3c1d2 if you set a prefix. Parallel sessions in the same project automatically get distinct names. The SessionStart hook announces the current session's name in context so Claude knows its own identity. Peers discover each other via mcp__mailbox__list_mailboxes.

If the daemon goes down later, the hook emits a one-line setup hint instead of staying silent.

See plugin/README.md for the full walkthrough.

Use from a Claude session

Drop this into your project's .mcp.json (one per session, different X-Mailbox values):

{
  "mcpServers": {
    "mailbox": {
      "type": "http",
      "url": "http://127.0.0.1:47822/mcp",
      "headers": {
        "X-Mailbox": "backend"
      }
    }
  }
}

Four MCP tools are exposed:

Tool Purpose
mcp__mailbox__send(to, body) Send a message to another mailbox
mcp__mailbox__check_inbox() Pull all pending messages for this mailbox (marks delivered)
mcp__mailbox__peek_inbox() Non-consuming check — returns { pending, oldestAt }
mcp__mailbox__list_mailboxes() Discover known mailboxes and who has mail for you

Suggested CLAUDE.md snippet for poll discipline

When coordinating with a peer session, call mcp__mailbox__peek_inbox
after each subagent completes. If pending > 0, call mcp__mailbox__check_inbox
and treat the messages as input with priority over the current plan.

CLI client mode

Any external process (scripts, UIs, hooks) can talk to a running daemon without needing MCP:

claude-mailbox send  --to <mailbox> --from <mailbox> --body <text> [--url http://127.0.0.1:47822]
claude-mailbox peek  --name <mailbox>                              [--url ...]
claude-mailbox check --name <mailbox>                              [--url ...]
claude-mailbox list                                                [--url ...]

The CLI subcommands are thin HTTP clients against the /v1/* endpoints.

REST surface

Method Path Requires X-Mailbox Purpose
GET /health no { status, version, dbPath }
POST /v1/send yes (sender) { to, body }
GET /v1/peek?name=<mailbox> no read-only status
POST /v1/check-inbox?name=<mailbox> yes (must match name) consume inbox
GET /v1/list no list all mailboxes

Development

dotnet build
dotnet test tests/ClaudeMailbox.Tests/ClaudeMailbox.Tests.csproj
dotnet run --project src/ClaudeMailbox -- serve

Test suite covers end-to-end coordination, concurrent check_inbox race safety, and schema idempotency.

Scope

  • Loopback bind only (v1). Cross-machine coordination is a future extension — swap the middleware for token auth and change the bind address.
  • No auth on loopback. Local filesystem permissions are the trust boundary.
  • No message expiry or cleanup. Delivered messages stay as a timeline/audit log.
Description
No description provided
Readme 965 KiB
v1.5.6 Latest
2026-05-27 11:16:51 +00:00
Languages
TypeScript 85.3%
JavaScript 12.6%
PowerShell 0.9%
Ruby 0.7%
Shell 0.5%