agentic engineering / part 1

The disciplined loop, part 1

Goals, specs, and the work you can't delegate

Part 1 of a series on agentic engineering strategies that actually hold up. This one covers the solo loop: one human, one agent, real software. Later parts widen the lens from there.


Andrej Karpathy likes to ask AI models a trick question: "I want to wash my car. The car wash is 50 meters away. Should I drive or walk?"

They tell him to walk. It's so close! Why waste the gas?

Every frontier model gets this wrong,[1] and the reason they get it wrong is the single most useful thing you can understand about working with coding agents in 2026. The model isn't dumb. It knows more about cars, distances, and fuel economy than you ever will. What it doesn't have is the point: that the car is not transportation here, the car is the whole reason for the trip. That piece of context lived in your head, you never said it out loud, and the model can't derive it from first principles no matter how smart it gets.

Now replace "car wash" with your codebase. Every time an agent builds you something technically correct and completely wrong, this is what happened. You gave it a task. You kept the point.

This post is a how-to for closing that gap. It's the workflow I've settled into after a lot of trial, error, and deleted branches, and it borrows its skeleton from a framework Karpathy laid out in 2026: three layers, stacked. A spec layer, a verifier layer, and an environment layer. I'm going to walk through all three slowly, because the details are where this either works or turns into ceremony. All you need coming in is a terminal, a coding agent like Claude Code, and the experience of having been burned at least once.

Why "just prompt better" stopped being the answer

Here's the state of the art as of late 2026, compressed: the models write good code. Genuinely good. Multi-file features, tricky refactors, hours-long autonomous runs. Typing speed and API recall, the things that used to make senior engineers expensive, are now approximately free.

So why does agent-built software still go sideways? Because the failures moved. They're not syntax errors anymore. They're the wrong abstraction chosen confidently. Two systems interacting in a way nobody specified. A feature that passes every test and misses the point of the request. Work that looks done because nobody defined what done meant.

Karpathy has a line that reframes the whole game: traditional computers automate what you can specify. These new machines automate what you can verify. Read that twice, because it quietly reassigns your job. Your value is no longer producing the code. Your value is producing two artifacts the model cannot produce for itself: a statement of what you actually want, and a way to check whether you got it.

There's a second line that pairs with the first, and it's the thesis of this whole series: you can outsource your thinking, but you can't outsource your understanding. Karpathy has been citing it everywhere, though it isn't originally his (it came from a pseudonymous engineer who posts as kache). Hold onto it. Everything below is just those two artifacts — want, and check — taken seriously, and both of them are made of understanding.

The hierarchy: goal, spec, plan

Before the loop, you need three words defined precisely, because almost everyone uses them interchangeably and the interchangeability is where projects die.

The goal is the why. It's the decision or outcome the work serves: the car wash, not the driving. "Build an export feature" is a task. "Our biggest customer is threatening to leave because they can't get their data into their BI tool" is a goal, and notice how it instantly reshapes the work: now you know the export needs to match their tool's format, ship this month, and doesn't need seventeen configuration options. The goal is the one artifact that can never, under any circumstances, come from the model. It comes from you. It's usually one sentence. It almost never changes, and when it does, everything beneath it is up for renegotiation.

Here's the uncomfortable part: you often don't know your own goal crisply until someone drags it out of you. So don't write it. Get interviewed for it. Literally tell your agent: "Before you build anything, interview me. Ask me three to six questions to figure out what this is actually for and what must not break." This works absurdly well. The model is a good interviewer, and answering pointed questions is easier than writing a requirements doc from a blank page. You'll say things you didn't know you knew.

The spec is the what. It's the goal translated into a contract, and it's a file in your repository, not a conversation. This distinction matters more than any other single thing in this post. A conversation dies when the session ends. A file survives: the next session can read it, a different model can read it, you-in-three-weeks can read it.

A useful spec is short and has five parts. The goal, at the top, so nobody forgets the point. The non-goals, meaning what you're deliberately not doing, which prevent the agent from helpfully building a notification platform when you asked for one email alert. The invariants: the things that must stay true no matter what, like "the public API doesn't change" or "data written by the old version still loads." The key decisions, as an explicit list. And the acceptance criteria: numbered, checkable statements of what done means, like "a user can export to CSV from the settings page" — written before any code exists.

That key-decisions list deserves its own paragraph, because it guards against the most expensive failure mode there is. Karpathy tells a story about a project where the agents needed to link accounts across two payment systems, and they decided — reasonably, silently — to match users by email address. The right answer was persistent user IDs. Nobody had specified it, so the model picked, and the wrong pick contaminated everything downstream. The defense is mechanical: before implementation starts, the agent presents every decision it's about to make on your behalf, in one message, each marked either decided by you or proposed, needs your yes. You read the list. You say yes or no. It takes ninety seconds and it is the single highest-leverage ninety seconds in the entire workflow, because a wrong assumption caught here costs a sentence, and the same assumption caught in three weeks costs a rewrite.

The plan is the how, right now. Which files, what order, what to watch for. It's the sequencing for the current chunk of work. And here's the counterintuitive rule: the plan is disposable. It lives in the conversation, it dies with the conversation, and that's correct, because anything in the plan worth keeping should have been promoted up into the spec. This is Karpathy's actual gripe with the "plan mode" buttons in modern coding tools. Planning isn't bad. Stopping at the transient layer is bad. People generate a beautiful plan, execute it, close the terminal, and have nothing — no goal on record, no contract, no criteria. All plan, no spec.

So the hierarchy runs: goal (yours, one sentence, permanent) contains spec (shared, one file, durable) contains plan (the model's, ephemeral, cheap). When something goes wrong — and it will — the hierarchy tells you where to route the failure. A failed test means redo the work. The checker failing half the criteria means the spec is wrong; stop iterating on code and fix the contract. The spec being satisfied while the result still feels wrong means the goal was wrong, and that's not a debugging session, that's a walk around the block.

One more property, and it's the one that future-proofs everything: a repo organized this way makes models interchangeable. The spec defines the job, the criteria define done, the repo holds the memory. Whichever model is best this quarter — and that answer has flipped three times in the past year — you slot it in and nothing else changes. You're not building a workflow around a model. You're building a shop that any competent worker can walk into.

The loop

Here's the whole thing on one screen. Top half runs once per piece of work. Bottom half runs once per slice.

brain-dump → capture every thread → pick ONE (rest → backlog)once per effort — you're neededper slice — mostly autonomousspec drifted? update it · log lessons · next slice … shipGOALwhat's this for?SPECinvariants · decisions · criteriaSLICESsmall jobs, criteria attachedPLANdisposableBUILDGATESbuild · lint · testsJUDGEgrades vs criteriaREVIEWfresh eyesCOMMITsmall, working, done per slice most criteria failing? spec bug — go up

A few of these boxes hide the actual craft, so let me be pedantic about them.

The brain dump is a feature, not a failure. You will arrive at the terminal with five tangled threads, because you're a human and that's how heads work. Dump all of it. The agent's job (put this instruction in its standing configuration) is to catch every thread, read the list back to you, propose which one matters now, and file the rest somewhere durable. The discipline isn't "arrive organized." The discipline is "nothing gets silently dropped." Big difference. One of those is a personality transplant; the other is a filing system.

Slices are small on purpose. The instinct is to hand the agent the whole feature and come back in an hour. That's the waterfall instinct, and it fails with agents for the same reason it failed with humans, except faster. Every slice is a tight scope with its own criteria, ending in a checkpoint where you review the outcome: did the change land as intended? Sometimes that means reading a diff. More often it means looking at the thing in situ, whatever in situ means right now — clicking through the feature, running the command, reproducing the bug that's supposedly dead. Agent-written code is trending toward what assembly became: output a human could read, but mostly doesn't, because the volume keeps growing and the code itself got ephemeral once the cost of producing it fell to near zero. Judge the work at the level where your judgment still operates. You're steering a series of short hops, not launching one long-range missile. When a hop lands wrong, you've lost twenty minutes, not a week.

The judge is a different agent than the builder. This one feels like overkill until you watch it work. The agent that wrote the code grading its own work is a student marking their own exam: not dishonest, just structurally blind to its own assumptions. So a fresh agent, with no memory of the implementation, gets the diff and the criteria list and grades each one: pass, fail, can't-verify. Then a separate fresh-eyes review reads the diff for problems the criteria didn't anticipate. And when the stakes are real, hand the diff to a different model entirely — if you build with Claude, have OpenAI's Codex critique it. Different models have different blind spots, and the disagreements between them are exactly where your bugs live. If you only run one AI subscription, you still aren't stuck with self-grading: a fresh instance of the same model, started with a clean context and shown only the diff and the criteria, avoids the student-marking-their-own-exam problem, because the blindness lives in the conversation history, not just the weights. A different model catches more. Fresh eyes catch plenty. Cross-model is recommended, never required.

Verify against reality, not against reasoning. An agent saying "the deploy succeeded" is a guess wearing a suit. An agent that curls the health endpoint and reads the response knows. Wire your checks to real signals: test output, actual HTTP responses, screenshots, logs, state dumps. For anything hard to automate (games especially) this means building small observability tools (a command that prints the game state, a seeded run that replays deterministically) so the checker has something real to look at. The people who created these tools keep saying the same thing: give the agent a real feedback loop and output quality doubles or triples. My experience agrees.

Hard rules go in hooks, not in prose. Your agent's config file can say "never skip the test suite," and the agent will honor that right up until the afternoon it's deep in a frustrating loop and decides, very reasonably, that just this once. A sentence in a config file is a request. If you genuinely mean never, use your tool's hook mechanism (Claude Code and its peers all have one) to physically block the action before it executes. My test for every rule is blunt: does a hook enforce this? Then it's a real never. No hook? Then it's actually an "ask me first," and I should be honest and file it that way.

Spend your smartest model on judgment, always. The temptation is to route work to cheap models to save money. Resist it for anything that authors: code, specs, plans, reviews. The expensive failures in this whole system are judgment failures, and a cheap model saves you pennies on the way to costing you a weekend. Cheap models earn their keep on the grunt work: searching the codebase, fetching docs, filtering data. Fetching, never deciding.

Lessons climb a ladder. When you learn something the hard way (this library lies about its defaults, this test is flaky on Tuesdays), write it where the next session will find it: a notes file, then the repo's agent-instructions file, then your global config once the lesson proves out across projects. An insight that lives only in a closed terminal session is an insight you've scheduled yourself to rediscover. This is the environment layer doing its real job: the shop gets smarter even though every worker shows up with amnesia.

And one instruction I added late and now consider load-bearing: the workflow polices me too. My agent's standing orders include watching for the moments I skip my own process — "just build it" on something big and fuzzy — and pushing back with exactly one gentle sentence: "This one's vague and large. Three spec questions first, or straight to code?" I'm allowed to say straight to code. It's allowed to ask. That one exchange has saved me more rework than any tool I've installed, which is a little embarrassing, and I'm telling you anyway because it'll save you the same.

What this actually buys you

Try the smallest version before you believe any of it. Next real feature: ask for the interview, demand the decision list before code, write five acceptance criteria into a file, have a fresh agent grade the result. One work item, maybe fifteen minutes of overhead. What you should notice is a specific absence: the "wait, that's not what I meant" moment arriving on day one, at the decision checkpoint, instead of at the end wearing a full costume of finished code.

Then notice the strange thing that happens next. Code stops being your bottleneck. The agent implements faster than you can specify, and the whole constraint of your work slides upstream, to knowing what you want, saying it precisely, and verifying you got it. The scarce skills are now goal-finding, spec-writing, and judgment, and the loop above is a machine for spending exactly those.

The part you can't outsource

Which brings back the line I asked you to hold onto: you can outsource your thinking, but you can't outsource your understanding. The loop's real danger isn't any single bad diff, it's the fugue state. The agent is doing so well that you ease off, skim a checkpoint, let it own one more piece, then another, and one day you're approving work you no longer understand. At that point you're not in the loop; you're a rubber stamp with anxiety. Understanding is the entire reason a human is still in this loop. Maybe that changes someday. Today it's the job.

For one person, that's a productivity story. For a team, it's an earthquake. When every engineer runs a loop like this, pull requests arrive faster than anyone can review them, merge queues replace typing speed as the constraint, and product planning — deciding what's worth building — becomes the slowest thing in the building. Sprint rituals designed around "how long will this take to write?" start asking the wrong question entirely, and the humans who thrive are the ones who moved upstream on purpose rather than by surprise.

That story — the same three layers scaled to a team: review at volume, merge-queue discipline, what happens to agile when execution is cheap, and how roles reshape around understanding, planning, and steering — is coming later in this track. The short version is that the discipline doesn't change. The number of people who need to share it does.

notes
  1. A dated claim, kept on purpose. Karpathy told this story at Sequoia's AI Ascent fireside chat in April 2026, and it was true when he told it. The question then went viral, and by mid-2026 a handful of frontier models had started answering it correctly (real progress, or the car wash landing in the training data? nobody outside the labs knows). The specific question will keep expiring. What it defines hasn't: as long as models fill in your missing context by pattern instead of by asking, you cannot trust them with the point of a task, and every method in this post assumes exactly that until it provably changes. ↩︎