Spike C — Plumbing proof for the relay/CLI loop
Status: ready to execute. Plumbing has been verified standalone (without Claude in the loop) and all three internal tests pass. The remaining test is the full round-trip through a real Claude Code session.
What this proves (and only this):
- ✅ A real Node HTTP+SSE relay with the four production routes (
/prompts, /prompt-stream, /events, /transcript-stream) under bearer auth.
- ✅ The production-shape
bin/monitor-prompts (always-on, session-state-gated, SSE consumer with bearer auth, no reliance on $CLAUDE_PLUGIN_DATA).
- ✅ The session-state gate works as a negative control — if
session.json is absent or mode != "host", nothing reaches Claude, even when prompts are flying through the relay.
- (Pending the runbook below) The full round-trip: joiner POSTs a prompt → relay → host monitor stdout → Claude wakes & responds → host's
Stop hook POSTs the response → joiner sees it on /transcript-stream.
What this explicitly does NOT prove (out of scope):
- The TUI (joiner just
console.logs — pure plumbing).
- Pairing / approvals / per-member tokens (single shared
COLLAB_CLAW_TOKEN).
PreToolUse / PostToolUse (Spike A confirmed the four hook events fire correctly).
- Skills beyond
host.
- Cross-network via Cloudflared.
Pass criterion: joiner.mjs --send "<prompt>" causes Claude on the host to respond, and the response shows up on the joiner's stdout. Sub-3s end-to-end on localhost.
Files
spikes/spike-c/
├── .claude-plugin/marketplace.json # marketplace catalog
├── plugin/
│ ├── .claude-plugin/plugin.json # manifest with top-level `monitors` (Spike B F5)
│ ├── hooks/hooks.json # Stop hook only
│ ├── skills/host/SKILL.md # /collab-claw-spike-c:host (disable-model-invocation)
│ └── bin/
│ ├── host # writes ~/.collab-claw/session.json (opens the gate)
│ ├── monitor-prompts # production-shape session-gated SSE consumer
│ └── stop # POSTs last assistant message to /events
├── relay/server.mjs # 4-route HTTP+SSE relay
└── joiner.mjs # Node CLI: send prompt + watch transcript
Prereqs
- macOS or Linux
- Claude Code 2.1.105+ (we tested on 2.1.119)
node 18+
jq, curl on PATH
node --version # v18+
jq --version
curl --version | head -1
Runbook
You'll need three terminals.
Terminal A — relay
cd spikes/spike-c
node relay/server.mjs
# logs:
# [...] spike-c relay listening on http://127.0.0.1:7475
Leave this running. Watch its log throughout.
Terminal B — install + run Claude Code as the host
# 1. Install the plugin
claude
> /plugin marketplace add sankalpgunturi/collab-claw-spike-c
> /plugin install collab-claw-spike-c@collab-claw-spike-c
> /reload-plugins
# 2. Verify the always-on monitor started (session.json absent, gate closed)
> /exit
$ tail ~/.claude/data/collab-claw-spike-c/monitor.log
# expect lines:
# [...] gate=closed (session.json absent or mode!=host); idling 5s
# 3. Open a fresh Claude session and host
$ claude
> /collab-claw-spike-c:host
# claude prints the verbatim banner from bin/host
# At this point session.json is written. Within ~5 seconds the monitor
# log should flip:
# [...] gate=open relay=http://127.0.0.1:7475 connecting SSE (max 30s)
# 4. Verify with healthz
$ curl -s http://127.0.0.1:7475/healthz
# {"ok":true,"promptSubscribers":1,"transcriptSubscribers":0}
# Leave this Claude session IDLE. Don't type anything.
Terminal C — the joiner
Test 1 — Negative control (gate closed before T-host)
Skip this if you already verified the standalone tests passed during scaffolding. The standalone tests exercise the same gate logic with no Claude in the loop, which is what we want for the negative control.
Test 2 — Positive: full round-trip with Claude in the loop
cd spikes/spike-c
COLLAB_CLAW_NAME=Sankalp node joiner.mjs --send "please write a one-line python script that prints the current time"
Expected behavior, in order:
- Joiner prints
Sankalp (you) and the prompt body, plus POST /prompts -> 200 {"ok":true,"delivered":1}.
- Within ~1s, Terminal B's Claude wakes up (no input from the host) and starts responding to
[Sankalp]: please write a one-line python script that prints the current time. Watch it write the script.
- When Claude finishes its turn, the
Stop hook fires. Watch ~/.claude/data/collab-claw-spike-c/hook.log for a line like stop: POST /events rc=0 bytes=… resp=….
- Joiner prints
Surya (host) followed by Claude's full response.
- Joiner prints
(round-trip: NNN ms). Pass criterion: NNN < 3000 on localhost.
Test 3 — Negative control mid-loop (optional)
After test 2 succeeds:
# Force-close the gate
rm ~/.collab-claw/session.json