Files
ClaudeMailbox/README.md
Mika Kuns 42237149a1
Some checks failed
CI (Node) / build-test (push) Successful in 9s
Release (Node) / release (push) Failing after 1s
Release / release (push) Successful in 7s
feat: stdio MCP wrapper + Windows Run-key autostart fallback (v1.0.1)
Two production-readiness fixes so colleagues can install cleanly:

1. Plugin's MCP server now spawns `claude-mailbox mcp-stdio`, a small
   stdio MCP wrapper that proxies tool calls to the daemon's REST API.
   Claude Code does not support env-var substitution in HTTP MCP `url`
   fields (issue #46889), so the wrapper is the only way to make the
   daemon URL configurable per machine via CLAUDE_MAILBOX_URL.

2. Windows `install-autostart` now falls back from `schtasks /Create`
   to an HKCU\Software\Microsoft\Windows\CurrentVersion\Run entry
   when Group Policy blocks the Scheduled Task path. Both modes are
   per-user, no admin, persist across logoffs. The chosen mode is
   recorded in ~/.claude-mailbox/autostart-mode so status/start/stop/
   uninstall-autostart pick the right cleanup path.

Also bumps the npm version to 1.0.1 to align with the published 1.0.0
plus this patch.
2026-05-19 13:43:55 +02:00

245 lines
8.5 KiB
Markdown

# ClaudeMailbox
A standalone MCP mail server that lets parallel Claude sessions coordinate with each other. Messages are queued in a tiny SQLite database via a local HTTP daemon. Any Claude session — Claude Code, ClaudeDo worktree, plain MCP client — can send to a peer's inbox, check for pending messages, and discover other active mailboxes.
Not a substitute for `run_in_background: true` (which handles single-session responsiveness). This handles **session-to-session** coordination.
---
## Getting started
Pick one path. Most users want path A.
### A. Claude Code plugin (recommended — three prompts)
Inside Claude Code:
```
/plugin marketplace add https://git.kuns.dev/releases/ClaudeMailbox.git
/plugin install claude-mailbox@claude-mailbox
/claude-mailbox:mailbox-doctor
```
The doctor command does the rest:
1. installs the daemon binary via `npm install -g @kuns/claude-mailbox` if missing (asks first)
2. registers the daemon for autostart and starts it
3. optionally lets you pick a base prefix (e.g. `backend`, `frontend`); without one, mailbox names are anonymous (`claude-a8b3c1d2`)
4. runs a self → self smoke test
After that, every Claude Code session automatically:
- gets a **unique mailbox identity** derived from its session UUID (so two parallel sessions never collide),
- announces that identity and the **list of currently active peers** at session start,
- pulls unread mailbox messages into context before every prompt.
You can then say things like:
> "I started a second session, coordinate with it on the refactor."
Claude already has the peer's mailbox name in context from the SessionStart announcement, so it calls `mcp__mailbox__send(from="<my-name>", to="<peer>", body="...")` directly.
See [`plugin/README.md`](./plugin/README.md) for the full walkthrough, including the `mailbox-status` and `mailbox-update` slash commands.
### B. Manual install (no Claude Code plugin)
If you're using a different MCP client, scripts, or you don't want the plugin:
```sh
# 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 + autostart
npm install -g @kuns/claude-mailbox
claude-mailbox install-autostart
```
Or the bootstrap one-liner:
```powershell
# Windows
irm https://git.kuns.dev/releases/ClaudeMailbox/raw/branch/main/install.ps1 | iex
```
```sh
# macOS / Linux
curl -fsSL https://git.kuns.dev/releases/ClaudeMailbox/raw/branch/main/install.sh | sh
```
Then drop this into your project's `.mcp.json`:
```json
{
"mcpServers": {
"mailbox": {
"type": "http",
"url": "http://127.0.0.1:47822/mcp"
}
}
}
```
Optionally add a static identity (so your client doesn't need to pass `from` / `name` on every call):
```json
"headers": { "X-Mailbox": "backend" }
```
### C. Build the .NET binary from source
The original .NET 8 implementation lives in `src/ClaudeMailbox/`. Wire-compatible with the npm build (same port, same `X-Mailbox` header, same MCP tool names, same SQLite schema).
```powershell
dotnet publish src/ClaudeMailbox -c Release -r win-x64 --self-contained -p:PublishSingleFile=true
```
Put the resulting `claude-mailbox.exe` on `PATH`. Windows-only `install-service` verbs (admin shell):
```
claude-mailbox install-service [--port 47822] [--bind 127.0.0.1] [--db-path <path>]
claude-mailbox uninstall-service [--purge]
```
---
## How identity works
Every Claude Code session gets a unique mailbox name derived from its UUID:
| Setup | Resulting mailbox name |
|---|---|
| Default | `claude-<8-hex-of-session-id>` |
| `CLAUDE_MAILBOX_NAME=backend` (in `.claude/settings.json` env) | `backend-<8-hex>` |
| Manual `.mcp.json` with `X-Mailbox: backend` header (no plugin) | `backend` (legacy mode) |
The plugin's `SessionStart` hook prints the session's identity and the list of peers active in the last hour into the conversation context, so Claude knows who it is and who's around without needing to call any tools first.
---
## Autostart
```sh
claude-mailbox install-autostart # per-user, no admin
claude-mailbox install-autostart --service # Windows only: 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); falls back to HKCU Run-key if Group Policy blocks schtasks | Windows Service (admin, via `node-windows`) |
| macOS | launchd LaunchAgent in `~/Library/LaunchAgents/` | n/a |
| Linux | systemd `--user` unit in `~/.config/systemd/user/` | n/a |
---
## MCP tools
| Tool | Required args | Purpose |
|---|---|---|
| `mcp__mailbox__send` | `to`, `body`, `from` | Send a message. `from` falls back to X-Mailbox header. |
| `mcp__mailbox__check_inbox` | `name` | Pull all pending messages and mark delivered. Falls back to header. |
| `mcp__mailbox__peek_inbox` | `name` | Non-consuming `{ pending, oldestAt }`. Falls back to header. |
| `mcp__mailbox__list_mailboxes` | `name` | Discover known mailboxes + `pendingForYou`. Falls back to header. |
The plugin's SessionStart announcement tells Claude exactly which name to pass for the current session, so the args are filled in automatically.
### 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
Any external process — scripts, UIs, manual debugging — can talk to a running daemon directly:
```
claude-mailbox send --from <mailbox> --to <mailbox> --body <text>
claude-mailbox peek --name <mailbox>
claude-mailbox check --name <mailbox> [--hook]
claude-mailbox list
claude-mailbox status
claude-mailbox session-announce # hook helper, reads stdin JSON
claude-mailbox install-hook --name <mailbox> [--user|--project]
claude-mailbox uninstall-hook [--user|--project]
```
All subcommands accept `--url <url>` to target a non-default daemon address.
---
## REST surface
| Method | Path | `X-Mailbox` required | Purpose |
|---|---|---|---|
| `GET` | `/health` | no | `{ status, version, dbPath }` |
| `POST` | `/v1/send` | yes (sender) | body: `{ 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` | optional (presence registers caller) | list all mailboxes |
---
## 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). Override with `--config <path>`.
Defaults: port `47822`, bind `127.0.0.1`, database at `~/.claude-mailbox/mailbox.db`.
---
## 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.
```
session-A session-B external sender
mailbox: claude-a8b3c1d2 mailbox: claude-d4e5f6a7 (CLI / UI / script)
| | |
| HTTP | |
+--------------+-----------------+--------------------------+
v
claude-mailbox serve (npm: Fastify; .NET: Kestrel)
/mcp MCP tools
/v1/* REST for non-MCP senders
/health
v
~/.claude-mailbox/mailbox.db (SQLite WAL)
```
---
## Development
```sh
# Node port (the recommended runtime)
cd node
npm install
npm run build
npm test
# .NET 8 port (wire-compatible alternative)
dotnet build
dotnet test tests/ClaudeMailbox.Tests/ClaudeMailbox.Tests.csproj
dotnet run --project src/ClaudeMailbox -- serve
```
The test suites cover end-to-end coordination, concurrent `check_inbox` race safety, schema idempotency, hook stdin parsing, session-id derivation, and settings-file patching.
---
## 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. Delivered messages remain as an audit log.