docs(handoff): state after epics A–E
So Many Crows
A flock of AI agents. Hand it a todo list; a Sentry crow triages each item, crows fly, and trust is earned over time.
Version one: command-line, text-only crows. No web, files, or APIs until each has guardrails.
Run
go build -o crows .
./crows run todo.txt # offline mock brain (no key needed)
ANTHROPIC_API_KEY=... ./crows run todo.txt # real crows (Claude)
./crows trust # trust ledger
./crows log -n 20 # flight log
Optional: CROWS_MODEL overrides the model. Results land in todo.crows.md; state lives in .crows/.
Web server
cd ui && npm install && npm run build && cd .. # builds the UI into ./web
./crows serve # localhost:8080; API + Server-Sent Events (SSE); Ctrl-C to stop
The server runs the same pipeline as crows run, but items fly in parallel and approvals come over HTTP. EVENTS.md is the contract for events and the API:
curl -XPOST localhost:8080/api/lists -d '{"text":"- [ ] What is a crow","requester":"me"}'
curl -N "localhost:8080/api/events?list_id=<id>" # replays the list's events so far, then streams
curl -XPOST localhost:8080/api/verdicts -d '{"item_id":"<id>-1","target":"triage","approve":true}'
curl localhost:8080/api/trust
- Item IDs are
<list_id>-<n>, numbered from 1 in list order. - Approvals left unanswered for 10 minutes count as rejected (
verdict: timeout).-approval-timeoutchanges this for testing. - A flooding requester gets 429 with
messageandcooldown_s; any list of theirs that is still flying also getsrequester.pranked. - UI development: run
crows serve, thencd ui && npm run dev(Vite proxies/api). The crow art isart/crow.svg; the UI'sCrowViewmirrorsRIVE_CONTRACT.md, so a Rive-backed view replaces the SVG stand-in later. - POST bodies are capped at 64 KB. Static files are served from
./webwhen that folder exists.
Nests
A nest is a room where a team of crows works together. Create one with its core crows; jobs in that nest use the core first and borrow from the rest of the flock when they need more (a murder of 3 in a 2-crow nest borrows one). The Sentry and Elder serve every nest.
curl localhost:8080/api/nests # {"roster": [...], "nests": [...]}
curl -XPOST localhost:8080/api/nests -d '{"name":"Launch copy","crows":["Pepper","Inky"]}' # 201, nest_id "launch-copy"
curl -XPOST localhost:8080/api/lists -d '{"text":"- [ ] Should we launch on a Tuesday","nest_id":"launch-copy"}'
./crows run todo.txt -nest launch-copy
- The default nest is
todo, with an empty core: crows come from the whole flock and are never "borrowed". crow.flyingcarriesborrowed: truefor a crow from outside the nest's core.- Names are 1–40 characters;
nest_idis the name as a slug and must be unique (409 on a clash). 1–8 roster crows, no repeats, at most 20 nests. Nests are saved in.crows/nests.json.
Jev triage (optional)
With TYPESAFE_API_KEY set, the Sentry asks Jev (TypeSafe's classifier) for mode and task type first. Jev's call stands when both answers reach CROWS_JEV_THRESHOLD (default 0.7) and no subtasks are needed. Otherwise the LLM Sentry decides: when Jev is unsure, when it calls a split (the LLM writes subtasks), or when Jev fails. The plan's reason shows Jev's confidence, and the flight log records each Jev call.
How an item flies
- Sentry classifies it:
solo(one crow),split(2–4 subtasks in parallel), ormurder(3 crows answer independently). - Split and murder results go to the Elder, who merges them and flags disagreement.
- You approve or reject, depending on trust.
Trust ladder
| Level | Triage | Output |
|---|---|---|
| Stranger | you approve | you approve |
| Regular | you approve | auto-accepted, marked unreviewed |
| Trusted | runs on its own | runs on its own |
- Promotion: 10 clean approvals in a row (the flock as a whole needs 20).
- Demotion: one rejection drops a level.
- A crow's level blends its own record with the flock's record for that task type, so new crows start on the flock's reputation.
- The Sentry earns triage trust separately, per task type.
- The least-trusted crow on a job sets the approval bar.
Guardrails (guardrails.go)
| Guardrail | Default |
|---|---|
| Crows in flight | 5 |
| Murder size | 3 |
| Items per list | 20 |
| Subtasks per split (depth 1, never re-split) | 4 |
| Tokens per item / per list | 20,000 / 100,000 |
| Crow timeout | 60s |
| Requests per minute per requester | 5 |
| Cooldown | 30s, doubling per strike, max 1h |
Fail-safe: any answer other than y, including no input, is a no.
Abuse
Flooding the flock earns a mild prank message and a cooldown. Strikes fade one per clean day. Nothing destructive, nothing public.