AboutExperienceBlogContact
LinkedInGitHubGitLabWhatsApp
All posts

6 min read

Anatomy of an Agent Fleet

aiagentsarchitecturetooling

The most expensive lie in AI tooling is the demo: one prompt goes in, one perfect answer comes out. Real production work does not behave that way.

What works looks more like a small firm. A planner reads the task and breaks it into a work list. Builders each own one piece and nothing else. Reviewers judge code they never wrote. Testers get context containing the spec and the diff, and not a word of anyone's intentions. None of them is smarter than the model underneath; they are all the same model. The structure is what makes them behave differently, and the structure is the engineered part.

Why a fleet at all

A single long conversation with a model degrades in a predictable way. The context fills with the model's own output, and it starts conditioning on its earlier answers instead of the code. Early mistakes become load-bearing.

Splitting the work buys the same thing it buys in a human team. A reviewer that never saw the builder's reasoning cannot inherit its blind spots. Fresh context is the point.

Here is the shape of one loop I run. A bug pipeline that carries a ticket from trigger to a converged pull request without further prompting:

Ticket
Isolatea fresh git worktree per bug: parallel runs cannot touch each other's files
Recallmemory before code: is the cause already written down?
Understandthree agents, three different questions
read the ticketlocate the codehistory & prior art
Does the bug reproduce?no → stop, report, change nothing
Diagnoseeach hypothesis must disprove itself, one survives
hypothesis Ahypothesis Bhypothesis C
Does the red test bite?green before the fix → rewrite the test
Landparallel again, one writer per file tree
fix the frontendfix the backendboot the app for smoke
Suite and smoke green?red never publishes, fix forward
Publishlogical commits · pull request
Convergereview-bot rounds, hard-capped
Reportcause, fix, evidence, and what still needs a human

Every fork in that picture is a named barrier, and a gate that fails either retries within a bound or stops with a report. Nothing gets waved through.

The harness

The agents don't get raw access to anything. Every tool call passes through hooks: small deterministic scripts that run before and after the call, and can block it. An agent that wants to run a shell command is making a request, not taking an action. The database lane is the strictest example. The connection itself is read-only, and a hook additionally rejects anything that parses as a mutation, in every permission mode; even a run explicitly allowed to skip confirmations cannot write. A prompt is a suggestion. A hook is a fact.

Orchestration follows the same rule. The pipeline above is code. The model fills in the leaves:

assert(database.isReadOnly);

await isolateWorktree(`fix/${bug.id}`);
const prior = await memory.recall(bug);

const [brief, sites, history] = await parallel([
  readTicket(bug),
  locateCode(bug),
  priorArt(bug),
]);

const repro = await reproduce(brief, sites);
if (!repro.ok) return report("NOT REPRODUCED");

const candidates = hypotheses(prior, brief, sites, history);
const verdicts   = await parallel(candidates.map(selfDisprove));
const cause      = pickSurvivor(verdicts);
if (!cause) return report("NO SURVIVING HYPOTHESIS");

const test = await writeFailingTest(repro);
assert(test.failsBeforeFix);

await parallel([fixFrontend(cause), fixBackend(cause), bootAppForSmoke()]);
const checks = await parallel([runScopedTests(cause), runSmoke(repro)]);
assert(checks.every((check) => check.green));

const commits = commitLogically();
const pr = await openPullRequest(push(commits));
await convergeReview(pr, { maxRounds: 3 });

return report({ cause, evidence: test, commits, pr });

The control flow is deterministic, and the run's state lives in a ledger file rewritten at every phase boundary. A bug run spans an hour, mostly waiting on builds, so it outlives sessions. When a session dies, the run resumes at the last gate it passed, because the structure was never held in a context window. It was in code.

Ten active bugs means ten isolated worktrees being worked in parallel. And when an attempt goes wrong, cleanup is deleting a folder, not untangling bad commits from a shared checkout.

What they know

Agents are exactly as sharp as what they can look up, so recall is the pipeline's first phase and its cheapest one. Codebases and documents are chunked into embeddings, and "where is the thing that behaves like this" becomes a lookup instead of a grep safari. Decisions live in a knowledge graph. Systems, constraints, and trade-offs are the nodes; replaced by, depends on, broke because are the edges. Embeddings answer where things are. The graph answers why they are that way.

Every finished run writes back what it learned: the cause, the trap, the gotcha. That is the difference between a fleet that gets smarter with every bug and one that rediscovers the same cause twice.

What breaks

Left alone, a fleet fails confidently. Findings that sound plausible and are wrong. Reviewers that wave through anything phrased with authority. The fix has never been a better prompt. It is adversarial structure: hypotheses instructed to disprove themselves, verifiers instructed to refute. A conclusion survives only if the skeptics fail to kill it. That one pattern has killed more false positives for me than any wording of "be careful and thorough" ever did.

And some actions the fleet cannot take by design, no matter how confident it is: applying a database migration, mutating data, completing the pull request, closing the ticket. It prepares everything, reports, and waits. The dangerous last step stays human, because when a migration goes wrong, a person answers for it. The fleet multiplies the judgment it is given, including the bad calls.

Every tool underneath this pipeline will eventually be replaced. The shape of it (gated actions, deterministic structure, adversarial review, memory that compounds) won't. That is the skill the agent era actually rewards: treating models as an engineering material.