I Stopped Writing Code and Started Running a Fleet

One session plans, several build, and I hold the veto. How the pattern works on a client's billing platform.

I used to write the code. Now I write the memo that tells the code-writers what the last memo forgot.

- Me, on my fourth brief before lunch

For most of my career, my hands were on the keyboard. On one client project this year, that changed. My role moved from writing code to directing the sessions that write it.

The project is a billing platform, where a wrong number is expensive and a wrong migration is worse. So this isn't a story about letting AI loose. It's about a structure where AI does the typing and the structure catches the mistakes. Here's the pattern, and the rules that hold it together.


One Session Plans. The Others Build.

The orchestrator is one Claude Code session. Its instructions open with a blunt line: you are the orchestrator, not the implementer. Plan, brief, coordinate, verify. Do not write application code.

The streams are separate Claude Code sessions. Each one gets its own git worktree and owns a ticket end to end: implement, review, open the pull request, watch CI, merge, clean up.

The orchestrator reads the tickets, maps dependencies and writes a brief for each stream. I launch the sessions. The orchestrator watches their progress and checks their results.

Why separate sessions instead of subagents inside one conversation? Because a subagent is expected to finish in one shot. Real stream work doesn't. On one day in September, streams ran for hours. Three hit an authentication block, and all three resumed. Each one corrected itself two or three times along the way. A single agent call can't do that.

Streams still use subagents for slices of the work. One rule doesn't bend: the parent session holds every commit. Subagents never touch git.


The Brief Is the Whole Job

The orchestrator's instructions say it plainly: a convention absent from the prompt does not happen.

A good handoff prompt reads like a note to a sharp contractor on day one. Mine carry:

  • The ticket, and a statement that the ticket is the authority.
  • What other sessions are working on in the same repository, down to the files they touch, and which files are shared.
  • How to set up the worktree, and that removing it after merge is part of the task.
  • The repository's traps: which merge commands don't work, how to run the test gate so a failure can't hide.
  • Constraints specific to this ticket, such as "don't delete this file, other screens still use it."
  • The coding standards, the review requirement and the test-first rule.
  • The ticket rules: fix what you can, file only what needs a decision, report your numbers at the end.
  • A definition of done.

I learned that the hard way. Rules I'd written down elsewhere, but left out of a prompt, simply didn't happen in that session. A later post has the details.


Coordination Through Plain Files

Streams coordinate through a shared folder. The orchestrator writes one file, the board, which streams read and never edit. Each stream writes exactly one file of its own. That rule keeps the folder from producing conflict copies.

Each stream writes at three moments, and only appends:

  • START, before its first commit: the tickets, the repositories, the worktree and the files it expects to touch.
  • MERGE, one line per pull request as it lands.
  • EXIT, before it tells me the work is done: what closed, what it filed, which pull requests are still open, whether the worktree is gone, and anything it called done that isn't merged.

START names the files it expects to touch, not just repositories, because two streams in one repository is normal. Two in one file is the collision. One day, three streams converged on the same repository within an hour, and none of them could see the others. So streams re-read the board before opening any pull request.

EXIT is the entry that matters most. Before this protocol existed, four of four streams reported "done" while leaving a pull request open. Two of those pull requests then failed review.


The Line Is Irreversibility

In July I approved an operating model with one idea at its center: the gate is irreversibility, not risk tier.

Under the old rule, anything touching schema, money or more than one repository waited for me. That was most of the work.

Under the new rule, Claude owns the whole loop through the dev environment: build, formal review, blast-radius analysis, real-database tests, merge, deploy to dev, smoke test, close. It doesn't wait for me. Dev is reversible, so a slip there is recoverable.

Today, three things stop for me:

  • A genuine domain fork that the reference system can't answer.
  • Anything irreversible: data-loss migrations, secrets, real money movement, promotion to production.
  • A change in behavior a user would notice, as opposed to fixing something that never worked as intended.

Tenant isolation used to be on that list. I took it off on August 1. On a fix involving cross-tenant payment writes, my sign-off caught nothing the review panel hadn't already found. It was pure latency.

I'm an async auditor with a veto. Every self-merge lands in an end-of-day digest I read on my schedule. The digest exists because some failures live in tooling and coordination, not in any diff, so no pull request review would catch them.

The line cuts the other way, too. In July, my orchestrator read "final prep for merging to main" as permission to merge. It launched a full redesign overnight, before a demo. We rolled it back the same day. Prep is not permission.


The Guardrails, and Why Each One Exists

Most of these rules started as something going wrong.

Commit before any git-touching agent runs. An agent checking its own work can restore files, and anything uncommitted from a sibling task goes with them.

Worktrees by default. Two early accidents destroyed uncommitted work in the main checkout. A worktree per stream prevents that. The catch is cleanup: one worktree was still sitting there three weeks later. Now finished worktrees get removed without asking.

Name the databases, not just the files. Every prompt now says which database an agent may touch.

Spend the strong model where judgment lives. The cheaper model is the default for searching, mechanical edits and running gates. The stronger model does every formal review and risk classification, because a misclassified change is the one error self-merging can't afford. Low-risk diffs get one reviewer instead of a panel, which cut roughly 30 percent of a small pull request's review spend.

No more than five agents in flight. It's a concurrency cap, not a lifetime one.

Parallel sessions own disjoint work. In July my orchestrator handed me three session prompts with no note about its own open work. One session started in a repository where an earlier pull request was still unmerged. Nothing broke, but nobody checked until after launch. Now every prompt names the orchestrator's own open branches in that repository before I launch anything.


The Weak Link Is the One Holding the Clipboard

Here's the uncomfortable part. When I measured this process, the weakest link wasn't the streams. It was the orchestrator.

That's a post for two weeks from now. Next week is a simpler question: did any of this shrink the ticket queue?

There's also a separate, more automated system on this project: a queue that turns tickets into unattended Claude sessions, with concurrency slots, spend ceilings, and a loop that keeps a session going until it reports it's finished or runs out of budget. That's a story for another day.


The Solo Version

Honestly, if you work one ticket at a time, most of this machinery is overkill. The board and the stream files earn their keep when several sessions run at once.

What scales down:

  • Separate planning from building. One session reads the task and writes the brief. A fresh one does the work.
  • Write your rules into every brief. If it isn't in the prompt, it won't happen. Keep a template.
  • Give each task its own worktree, and commit before you hand any agent something that touches git.
  • Pick your stop list by irreversibility. Decide what you'll always check yourself: production, migrations that lose data, money. Let the rest move.
  • Have a separate agent review every change, and ask it to prove the change wrong rather than approve it. I wrote a field guide to that. It matters because agents are confidently wrong more often than you'd guess.
  • End each task with an EXIT note: what's done, what's open, what you filed. It takes a minute.

The fleet isn't the point. The point is that the rules live outside my head, in the briefs and the files, where every session can see them.