Delivers peer messages that arrive during a long-running subagent into the parent context the moment the Task tool returns, instead of waiting until the next user prompt. Reuses the existing `claude-mailbox check --hook` so the mailbox identity stays consistent with UserPromptSubmit. Plugin 1.2.0 → 1.3.0. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
90 lines
4.9 KiB
Markdown
90 lines
4.9 KiB
Markdown
# claude-mailbox plugin
|
|
|
|
Lets Claude Code pull unread messages from a local `claude-mailbox` daemon before every prompt and inject them into the conversation context. Each Claude session gets a **unique mailbox identity** auto-derived from its session id, so two sessions in the same project never collide.
|
|
|
|
## Setup (three prompts, all 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 walks the rest:
|
|
|
|
1. installs the `claude-mailbox` binary via `npm install -g @kuns/claude-mailbox` if missing (asks first)
|
|
2. registers the daemon for autostart and starts it if needed
|
|
3. health-probes `http://127.0.0.1:37849/health`
|
|
4. optionally lets you set a **base prefix** (e.g., `backend`) — without one, mailbox names are anonymous (`claude-XXXXXXXX`)
|
|
5. runs a self → self smoke test
|
|
|
|
Restart Claude Code only if step 4 wrote a new prefix. After that, every prompt auto-pulls unread messages.
|
|
|
|
## Mailbox identity (the important bit)
|
|
|
|
Each Claude Code session gets its own mailbox name, derived from the session's UUID:
|
|
|
|
| Configuration | Resulting mailbox name |
|
|
|---|---|
|
|
| No `CLAUDE_MAILBOX_NAME` set | `claude-a8b3c1d2` (first 8 hex chars of session_id) |
|
|
| `CLAUDE_MAILBOX_NAME=backend` in `.claude/settings.json` env | `backend-a8b3c1d2` |
|
|
|
|
So if you open two Claude Code sessions in the same project, they'll be e.g. `backend-a8b3c1d2` and `backend-d4e5f6a7` — distinct, addressable, no manual setup.
|
|
|
|
The `SessionStart` hook announces the current session's mailbox name in the conversation context on startup. Peers discover each other via `claude-mailbox list` or the `mcp__mailbox__list_mailboxes` MCP tool.
|
|
|
|
## What the hooks do
|
|
|
|
| Hook | Command | Effect |
|
|
|---|---|---|
|
|
| `SessionStart` | `claude-mailbox session-announce` | Registers the session with the daemon, then prints (a) this session's mailbox name, (b) the exact `from` / `name` args to pass to MCP tools, and (c) a list of other mailboxes active in the last hour — so Claude knows who's around without needing to call `list_mailboxes` first. |
|
|
| `UserPromptSubmit` | `claude-mailbox check --hook` | Pulls unread messages for the session's mailbox and injects them as context. Silent on empty inbox; emits a one-line setup hint when the daemon is unreachable. |
|
|
| `SubagentStop` | `claude-mailbox check --hook` | Same as `UserPromptSubmit`, but fires when a subagent finishes (Task tool). Lets the parent see peer messages that arrived during a long-running subagent run, instead of waiting until the next user prompt. |
|
|
|
|
Cost: one local HTTP round-trip per prompt and per subagent stop + Node coldstart (~100ms on Windows).
|
|
|
|
## MCP tools
|
|
|
|
The plugin ships a `.mcp.json` that spawns a **stdio MCP wrapper** (`claude-mailbox mcp-stdio`) so the daemon URL is configurable per machine via the `CLAUDE_MAILBOX_URL` env var (Claude Code doesn't yet support env substitution in HTTP MCP URLs — see issue #46889). The wrapper proxies tool calls to the daemon's REST API.
|
|
|
|
Each MCP tool takes the caller's mailbox name as an explicit argument (from the SessionStart announcement):
|
|
|
|
| Tool | Required args | Purpose |
|
|
|---|---|---|
|
|
| `mcp__mailbox__send` | `from`, `to`, `body` | Send a message to another mailbox. |
|
|
| `mcp__mailbox__check_inbox` | `name` | Pull all undelivered messages for your mailbox (marks delivered). |
|
|
| `mcp__mailbox__peek_inbox` | `name` | Non-consuming count of pending messages. |
|
|
| `mcp__mailbox__list_mailboxes` | `name` | Discover known mailboxes and `pendingForYou` counts. |
|
|
|
|
The SessionStart announcement spells out the exact args to pass, so Claude picks them up automatically.
|
|
|
|
## Slash commands
|
|
|
|
| Command | What it does |
|
|
|---|---|
|
|
| `/claude-mailbox:mailbox-doctor` | Diagnose + auto-fix the full setup. |
|
|
| `/claude-mailbox:mailbox-status` | Read-only health check. No changes. |
|
|
| `/claude-mailbox:mailbox-update` | Update the daemon to the latest npm version and restart it. |
|
|
|
|
## Coordinating two Claude Code sessions
|
|
|
|
1. Open two Claude Code sessions in the same (or different) project.
|
|
2. Each session's SessionStart hook registers itself with the daemon and prints both its own mailbox name and the **list of currently active peers** into context.
|
|
3. In session A you can simply say: *"I started a second session, coordinate with it."* Because the peer's mailbox name is already in context, Claude can call `mcp__mailbox__send(from="<my-name>", to="<peer-name>", body="...")` straight away — no manual `list_mailboxes` step needed.
|
|
4. Session B's `UserPromptSubmit` hook pulls the message on its next prompt and injects it as context.
|
|
|
|
You can also send from any shell:
|
|
|
|
```sh
|
|
claude-mailbox list
|
|
claude-mailbox send --from probe --to backend-a8b3c1d2 --body "hi"
|
|
```
|
|
|
|
## Uninstall
|
|
|
|
```
|
|
/plugin uninstall claude-mailbox@claude-mailbox
|
|
npm uninstall -g @kuns/claude-mailbox
|
|
claude-mailbox uninstall-autostart # if you registered it
|
|
```
|