- ui/: Vite + plain TypeScript, builds into ./web for `crows serve` - CrowView mirrors CrowModel in RIVE_CONTRACT.md (pose, trust, reactions) so the .riv can replace the SVG later - Event handling follows the contract's mapping table; server text is only ever inserted as text - Prank: toast plus a send-button cooldown countdown - art/crow.svg: source art for Rive import Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UQnSw4RRWp8uqpj3nsnnXF
79 lines
3.4 KiB
Markdown
79 lines
3.4 KiB
Markdown
# 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-timeout` changes this for testing.
|
||
- A flooding requester gets 429 with `message` and `cooldown_s`; any list of theirs that is still flying also gets `requester.pranked`.
|
||
- UI development: run `crows serve`, then `cd ui && npm run dev` (Vite proxies `/api`). The crow art is `art/crow.svg`; the UI's `CrowView` mirrors `RIVE_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 `./web` when that folder exists.
|
||
|
||
## How an item flies
|
||
|
||
1. **Sentry** classifies it: `solo` (one crow), `split` (2–4 subtasks in parallel), or `murder` (3 crows answer independently).
|
||
2. Split and murder results go to the **Elder**, who merges them and flags disagreement.
|
||
3. 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.
|