Agentic Engineering on Claude Code
There’s a story going around that AI coding tools removed the bottleneck in software engineering, and that the bottleneck was typing.
That’s wrong, and it was wrong before the agents showed up. Nobody’s project ever slipped a quarter because their team couldn’t type fast enough. Projects slip because the data model was wrong, because two services disagree about who owns a piece of state, because the retry logic amplifies a partial outage into a full one, because nobody decided what “done” meant. The bottleneck was system design. It still is.
What actually changed is that the cost of producing code fell to roughly zero, and the constraint that was always there is now fully exposed — with ten times the throughput running at it. If your design is muddy, you no longer find out in three weeks. You find out in an afternoon, across forty files.
So the interesting question isn’t “how do I get the agent to write more code.” It’s “how do I run this thing such that my judgement stays in the loop at the points where judgement is the scarce resource.”
The loop is the unit of work
Addy Osmani has a good framing for this in Practical Loop Engineering: stop thinking in prompts and start thinking in loops — act, evaluate against a check, feed the result back, repeat until a stopping condition fires.
Once you see it that way the design questions get concrete, because a loop has exactly three parts you can get wrong:
- The goal — what finish line are we running at, stated so a machine can tell whether we crossed it.
- The check — what evidence closes the loop.
- The bound — what stops it when the check never goes green.
Most bad agent sessions are a loop with a missing part. No goal: it wanders. No check: it declares victory on vibes. No bound: it burns forty minutes rewriting the same function four ways.
Weak checks and strong checks
This is the part that actually separates people who get value from these tools from people who don’t, and it has nothing to do with prompting.
A weak check is the agent’s own assessment. “I’ve updated the component and it should now render correctly.” That’s not evidence, that’s a prediction. Every frustrating agent session I’ve had traces back to accepting one of these.
A strong check is external and falsifiable:
Refactor the data-fetching in Dashboard.tsx.
Done when: `pnpm typecheck` passes, `pnpm test:dashboard` is green,
and Lighthouse LCP on /dashboard is under 1.8s.
Stop and report if you can't get there in three attempts.
Typecheck, test suite, linter, a curl against a running server, a Lighthouse run, a screenshot diff. The agent can run all of these itself, which means it can close its own loop instead of handing you plausible-looking guesses.
Which produces the observation that keeps surprising people: your test suite is now an agent-productivity feature. Teams with fast, trustworthy checks get enormous leverage out of these tools. Teams without them get a very confident intern with commit access. The investment you keep deferring is the one gating all of this.
And notice what “define the check” actually is. Deciding what correct means, what the acceptable latency is, what the invariants are — that’s system design work. It didn’t go away. It moved to the front and became the thing you type.
What I actually delegate
Roughly, I sort work by how good the available check is.
Delegate freely — strong mechanical check exists:
migrations across many call sites, test coverage for existing behaviour, type
errors, dependency bumps, “find every place we construct a StripeClient,”
codemods, docs that drift from the code.
Delegate, then review properly — check exists but is partial: new features behind existing interfaces, bug fixes with a failing test to go green, refactors inside one module.
Don’t delegate the decision — no mechanical check exists: schema design, service boundaries, auth and permission models, anything touching money, concurrency semantics, the public API you’ll be stuck with.
That last group isn’t off-limits to the agent — it’s great at drafting options and arguing both sides. But the choice is yours, because there is no test that tells you a boundary is in the wrong place. You have to already know.
Maker–checker
The single highest-leverage pattern I’ve adopted: the agent that wrote the code does not get to be the agent that reviews it.
Fresh subagent, no context about the implementation, one job — try to break this. It catches a genuinely different class of problem, because the implementing agent has spent its whole context window convincing itself the approach is sound. So have you, if you watched it work.
Same reason we don’t let people approve their own PRs. The principle didn’t change; only the participants did.
Boring infrastructure that pays for itself
Three things, in order of impact:
A CLAUDE.md that is falsifiable. Not “write clean code” — that does
nothing. “Package manager is pnpm, never npm install.” “Run pnpm test:unit
before claiming a change works; integration tests need Docker, don’t run them
unprompted.” “No raw SQL outside src/db/queries/.” It’s the onboarding doc you
never wrote for humans, and the humans benefit too.
Hooks for anything you’ve said twice. If you’re asking for the formatter a fourth time, that’s a configuration bug, not a prompting problem. Hooks fire deterministically on tool calls. The agent shouldn’t have to remember your invariants; the harness should enforce them.
Subagents for anything search-shaped. Context is a budget. Spend it on the reasoning, not on file dumps. Fan the search out, get the three-line answer back, keep your working context clean.
What loops don’t buy you
They don’t buy you a correct design. A loop with a green check and a bad data model just arrives at the wrong place faster and with better test coverage.
They don’t buy you understanding. You can ship a subsystem you could not explain under questioning, and you will find this out at 2am.
And they don’t buy you taste. Knowing that the plausible-looking suggestion falls over under concurrency, that this abstraction will be a liability in six months, that the requirement as written is the wrong requirement — none of that is in the loop. It’s in you, or it’s nowhere.
Which brings me to certificates
I spent most of my career mildly dismissive of certifications. In a world where a GitHub profile and a whiteboard were the signal, a PDF from a training provider was noise.
I’ve changed my mind, for one specific reason: the old signals got much noisier.
A green contribution graph used to imply sustained effort. A clean, well-factored PR used to imply taste. A working side project used to imply follow-through. Every one of those is now cheaply generated. That doesn’t make them worthless, but they no longer separate people the way they did.
When cheap signals get noisy, expensive signals get valuable. A credential requiring a proctored exam or a hands-on lab is expensive in exactly the way that makes it informative.
| Worth it | Why |
|---|---|
| Cloud platform certs (AWS/GCP/Azure, associate and up) | Hands-on, proctored, and they map to real operational responsibility. Still the strongest single credential in the market. |
| Security certifications | The one domain where “the agent wrote it” is the start of the conversation, not the end. Demand here is structural. |
| Kubernetes / platform certs (CKA, CKAD) | Performance-based. Real cluster, real problems, against a clock. Very hard to fake. |
| Vendor AI/agent credentials | Early and uneven, but the good ones make you demonstrate evaluation and safety practice, not prompt-writing. |
| The distributed systems and databases coursework you skipped | Not a certificate. Compounds harder than any of the above when you’re the one reviewing agent output. |
What isn’t worth it: anything you can pass by watching a video at 2× speed. No lab, no proctor — it’s a receipt, not a credential.
But signalling is the smaller half of the argument. The bigger half is that studying for a hands-on exam is one of the few remaining structured excuses to build depth in exactly the areas agents let you skip. You cannot delegate your way to understanding why the health check is failing, or what your database does under write contention. Sitting the exam is a forcing function for actually learning the thing — and that depth is precisely what “define the check” and “don’t delegate the decision” are drawing on.
Where this leaves us
The job didn’t get easier and it didn’t change as much as people claim. The hard part was always deciding what to build and knowing when it’s right. That part is now the whole job, running against a code-generation firehose.
So: define goals a machine can check. Make your checks strong and your feedback loops fast. Keep the decisions that have no test. And go rebuild the depth the tools make it easy to skip — because the loop closes on your judgement, and nothing else.
Related reading: Addy Osmani, Practical Loop Engineering — the loop/goal framing above owes a lot to it.