← jddavenport.com
Production teardown

Running 30 agents in production: what it actually takes

Anyone can demo an agent. Keeping a fleet of them alive for months, with real permissions and real consequences, is a different job, and almost nothing published about agents describes it honestly. This is the teardown of the Nerve Center, a 30-agent AI organization I designed, built, and operate in production: the architecture, three failures with root causes and the systemic fixes, how changes get reviewed, what it costs in real dollars, and the one constraint that makes the whole thing safe to hand authority.

The build itself stays private because it runs my actual life and work. Everything below is the real operating record, sanitized only where it has to be.

The architecture

The system in one sentence: a supervising daemon owns long-lived agent sessions, a message bus routes work between them and me, a shared memory graph gives them recall, Postgres holds durable state, and a watchdog layer assumes everything above it will eventually fail.

The stack: Python daemons for orchestration and services · TypeScript/Next.js cockpit (Vercel) · Postgres on Supabase for durable state · vector + graph stores for memory · local LLM routing for rote jobs · launchd supervision on always-on hardware
operator (me) phone · desktop · chat cockpit TypeScript / Next.js · tombstone sync message bus / bridge Python · routes work, sessions, events supervising daemon launchd-owned · guarded restarts only agent sessions (PTY children) 1 CEO agent → 30 specialists · 14 domains frontier models for hard work · small models for rote memory graph vector + graph store retrieve before act durable state Postgres / Supabase 250+ tables · workflows watchdog layer liveness = work completed, not uptime · death-cluster detector · auto-unwedge · stale-job alerts send gate → the outside world
Sanitized architecture. Every agent session is a PTY child of the supervising daemon. The watchdog layer observes every component above it. Every outbound message, no exceptions, exits through the send gate.

The pieces, briefly

Failure 1: one restart killed 12 sessions at once

Every agent session runs as a child of the supervising daemon. One agent restarted that daemon with a raw process-manager command instead of the guarded reload script. The OS killed the whole process group, and all 12 live sessions died within the same two seconds, including the one that issued the command.

The root cause was not the command. It was that the safety check lived inside one script on the honor system, and nothing stopped an agent from going around it. An agent under token pressure or a confused plan will eventually take the shortest path, and prose instructions are not a barrier.

The fix came in three layers: a pre-execution hook that blocks raw restarts of protected services outright, reload scripts that refuse to run while sessions are live and print the casualty list if forced, and a detector that watches for multi-session death clusters and names the exact culprit session and command within five minutes. The postmortem is a file in the repo, and the rule it produced is enforced by a machine, not a memo.

Prose rules do not survive contact with autonomous agents. Machine enforcement does.

Failure 2: a stale phone tab resurrected dead sessions

The cockpit syncs open sessions across devices. A phone tab left open overnight held an old copy of that state, and its writes were last-write-wins. So it kept reviving sessions I had already closed and killed: zombie entries that burned tokens, confused the fleet, and reappeared no matter how many times I killed them.

This is a classic distributed-systems bug wearing an AI costume. The moment two devices can write the same state, a full-blob write is a time machine: the staler device overwrites the newer truth. The fix was to stop syncing state and start syncing intent. Per-entry tombstones make a close a fact that cannot be overwritten by anything, and semantic writes mean a device can only add what it knows, never erase what it missed.

The regression suite now pins that exact interleaving, a stale reader racing a newer writer, so the bug class stays dead rather than the bug instance. UI changes run end-to-end on phone and desktop viewports, because this failure taught me the device matters.

Failure 3: a confirmation modal froze the org for 4.5 hours

The CLI under one daemon hit a usage limit and popped a confirmation modal. The daemon's turn loop sat waiting on a prompt no human would ever see, and inbound messages queued invisibly for four and a half hours. Nothing crashed, so nothing alerted.

That is the nastiest failure shape in agent systems: alive but wedged. Process supervision says healthy, the port answers, and no work is happening. Any liveness check based on uptime is blind to it by construction.

The fix was a watchdog that detects the stuck state and auto-confirms the modal, plus liveness checks that measure output: messages processed, work completed, state advanced. The same principle got applied fleet-wide, because a relay once wedged the same way on a dead database socket and silently swallowed outbound messages for hours. Now anything that can wedge has a detector that asks "did you do work?" instead of "are you running?"

How changes get in

Nothing merges on one agent's word. Every substantive change goes through adversarial review by three separate agents with different instructions, one of which is explicitly told to try to reject the change. Then CI gates: a QA gate, an architecture gate, and a unit-test suite. Any bug that reached production gets a fixture test reproducing the exact failure interleaving before the fix lands, which is how the failures above became regression suites instead of stories.

The same pipeline governs the autonomous work. An agent that fixes a bug does it in an isolated worktree, proves it with a failing test that passes after, and clears blast-radius caps and a deny-list before merge. I open-sourced that engine because the governance model is the interesting part.

What it costs

Real numbers, because "AI is expensive" and "AI is cheap" are both lazy. A heavy build session runs $30 to $35 in API cost; two recent ones came in at $34.67 across 201 model calls and $32.13 across 188. A five-reviewer audit panel is roughly 300k tokens. A rote heartbeat that formats a status report costs pennies on a small model.

So the system tiers cost by work type: frontier models for building, reviewing, and deciding; small models pinned to rote jobs like heartbeats and report formatting; local models for bulk extraction where latency and privacy beat quality. Cost is tracked per run in the same tables as everything else. The question is never the bill. It is whether the work earns the model.

The constraint I chose on purpose

The system can draft anything: email, messages, posts. It can send nothing. Every external message routes through one gated chokepoint with a global freeze switch and single-use approval tokens, and it transmits only after an explicit yes from me. I built it that way after watching how many places an autonomous system will grow an ungated send path if you let it; an audit found five separate paths that could have sent email without approval, all of them added for convenience, none of them malicious. They are all closed, and the gate is enforced at the same pre-execution layer as the restart guard.

An autonomous system is only as trustworthy as what stops it.

That principle sits under every design decision here. Capability is easy to add. The stop conditions, the tombstones, the freeze switch, the deny-list, the liveness detectors: those are the difference between a demo and something you can hand real authority.

If you are building one of these