AI promised faster code and faster deployment. So we should be seeing more products reach the market, faster.
We aren't. And most teams feel that gap without being able to name it.
The reason is that the constraint was never code generation. It's what happens before you generate code, and what happens after. Make the middle ten times faster and you've optimized the one part that wasn't slow.
So I mapped my own process end to end to find where the time actually went. This is what I found, what I built, and what it cost me to get there.
Where I landed: 4 to 5 solutions in flight at once, delivered at roughly a 90 to 95% initial bug-free rate.
Not because the model got better. Because I stopped asking it to do unbounded work.
The first bottleneck: I couldn't trust "done"
My sub-agents would code overnight. I'd come down in the morning and the report said complete.
It wasn't complete.
When I actually reviewed the work, there were failures scattered through it. And this wasn't an AI problem, it was old-school reliability engineering. I'd broken the work into smaller sub-agent tasks, and some of those tasks depended on each other. If one link was wrong, everything downstream of it was wrong too.
What I got was a false positive. "We're done." Then I'd open it up and find the chain had broken three steps back and kept running anyway.
The second bottleneck sat right next to it. I was stuck just before merge, every time, because evaluating what had been written took me forever. Going through the evidence was the slow part, not the writing.
Fix one: gates the agent cannot mark itself past
I introduced test nodes. Concretely: unit tests written as each story is created, baked into the runtime that runs overnight.
The rule that matters is not that tests exist. It's who gets to declare completion:
A sub-agent cannot mark its story done, and cannot release the next dependent story to run, until it passes its test nodes. It keeps retrying until it does.
That single change is why the morning report became trustworthy. When it says 60% done now, it means 60% has passed every gate attached to it. Before, 60% meant 60% of the work had been attempted.
Fix two: a review that reads the reasoning, not just the diff
For the evaluation problem, I wrote a skill that reads the finished work and produces a morning report. It walks the code, draws diagrams, writes detailed descriptions of what the AI actually did, and reads the sub-agent transcripts, because I force my agents to write transcripts as they go.
Then it links out to the pieces of code that actually matter.
The point is that I don't want to review every line. I want to review the decisions, and I want to land directly on the parts worth pressure-testing. That's what collapsed my evaluation time.
Working backward: why the agents got it wrong at all
With those two in place I went upstream. Why were sub-agents completing things incorrectly in the first place?
Two reasons, and the second one is the one people miss.
One, I wasn't giving them clear enough instructions.
Two, I was breaking stories down too large. Too much work per task meant too many tokens consumed to finish it. And I noticed a direct relationship: as the context grew, reliability dropped. Reliability meaning the chance the agent actually produced what I asked for.
The bigger context cost more money. That was the obvious problem.
The real problem was that it lowered the probability of getting it right.
Cost is the symptom people notice. Reliability is the one that actually hurts.
Fix three: bounded work packages
So I scope stories by the tokens they'll take to complete. I ask the LLM to estimate, and I set a hard ceiling in the project config.
My rule: do not exceed 150,000 tokens, and prefer to stay near 100,000.
Plenty of people doing agentic coding will tell you not to go past 100K at all. It gets expensive and unreliable after that. I'll stretch to 150K when a story is genuinely simple and the instructions are unambiguous. Never past it.
That ceiling is the floor of the whole system. Everything else exists to make a package fit under it without losing meaning.
Fix four: borrow definition of done from agile
Clear instructions needed a real definition, so I took one that already exists.
A definition of done spells out what has to be true for a story to count as complete. It carries acceptance criteria, which lay out the functionality. It also carries non-functional requirements, the things that aren't features: speed, security, and so on.
Now the instruction inside each bounded work package is both clear and bounded.
Agents still missed things, so I went back to agile again for scenario-based acceptance criteria. Given, when, then.
Building a login: given someone is not logged in, when they provide an invalid password, then this happens. You walk the feature and enumerate every scenario you can envision, and those become the criteria.
There's a counterintuitive result here worth sitting with. More detail in the package means fewer tokens spent, not more, because there's less ambiguity for the agent to burn context resolving. Specificity is a cost control.
When I started doing this, the output got roughly ten times better.
Going further upstream: the context I never wrote down
Working with the LLM to generate scenarios, I kept hitting a wall. Sometimes I'd miss scenarios. Sometimes the LLM invented ones that made no sense for what we were building.
The cause was that I didn't have enough context captured. I'd have ideas about requirements in my head and simply not write them down.
So the pipeline now starts with conversation. I record myself talking. I use conversations with mentees and the people I work with. Every transcript about a project, plus emails, plus everything else, gets dumped in, and a skill converts it into a usable format.
Then come ADRs, architectural decision records, with the LLM in the role of a senior developer while we go back and forth. REST or webhooks. Lambda or EC2 or Cloudflare. JWT or Cognito.
An ADR is not just the decision. It records what else was considered, why those were rejected, and why this one won.
That last part is what makes autonomy safe. When a sub-agent runs at 2am, it doesn't just know what to do. It knows what I already ruled out and why, so it can reason inside my boundaries without me being awake to enforce them.
The two checks that make the ADRs hold
At this stage I run two things, and they catch different failures.
Red teaming. An adversarial pass that attacks every assumption in the ADRs. It returns gaps, I review them, and they go back in to make the decisions stronger.
But red teaming has a blind spot: it can only challenge what I actually wrote down.
Requirements traceability audit. This catches the opposite failure. Say the transcripts mention we need SSO and social login, and the ADRs never address how. Red teaming will never notice, because there's no assumption there to attack. The traceability audit finds the requirement that exists upstream but was never decided on, and forces the conversation.
One checks what you decided. The other checks what you forgot to decide. You need both, and I run them in a loop.
The rest of the planning chain
From the ADRs: story arcs (epics, but I like the more dramatic term), then PRDs covering the what and the why with business context, then specification files for the how.
All of that context exists so that when coding starts, the agent knows why it's doing something. Not just what.
The part I don't do myself: the graph
I don't write the bounded work packages. The LLM does, because it has the transcripts, ADRs, story arcs, PRDs, and specs.
And it doesn't produce a flat list. I treat the project as a graph, with stories as nodes and real dependencies as edges, and ask for the optimal graph for the project. That graph gets stored in a state database.
Then test nodes get generated from the scenarios, as deterministic code, and added to the graph. Each bounded work package is wired to the gates it must pass. Validators enforce that the agent calls them.
State in a database also means an overnight run survives my machine dying. It resumes.
The lifecycle, in two rows
Row one, human in the loop: conversation, ADRs, story arcs, PRDs, specifications. This is me and the LLM going back and forth, governed by skills and plugins. I use Whisper Flow, so mostly I'm talking.
Row two, fully autonomous: bounded work packages, definition of done, acceptance criteria, test nodes, test plans, sub-agents, validators, state. I have nothing to do with this row beyond confirming it.
Then I run the graph and go to bed. Sub-agents code for five or six hours.
In the morning I do not merge first. I run the report, go back and forth, tweak, and then accept or reject. Accept triggers the merge. It also generates a podcast of what was done, so I can listen while I walk.
What to actually take from this
Mine is on steroids because I've automated the second row. That is not the requirement.
Every piece of row one can be done by hand. Write the ADRs manually. Write test plans with your LLM. Look at the evidence yourself. That's exactly where mine started, and it moved toward automation over time, not on day one.
The shape is what transfers:
Spend real time up front on conversation, decisions, and specs.
Break work into packages small enough to stay reliable, and let token count be the hard constraint.
Make completion something the agent has to earn against deterministic gates, not something it declares.
AI genuinely does make software development faster. Just not in the place everyone is optimizing.
The 23-minute walkthrough, with the lifecycle on screen, is here: I Mapped My AI Software Lifecycle. Code Wasn't the Bottleneck.
Chris