A Better Way to Build Software With AI: The Workflow That Holds

Work in small vertical slices, write the contract before the implementation, give each slice a fresh session, and commit at every green state. The discipline that matters is not prompting. It is keeping each unit of work small enough to review honestly and specified well enough that correctness is checkable without rereading everything.

Why the demo workflow collapses on a real codebase

In a demo, the task is greenfield, the context fits, and success is visible in the browser. On a real system none of that holds. The change touches code with history, the relevant context is spread across files nobody has read this quarter, and correctness means not breaking eleven things you cannot see from here.

So the workflow that works is not about getting more out of the model. It is about structuring the work so that the model's output is verifiable and your review is honest.

That reframing has a useful consequence. Every practice below is one you would apply to a fast junior engineer with excellent recall and no institutional memory. That is a reasonable mental model, and it predicts both the failures and the fixes better than treating the agent as either a magic box or a search engine.

The unit of work: small vertical slices

A slice is the smallest change that leaves the system working and demonstrably better. One endpoint with its validation and test. One migration with its rollback. One component with its states.

Small slices are not a productivity ritual. They are what makes review real. A diff touching four files with one clear intent gets read line by line. A diff touching forty gets skimmed, approved, and discovered later, and skimmed review is indistinguishable from no review at the moment it matters.

Slicing vertically rather than horizontally matters too. Building the entire data layer before any feature works means nothing is verifiable until the end, which is exactly the failure mode agents accelerate. A vertical slice can be run, tested, and rejected today.

The practical test: if you cannot describe what this slice does in one sentence, and cannot say how you will know it worked, it is too big. Split it before starting, not after the agent has produced nine hundred lines.

Write the contract before the implementation

Before the agent writes code, three things should exist in writing.

What changes. The behavior being added or altered, stated in terms a user or caller would recognize.

What must stay true. The invariants. The existing behavior that must not move, the interfaces other code depends on, the performance characteristic that matters, the data that must not be touched. This is the section that prevents the plausible-but-wrong refactor, and it is the one people omit.

How you will know. The test, the command, the manual check. Ideally the test exists before the implementation, because then correctness is mechanical rather than a matter of your opinion at review time.

This costs a few minutes and changes the nature of review completely. Without a contract you are judging whether the code seems right. With one you are checking whether it does what was agreed. The second is faster, more reliable, and does not degrade when you are tired.

Let the agent write the contract, then edit it

Asking the agent to draft the slice specification, including the invariants it thinks apply, is a fast way to surface misunderstandings before any code exists. What it gets wrong in that draft is exactly what it would have gotten wrong in the implementation, discovered at the cheapest possible moment.

Session hygiene: fresh context, frequent commits, early restarts

Treat the session as a resource that degrades.

One slice, one session. Context from the previous task does not help the next one. It supplies stale file contents, an abandoned approach, and instructions that no longer apply, all of which still influence output. Start clean and supply the current contract.

Commit at every green state. Tests pass, commit. This is not ceremony, it is a checkpoint that turns a wrong direction into a discarded ten minutes rather than a tangled afternoon. It also gives you a diff per logical step, which is what makes review tractable.

Restart after two failed corrections. When a session goes wrong, the instinct is to explain the mistake and continue. Each correction adds text describing what not to do, and the conversation fills with wrong approaches that still influence generation. Take what you learned, reset, and write a better brief. Restarting feels like losing progress and is usually the fastest path.

Never let it fix a test to make it pass. Say so explicitly. A failing test is information, and the most expensive silent failure in agent-assisted work is a suite edited into agreement with broken code.

The input that decides everything: grounding

Every practice above is about structuring work. The remaining variable is what the agent knows when it starts.

On an unfamiliar codebase, an agent spends its opening moves rediscovering the same facts: the module layout, the test command, the conventions, why a past decision was made. That work is identical every session, you pay generation prices for it every time, and the result is a summary the agent then reasons over instead of the source.

Making that knowledge retrievable removes the whole layer. RDK indexes files from local vaults, docs, and code as encrypted private chunks, and agents search those chunks before querying a model. Token spend drops 80 to 90 percent on repeated or reference-heavy work because the answer is retrieved instead of regenerated. Stacked retrieval sets the proportions: a private vault answers 40 to 65 percent of queries, the public network adds 15 to 20 percent, and the model handles the remaining 5 to 10 percent.

Combined with small slices and written contracts, that is the whole workflow. Structure the work so review is honest, and ground the session so the agent is not guessing about your system.

Frequently asked questions

How big should an AI-assisted change be?
Small enough to review line by line, which in practice means one vertical slice: a single behavior with its test, or one migration with its rollback. A diff across forty files gets skimmed rather than read, and skimmed review provides no verification at the moment it actually matters.
Should I write tests before letting an agent implement a feature?
Where practical, yes. A test written first turns review from judgment into a mechanical check, and it gives the agent an unambiguous target rather than an interpretation of your description. At minimum write down what must stay true, since invariants are what stop a plausible refactor from breaking behavior nobody was watching.
Why does my agent session get worse the longer it runs?
The conversation accumulates stale file contents, abandoned approaches, and corrections describing what not to do, and all of it still influences generation. After two failed corrections, reset and write a better brief. Restarting feels like losing progress and is usually faster than continuing to argue with the context.
What is the most common way AI-assisted code fails review?
It is technically fine and violates something unstated: a convention, an invariant, an interface another caller depends on. That is a specification failure rather than a model failure. Writing what must stay true before implementation prevents most of it, and indexing the reasoning behind past decisions prevents the rest.