- 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
2.7 KiB
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_idis<list_id>-<n>, numbered from 1 in list order.POST /api/listsreturns 202. Bad input returns 400 with{"message"}.POST /api/verdictsreturns 404 when nothing is waiting (including a second answer), 400 for a bad body.approveis 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.flyingandcrow.landedfire for the Sentry and Elder too.requester.prankedgoes 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 withLast-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.