Solution · Multi-agent build pipeline
Ivan's Workflow Orchestration
IWO-DBOS
The durable orchestrator that runs Claude Code as a specialized engineering team — plan, build, review, security-check, test, deploy, document — for every codebase I run through it. Every agent step is durable, every human gate survives a reboot, and every LLM call is idempotent.
Why I rebuilt it on DBOS
The legacy daemon ran the same six agents in tmux panes against the same spec files. It worked — until it didn't. State lived in in-process Python objects and a .active-specs.json reconciliation file. A laptop reboot mid-spec meant manually replaying handoffs. A crash between "agent finished" and "state written" meant paying for a second claude -p call.
DBOS is a lightweight library — not a platform — that turns ordinary Python functions into crash-safe, replayable workflows backed by Postgres. No new orchestrator service to run. No vendor. Just rows in a database I can SELECT when something goes wrong.
DBOS itself isn't something I built — it started as academic database-systems research at MIT, Stanford, and Carnegie Mellon (Michael Stonebraker and Matei Zaharia among the researchers behind it), later commercialized as DBOS, Inc. I'm building on that foundation, not reinventing it.
How it works
One control plane, one Postgres instance, and a worker per codebase. The control plane never touches code directly — it dispatches to whichever project's worker owns the spec, and that worker runs the actual Claude Code agents. Drag to pan, scroll to zoom, click a node for detail.
Three properties the legacy daemon could not give me
Crash-safe state
Kill the daemon mid-spec and restart it — every in-flight agent resumes from its last completed step. No reconciliation file to hand-patch, no missed handoffs to re-drop.
Durable human gates
DBOS.recv(timeout_seconds=N) blocks a workflow for up to the timeout. The deadline and any buffered approval message live in Postgres, so the wait survives daemon restarts and laptop reboots.
Idempotent LLM dispatch
A step's output is checkpointed to Postgres; an already-written handoff on disk short-circuits re-dispatch. A crash in the narrow window between 'agent finished' and 'DBOS checkpointed' does not cost a second claude -p invocation.
The pipeline
Seven stages, one spec, durable handoffs between every step. The security stage is inserted between Reviewer and Tester by the orchestrator's own configuration — a spec's prose can never insert or skip it — and it runs on every project I have live today. Any stage can hand work back to the builder; the pipeline caps total handoffs per spec as a backstop against an infinite back-and-forth. The workflow body is deterministic glue — every side effect (dispatch, handoff write, ops action, human gate) is a checkpointed step that DBOS can replay after a crash.
- 1
Planner
Decompose the spec, write a plan, hand off to Builder.
- 2
Builder
Implement against the plan, write code + tests.
- 3
Reviewer
Read the diff cold, raise blockers, request changes.
- 4
Security
Adversarial OWASP-focused pass, inserted by the orchestrator — not the spec. Live on every project I run today.
- 5
Tester
Run the suite, exercise edge cases, file failures.
- 6
Deployer
Ship the artifact, verify health, record version — gated by human approval.
- 7
Docs
Update changelog, as-built, and operator docs.
The six core roles — planner, builder, reviewer, tester, deployer, docs — are inspired by the parallel multi-agent Claude Code workflow practice popularized by Boris Cherny, creator of Claude Code at Anthropic. I built the orchestrator, the durability layer, and the security/program/learnings systems around that starting point. Each agent runs from its own dedicated, open-sourced skill definition — one file per role, sharing a common honesty protocol that bans inflated language and enforces a strict handoff contract between agents, so one stage can't quietly overstate progress to the next.
Autonomy dials
Two independent, operator-set toggles decide how much of this runs unattended. Auto-deploy decides whether the deployer waits for my approval before shipping, or ships the moment testing passes. Auto-continue decides whether finishing a spec stops there, or immediately chains into the next sprint on the same spec or the next spec in an operator-authored queue. They're unrelated to each other — a deploy rejection still halts the run, so a bad deploy never gets auto-continued past.
From Plan to shipped project
Hand it a PRD or a Plan — a dependency graph of phases, sprints, or individual features, with or without specs already written — and it works out the priorities itself. Any item with no spec yet gets one drafted by a dedicated spec-author agent; every drafted or hand-written spec still waits for my approval before it runs. From there it's the same seven-stage pipeline above, repeated autonomously across every item until the entire project is built, reviewed, security-checked, tested, deployed, and documented — no manual sequencing anywhere in between.
It gets smarter with use
Every reviewer, security, and tester finding is captured — always on, per project, append-only — whether or not anything ever reads it back. Reading it back is a separate decision: same-project injection into the next planner's prompt is one toggle; sharing a generalizable version with other projects is a second, independent toggle, gated behind a fail-closed screen that strips project identifiers and secret-shaped tokens before anything crosses.
One instance, no cross-pollination
ebatt, atlas, and phase3b share one control plane and one Postgres instance today — but each is routed to its own worker container, with its own workspace, its own tmux session, and its own Postgres row, enforced unique by the database schema itself. The only channel that can ever cross a project boundary is the containment-gated learnings bridge above — and it's off by default. Specs, code, and handoffs never cross.
What it actually ships for ebatt.ai
- Specs survive reboots. Restart the daemon and every in-flight spec resumes from its last completed step. No
.active-specs.jsonreconciliation. - Approvals can wait. A human gate set for tomorrow morning still fires tomorrow morning, even if the laptop sleeps overnight. The deadline lives in Postgres.
- No double LLM spend. If the process dies right after Claude returns but before the handoff is written, the next run sees the cached step output and skips the re-dispatch.
- State is queryable. Debugging a stuck spec is a few
SELECTs, not parsing a black-box dashboard.
Status
- Running in production. Every codebase I maintain — ebatt, atlas, and phase3b — runs through the full seven-stage pipeline today, not a shadow-run or a canary.
- Security and learnings are both live. The security stage and the learnings system (per-project and cross-project, containment-gated) are both switched on for every current project.
- Legacy daemon retired. The original in-process, non-durable daemon this replaced is no longer part of the build path — every spec runs through the DBOS-backed orchestrator described above.
Want a durable build pipeline for your team?
If you're running Claude Code or another agentic build loop at any scale, the same crash-safety, human-gate, and idempotency properties apply. I can help you adopt the pattern.