Eight agents, 298 tickets, 62 videos. Every failure came from the same place: everything was readable, and nothing was delivered.
This is a retraction. I built a faceless AI YouTube channel and
[closed it into a single autopilot loop]. Then I[tore that loop out and replaced it], and wrote it up like it was progress. This is what
with eight agents passing tickets
running that company taught me. It stands on its own; you don't need the earlier posts.
Data status: real-now.Every count is measured from the live system.[Open source].
I built an eight-agent AI company to make 60-second videos. It needed 298 tickets to produce 62 of
them. Four and a third handoffs per minute of finished content, and not one of those handoffs put
a frame on screen.
The architecture looked fine on paper: an orchestrator, specialist workers for scripting,
production, QA, analytics, publishing, all coordinating by ticket. A textbook star topology. It is
what the frameworks push you toward.
Then I ran it, and every distinct failure turned out to be the same failure. Not a missing store,
either: the runtime shares almost everything. Comments, documents, the goal tree, an append-only
activity log, and the whole repo are readable by any agent that asks.
That is the trap. Shared storage is not shared context. Nothing is pushed to an agent when it
wakes. It gets its role prompt and a ticket id, and from there every fact about the world is
something it must decide to go fetch. So each agent reconstructs the world from whatever it
thought to look up, and a cold process does not know what it does not know.
Everything below follows from that.
One caveat: no wall-clock numbers. I was in that loop, so stall times measure my availability as
much as the architecture. Structural failures and counts only.
| Metric | Value |
|---|---|
| Agents | 8, each its own LLM session |
| Tickets created | 298 for 62 videos, or 4.3 per video |
| Worst single video | 11 tickets |
| Cancelled tickets | 21, plus 1 permanently blocked |
| Agent spend tracked | $0.00, across all eight agents |
My QA agent returned a clean verdict on one video: "Gate 2 = FAIL, final video does not exist."
It was right. A separate ticket had sent the script back for a rewrite, so the render was running
again and the directory was nearly empty. QA woke a second time, re-checked, and doubled down. The
file appeared later. The verdict never re-evaluated, so the ticket carried a failing grade for
work that had succeeded. The video it says does not exist is 23MB on my disk.
None of this is an LLM failure; the same code with no model in it fails the same way. QA read a
directory mid-rewrite and then persisted a conclusion instead of an observation: not "absent when
I looked" but "does not exist", a claim with no shelf life and nobody responsible for
invalidating it. The correcting event was unobservable anyway, because a file appearing is not
one of the four things that can wake an agent. Pulling context gives you a sample; staying
correct needs a subscription, and there was no way to express one.
Same shape, one level up. My CEO agent added a video to the backlog by hand, overriding the Growth
Lead's duplicate check, because the CEO was reading the goal and the Growth Lead was reading the
backlog and neither could see the other's screen. The subject was already published. The journal
entry records the whole thing:
Duplicate of j0037 (Banach-Tarski Paradox already published, SLO-93). Board added this manually
overriding Growth Lead dedup check.
Two agents, two views of the same channel, one of them authoritative and wrong. The check existed
and worked. It just wasn't where the decision got made.
Neither agent was dumb. Both were locally correct given what they could see. That is the whole
problem.
The daily cap was three videos. I found it publishing one and assumed something was throttling it.
Nothing was: the backlog had run empty and it was producing everything it could. Eight agents, one
of them a planner, and none noticed the pipeline was dry. Every agent did its job correctly.
Nobody's job was noticing.
The runtime does keep a company-wide activity log, an append-only stream of everything every agent
did. No agent was ever told to read it. Instead I solved org-awareness by hiring for it: two roles
whose whole job was reading everything and writing me a digest. A view of the system became a
staffing decision rather than a query.
That gap hides everything else. An agent flipped into an error state with no message after
finishing its work, with nothing useful in 268MB of logs. Research puts ~75% of multi-agent
failures in this silent category, which matches what I saw. The system almost never told me it was
broken. I had to go ask.
Two more of the same: eight agents shared one git checkout and stepped on each other's uncommitted
changes, and a half-abandoned second agent company on the same runtime quietly captured all my
notification digests. I was blind without knowing it.
Work moves only when an agent wakes, and there are exactly four ways to wake one: assign a ticket,
fire a cron, tick an idle heartbeat, or @mention an exact handle. A comment with no mention moves
nothing. A file appearing on disk moves nothing.
So when a run died mid-task, its ticket kept a lock pointing at a run that no longer existed. The
assignee tried to pick up its own ticket, hit a conflict, and stopped. No timeout, no retry. I
found two finished videos sitting encoded on disk while their tickets sat stuck behind a dead
run's lock.
I had caused it myself. Heartbeats were 240 no-op LLM calls a day and the biggest line in my token
bill, so I killed them. Heartbeats were also the only thing that would have retried a stranded
ticket. Every knob in an orchestrated system is load-bearing for something you aren't thinking
about.
Three tickets stalled because a handoff tagged @QACritic
. The real handle was @qa-critic
.
No error, no warning, no "unknown recipient." The mention matched nobody, the wake never fired.
Nothing threw, so there was no stack trace. No call was made, so there was no failed call to find.
The system did not do the wrong thing. It did nothing, correctly, and I found it by diffing prose
against configuration by eye.
These bugs also don't reproduce. Re-run the stage, the agent phrases the handoff differently, and
the bug moves or evaporates. Nothing to bisect, nothing to regression-test.
The deeper version of this is what a handoff actually carries. Most of mine created a new ticket
for the next owner rather than reassigning the old one, so the accumulated comment thread stayed behind and only the fields the sender chose to retype travelled forward. Which means I ended up
writing, by hand, a copy-forward schema for every hop:
Entry id: / Channel: / Idea: / Target keyword: / Title candidate: / Hook: / Assumption: / Goal:
/ Theme/tags: / Duration: / Constraints:
There is one of those in every agent's instructions, each slightly different, all of them prose,
none of them validated. That is an interface definition with no compiler. Miss a field and the
next agent doesn't error, it just proceeds with a hole in its picture.
The same softness hit the gates. Some fired after the thing they were meant to gate had already
run, and reported success anyway. One critic declined every script it saw, including ones that
shipped and did well. A gate that always says no is noise, and everyone downstream learns to route
around it.
Every handoff means the receiving agent reads the ticket, reconstructs the situation, re-derives
the state, and decides what to do, all from cold. At 4.3 tickets per video that is 4.3 cold starts
per minute of finished content, and coordination produces no artifact. An agent that stays
resident pays that cost once.
Retrieval is the expensive half. Because nothing arrives with the wake, every agent needs
instructions for what to go fetch, and those instructions grow with every bug you find. Mine ended
up telling the planner to grep the entire journal on every single ideation, because trusting a
window had already burned me. That is the pattern: each missed fact adds another mandatory lookup
to somebody's prompt. The prompts get longer, the wake gets slower, the token bill goes up, and
the system is still fragile, because the next gap is one you haven't hit yet. You are hand-writing
a cache-warming strategy in English and paying to re-run it at every hop.
The latency has the same source. The system was never compute-bound, it was wake-bound: trigger
fires, agent starts cold, works, hands off, exits, next one waits its turn. Nothing happens in
between, and "in between" is most of the pipeline.
And the bill is split eight ways, so nobody sees it. The org's own per-agent spend tracking read
$0.00 after hundreds of LLM calls, and I didn't catch it, because there was no one place where
the cost of a video added up.
Four cases, none rare. Real parallelism, where subtasks are independent and fan-out is the
point. Adversarial separation, where the reviewer must not share the author's context, because
a critic that watched you write the code will rationalize it. Isolation as a requirement:
untrusted code, per-tenant boundaries. Genuine scale, where the problem does not fit in one
context window.
My pipeline was none of these. Script, images, clips, voice, stitch, publish is a strictly
sequential chain. No parallelism to exploit, no isolation to satisfy. I took a dependency chain,
dressed it in an org chart, and paid for coordination I had no use for.
One main agent holds the context for the whole job. Subagents do work and return results into that context. They never decide anything.
That's it. The difference isn't a better store, it's that context is resident instead of
retrieved. The main agent watched the video get produced, so it cannot file a FAIL saying the
video doesn't exist. It never restarts cold, so it isn't paying to re-derive what it already
knows. And it needs no copy-forward schema, no mandatory-lookup list, no instructions about what
to go fetch, because nothing is handed off.
The subagent's job is keeping bloat out of that context, which is the part people get backwards.
A subagent is not a coworker, it's a filter. Send it at work whose output you need but whose
intermediate tokens you don't: scan a 268MB log, sweep a codebase, search 200 files. It burns
50,000 tokens and returns 200. The main agent gets the answer without the noise.
The direction matters. Results flow in, decisions stay put. Nothing is negotiated between
peers, so there is no handoff protocol to mistype and no gate to rubber-stamp. There is only
retrieval.
And whatever coordination genuinely remains gets a mechanical fix, not an agent. My stranded-lock
janitor is 150 lines of Python on a cron, and it beats an agent at the job because it is
deterministic, free, and never misreads the situation.
I already went back. The channel now runs on the autopilot I replaced: one pure function,
plan(journal, now)
, returning the single most useful action per tick. It is more robust, more
effective, and far easier to reason about than the org that replaced it. No ticket to strand, no
handle to mistype, no snapshot to go stale. When it breaks I get a stack trace with a line number,
which after months of reading agent transcripts felt like a luxury.
The proof was in the fix itself. Diagnosing those two stuck tickets, writing the janitor,
dry-running it, installing the cron, and clearing both videos happened in one sitting, by one agent
holding the whole problem at once. The eight-agent company never noticed those tickets, and
couldn't: no agent in it could see ticket state, files on disk, and agent health at the same time.
What fixed the agent company was not an agent company.
An org chart is not an architecture. Multi-agent topology buys parallelism and isolation, and it
costs you context, tokens, and truth. If your work is a dependency chain, you don't need a
company of agents. You need one agent that remembers everything, and workers that hand it
answers instead of opinions.
Prior write-ups of the same system, for anyone who wants the build rather than the postmortem.
plan(journal, now)
.