Files
ClaudeMailbox/plugin/README.md
Mika Kuns b10ac36ed0 feat(naming)!: auto-derive mailbox name from project + runtime rename
Mailbox names are now built as <project>-<session-short>, where <project>
is the sanitized git-repo basename (or cwd basename) — no more env-var
prefix step. Sessions can re-tag themselves at runtime via the new
mcp__mailbox__rename tool (POST /v1/rename), which transfers all
pending messages to the new name in a single transaction. Peers using
the old name re-discover via list_mailboxes.

BREAKING: \$CLAUDE_MAILBOX_NAME is no longer read. Existing setups that
relied on the env-var prefix should remove it from .claude/settings.json;
the prefix now comes from the working directory automatically.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 13:14:15 +02:00

93 lines
5.2 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. runs a self → self smoke test
After that, every prompt auto-pulls unread messages.
## Mailbox identity (the important bit)
Each Claude Code session gets its own mailbox name, automatically derived as `<project>-<session-short>`:
| Where the session runs | Resulting mailbox name |
|---|---|
| Inside a git repo | `<repo-basename>-a8b3c1d2` (e.g. `claude-mailbox-a8b3c1d2`) |
| Outside a git repo | `<cwd-basename>-a8b3c1d2` |
| No cwd in stdin (rare) | `claude-a8b3c1d2` |
So if you open two Claude Code sessions in the same project, they'll share the project prefix but differ in the session-short — e.g. `claude-mailbox-a8b3c1d2` and `claude-mailbox-d4e5f6a7`. No env-var, no manual prefix step.
If a session focuses on a sub-area (frontend, backend, …), Claude can call `mcp__mailbox__rename(current_name="…", new_name="claude-mailbox-frontend-a8b3c1d2")` to tag itself; pending messages are transferred. Peers using the old name re-discover via `list_mailboxes`.
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. |
| `mcp__mailbox__rename` | `current_name`, `new_name` | Rename your own mailbox (e.g. add an area tag). Pending messages are transferred. Use the new name afterward. |
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
```