I want to share a piece of engineering I did recently that changed how I think about working with AI coding agents. It started from a naive question I asked out loud: "can I make Sonnet and Opus behave like the frontier model?" It ended somewhere more useful than the question deserved.
The short version: you cannot make a smaller model as capable as a larger one. That's weights, and no prompt moves weights. But capability is not the only thing that separates a good agent turn from a mediocre one. The other half is doctrine: how the agent communicates, when it stops, how it proves its work, how deeply it analyses before deciding. And doctrine is completely portable. You can write it down once, apply it as a system-prompt layer, and every model tier, the expensive one and the cheap one alike, starts operating to the same contract.
This post is the thesis and the blueprint. Everything here is adaptable to your own stack; I'll point out where the reusable pattern lives versus where my specifics are just illustration.
The problem, stated honestly #
I run a fairly heavy codebase: a blockchain-based financial protocol, twenty-plus backend microservices, several Next.js frontends, smart contracts, and a Kubernetes cluster. I drive most of the work through Claude Code with a fleet of specialised sub-agents. On any given day, an architecture agent runs on the most capable model, an implementation agent runs on a mid-tier model, and a fast research agent runs on a small one. Three different intelligences, one codebase, one set of standards.
The friction was never that the cheap model was dumb. It was that the cheap model behaved differently. It would declare a task "done" without running the test. It would open its final message with a wall of implementation detail instead of the answer. It would make a change from a single grep instead of tracing the blast radius. It would stop mid-task and ask a question it could have resolved itself. The expensive model did these things right by default; the cheaper one needed to be told.
For a long time I treated that as an unavoidable tax of using cheaper models. That was the wrong frame. The behaviours I wanted were not intelligence. They were conduct. And conduct can be specified.
The core idea: doctrine is not capability #
This distinction is the whole thesis, so let me be precise about it.
Capability is what the model can figure out: the hard reasoning, the novel synthesis, the ability to hold a large problem in mind. It lives in the weights. A prompt cannot add it. Anyone selling you a "system prompt that makes GPT-3.5 as smart as GPT-5" is selling you nothing.
Doctrine is how the model conducts itself around whatever capability it has: the communication contract, the bar for calling something done, the discipline of tracing a change end-to-end before committing to it, the rule about not stopping while there's still work you can do. None of that is intelligence. All of it is specifiable in text. And critically, when a capable model already does these things, it's because it was trained toward them, which means the same behaviours can be instructed into a less capable model, closing most of the visible quality gap even though the underlying intelligence gap remains.
So the goal was never "make the small model smart." It was: make every model, whatever its tier, honour one operating contract. A mid-tier turn that leads with the outcome, backs every completion claim with evidence, traces before it decides, and doesn't stop early is, by every externally observable measure, a frontier-standard turn. You reach for the genuinely bigger model when the task's correctness ceiling demands the extra capability, not for basic professional conduct, which you can standardise.
Writing the standard down #
The artifact at the centre of all this is a single document I call the Operating Standard. It's about a dozen sections, and it encodes the contract as enforceable behaviour rather than vibes. The load-bearing pillars:
Lead with the outcome. The final message is the reader's first look at the work: it opens with the answer, then supports it. Readability beats brevity: you shorten by cutting detail that doesn't change the reader's next move, never by compressing into fragments and arrow-chains. Everything the reader needs lives in that last message.
Prove completion with artifacts. No "should work," no "looks good." Every
done / fixed / passingclaim carries a commit hash, verbatim test output, an exit code, or a file listing. The orchestrator re-runs the acceptance command itself before it trusts a completion claim. It does not take the agent's word.
Decide depth-first, never from a hunch. Trace a cross-cutting change through every layer it touches before deciding: schema, data access, domain, application, API contract, every frontend, the async pipeline, the chain, the migration, the tests. A green type-check proves nothing about runtime or contract ripples.
Do not stop early. For reversible actions that follow from the request, proceed. Before ending a turn, re-read the last paragraph: if it's a plan, a question, or an "I'll do X next" promise, do that work
now. Stop only when the task is complete or genuinely blocked on the user.
Do the simplest thing that works well. No unrequested features, refactors, or abstractions; no defensive validation for impossible states, while still failing
closedwith typed errors on the paths that matter, like money and user-facing displays.
Disclose every honest finding, uncapped. Never trim the long tail of caveats to look tidy. A report that always surfaces "about two" findings is under-disclosing by construction.
Here's the part I want to stress for anyone adapting this: I did not invent these snippets from taste. The behavioural nudges, the exact wording that pulls a model toward this conduct, are drawn from the model vendor's own published migration and prompting guidance. The frontier model exhibits these behaviours by default; the vendor documents the precise phrasing that instils them in models that don't. I lifted that phrasing and organised it into a contract. That grounding is why it actually works rather than just reading well. When you build your own, source your snippets from your provider's guidance, not from a blog post's opinion (including this one).
Two channels, so it can't be skipped #
A standard nobody loads is decoration. I apply mine two ways so it's present whether or not someone remembers to opt in:
At launch, as an appended system-prompt file. A thin wrapper script starts the agent with the full doctrine already in the system prompt, inherited by every sub-agent it forks.
In-session, as an always-loaded rule. The harness auto-loads a small rule file every session that carries the non-negotiable core inline and points to the full doctrine. So even a session started the plain way still runs to the contract.
The small in-session rule is deliberately tiny: the full doctrine lives in the launch layer, which sits outside the always-loaded context budget. That keeps the permanent cost low while still guaranteeing the core is present.
The lesson that humbled me: verify the harness actually loads #
Here is the finding I'm most glad I caught, because it's the kind of thing that quietly makes a whole system a placebo.
I had twenty beautifully written sub-agent role definitions. They'd existed for months. They were referenced in my config. I believed they were being dispatched. When I actually inspected the running agent's list of available sub-agent types, none of them were there. The runtime showed only the built-in generic agents.
The role files were using a bespoke metadata format the agent framework never parsed as agent definitions. They were, functionally, documentation. My orchestration had been quietly falling back to generic agents the whole time and compensating by pasting role context into prompts. It worked well enough that I never noticed the declared specialists weren't real.
The fix was mechanical: normalise every role file to the framework's actual native format, valid frontmatter with a name, a description, a tool allow-list, and a model tier, so the framework discovers each one as a first-class dispatchable agent. I wrote a deterministic script to do it uniformly across all twenty, validated that every file parsed, and confirmed against the runtime that the agents now appear.
The transferable lesson is bigger than the bug: the ground truth of a harness is what the runtime actually loads, not what your config claims. A declared agent, a wired hook, a scoped rule: none of it is real until you've watched the runtime confirm it. Treat "it's in the config" as a hypothesis, and the runtime's own report of what it loaded as the only evidence that closes it. I now verify discovery the same way I verify a passing test: by looking at the output, not the intention.
Safe enforcement: a completion gate that can't wedge your session #
Doctrine in the prompt is guidance. Sometimes you want a mechanism. The strongest one I built is a completion gate: a hook that fires when the agent tries to finish and forces it to re-check its "done" claims against real evidence before the turn actually ends.
Hooks that can block completion are genuinely dangerous to write, because the naive version creates an infinite loop: the hook blocks the stop, the model continues, tries to stop again, the hook blocks again, forever. A badly built gate doesn't annoy you. It wedges the session. So the engineering here is almost entirely about safety, and the three invariants are worth stealing directly:
Inert by default. The gate does nothing unless an environment flag turns it on. It ships wired but off, so it can never surprise an existing workflow. You enable it for the long autonomous runs where premature-completion is the real risk.
Loop-safe. The framework tells a stop-hook whether it
already fired this turn. The gate reads that flag and refuses to block a second time. It intervenes at most once, then lets the turn end. This single check is the difference between a useful gate and an infinite loop.
Fail-open. Any exception, any malformed input, any surprise: the gate exits cleanly and lets the stop proceed. A bug in the gate degrades to a no-op, never to a stuck session. On a tool that sits in the critical path of
everyturn, fail-open is not optional.
I tested all three properties from the shell before wiring it in: inert when the flag is unset, blocks exactly once when enabled, never re-blocks under the already-fired flag, exits clean on garbage input. A safety mechanism you haven't adversarially tested is a liability, not a safeguard.
Tiered configuration: global doctrine, local specialists #
Once the standard worked in one project, the obvious question was: does it apply everywhere I work, or just here? Getting the scoping right turned out to be a real architectural decision, not a detail.
Agent frameworks typically have (at least) two configuration tiers: a project tier that loads only when you're working inside that project, and a user tier that loads in every session, everywhere. The mistake would be to shove everything into one. The right move is to split by reach:
The doctrine is universal, so it belongs in the user tier. The Operating Standard applies to any codebase; conduct is not project-specific. I placed it at the user level so every session on the machine, in any directory, runs to the contract. I kept a single source of truth by linking the global copy back to the versioned one in my main repo, so it can never drift.
The specialist agents are domain-specific, so they stay in the project tier. My twenty agents know about
thisprotocol's services, its chain, its namespaces. Making them global would surface protocol-specific agents inside unrelated projects, where they're noise at best and actively wrong at worst.
That split, global conduct, local expertise, is the reusable principle. Standardise the behaviour everywhere; scope the knowledge to where it's true.
Verifying the work with the work #
The last piece is almost recursive, and it's my favourite. Before I trusted any of this, I had the agent system review its own harness, a small multi-agent verification pass with independent reviewers, each pointed at a different risk surface: one adversarially probing the completion gate for loop and failure paths, one fact-checking the standard for any dishonest or self-contradictory claim, one auditing my own findings report against the actual files to catch me overstating.
It earned its keep. It confirmed the gate was safe and the report accurate, and it caught one real internal contradiction in the standard, where a preamble claimed the frontier model never needs a certain nudge while the document's own labels said otherwise. A genuine defect, low-severity, exactly the kind of thing that erodes trust in a document loaded into every session. I fixed it. A second proposed issue was independently checked and correctly rejected as a misread, which is just as important: an honest verifier that never rejects anything is a rubber stamp.
The discipline underneath is one I hold for all agent work: surface every honest finding, uncapped, and never let the summariser trim the long tail to look finished. When I closed out the harness, I published the residual work too: one agent's documentation still needs a deeper rewrite I chose not to fake. Disclosing a known gap is cheaper than having the next person discover it in production.
What you can take from this #
If you're building your own agent harness, here's the distilled, adaptable version: Separate capability from conduct. Stop trying to make cheap models smart. Make every model, cheap or not, follow one written contract for how it communicates, completes, and analyses. That closes most of the visible quality gap for free.
Write the standard down, and source its wording from your provider's own guidance rather than taste. Ground beats opinion.
Apply it on two channels: a launch-time system-prompt layer and an always-loaded in-session rule, so it's present whether or not someone opts in.
Trust the runtime, not the config. Verify your declared agents, hooks, and rules actually load. "It's configured" is a hypothesis; the runtime's report is the proof.
If you build enforcement hooks, engineer them for safety first: inert by default, loop-safe against re-firing, fail-open on any error. Adversarially test those properties before wiring them in.
Scope by reach: universal conduct at the user tier, domain expertise at the project tier. Global doctrine, local specialists.
Verify the harness with the harness, disclose every honest finding uncapped, and publish the residuals you chose not to fix.
The honest boundary #
I'll end where I began, because it's the part people most want to over-claim. This does not make a smaller model as capable as a frontier one. It does not transfer intelligence, and it does not, cannot, reproduce or strip any of a model's safety behaviour, which is set at the model level and is not something a prompt should touch. What it does is raise the floor: it makes every tier conduct itself professionally, prove its work, and communicate like it respects your time. The ceiling is still the model's; you reach for the bigger one when the problem genuinely needs more thinking. But an enormous amount of the day-to-day frustration with cheaper agents was never about thinking. It was about conduct, and conduct, it turns out, is just engineering.
If any of this is useful in your own setup, take it and adapt it. That's the whole point of writing it down.