Files
so-many-crows/EVENTS.md
T
SmokeyandClaude Opus 5.5 940c74672a Add web server, event stream, and Rive contract
- crows serve: HTTP API, Server-Sent Events per list, web approvals
  with a 10-minute fail-safe timeout; localhost only by default
- Shared pipeline for command line and server; trust.changed events
- EVENTS.md: server/UI contract; RIVE_CONTRACT.md: data-binding spec
  for the animator (one Crow artboard for v1)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UQnSw4RRWp8uqpj3nsnnXF
2026-10-27 08:31:27 -06:00

2.7 KiB

Events: the shared contract

The Go server emits these over Server-Sent Events (SSE). The web UI turns them into Rive state machine inputs. Both sides build against this file; change it first, then the code.

Each SSE message: event: <name> and data: <JSON>. Every payload includes list_id and ts (RFC 3339).

Event Payload (besides list_id, ts) Meaning
list.started items: [{item_id, text}], requester Flock accepted a list
item.triaged item_id, mode (solo/split/murder), task_type, subtasks[], reason, needs_approval (bool) Sentry made its call
crow.flying item_id, crow A crow (or Sentry, Elder) took off
crow.landed item_id, crow, ok (bool), tokens, error? A crow came back, or didn't
item.answered item_id, answer, crows[], needs_approval (bool) Result ready
verdict item_id, target (triage/output), verdict (approved/rejected/auto/timeout) Judgment recorded
trust.changed holder (crow name or "flock"), task_type, from, to (0 stranger, 1 regular, 2 trusted) Level up or down
item.skipped item_id, reason Item dropped (rejected triage, budget, failure)
requester.pranked message, cooldown_s Abuse response
list.finished tokens_used, token_budget Done

HTTP API

Method Path Body / query Returns
POST /api/lists {"text": "<todo list>", "requester": "<id>"} {"list_id"}, or 429 with {"message","cooldown_s"} when pranked
GET /api/events ?list_id= SSE stream
POST /api/verdicts {"item_id", "target": "triage"|"output", "approve": bool} 204
GET /api/trust ledger JSON

Pending approvals that get no answer within 10 minutes count as rejected (verdict: timeout). Fail safe.

Settled details

  • item_id is <list_id>-<n>, numbered from 1 in list order.
  • POST /api/lists returns 202. Bad input returns 400 with {"message"}.
  • POST /api/verdicts returns 404 when nothing is waiting (including a second answer), 400 for a bad body. approve is required, so a missing value is never read as a no.
  • When trust skips approval, the server still emits verdict: "auto", so every target gets exactly one verdict.
  • crow.flying and crow.landed fire for the Sentry and Elder too.
  • requester.pranked goes to every list of that requester's still flying; if none, only the 429 is sent.
  • Each SSE message carries an id: line, so clients can reconnect with Last-Event-ID. Heartbeat comment every 15 seconds.
  • The server listens on localhost only by default. There is no login yet, and requester names are self-asserted.