# agent-watcher-mcp (Layer 2) The MCP Watcher: a Claude Code stdio MCP server that surfaces ping-inbox events into your Claude Code session via Channels, and exposes reply tools (`ack` / `respond` / `mark_handled`) so Claude can react. Spec: `../spec/agent-watcher.md` §4. ## What it does 1. Resolves identity (env / `$CLAUDE_HOME/ping-agent` / `~/.ping-agent`). 2. Writes `pings/..watcher-active` so the existing agent-ping `UserPromptSubmit` hook stands down on this host. 3. Watches `pings/.inbox` via inotify (chokidar). 4. On change, drains unread pings (since HWM), applies sentinel deferral (warn-after-3), and emits each as a `notifications/claude/channel` event. 5. Exposes three MCP tools so Claude can ack, respond, or mark a ping handled. 6. Removes the sentinel on graceful shutdown. ## Install Per CLAUDE.md rule #2, the agent does not install on itself. A human runs: ```bash cd /path/to/agent-watcher/mcp-watcher ./install.sh ``` This installs deps, builds, symlinks the binary into `~/.local/bin/`, adds `.stignore` patterns, and prints the `mcp.json` snippet to paste into Claude Code's config. ## Launch Channels is in research preview. Start Claude Code with: ```bash claude --dangerously-load-development-channels server:agent-watcher ``` ## Sandbox testing To run a separate Claude Code session with a different identity (so it won't compete with the default `~/.ping-agent` for inbox reads): ```bash mkdir -p ~/.claude-sandbox echo sandbox > ~/.claude-sandbox/ping-agent CLAUDE_HOME=~/.claude-sandbox \ claude --dangerously-load-development-channels server:agent-watcher ``` The sandbox session reads `pings/sandbox.inbox` and writes `pings/.sandbox.watcher-active` — fully isolated from prod. ## How it interacts with agent-ping The `agent-ping` UserPromptSubmit hook checks for the sentinel file `pings/..watcher-active` at startup. If the file is present and the PID inside is alive, the hook stands down — the watcher is the delivery primitive. If the watcher exits (graceful or crash with stale sentinel cleared by the hook's age check), the hook resumes async-on-next-prompt delivery. This means **you can run with the watcher OR the hook OR both configured** — the sentinel arbitrates. ## Tests ```bash npm test # unit tests via vitest (35 currently passing) npm run typecheck # tsc --noEmit npm run build # tsc → dist/ ``` ## Observability - Logs to stderr (visible via `claude --debug` or the Claude Code MCP debug log at `~/.claude/debug/.txt`). - Sentinel file content includes PID + start time for the hook's age/liveness check. ## Limitations / v2 - Sentinel hook coexistence requires the agent-ping hook to know how to read the sentinel. PR pending against `agent-ping` to add the check. - No reconnection / restart on Claude Code session restart — Claude Code spawns the subprocess anew each session, so the watcher re-drains from HWM cleanly. - One watcher process per agent identity. Two sessions with the same identity contending on the same inbox is undefined behaviour (use `CLAUDE_HOME` to scope identities). - Channels is research preview; if the API changes, expect to update the meta-key sanitization or notification shape.