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. A reliable agentic loop follows a short formula, and it fits on an index card.
The Formula Fits on One Page
People talk about using coding agents as though it were a feel: a knack some engineers have and others don’t, earned 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, bad output can be written off as a bad day, a model that wasn’t in the mood, or a prompt that 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.
The formula has three stages. Plan by turning a fuzzy intent into a spec you can argue with and a checklist you can measure. Develop by giving the agent the tools and tests it needs to build against that checklist. Validate by letting the agent drive the real app and grade its work against the spec. That’s the whole index card.
One detail saves this from becoming 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 into the work. When the agent drives the app and discovers that the spec asked for the wrong thing, that result returns to planning and changes the spec. Plan, develop, validate, then return to planning. 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 essay opens up each stage. None of it is exotic, but by the end you should be able to identify the stage your own setup is missing. 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, because its gaps are often invisible to the person who has them. Before you write a word, point a grilling tool such as grill-me at yourself and let the model ask the questions you didn’t think to ask: What happens when this field is empty? Where is the authentication boundary? What does failure look like to the user? What is explicitly out of scope?
Then don’t trust one model to draft it. Run two independently and in parallel on the same intent. 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 applies the model-fusion idea behind tools such as OpenRouter Fusion and Sakana Fugu to specification writing, and it works for the boring reason that a review panel beats a lone reviewer. One model has blind spots it can’t see in itself; three arranged against one another can surface them. Benchmarks for those systems show combined models outperforming any single participant, and my experience has matched that result.
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 work, this is easy because the criterion can be a hard assertion: it passes test X or responds within 200 milliseconds. Build as much of the checklist out of hard assertions as the problem allows, because each one gives the agent less room to fool itself.
Plenty of what we build resists pass/fail grading, including the quality of generated copy, whether an error message actually helps, and whether a flow feels right. The instinct is to save those questions for human judgment at the end. Instead, give the agent a rubric and a sliding scale: grade this from 0 to 100 and keep going until the score passes 95. Now a 72 isn’t something you have to catch later; it’s a signal the agent can act 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 process. Tests are no longer just a safety net for humans; they’re how the agent knows whether the code it just wrote works before anyone looks. An agent without tests is writing in the dark. It produces something plausible, has no way to know whether it’s right, and hands you confidence it never earned.
One requirement is nonnegotiable: the agent must be able to run the suite itself with one command and no human in the loop. There can be no separate instruction to spin up the test database, no manual setup, and no flaky step that needs babysitting. As soon as running the tests requires you, the agent’s feedback loop requires you, too, putting you back in the middle of the process you meant to automate. The point is for the agent to write code, run the suite, read the failures, and fix 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.
The tests aren’t a Develop formality you file away. They’re the instrument the Validate stage 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.
This rig is worth building deliberately: a working local environment with the real app in a state the agent can reach and reset; test credentials with the right permissions and enough seeded data to exercise the important flows; and a browser bridge such as a Playwright MCP, so the agent can click through the product, submit forms, and observe 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
Once the agent is driving the app, have it grade what it sees against the criteria from stage one and then loop. The hard assertions pass or fail outright: the token came back, the 401 fired, and the account locked after five tries. The fuzzy criteria use the sliding scale; if the flow earns a 78, the agent tries 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.
This is where it genuinely becomes a loop. Sometimes validation doesn’t reveal a bad implementation; it reveals a bad spec. The behavior the checklist demanded turns out to be the one nobody wants after seeing it run. Instead of patching around the problem, you return to stage one, revise the spec, and roll the change through Develop and Validate again. A spec that never changes on contact with reality is just a guess you refused to update.
The whole process is straightforward. Forge a spec you can argue with and cut it into a checklist whose items each explain how you’ll know they’re done. Onboard the agent with documented patterns and reachable tools, give it a test suite it can run itself, and hand it the keys to the real app. Grade the result against the spec, loop until it passes, and send failures in the spec itself 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.