Architecture
A board, a lease, and a worktree. Every other property in COODDEE falls out of those three.
The board is the scheduler
Work is cards on a kanban board, not a queue of prompts. A worker does not receive a task — it claims one, by taking a lease on a card in a lane its role is allowed to pull from.
That inversion is what makes the system recoverable. A queue loses work when a consumer dies; a board simply shows a card whose lease expired, and the next sweep puts it back in circulation.
- Builders pull from
readyandneeds_rework - Refiners pull from
built - Reviewers pull from
refinedandbuilt
One worktree per worker
Concurrent workers never share a checkout. Each claims its own git worktree, so two agents editing the same repository cannot interleave writes into one another's files.
This is enforced structurally rather than by convention: constructing an orchestrator with max_concurrency > 1 and no WorktreeManager raises immediately, with the reason stated in the error. A rule people have to remember is a rule that eventually gets forgotten.
Leases, not heartbeats
A claim carries an expiry. The default lease is 900 seconds with a 600-second margin, computed as turns × max_minutes × 60 + margin so it always outlives the work it covers.
A sweep runs during the pipeline, not only at startup. A worker that dies mid-run has its card reclaimed inside that same run rather than sitting owned-and-unpullable until somebody starts the next one.
The reclaim is a compare-and-swap on the owner, not a timestamp check alone — so a sweep can never clear a claim that a live worker has legitimately taken in the meantime.
Tenant isolation goes all the way down
Every database session sets the app.organization_id GUC and relies on PostgreSQL row-level security, so a query that forgets a filter returns nothing rather than another tenant's rows.
Credentials are scoped the same way. A credential submitted by one organisation resolves for that organisation alone; ambient process-environment values remain board-wide and read-only, and a submission never writes into os.environ.
| Component | Responsibility |
|---|---|
board/ | Lanes, claims, leases, conditional-UPDATE checkout |
orchestrator.py | The pipeline: dispatch, concurrency, reclaim sweep, spend ceiling |
agents/ | Executors (Claude, Codex, Gemini, OpenRouter) and the budget envelope |
secrets.py | Per-organisation credential resolution and OS keychain custody |
memory/ | Namespace-addressed episode store and curator |
compliance/ | Source-checkable control scanners |