Karpathy nailed the dawn of this era with the term “vibe coding”, that frictionless, syntax-free honeymoon phase where you simply prompt, paste, and watch a weekend prototype assemble itself. It’s exhilarating. You feel like a wizard. Then Monday arrives, and you try to vibe code your way through a legacy Spring Boot lending service. Suddenly, the wizard is setting production on fire.

Updated August 2026: I first wrote this piece in early 2025, when the interesting question was which assistant autocompletes Code best. Eighteen months of daily use and billions of tokens later, I am here to tell you that this question is dead. The models all got good enough. What separates a useful setup from a frustrating one now is the harness: the layer of context, permissions, hooks, verification, and delegation you build around the agent.

So this is a rewrite. Less tool comparison, more of the thing I actually spend time on. Same motive as the original: this isn’t a feature list, it’s what I really run, on a real Spring Boot codebase, day to day.

If the agentic computing shift is real, this is the unglamorous half of it — not the agent, but the rails around it.

The Shift: Tools Became Commodity, Harnesses Didn’t

In 2025 I ran four assistants and rated them against each other. Now I run multiple agents in terminals plus an IDE(I’m a creature of habit) for reading, debugging, and stepping through, although I must admit the loops are far superior now than human verification in almost all regards.

Splitting attention across four assistants meant none of them had enough context to be useful, and context turned out to be the whole game. An agent that knows your layering rules, your build wrapper, and your transaction gotchas beats a smarter agent that knows none of them, every single time.

The corollary is the useful bit: swapping agents costs an afternoon. Rebuilding the harness around one costs weeks. That asymmetry tells you where to invest.

The Harness: Five Layers

Build these in order. Most people start at layer 5 and wonder why it doesn’t help.

LayerWhat it doesWhere it lives
1. ContextWhat the agent knows before it actsCLAUDE.md, .coding-standards/
2. PermissionsRemoves friction so I stop babysitting.claude/settings.json
3. DeterminismThe harness enforces, so the model doesn’t have to remember.claude/hooks/
4. VerificationThe agent proves the change works before claiming donereview + tests/security passes
5. DelegationSubagents, skills, workflows.claude/skills/, .claude/agents/

Two principles do most of the work.

Anything the model must remember, it will eventually forget. A rule in a markdown file is a hint. A hook is a law. When a rule matters and is cheaply checkable from the text, promote it from layer 1 to layer 3.

Write down conclusions, not commands. If the agent greps for the same fact twice, that fact belongs in a doc. A permission allowlist bloated with one-shot search patterns is the tell — it means the answers were never recorded, so they keep getting re-derived.

Layer 1: context, with the why attached

My main service has thirteen critical rules in CLAUDE.md and nine detailed standards files split by topic — Java, Spring, persistence, logging, testing. The split matters: the agent reads the index every session and pulls the detailed file only when it’s working in that area.

The rules that pay off are the non-obvious ones, where default behaviour is confidently wrong:

  • @Transactional self-invocation is silently broken. Call a @Transactional method from another method in the same class and Spring’s proxy never runs — no error, no rollback, just a transaction that quietly wasn’t. I’ve watched an agent “simplify” a service by inlining a call into the same class and produce exactly this. It compiled, tests passed, and the transactional boundary was gone.
  • @Scheduled fires on every replica. We run seventeen. A sweep job written the obvious way runs seventeen times concurrently. This one nearly bit us on a cancellation sweep — the fix is the internal distributed scheduler, but nothing in the code looks wrong, so it has to be written down.
  • Read/write datasource routing keys off @Transactional(readOnly = true). Forget it on a read and you’ve put load on the primary; set it on a write and the write fails.

None of these are discoverable by reading the file you’re editing. That’s the test for whether something belongs in layer 1: would a competent engineer get this wrong on their first day? If yes, write it down — with the reason, because the reason is what makes the model generalize instead of pattern-match.

Layer 3: which rules can be laws

Three of my thirteen rules are hooks. The split is the interesting part.

“Always use the Maven wrapper ./mvnw, never bare mvn” is a string match on a command. That’s a hook, and it blocks. Same for the checkstyle gate before a commit.

@Transactional self-invocation can’t cheaply be a hook — catching it properly needs call-graph analysis, and a naive regex would either miss the real cases or block every edit near legacy code. So it stays a documented rule.

Three things I learned the hard way writing these:

  1. Gate expensive hooks to the moment they’re needed. My first checkstyle hook ran on every file write. It taxed every keystroke and made the whole setup feel worse than no setup. Now it fires only on git commit.
  2. Count existing violations before you add a rule. If hundreds of places already break it, the hook must only catch new introductions — otherwise every edit near old code gets blocked and you’ll disable it within a day.
  3. Pipe-test it before wiring it up, including the cases that should pass. A hook that silently does nothing is worse than no hook, because you’ll trust it.

Keep stack-specific hooks project-scoped. Global settings fire in every repo — a ./mvnw hook in your global config starts firing in Node projects that have no wrapper. Global is for genuinely stack-agnostic things: model, effort level, notification behaviour.

Agentic Workflows That Actually Earn Their Keep

This is the part that didn’t exist in the 2025 version, because most of it didn’t exist.

Plan before edit. For anything touching more than two files, the agent plans first and I approve the plan. Catching a wrong approach in a plan costs a paragraph; catching it in a diff costs a rollback.

Subagent fan-out for reading. Investigating “where does this flow touch the DB” used to mean the agent reading twenty files into its own context until it had no room left to think. Now that goes to parallel subagents — each reads its slice in a fresh context window and reports back a summary. The orchestrator stays clean. Reading-heavy work goes to a cheaper, faster model; the expensive model does planning, judgment, and synthesis.

Adversarial verification. The single most valuable technique I’ve added. For a non-trivial finding, spawn several independent reviewers, each prompted to refute rather than confirm. Keep what survives. Most “bugs” don’t. On our reject-and-markup edge cases this cut the noise dramatically — plausible-sounding findings that dissolve the moment something actively tries to disprove them.

The counterintuitive bit: telling a reviewer “only report high-severity issues” makes measured recall drop. Current models follow that filter faithfully — they find the bugs, judge them below the bar, and say nothing. Ask for everything with confidence and severity attached, then filter in a separate pass.

Worktrees for parallel work. Agents editing the same tree in parallel trample each other. Give each one its own git worktree and they don’t.

Skills for procedures, docs for facts. If I catch myself re-explaining the same sequence — ordered steps, a specific invocation — that’s a skill. Facts stay in layer 1 docs. Getting this backwards produces bloated docs nobody reads and skills that don’t fire.

MCP for the stuff outside the repo. Tickets, wiki pages, calendars. Worth knowing the sandbox has its own network path — ours can’t reach the internal wiki, so design docs get pasted in rather than fetched. Better to know that than to watch an agent retry a blocked fetch five times.

Persistent memory. One durable fact per file, with the why. It’s the difference between an agent that re-derives your deployment topology every session and one that already knows it.

Review: Two Gates That Share No Config

Verification is layer 4, and the design principle is independence:

  1. Local, before the push — a review pass over the diff plus a security pass, with the adversarial verification above for anything non-trivial.
  2. A bot on the pull request — server-side, independent of my local setup.

If both gates share my configuration, they share my blind spots, and they’ll agree with each other confidently while being wrong together. Two gates with no shared config disagree in useful ways. Two gates with the same config are one gate.

What the Data Says

Two things worth knowing, because they point in opposite directions.

GitClear’s 2026 research with GitKraken, across ~623 million code changes from 2023–2026:

  • Refactoring is down ~70%, to under 4% of changed lines. Developers are now roughly five times more likely to duplicate code than consolidate it.
  • Duplication up ~81%.
  • Error-masking constructs up ~47% — the catch (Exception e) {} genre of “fix”.
  • Long-term legacy maintenance down ~74% since 2023.

DORA’s 2025 report, ~5,000 respondents, splits the outcome cleanly:

  • Throughput flipped positive. “Unlike last year, we observe a positive relationship between AI adoption on both software delivery throughput and product performance.” In 2024 that correlation was negative.
  • Stability is still negative. “AI adoption does continue to have a negative relationship with software delivery stability.”
  • 90% of respondents use AI daily, median ~2 hours a day.

And the sentence that reframed my whole setup:

AI accelerates software development, but that acceleration can expose weaknesses downstream. Without robust control systems — like strong automated testing, mature version control practices, and fast feedback loops — an increase in change volume leads to instability.

Control systems. That’s what a harness is. The hooks, the pre-commit gate, the two independent review passes — those aren’t productivity hacks, they’re what decides whether the extra throughput ships features or ships incidents. DORA’s headline is that AI is an amplifier: it magnifies the practices you already had. So the harness isn’t an optimization on top of the speedup. It determines the speedup’s sign.

Matching This to Real Projects

The original post matched a tool to each project. Here’s the updated version — same projects, but the variable that changes is the harness, not the tool.

Algorithmic systems (a Java credit-card recommendation engine — comparators, rule evaluation, eligibility) Correctness is subtle and the tests are the deliverable. High effort, plan mode on, adversarial review on every scoring change. This is where “only report high-severity” would have hidden the exact class of bug I cared about.

Rapid prototyping (the realtime Elasticsearch DSL compiler I built at Bik) Almost pure upside, minimal harness needed. Nothing is load-bearing yet, the feedback loop is instant, and being wrong is cheap. Let it run.

Established production services (a multi-replica Spring Boot lending service) Maximum harness. Every rule above exists because default behaviour is confidently wrong here. Layers 1 and 3 are doing most of the work, and the read/write split, transaction boundaries, and scheduler semantics are exactly what an agent cannot infer from the file in front of it.

Fun Fact, preserved from 2025 because it held up: I spent about 2 days in 2019 building a portfolio site and hand-wiring EC2 and an Elastic IP. I rebuilt it in about 45 minutes with auto-deploy on Cloudflare Pages. That gain was real and it stayed real. What I’ve since learned is that a 45-minute site and a 45-minute production change are completely different risks — and the difference is entirely the control system around the second one.

The Tradeoffs

LeverWhat you getWhat it costs
Rich context (layer 1)Fewer confidently-wrong changesDocs need maintaining, or they rot into lies
Hooks (layer 3)Rules that can’t be forgottenBadly scoped hooks block legitimate work
Wide permissions (layer 2)No babysittingLess oversight of what actually ran
Subagent fan-outBig investigations without context bloatMore tokens, more coordination
High effort settingsBetter judgment on hard problemsSlower and pricier on easy ones
Two review gatesCatches what one gate missesReal latency before merge

Most of these want tuning per repo, not one global answer. The prototype and the production service should not have the same harness.

The Bottom Line

The 2025 version of this post ended by saying that combining tools beats any single magic bullet. I’d put it more narrowly now:

The tool is nearly fungible. The harness is not.

If you’re starting out, skip the comparison tables — mine included. Keep a running list of what your agent keeps getting wrong. Then, for each item, ask the only question that matters: can this be a law, or does it have to stay a hint? Turn as many as you can into laws. Attach the reasoning to whatever’s left.

That list is the actual artifact. The tool you point at it is a detail.