Note: everything here was built and validated with Claude Code, and the examples use its primitives, CLAUDE.md, hooks, skills, subagents. The method doesn’t depend on the tool. Any agent that offers permanent instructions, deterministic gates and isolated context for review supports the same design: the file names change; the decisions stay the same.
The scene repeats in every team that adopted coding agents: the model writes in twenty minutes what would take an afternoon, a test breaks, someone copies the error message, pastes it into the chat, the model apologizes and tries again. Until it passes. At the end of the day, the most expensive person in the room worked as a clipboard between the machine that generates and the machine that validates. Code generation got absurdly cheap, and the team’s throughput stayed the same, because the bottleneck was never generating. It’s verifying.
I’ve been building and refining a guideline for developing with AI for over a year, in a context where mistakes are expensive: regulated domain, rules with a normative source, money where a wrong rounding becomes a liability. Along the way I mined dozens of sources, from Anthropic engineering articles to listicles inventing commands that don’t exist, and every idea only entered the system after being verified at the primary source. This article is the distillation: how to do it, why to do it, and above all why the design is this one and not another. And the full guideline, with the implementation skills, the reviewer, the commands, the hooks and the spec template ready to install, is published in an open repository: this article explains the design, the repo delivers the artifacts.
The thesis: the bottleneck moved from generation to verification
Developing software was never typing code. It’s turning ambiguous intent into verified change, and AI brutally attacked only the middle of that process. Understanding what the business needs is still expensive. Guaranteeing the change does what it should is still expensive. When you accelerate the middle without scaling the ends, the result is faster slop: output that looks complete but doesn’t reduce the mess. It compiles, looks done, and leaves the system harder to change than it was.
Lucas F. Costa wrote the line that became the permanent lens of my system: any flow that depends on a human to catch the machine’s errors is limited by the human, not the machine. If every agent PR needs a human reading line by line, your production capacity is your team’s reading capacity, and you paid for a generator that spends the day waiting for a reviewer. And the failure mode is worse than the queue: when volume saturates the reviewer, review turns into skimming, and slop gets through. His answer is called backpressure, and I adopted it as a founding principle: every no the machine can produce, a failing test, a type error, a lint rule, an automated reviewer’s objection, has to fire before a human looks at the work. The symptom that backpressure is missing is catching yourself copying machine feedback back to the agent. At that moment a check is missing, and the fix is building the check instead of accepting the clipboard role.
The auto industry solved this problem decades ago and gave it a name: jidoka. Toyota’s line stops itself when it detects a defect, instead of letting the bad part travel to the inspector at the end of the belt. The human inspector exists, but looks at exceptions; the ordinary part rolls straight through. With agents it’s the same design: the human reviews what survived every gate, and when something slips through, the answer is designing the gate that was missing.
The second half of the thesis is about intent. Addy Osmani named the problem that specs and context files solve: intent debt, the debt of the why that was never externalized. With human teams, implicit intent was a tax paid at onboarding and in git blame archaeology. With agents, the cost changed scale: an unwritten why is paid again in every session, multiplied by every agent that touches the code, because the model has nowhere to read the intent and re-derives it, or invents it, every time. That’s why the guideline insists on intent externalized in versioned artifacts, each at the altitude where it’s born: the spec for business rules, the constitution for non-negotiable principles, ADRs for dated architectural decisions, the approved plan for the implementation rationale, lessons for the mistake that can’t repeat.
The third pillar is the difference between instruction and enforcement. CLAUDE.md, AGENTS.md, rules in markdown: all of that is instruction, and instruction the model follows most of the time. Anthropic themselves are explicit about this: in a long session, under ambiguity or pressure, a prompt rule can be ignored, and a real guardrail needs to be deterministic. In my experience adherence sits around 70%, a number the community repeats anecdotally, without rigorous measurement, but one that matches what I see day to day. For a naming convention, that’s fine. For “never use float for monetary values” in a tax system, it’s a scheduled incident. The rule that needs 100% becomes mechanism: a hook that blocks the commit, a linter rule, an AST check in CI. Instruction is hope; a hook is a guarantee. A good part of the design decisions that follow derive from this distinction.
The five principles
Everything in the system derives from five principles. When a new situation shows up and no rule covers it, these are what I go back to.
- Smallest possible change. Deleting a line beats adding one. No unrequested refactors, speculative helpers, abstractions for a future that may never come. Agents have a chronic tendency to do more than asked, and every extra line is review surface someone pays for later.
- Root cause, not band-aid. A bug showed up, find out why. A temporary fix that hides the symptom becomes permanent, and with an agent generating plausible fixes in seconds, the temptation to treat symptoms only grows.
- Verification is part of the work, not optional. Every change is born with its form of verification: a test, an expected output, an observable behavior. If it can’t be verified, it doesn’t merge. Without this, “done” is an opinion.
- Determinism where possible, agent where necessary. Predictable tasks, moving a file, indexing, manipulating issue labels, appending to a log, become scripts the agent calls, and come off the agent’s to-do list. The agent is expensive, non-deterministic and burns context; a script is cheap, auditable and gives the same result every time. If you’re asking the model for something a shell would solve, move it to the shell.
- The first no comes from the machine. The backpressure from the previous section, promoted to a design principle: every gate the machine can run fires before asking for a human’s eyes.
The first four sound like engineering common sense, and they are. The difference is that with an agent they stop being personal virtue and become externalized rules, because the one who needs to follow them now is a model born without memory in every session.
Spec-anchored: the business decision comes before the code and anchors everything after
The guideline has a name, Spec-Anchored Agentic Development, and the name states the design: development organized by capability, with one spec per capability playing two roles. A capability is a cohesive slice of what the system does for the business: payments, orders, notifications, billing. It’s not a technical layer (controller, repository), nor an entity (Product, Customer), nor a mechanism (cache, queue). It’s the natural unit for writing a spec because the business already drew its boundary. If you’ve read what I wrote about DDD on serverless you’ll recognize the kinship with bounded contexts, but the vocabulary is optional: you don’t need DDD to know that payments isn’t orders.
The two roles are the two halves of the name. The spec comes before: the business decision precedes the code instead of emerging from it, because vibe coding doesn’t discover architecture, it discovers the model’s path of least resistance, which rarely coincides with your domain’s boundary. And the spec anchors: from then on it’s the fixed point everything verifies against, tests anchor on its acceptance criteria, the reviewer compares the diff against it, and divergence between spec and code goes into the queue like any other bug. A spec written and abandoned is dead paper; the value lives in the anchor that keeps being enforced after the merge. Identifying the boundaries, in turn, costs less than it seems, because in most projects you already know where they are. When it’s not obvious, there are signals, and the best one is linguistic: if the same word changed meaning, you crossed a boundary. “Product” in the catalog, name, photo, description, is not “product” in inventory, balance, reservation, location. The other signals follow the same logic: the main actor changed, the cadence of change changed (the catalog changes every day, payment rules change once a quarter), what always changes together groups together, what needs to be atomic stays together. In a large brownfield, where the intended boundary and the real one diverged long ago, mine evidence instead of opining: co-change in git history, files that always change together belong in the same place, and clustering on the dependency graph. Event Storming and heavy modeling ceremonies come in as escalation, when the case is genuinely hard.
And the name has grounding beyond this blog. A taxonomy is consolidating in the literature, in a 2026 arXiv paper echoed by the exploring-gen-ai series on Martin Fowler’s site, with three levels of rigor inside spec-driven development. Spec-first: the spec precedes the code but may drift or be discarded afterwards, and the code becomes the primary artifact. Spec-anchored: the spec is permanent and the code answers to it continuously. Spec-as-source: the code is generated or derived from the spec. Kiro and Spec Kit, the tools you probably know from this conversation, are spec-first, per-feature specs that guide the work and then become history; the series’ field observation is that nearly every SDD approach today stops at that level. This guideline is spec-anchored by construction, drift is a bug and conformance is checked value by value. And for normative rules it moves toward as-source: the spec’s reference values generate the golden tests that act as the oracle.
Two opposite mistakes kill projects here. The first is starting to code without identifying capabilities: by week eight it’s 30 thousand lines, nobody knows where anything lives and every change breaks three things. The symptom is you, or the model, asking “where does this go?” and there being no clear answer. The second is the inverse, trying to specify every rule and every edge case on paper before the first line of code. Boundaries get sharp during implementation, and a complete tactical spec written upfront becomes debt before the first deploy; the symptom is editing more spec than code in the first weeks. The balance that works: boundaries upfront and light, tactical detail evolving along with the implementation. Strategic upfront, tactical emergent.
The capability spec captures the business source of truth: domain rules, edge cases with their expected handling, non-goals (what this capability explicitly does not do), contracts with its neighbors. A rule derived from an external source cites the source, norm such-and-such, version such-and-such, and in a regulated domain that is an auditable obligation. The most efficient way I’ve found to write a spec is inverting the flow: a Plan Mode session where the model reads the neighboring contracts and the constitution, then interviews me, one question at a time, each with a recommended answer I confirm or correct, about rules, edge cases and non-goals before writing anything; in the repository, this flow is the /shape command. The model asks far better than it fills templates, and the questions it asks expose ambiguity I didn’t even know I was carrying.
One design decision closes this part: a spec change is a business rule change, so any PR that updates a spec carries a requires_human_approval flag. The agent can evolve the spec during implementation, but business rules never pass without human eyes.
And the entry point is smaller than all this apparatus suggests: one file. specs/payments/payments.md with rules, edge cases and non-goals in half a page is already spec-anchored. You don’t need a constitution, a reviewer or an autonomy trajectory to start; you need the business decision written before the code. Everything else in this article is how the system scales, and each piece comes in when the corresponding pain shows up.
Context in three layers
Context engineering here operates in three layers, and mixing them is the biggest source of problems I see in agent setups. Layer 1 is permanent knowledge: conventions, domain rules, architectural decisions, glossary. It lives in versioned files and changes rarely; every change is a conscious commit. Layer 2 is active work: the feature plan, research notes, local decisions. It changes all the time during the feature and is disposable after it. Layer 3 is intent and prioritization: what to do, in what order, why. It lives in GitHub Issues with labels. If it helps, think long-term memory, working memory and agenda. And the flow rule between layers is what keeps the system alive: what was learned in layer 2 and deserves to survive moves up to layer 1; what’s obsolete in layer 1 gets updated or dies.

The three context layers: versioned permanent knowledge, disposable active work, an intent backlog. The flow rule between them is what keeps the system from rotting: what deserves to survive moves up, what went obsolete dies.
In practice, the permanent layer has a topology:
project/
βββ CLAUDE.md β entry point, ~60 lines (never 100)
βββ architecture/
β βββ constitution.md β non-negotiable principles
β βββ pipeline.md β contracts between capabilities
β βββ decisions/ β ADRs
βββ .claude/
β βββ rules/ β invariant rules, auto-loaded
β βββ commands/ β /implement, /review, /shape, /spec-to-tickets
β βββ agents/reviewer.md β the independent reviewer
β βββ skills/ β implement-feature, implement-backlog
β and the review criteria
βββ docs/ β glossary, norms, walkthroughs
βββ specs/ β source of truth, mirrors src/
β βββ payments/
β βββ payments.md
β βββ contracts/
βββ src/
βββ payments/
βββ CLAUDE.md β pointer to the spec, 20-40 lines
βββ ...
Two decisions in this structure carry the weight. specs/ and docs/ are centralized, source of truth in one place, mirroring the names in src/. And each capability has its own CLAUDE.md (or AGENTS.md, the open standard that Codex, Cursor and the others read; same mechanics), next to the code, because these files load by proximity: the agent loads the one closest to the file it’s editing. A context file far from the code it describes simply doesn’t get read at the right time. And one convention worth adopting from the start: everything the agent reads, context files, specs, rules, skills, is written in English, even on a team that doesn’t speak it, because the models are trained predominantly on English and English context reduces terminology drift.
More important than the structure is the discipline of what to write in it, and there are three golden rules.
Document only what the agent can’t infer. Don’t describe folder structure; let the layout speak. A stale structural reference actively misleads, while an absent one costs nothing. The corollary is that this only works if the layout actually reveals the domain, and that’s why package-by-feature is a precondition: payments/, orders/, notifications/, each folder a complete vertical slice of the capability, never controllers/, services/, repositories/ scattering each capability across three places. It’s Robert Martin’s Screaming Architecture with a new justification: structure that screams the domain is structure that spares the agent documentation. And watch out for package-by-entity in disguise, a folder with a data noun (product/, customer/) that looks like a feature folder but reproduces anemic slicing. The test is threefold: the name is a verb or a business outcome, the folder is a vertical slice, and the imports point inward.
Pointer, not copy. The capability’s CLAUDE.md has 20 to 40 lines: scope in three sentences, the three to five most important rules summarized, where things live, and a pointer to the full spec with the instruction to read it before touching domain rules. It doesn’t import the whole spec, because that would load the spec on every trivial edit, burning context for nothing. Trivial edits are handled by the summary; a rule change triggers the spec read. The root file stays around 60 lines and never crosses 100: build and test commands, a structure map, pointers to the reference documents. Every token in these files is loaded on every turn, so lean beats complete.
Treat drift as a bug. Specs and context files diverge from the code over time, and there’s no automatic staleness detector. The defense is treating these files as code: versioned, reviewed in the diff, updated in the same PR that changes behavior. A false spec misleads more than a missing one.
The constitution and the rules close the permanent layer. The constitution is the system’s non-negotiables in 15 to 30 lines; in my case: sensitive values use decimal types, never float; every critical decision is traceable to the rule applied, the input and the code version; a rule codified from an external source cites the source; and a past-period rule never changes retroactively. The rules in .claude/rules/ are short auto-loaded rules, each file under 30 lines and, when they only apply to one region of the code, with paths: in the frontmatter so they load only when the agent touches that glob. And here the instruction-versus-enforcement distinction returns: a rule is instruction, with those ~70% adherence. The critical subset gets promoted to a hook. Decimal handling was the first candidate in my domain; in yours, it’s the rule whose violation costs the most.
The implementation flow and the reviewer that never writes
With context in place, work runs through a seven-phase flow: understand, resolve ambiguities, plan, implement, test, review, close the loop. In local mode, the one who confirms the first three is you. They’re human gates positioned where the load-bearing decisions live, the ones that determine whether the approach works and which architecture is being committed to, and the plan pins those now; the rest is deferrable detail, reversible, that implementation decides on the spot. That’s the decisive test of a good plan, and it’s where human attention pays off: on what’s expensive to reverse.
The ambiguity phase exists because ambiguity has no gradient. A model facing an ambiguous instruction doesn’t stop, it picks an interpretation and proceeds with full confidence. The flow forces the opposite: ambiguities go up structured, with proposed interpretations, and nothing proceeds without an answer. I promise you this phase alone pays for the guideline, because the most expensive waste in agent development is the perfect PR built on the wrong interpretation.
In implementation, two habits that come straight from backpressure. Lint, type check and the tests for the touched area run on every chunk, never accumulated at the end, and red doesn’t advance: an agent stacking forty minutes of work on top of a broken test multiplies the cost of the fix. And tests anchor on the spec’s acceptance criteria. A test that mirrors the implementation only codifies current behavior, bugs included, and from then on it defends the mistake against the fix.
After green comes review, and here lives the most important design decision in the flow: the one who reviews is not the one who wrote. The reviewer is a separate agent, running in isolated context, that receives the diff and the plan without the history of whoever produced the work, and that never writes, read-only by tool configuration instead of prompt instruction. The reason is self-evaluation bias, which Anthropic documented firsthand in their harness engineering article: an agent confidently praises its own mediocre work, and calibrating an independent evaluator to be skeptical is tractable in a way that making the generator criticize itself is not. It’s the same blind spot that keeps you from seeing the bug in code you just wrote.
And the reviewer is a router: what it carries is the decision of which criteria apply to what it received. The criteria themselves live in modular skills: plan-review judges the approach before any code; general-code-review covers the generic part that applies in any project, correctness, simplicity, test quality, type design; constitution-compliance-review comes in when the diff touches domain rules, calculations, sensitive values or the audit trail, and checks against the constitution; conformance-review comes in when the diff implements a spec or an approved plan, and checks both conformances, the code does what the spec requires, value by value, and does what the plan promised, intent versus implementation. Adding a new dimension, security, for example, is a new SKILL.md and one routing line. Nothing else changes.
This separation between generic and contextual criteria also defines the place of the external reviewer, the LLM code review SaaS: it complements the generic side with a model of different architecture, which catches a set of bugs reasonably disjoint from what your reviewer catches, but it enters as advisory, never as a gate. Median precision in an autonomous gate means a loop aborted on a false positive. What blocks is deterministic, tests, lint, type check, plus the contextual reviewer that knows your constitution; the rest comments for the human who decides the merge.

The implementation flow: human gates on the load-bearing decisions, deterministic verification on every chunk, and an independent reviewer that routes modular criteria and never writes.
The last phase closes the loop, and it’s the most neglected: the lesson learned becomes a line in lessons or a versioned rule, the spec updates if a rule changed, with the human approval flag, and everything in the same PR. Updating context “later” is never updating.
Autonomy is a gradient, not a switch
The question I get most about this system is when to let the agent run alone. The answer has three parts: a division of labor, a narrow start and a rule for widening.
The division: architecture work never enters the autonomous lane. New capability, new sub-area, contract reorganization, all of that is business decision in code form, and it stays human-led: you create the spec, drive the implementation through the previous section’s flow, review the PR. There is no milestone where this changes. What enters the lane is increment: bugfix, tech debt, a feature inside an existing capability, an isolated adjustment with a cited source. Increments enter through the backlog, GitHub Issues with capability, type and priority labels, a weekly half-hour triage and a hard limit of three issues in priority:now. Minimal cadence, but non-negotiable: when triage dies, the rest becomes theater.
The start is deliberately narrow, because autonomy is a gradient. The narrow start turns on early: the routine only picks issues from a hard-coded allowlist of trivial classes, well-specified bugfix, small tech debt, adjustment with an already-cited source, with permitted paths enforced in the harness, something a prompt never guarantees; green CI is mandatory before any review; and a human approves every PR. The human here is the last line of defense; before them, the suite accumulated from every previous feature, each test anchored on its spec’s acceptance criteria, is the mechanical net that catches regressions outside the diff, exactly what a human looking at the diff can’t see. And this start doesn’t require a formal eval suite: allowlist plus a human on every PR keeps the risk proportional to the protection.
The engine of the lane is Claude Code’s native /goal, and using the native mechanism instead of packing a loop into a skill is a deliberate choice. /goal is a session Stop hook: at the end of each turn, a fresh model, one that didn’t do the work, re-checks the done condition and forces another turn if it doesn’t hold. That’s enforcement. A skill is instruction, and instruction the agent can ignore precisely on the turn where it matters most. It’s the reviewer principle showing up again, whoever declares done is never whoever did the work, and it’s worth so much that, even in local mode, with the human gates intact, the invocation I use is the skill wrapped in a supervised /goal: questions still pause the turn for me to answer, but the worker loses the power to declare itself finished. Only the small increment skips the loop, when the overhead outweighs what it protects.
In headless mode, one property governs the whole design: a question to the user doesn’t hold a run that has no user, because there’s nobody to answer and the evaluator only reads the transcript; an interactive gate would be silently run over instead of blocking. That’s why the autonomous skill never asks: every question that would exist becomes an abort with a named blocker, and human judgment moves to the edges, the issue’s acceptance criteria before the run, the PR review after. And the condition is everything, because the evaluator decides only on what’s visible in the conversation, so it demands concrete evidence:
/goal Implement issue #142 following the implement-backlog skill end to end.
DONE only when, all of it visible in the conversation: every acceptance
criterion verified by a passing test, with the runner's real output in the
conversation, not by claim; full suite green, with tests anchored on the
spec's acceptance criteria; lint and coverage at threshold; the reviewer ran
on the final diff with no [BLOCKER]; PR open with CI green all the way.
OR DONE WITH A NAMED BLOCKER when the skill aborts, comments on the issue and
applies the label: ambiguity β needs-refinement; scope expansion β
scope-expansion-needed; same failure 3+ times β qa-blocked.
Constraints: no silent scope expansion; a spec update marks the PR as
requires_human_approval; never declare done with a red check. Max 40 turns.
Notice two details, because the philosophy lives in them. First, abort is a legitimate final state of the condition: without the named-blocker clause, the evaluator would force turn after turn against an ambiguous issue. Ambiguity comments on the issue with the possible interpretations and leaves with a label; scope that grew, comment and leave; the same failure three times, leave. Aborting early is cheaper than a whole PR built on the wrong interpretation. Second, opening a PR is not done. The agent monitors until the PR is merged clean: CI to the end, a late review comment, a merge conflict.
Widening is another story. More classes, more volume, any step toward auto-merge: that does require a four-milestone trajectory with explicit exit criteria, which I keep in a playbook separate from the guideline, to be read when it’s time to widen and not before. Milestone 1 builds the measuring net: a regression suite from real closed issues, and twenty tasks beat zero waiting for the perfect suite, measured with the right metric, which is pass^k, not pass@k. pass@k measures whether the agent gets it right in at least one of k attempts; pass^k measures whether it gets all k right. For a demo, the first will do; for an agent opening PRs unsupervised, consistency matters more than capability. And the measurement has two axes, the final output and the run’s trajectory: a fluent output that skipped its verification steps is a more dangerous failure than one with a visible error. Milestone 2 puts Tier 1 into CI, coverage per capability, cyclomatic complexity, mutation testing, plus the domain checks, and only then do the allowlist classes widen. Milestone 3 adds dynamic post-deploy validation in an integration environment: QA, E2E and contract agents exercising the real application, beyond the diff. And milestone 4 is conditional auto-merge per class, with track record: the class “parameter adjustment with cited normative source” accumulated thirty consecutive autonomous PRs without a human rejection, everything green? It qualifies for auto-merge. A change to a critical calculation or to the audit trail? Human forever. The agent can probably do it; the cost of the error is what rules out the delegation. Widening without this ladder is faith, and faith is not an engineering criterion.
And one boundary is permanent beyond architecture: normative calculation. A change touching a calculation with a normative source only enters the lane, at any width of autonomy, with golden verification in front, a reference dataset with inputs and expected outputs, because a human PR reviewer doesn’t recalculate values against the norm. Without the golden set, nobody is actually verifying, and approval becomes liturgy.
Aviation treats certification exactly this way: a pilot isn’t cleared “to fly”, they’re rated by aircraft type, with an audited history and periodic revalidation. Agent autonomy with the same design: per change class, with verifiable track record, reviewed quarterly. What I see the market do, turning on global autonomous mode on day one because the demo looked good, is handing an A350 type rating to someone who has taxied a Cessna.

Autonomy as a gradient: the narrow start turns on early, with a narrow allowlist, mandatory green CI and a human on every PR; widening requires the regression suite and the four milestones. Architecture never enters, and normative calculation waits for the golden-test net.
Why it’s designed this way: the method behind the guideline
Beyond what the system is, how it got here matters, because the method is replicable even if your final guideline turns out different.
Mine ideas, don’t adopt packages. The reviewer architecture with modular criteria came from Lucas Costa’s repository; the criteria themselves I rewrote entirely for my domain, because his don’t know what a normative source is. From AWS’s AI-DLC methodology I took the skeleton, plan, clarify, human validates, implement, which is the sequence of my phases, and discarded the ceremony, because there every no is a human in a synchronous mob, the human-as-limit anti-pattern institutionalized. Ceremony without mechanism. The difference between installing a solution and understanding why it works is the difference between dependency and design, the same first principles argument I’ve made here before: copying a pattern without understanding the problem it solves carries the cost with no guarantee of the benefit.
Verify at the primary source. A popular “Claude Code patterns” article invented two commands that exist nowhere. Another presented a community prompt trick as if it were supported tool syntax. A third cited productivity gains impossible to trace. A listicle is a lead: the reference is the doc, the repo, the primary blog it points to. Half of what circulates about AI tooling doesn’t survive five minutes of verification, and the half that survives usually arrives with inflated numbers.
Convergence is the signal. An engineer writing about backpressure, AWS formalizing a lifecycle for enterprise customers, Addy Osmani naming intent debt, Anthropic publishing their own harness architecture, and Google, in a 50-page whitepaper co-authored by that same Osmani, drawing the spectrum from vibe coding to agentic engineering, where what separates the two ends is exactly how the output gets verified. Independent sources, not citing each other, arriving at the same shape: intent externalized in versioned artifacts, machine gates before human review, humans on the load-bearing decisions. Independent convergence on the design you built is the strongest evidence available before running in production. It’s not proof; it’s the best signal there is.
Determinism first is what shows up in whoever operates at scale. Stripe published the minions case, their internal coding agents: over 1,300 merged PRs per week without a line written by a human. Reviewed by humans, that yes, and that is this thesis’s division at scale: generation left human hands, the merge decision stays in them. The interesting part is where the reliability lives: before the agent wakes up, the pipeline runs deterministic tooling to assemble the context, pulls the ticket, internal documentation, build status, locates the relevant code via Sourcegraph, and the loop itself interleaves deterministic steps for git, linter and tests. Nothing that deterministic logic can solve reaches the model, and where you draw that line is what decides whether the loop is reliable. In my domain the line is even sharper: which norm applies, which contract holds, which slice of the spec matters are rules, so they’re injected deterministically instead of letting the model search and confidently cite the wrong norm. In the same direction, the Bun runtime port from Zig to Rust with agents, 750 thousand lines with 99.8% of the suite passing in 11 days, and still out of production, proves the general principle: scale tooling amplifies exactly what the verification harness allows. Bun’s suite was the executable spec; without it, the same 750 thousand lines would be slop at industrial volume. And 0.2% error there is 1,500 wrong lines, acceptable for a runtime preview, unacceptable for calculations with legal consequences. The acceptance bar belongs to the domain, never to the tool.
And I owe honesty about the current weakness: the ratio between written process and executed process is still too high in my system. The next lesson won’t come from another mined article, it will come from real issues crossing the lane. I write this as a reminder to myself and a warning to you: a guideline is validated by running it.
The honest cost and when not to use it
A harness is expensive, and pretending otherwise is intellectual dishonesty. The numbers Anthropic published from their experiment: the task the model solves alone for about 9 dollars in 20 minutes came out at about 200 dollars in 6 hours with the full harness, and the second version brought it down to about 124 dollars in 4 hours. An order of magnitude more, in money and in time. The harness pays when the task exceeds what the model delivers alone reliably, and only then. For a small, well-bounded task, vanilla Claude Code beats an elaborate workflow in almost every scenario. Before asking whether the process is complete, ask whether this task’s cost of error justifies this gate’s overhead.
Second cost: harnesses rot. Every component, every gate, every rule codifies an assumption about what the model can’t do alone, and those assumptions expire with every model release. Anthropic themselves describe tearing down pieces of their harness as models improved: the context resets Sonnet 4.5 required, Opus 4.5 made unnecessary; the decomposition of work into sprints fell in the following generation. What was load-bearing became dead weight without warning. The practice I adopted: with every new model, re-audit the harness by ablation, turning off one component at a time, and cut what’s no longer necessary. Today’s harness is tomorrow’s overhead, and a harness that only grows becomes bureaucracy with YAML syntax.
And the final failure mode isn’t technical: it’s the system becoming a museum. If the weekly triage dies, if the specs stop reflecting the code, if the regression suite doesn’t run, the guideline becomes a beautiful document describing a process that doesn’t exist. Against that, quarterly yes-or-no checks: am I still doing triage? Are the context files still small and current? Do the specs reflect the code? Does the suite run? A no is a bug, and it gets treated as one. And if in six months the system became a museum of good intentions, burn it and restart with a third of the content. The guideline exists to serve you, and changing a rule in the open is part of the game; what kills is its silent erosion.
Finally, when not to use it: a weekend prototype, a disposable project, exploration where the cost of error is zero. There, vibe coding is honest and efficient, and setting up a constitution for it is ceremony without purpose. This system is for software that will live, receive maintenance and cost real money when it fails. The bar, again, is cost of error times frequency of change, and it decides even how much of the system is worth adopting.
Wrapping up
The guideline fits in four moves. The business decision comes before the code, written as a spec per capability that keeps anchoring tests, review and conformance from then on, with light boundaries and tactical detail emerging with the implementation. Context lives in three layers, with intent externalized where the agent reads it and discipline so it doesn’t rot. The machine gives the first no: deterministic verification on every chunk, an independent reviewer that never writes, a hook where instruction isn’t enough. And autonomy is a gradient: it starts narrow, with a human on every PR, and widens per change class with evals and track record, without ever touching a global switch. Evidence before “done”, at every level.
The concrete next step, and I recommend it be this week: pick the capability you’ll touch next sprint and write its spec, half a page with rules, edge cases and non-goals. Take the correction you most repeat to your agent and turn it into a versioned rule; if violating it is expensive, promote it to a hook. And run one real issue through the full flow, plan with a gate, implementation with tests on every chunk, independent review, before adding any more pieces. The whole system was born this way, one piece at a time, each when the pain justified it. And when the next article presents you a practice or a tool, this one included, verify at the primary source before adopting. If you take a single thing from here, let it be that. The sources are right below.
References
- Raphael Moura β spec-anchored-agentic-development, this article’s full guideline and the installable bundle (skills, reviewer, commands, hooks, spec template)
- Lucas F. Costa β Backpressure is All You Need and the backpressured repository
- Addy Osmani β The Intent Debt
- Anthropic Engineering β Harness design for long-running application development
- Anthropic Engineering β Demystifying evals for AI agents
- Anthropic β Steering Claude Code: skills, hooks, rules, subagents, and more
- Anthropic β Introducing dynamic workflows in Claude Code (the Bun port case)
- Claude Code Docs β /goal
- Stripe Engineering β Minions: Stripe’s one-shot, end-to-end coding agents
- AWS DevOps Blog β AI-Driven Development Life Cycle
- Robert C. Martin β Screaming Architecture
- arXiv β Spec-Driven Development: From Code to Contract in the Age of AI Coding Assistants
- Birgitta BΓΆckeler (martinfowler.com) β Understanding Spec-Driven Development: Kiro, spec-kit, and Tessl
- Google β The New SDLC With Vibe Coding
Changelog
- 2026-07-08 β The repository evolved and the article followed. The spec interview became
/shape, five modes in one machine (idea, transcript, brownfield, spec refinement, task sharpening), always one question at a time with a recommended answer; and it gained a sibling,/spec-to-tickets, which breaks the spec into vertical tracer-bullet tickets anchored on the numbered acceptance criteria, with explicit blocking edges between them. Type check joined lint and tests in the per-chunk loop. And a review finding now closes with a regression test that failed before the fix and passes after it, whenever the finding is test-shaped. - 2026-07-02 β Published.
