docs: document watch --block push delivery and bootstrap behavior
Adds a Push delivery (watch) section to the root README with exit-code table, cross-process semantics, and the active-vs-idle latency caveat that came out of the empirical Claude Code BashOutput test. Adds a brief reference + cross-link in node/README.md, and notes the SessionStart bootstrap behavior in plugin/README.md alongside the existing hook table. Adds /v1/watch to the REST surface table and the watch verb to the CLI listing. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
31
README.md
31
README.md
@@ -150,6 +150,35 @@ and treat the messages as input with priority over the current plan.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Push delivery (watch)
|
||||||
|
|
||||||
|
The `watch --block` subcommand turns mail delivery from pull (poll between turns) into push (the receiver reacts as soon as a peer sends). It's a long-poll that exits the moment one message arrives.
|
||||||
|
|
||||||
|
```
|
||||||
|
claude-mailbox watch --block --name <mailbox> [--timeout 25] [--url <daemon>]
|
||||||
|
```
|
||||||
|
|
||||||
|
Intended use: a Claude Code background bash task. The plugin's `SessionStart` hook now tells Claude to start one on its first turn, so peers can `mcp__mailbox__send` to it and Claude reacts mid-session via `BashOutput` — no user prompt needed. After every exit Claude relaunches the watcher in the background.
|
||||||
|
|
||||||
|
| Exit code | Meaning |
|
||||||
|
|---|---|
|
||||||
|
| `0` | One message delivered (or mailbox renamed — stdout disambiguates) |
|
||||||
|
| `1` | Generic error (e.g. missing `--name`) |
|
||||||
|
| `2` | Daemon unreachable |
|
||||||
|
| `3` | Timeout reached with no message |
|
||||||
|
|
||||||
|
The CLI consumes exactly one message per cycle (single-delivery, FIFO winner across concurrent watchers on the same mailbox). Backlog drains one message per reconnect (~100 ms turnaround).
|
||||||
|
|
||||||
|
Cross-process semantics:
|
||||||
|
- **Concurrent watchers on the same mailbox:** the first to register wins each individual message; others continue waiting.
|
||||||
|
- **Rename mid-watch:** the open `watch` exits 0 with a `Mailbox renamed to '<new>'` notice; relaunch with the new `--name`.
|
||||||
|
- **Daemon restart:** all watchers see exit 2; back off and retry.
|
||||||
|
- **Session end:** Claude Code reaps background bash on exit; the `fetch` aborts and the daemon-side waiter is cleaned up.
|
||||||
|
|
||||||
|
**When push helps:** during active turns where the receiver is busy with tool calls — `BashOutput` notifications surface between tool calls, so peer messages arrive mid-turn. **When push degrades to pull:** when the receiver is idle between turns, BashOutput is buffered until the next user prompt, at which point the existing `UserPromptSubmit` poll hook delivers the same message. The two channels coexist.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## CLI
|
## CLI
|
||||||
|
|
||||||
Any external process — scripts, UIs, manual debugging — can talk to a running daemon directly:
|
Any external process — scripts, UIs, manual debugging — can talk to a running daemon directly:
|
||||||
@@ -158,6 +187,7 @@ Any external process — scripts, UIs, manual debugging — can talk to a runnin
|
|||||||
claude-mailbox send --from <mailbox> --to <mailbox> --body <text>
|
claude-mailbox send --from <mailbox> --to <mailbox> --body <text>
|
||||||
claude-mailbox peek --name <mailbox>
|
claude-mailbox peek --name <mailbox>
|
||||||
claude-mailbox check --name <mailbox> [--hook]
|
claude-mailbox check --name <mailbox> [--hook]
|
||||||
|
claude-mailbox watch --block --name <mailbox> [--timeout 25]
|
||||||
claude-mailbox list
|
claude-mailbox list
|
||||||
claude-mailbox status
|
claude-mailbox status
|
||||||
claude-mailbox session-announce # hook helper, reads stdin JSON
|
claude-mailbox session-announce # hook helper, reads stdin JSON
|
||||||
@@ -177,6 +207,7 @@ All subcommands accept `--url <url>` to target a non-default daemon address.
|
|||||||
| `POST` | `/v1/send` | yes (sender) | body: `{ to, body }` |
|
| `POST` | `/v1/send` | yes (sender) | body: `{ to, body }` |
|
||||||
| `GET` | `/v1/peek?name=<mailbox>` | no | read-only status |
|
| `GET` | `/v1/peek?name=<mailbox>` | no | read-only status |
|
||||||
| `POST` | `/v1/check-inbox?name=<mailbox>` | yes (must match `name`) | consume inbox |
|
| `POST` | `/v1/check-inbox?name=<mailbox>` | yes (must match `name`) | consume inbox |
|
||||||
|
| `GET` | `/v1/watch?name=<mailbox>&timeout=<sec>` | yes (must match `name`) | long-poll one message: `200` + body / `204` timeout / `409 { reason: "renamed", to }` |
|
||||||
| `GET` | `/v1/list` | optional (presence registers caller) | list all mailboxes |
|
| `GET` | `/v1/list` | optional (presence registers caller) | list all mailboxes |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -39,6 +39,16 @@ Under the hood the hook runs `claude-mailbox check --name <mailbox> --hook`, whi
|
|||||||
|
|
||||||
Cost: one local HTTP round-trip plus Node coldstart per prompt (~100ms on Windows).
|
Cost: one local HTTP round-trip plus Node coldstart per prompt (~100ms on Windows).
|
||||||
|
|
||||||
|
## Push delivery (watch)
|
||||||
|
|
||||||
|
For long-running autonomous sessions, run the watcher as a background bash task so peer messages surface immediately via `BashOutput`:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
claude-mailbox watch --block --name <mailbox>
|
||||||
|
```
|
||||||
|
|
||||||
|
Exit codes: `0` delivered or renamed, `1` error, `2` daemon unreachable, `3` timeout. See the [repository README](https://git.kuns.dev/releases/ClaudeMailbox/src/branch/main/README.md#push-delivery-watch) for the full contract.
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
`npm install` returns `401 Unauthorized`
|
`npm install` returns `401 Unauthorized`
|
||||||
|
|||||||
@@ -45,6 +45,8 @@ The `SessionStart` hook announces the current session's mailbox name in the conv
|
|||||||
|
|
||||||
Cost: one local HTTP round-trip per prompt and per subagent stop + Node coldstart (~100ms on Windows).
|
Cost: one local HTTP round-trip per prompt and per subagent stop + Node coldstart (~100ms on Windows).
|
||||||
|
|
||||||
|
The SessionStart announcement also instructs Claude to start `claude-mailbox watch --block --name <derived-name>` as a background bash task on its first turn. While that watcher is alive, peers can `mcp__mailbox__send(...)` and Claude reacts mid-turn — no user prompt needed. After processing each completion (delivery, timeout, rename, or daemon-down), Claude relaunches the watcher in the background. The pull hook (`UserPromptSubmit`) remains as a fallback for any messages that arrive while no watcher is running.
|
||||||
|
|
||||||
## MCP tools
|
## 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.
|
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.
|
||||||
|
|||||||
Reference in New Issue
Block a user