← All Essays

The Agentic Engineering Formula: Plan, Develop, Validate

Stop treating coding agents like a slot machine. Agentic engineering is a short, repeatable formula: plan, develop, validate, and close the loop.

I keep watching developers treat coding agents like a slot machine: pull the lever, pray, pull again. It doesn’t have to be like that. Agentic engineering and loop design is a short formula, and it fits on an index card.

The Formula Fits on One Page

People talk about coding agents like they’re a feel. A knack some engineers have and others don’t, something you earn after a thousand hours in the chat window until your gut just knows. That story is comfortable because it excuses every bad result. If it’s an art, a bad output is just a bad day. The model wasn’t in the mood. The prompt didn’t land. You shrug and pull the lever again.

It isn’t an art. It’s a pipeline with named parts, and once you can name the parts you can fix the one that’s broken instead of re-rolling and hoping.

Three stages. Plan: turn a fuzzy intent into a spec you can argue with and a checklist you can measure. Develop: give the agent the tools and the tests it needs to build against that checklist. Validate: let the agent drive the real app and grade its own work against the spec. That’s it. Fits on an index card.

One detail saves this from being another tidy slide nobody follows. It’s a loop. Validation doesn’t sit at the end like a gate you walk through on your way out. It feeds back. When the agent drives the app and finds out the spec asked for the wrong thing, that goes back into planning and the spec changes. Plan, develop, validate, back to plan. Most teams that are stuck have quietly flattened the loop into a line. They plan once, build, ship, and then wonder why the output keeps drifting.

The rest of this is each stage, opened up. None of it is exotic. By the end you’ll be able to point at the stage your own setup is missing, because almost everyone is missing one, and it’s usually the same one.

Forge a Spec the Agent Can’t Wriggle Out Of

Everything downstream inherits the spec. This is the part people skip, because typing a paragraph of intent and watching code appear feels like progress, and writing an actual spec feels like homework. A vague spec doesn’t save you the work, though. It moves the cost to the moment the agent confidently builds the wrong thing, and now you’re debugging a misunderstanding.

Start by getting interrogated. You don’t know everything your spec needs to cover. That’s the nature of specs: the gaps are invisible to the person who has them. So before you write a word, point a grilling tool at yourself. Something like grill-me, where the model’s whole job is to ask the questions you didn’t think to ask. What happens when this field is empty. Where’s the auth boundary. What does failure look like to the user. What’s explicitly out of scope.

Then don’t trust one model to draft it. Run two in parallel on the same intent, independently. They’ll frame the problem differently and catch different edge cases. Hand both drafts to a third model whose only job is to merge them into the strongest single spec. This is OpenRouter’s Fusion/Sakana Fugu/etc idea pointed at specs, and it works for the boring reason a review panel beats a lone reviewer. One model has blind spots it can’t see in itself. Three arranged against each other surface them. OpenRouter Fusion and Sakana Fugu benchmarks show that combining the models crushes what any single model, even Fable, can do - anecdotally, that has been my experience.

What you want out of this is not pretty prose. It’s a flat statement of what “done” means, including the things that are deliberately out of scope. A spec you can argue with is a spec the agent can build against. A hopeful, hand-wavy one is a spec the agent will satisfy on a technicality while missing the entire point.

Turn the Spec Into a Checklist You Can Measure

A spec, even a good one, is too big to hand over and walk away from. It’s a destination with no route. Agents do their best work the same way junior engineers do: against small units with clear edges, not sprawling mandates. So the second move is decomposition. Have the AI break the spec into a checklist of small tasks, each one buildable and checkable on its own.

The rule that makes or breaks this: every task carries a success criterion you can measure. Not “implement the login flow.” Instead: the flow accepts a valid credential pair and returns a session token, rejects a bad pair with a 401, and locks the account after five failed attempts. A task with no criterion is a wish, and an agent can’t tell whether it satisfied a wish. Writing the criterion also smokes out ambiguity you’d otherwise ship, because you can’t write a check for a behavior you haven’t actually decided on.

For objective stuff this is easy. The criterion is a hard assertion. Passes test X. Comes back under 200ms. Build as much of the checklist out of hard assertions as the problem allows, because every one is a place the agent can’t fool itself.

Plenty of what we build resists pass/fail, though. The quality of generated copy. Whether an error message actually helps. Whether a flow feels right. The instinct is to save those for human judgment at the end. Don’t. Give the agent a sliding scale instead: grade yourself 0 to 100 on this, keep going until you’re past 95. Now a 72 isn’t something you have to catch later. It’s a number the agent reads and acts on by trying again. You’ve turned taste into a slope it can climb.

Onboard the Agent Like a New Hire

Now the agent builds. But what it builds is mostly decided before it writes a line, by the environment you drop it into. This is the front half of Develop, and most teams don’t think of it as a step at all. They picture “develop” as the agent’s job and theirs as waiting.

Picture a strong engineer starting Monday. If your conventions live in three people’s heads, if the right way to make an API call is folklore passed around in code review, if your internal helpers are undocumented and impossible to find, that engineer spends week one rebuilding things that already exist and breaking patterns nobody wrote down. An agent does the same in seconds, with a straight face, and it never gets embarrassed enough to ask. Missing context doesn’t slow an agent the way it slows a person. It just produces inconsistent output faster.

So do for the agent what you should have done for the humans. Make the good path the obvious path. Document the patterns and link the shared libraries from the files the agent actually reads. Put a working example next to the helper so it gets used instead of reinvented. If there’s a sanctioned way to talk to the database, write it down where the agent will trip over it.

This is a documentation and tooling investment, not a model problem, which is the good news: it’s in your hands and it compounds. And none of it is wasted on your people. Every link and every example makes the repo easier for the humans too. You’re paying down the onboarding debt you already owed, and the agent is just the first teammate that won’t quietly absorb it with effort.

Give the Agent a Way to Check Its Own Work

The other half of Develop is the test harness, and it’s the most underrated piece of the whole thing. Reframe it. Tests aren’t mainly a safety net for humans anymore. They’re how the agent knows whether the code it just wrote works, before anyone looks. An agent with no tests is writing in the dark. It produces something plausible, can’t feel whether it’s right, and hands you confidence it never earned.

One hard requirement: the suite has to be runnable by the agent itself, one command, no human in the loop. No “spin up the test database first,” no manual setup, no flaky step that needs babysitting. The second running the tests needs you, the agent’s feedback loop needs you, and you’ve put yourself back in the middle of the thing you were trying to automate. The point is that it writes code, runs the suite, reads the failures, and fixes them while you’re somewhere else.

This is also where thin coverage finally bites. The agent amplifies whatever coverage you already have. Good coverage becomes a fast, trustworthy loop. Thin coverage becomes a fast loop confidently stacking new code on top of bugs nobody caught. Same speed, opposite outcome.

And the tests aren’t a Develop formality you file away. They’re the exact instrument Validate is about to pick up and run.

Hand the Agent the Keys to the Running App

Unit tests prove the functions return the right values. They don’t prove the app works. The space between those two is where the real bugs live: the integration seam where two correct components disagree about a contract, or the flow that passes every unit test and then throws on the third screen. Validate exists to close that gap, and the first move is to let the agent drive the actual product.

The rig is worth building on purpose. A working local environment, the real app running in a state the agent can reach and reset. Real test credentials with the right permissions and seeded data, enough to get past the front door into the flows that matter. And a browser bridge, a Playwright MCP, so the agent clicks through the product like a user, submits the forms, and reads back what actually happened.

Now validation is something the agent does to the running app. It logs in and walks the checkout flow. It submits a form with a malformed value and checks the error shows up where the spec said it would. It does what a QA engineer does on a manual pass, except every iteration, and it never calls something “probably fine” because it’s 6pm on a Friday. This is the level the spec was written at, behavior a user can see, so it’s the only level where you can honestly say the spec is met.

This is the step almost everyone skips, and it’s why so many agent-built features pass every test and still feel broken in someone’s hands. Unit tests will happily confirm that your wrong assumptions are consistent with each other. Driving the live app is what catches the thing no test was ever aimed at. It costs more to set up than the earlier moves, and that cost is exactly why it gets cut.

Grade Against the Spec, Then Close the Loop

The agent’s driving the app. Last move: have it grade what it sees against the criteria you wrote back in stage one, then loop. The hard assertions pass or fail outright. The token came back. The 401 fired. The account locked after five tries. The fuzzy ones get the sliding scale: grade the flow, and if it’s a 78, go again. The “loop until 95” rule you wrote into one task now runs across the whole build.

For the loop to close, the agent has to see why something failed, not just that it did. Give it observability it can read: logs and the stack trace the app coughs up when it’s unhappy. A failed assertion with no visible cause is a dead end. The agent knows it’s wrong, has no idea why, and starts thrashing. The same failure sitting next to a stack trace is something it can actually fix. The more signal you expose, the faster the loop runs and the less often you get dragged back in to diagnose by hand.

Then the part that genuinely makes it a loop. Sometimes validation doesn’t tell you the agent built it wrong. It tells you the spec was wrong. The behavior the checklist demanded turns out to be the one nobody wants once you can see it running. That doesn’t get patched in place. It goes back to stage one, the spec changes, and the change rolls forward through Develop and Validate again. A spec that never changes on contact with reality was never a spec. It was a guess you refused to update.

So the whole thing, once more, fast. Forge a spec you can argue with. Cut it into a checklist where every item says how you’ll know it’s done. Onboard the agent with documented patterns and reachable tools. Give it a test suite it can run itself. Hand it the keys to the real app. Grade against the spec, loop until it passes, and send the spec-level failures back to the start.

Next time an agent’s output lets you down, don’t reach for a cleverer prompt and another spin. Walk the stages and find the one you’re missing. You’re probably missing one, and now it has a name.