agent-mailbox
# agent-mailbox
**Give every local AI agent its own mailbox.**
One MCP server. Register once, message any agent on this machine. No cron. No polling daemons. No shared markdown files. No cloud.
π **Docs**: [English](README.md) Β· [δΈζ](README.zh-CN.md) Β· [ζ₯ζ¬θͺ](README.ja.md) Β· [EspaΓ±ol](README.es.md) β [Architecture diagram](docs/architecture-en.html) Β· [δΈζη](docs/architecture.html)

```bash
uvx --from git+https://github.com/polaris-smart/agent-mailbox agent-mailbox # stdio transport, ready for any MCP host
uvx --from git+https://github.com/polaris-smart/agent-mailbox agent-mailbox --http 8642 # or expose it over HTTP for remote agents
```
---
## The problem
Your coding agent, your ops agent, your review agent β all running on the same machine, all perfectly capable β cannot talk to each other. So **you** end up being the messenger: copying conclusions from one terminal, pasting instructions into another, relaying status updates by hand.
File-based workarounds (a shared markdown "log", a `dropped-notes/` folder) decay into an unreadable transcript. Cron-and-scan workarounds burn tokens on empty polls. Cloud relays put your workflow data behind someone else's API.
## The fix
A mailbox that is **just another tool**:
| Tool | What it does |
|---|---|
| `mailbox_register` | Claim your mailbox. Idempotent. |
| `mailbox_send` | Deliver to one agent, a list, or `"all"` for broadcast. |
| `mailbox_check` | Fetch pending messages β they auto-ack on read. |
| `mailbox_reply` | Reply inside a thread, auto-routed to the sender. |
| `mailbox_list` | Browse by status (`pending` / `acked` / `done`). |
| `mailbox_done` | Mark handled; done messages archive automatically. |
| `mailbox_broadcast` | One call, every registered agent. |
| `mailbox_whoami` | Who's registered, where the mail root is. |
Messages are plain JSON with a tiny lifecycle: `pending β acked β done`. A message that arrives while the recipient is offline simply waits β mail, like mail should.
## Quick start
**Hermes** (`~/.hermes/config.yaml`):
```yaml
mcp:
servers:
agent-mailbox:
command: uvx
args: ["--from", "git+https://github.com/polaris-smart/agent-mailbox", "agent-mailbox"]
```
**Claude Code** (`~/.claude/settings.json`):
```json
{ "mcpServers": { "agent-mailbox": { "command": "uvx", "args": ["--from", "git+https://github.com/polaris-smart/agent-mailbox", "agent-mailbox"] } } }
```
**Any MCP client** (stdio):
```bash
uvx --from git+https://github.com/polaris-smart/agent-mailbox agent-mailbox
```
**Remote agents** (e.g. an agent on another server):
```bash
uvx --from git+https://github.com/polaris-smart/agent-mailbox agent-mailbox --http 8642 # on the mail host
```
```json
{ "mcpServers": { "agent-mailbox": { "url": "http://your-host:8642/mcp" } } }
```
## Waiting for mail (no polling)
Agents don't need to poll. `mailbox_wait` blocks (long-poll) until a message
arrives β call it as the last action of a turn and the next message wakes your
agent immediately:
```json
{ "tool": "mailbox_wait", "arguments": { "timeout_seconds": 25 } }
```
For humans and dashboards, a companion watcher prints every new message as a
JSON line and can fire macOS notifications for chosen agents:
```bash
uvx --from git+https://github.com/polaris-smart/agent-mailbox agent-mailbox-watch --notify boss # macOS notification center
agent-mailbox-watch --once # single scan (cron-friendly)
```
## Design
- **Local-first** β plain JSON files under `~/.agent-mail/`. No SMTP, no IMAP, no domain, no cloud relay, no network by default.
- **Register-once addressing** β `mailbox_register("WB")` is all it takes; every registered agent is immediately addressable by everyone.
- **Zero external dependencies** β only `mcp`. The store is one Python file with `flock`-guarded atomic writes; multiple MCP host processes share one mail root safely.
- **Human-readable** β every message is a small JSON file you can `cat`. The boss can read the inbox directly.
- **Honors existing identities** β set `AGENT_MAIL_ID` in each agent's environment and its tools become self-addressed.
### When you outgrow it
Local mailboxes solve same-machine and trusted-LAN coordination. The message lifecycle (`pending β acked β done`) is designed to carry over unchanged when an agent's threads need to reach other machines and organizations over real email infrastructure.
## Security notes
- Mail root lives in your home directory; messages never leave the machine unless you opt into HTTP transport on a trusted network.
- Agent ids are strictly validated (`[A-Za-z0-9_-]`, β€64 chars) β no path traversal.
- The store is append-oriented with atomic writes and file locks; a crashed writer cannot corrupt the registry.
- For tamper-evidence, signed receipts (ed25519) are on the roadmap.
## Roadmap
- **v0.1.0** (current) β same-machine agent mailboxes over stdio MCP. Zero infrastructure. Includes long-poll `mailbox_wait` and a companion watcher β no polling daemons needed.
- **v0.2.0** β federation: streamable HTTP transport for agents on other machines (Tailscale/LAN friendly).
- **v0.3.0** β signed receipts (ed25519) for tamper-evident delivery.
- **v1.0.0** β cross-organization bridge: local threads reach agents on other machines and organizations over standard email infrastructure, with the same mailbox lifecycle.
Sister project: [dsh-devices](https://github.com/polaris-smart/dsh-devices) manages your devices; agent-mailbox manages the conversation between the agents on them.
## Development
```bash
git clone https://github.com/polaris-smart/agent-mailbox && cd agent-mailbox
pip install -e ".[dev]"
pytest
```
## License
MIT β see [LICENSE](LICENSE).
TDQS
Scored across 9 tools
mailbox_send with 'all' overlaps significantly with mailbox_broadcast, creating redundant paths for the same action. mailbox_check and mailbox_list both involve fetching messages, though check ack semantics and list filtering differentiate them. Overall boundaries are mostly clear but these overlaps introduce real selection ambiguity.
All tools share a consistent mailbox_ prefix and snake_case style, with most names following a verb form like check, register, send, reply, list, and wait. The non-verb names 'done' and 'whoami' deviate slightly, and send/broadcast are near-synonyms, but the overall pattern is coherent and predictable.
Nine tools is well-scoped for a mailbox domain, covering registration, sending, receiving, replying, listing, waiting, and completion. Each tool earns its place and the count does not feel bloated or thin.
The tool set covers the core mailbox lifecycle: register, send, receive, reply, list, wait, and mark handled, so typical agent communication flows are supported. Missing explicit archive/delete operations and unread/read state controls are minor gaps that agents can work around.