Most agent demos show the happy path. This shows what happens when a worker crashes mid-step, two workers race for the same job, or a tool call fails — and proves the run still finishes correctly, exactly once, every time.
POST a goal plus a list of steps, each with an optional dependsOn. Steps with no dependencies become ready immediately; everything else waits.
Each worker polls Postgres with SELECT ... FOR UPDATE SKIP LOCKED inside a transaction — the same primitive companies like GitHub use for production job queues. Exactly one worker ever wins a given step, with zero blocking between workers.
Success promotes dependent steps to ready. Failure schedules a retry with exponential backoff (capped, then dead-lettered). A worker that dies mid-step leaves an expiring lock — a reaper requeues it automatically.
Postgres LISTEN/NOTIFY bridges worker processes (separate OS processes) to the API server, which fans events out over WebSocket to anyone watching that run — see it below.
| Guarantee | Mechanism |
|---|---|
| Exactly-one claim per step | FOR UPDATE SKIP LOCKED inside a transaction |
| No lost work on worker crash | 30s lock TTL + reaper requeues orphaned steps |
| No duplicate run creation | idempotency key = runId:stepName via ON CONFLICT |
| Bounded retries | exponential backoff (1s→60s), dead-letter after max_attempts |
| Full auditability | every transition written to audit_log |
| DAG correctness | dependents promoted to ready only once all deps succeed |
docker compose up -d # local Postgres
cp .env.example .env
npm install
npm run migrate
npm start # API + WebSocket server
npm run worker # run 2-3x to see SKIP LOCKED in action
curl -X POST localhost:4000/runs -H 'Content-Type: application/json' -d '{
"goal": "Research and summarize a topic",
"steps": [
{ "name": "tool_call.fetch_data", "input": { "tool": "fetch_data" } },
{ "name": "llm_call.summarize", "input": { "prompt": "..." }, "dependsOn": ["tool_call.fetch_data"] }
]
}'
Full chaos test (kill a worker mid-run, watch it self-heal) and architecture notes are in the README.
This is the real engine running right now, on this server. Edit the DAG below or submit as-is — you'll see steps go queued → executing → done in real time, including a simulated transient failure and retry.