---
name: patchcord:subscribe
description: >
  Start a persistent background WebSocket listener (Supabase Realtime) that
  wakes Claude when new Patchcord messages arrive. Survives across turns
  until the user kills it or closes the session. Use ONLY when the user
  explicitly runs /patchcord:subscribe.
---

User invoked /patchcord:subscribe — do NOT substitute `wait_for_message()`. Spawn the listener.

# Start

1. **Drain the inbox first.** Call `mcp__patchcord__inbox`. If anything is pending, process it per the patchcord:inbox skill before continuing. Backlog can accumulate while no listener was up; subscribe must catch it.

2. **Spawn the listener under Monitor** (not Bash with run_in_background — Monitor turns each stdout line into a notification):

   ```
   Monitor(
     description: "patchcord realtime listener",
     persistent: true,
     timeout_ms: 3600000,
     command: "patchcord subscribe | grep --line-buffered '^PATCHCORD:'; exit ${PIPESTATUS[0]}"
   )
   ```

   The grep filter drops internal `HEARTBEAT` keepalive lines (written every 30 s to detect a dead pipe) — only `PATCHCORD:` lines fire notifications. `${PIPESTATUS[0]}` preserves subscribe's exit code through the pipe.

   `subscribe.mjs` handles its own pidfile guard — if another listener is already active for this agent it exits with code 2 and stderr `already running (pid N)`. Monitor catches the stream-end event; read the output file and report.

3. **Tell the user one line:** *"Patchcord listener active — I'll pick up new messages as they arrive."*

# When a notification fires

Monitor surfaces `PATCHCORD: 1 new from <sender>`:

1. Say: *"Got a Patchcord ping from <sender> — checking inbox."*
2. Call `mcp__patchcord__inbox`.
3. Do the work per the patchcord:inbox skill, reply with what you did.

# Stopping

Tell the user one of:
- Close this Claude Code session.
- `kill $(cat /tmp/patchcord_subscribe_<namespace>_<agent>.pid)`

# If the Monitor stream ends

Read the output file. Scan the last ~15 lines for one of:

- `no .mcp.json in <cwd>` — session is not in a patchcord project dir
- `ticket: token rejected (HTTP 401|403)` — bad bearer; user regenerates from dashboard
- `ticket: server not configured for realtime` — self-hosted without Supabase
- `ticket: namespace not owned` — token lost its owner; regenerate
- `already running (pid N)` (exit 2) — another listener is active; report and stop
- `subscribe: fatal: ...` — surface the line verbatim

Report the cause in one sentence. STOP.

**Forbidden on failure:** no `pgrep`/`ps`/`kill`/`pkill`/`killall`, no pidfile writes, no respawning. The script manages pidfile cleanup itself; respawning will not fix a config problem.

No matching error pattern = the listener exited cleanly (session ended, user killed it, or EPIPE detected). Nothing to do.
