Skip to content
best-practices tools productivity

Context Engineering for Cleaner Code

The biggest lever for AI code quality isn't a smarter model — it's better context and guardrails. Here's the modern toolkit that turns a generator into a collaborator.

Pierre Sauvignon
Pierre Sauvignon 14 min read
An abstract editorial illustration of structured channels guiding a stream of light into ordered lines

The instinct, when AI-generated code disappoints, is to reach for a bigger model. The output was sloppy, so you want a smarter writer. But most of the quality problems teams hit with AI coding tools are not intelligence problems. They are context problems. The model wrote something plausible because you gave it a plausible-sounding request and a vague picture of your codebase, and it filled the gaps with the average of everything it has ever seen.

That average is not your house style. It is not your error-handling convention, your test framework, your naming scheme, or the three internal libraries you already use instead of pulling a new dependency. The model cannot know any of that unless you tell it. And the way you tell it — what you put in the window, what rules you set, what checks you run on the way out — is now the single most controllable lever you have over the quality of what comes back.

This is the discipline that has come to be called context engineering, and it has quietly become more important than prompt phrasing. A clever prompt is a one-time trick. A well-engineered context is a system that produces good output repeatedly, across teammates, across sessions, across tools. This post is a tour of that system: the rules files, the reusable skills, the automated taste of linters and type checkers, the CI gates, and the art of feeding the right files instead of the whole repo. None of it requires a better model. All of it makes whatever model you use behave like a disciplined collaborator instead of an unconstrained generator.

Why context, not cleverness, is the lever

Start with a finding that should change how you think about long context windows. In Lost in the Middle, Liu and colleagues showed that language models do not use long inputs uniformly. Performance is highest when relevant information sits at the very beginning or the very end of the context, and it degrades — sometimes sharply — when the model has to retrieve something buried in the middle, even for models explicitly built for long contexts. The takeaway is uncomfortable for anyone who reasons “I have a 200K window, so I’ll just paste the whole repo.” More tokens are not more understanding. A model can have your answer in its context and still miss it because of where it sits.

So the goal is not maximal context. It is curated context: the right files, the right rules, the right examples, placed where the model will actually weight them. The emerging consensus is to treat this as engineering rather than art. As Phil Schmid puts it, context engineering is “the discipline of designing and building dynamic systems that provide the right information and tools, in the right format, at the right time.” Or, in the blunter framing that has spread through the field: most agent failures are not model failures, they are context failures.

There is independent evidence that the failure mode is real and expensive. GitClear’s 2025 analysis of 211 million changed lines of code found that as AI assistance spread, code clones grew roughly fourfold, while the share of changed lines associated with refactoring fell from around 25% in 2021 to under 10% in 2024 — and, for the first time GitClear has measured, copy-pasted lines overtook moved (refactored) lines. AI is very good at generating valid code. It is much worse, left to its own devices, at reusing and adapting the code you already have. That is precisely the gap context engineering closes: tell the model what already exists, and it stops reinventing it badly.

The rules file: your conventions, written down once

The first and highest-leverage move is to write down what you would otherwise re-explain every session. Every major AI coding tool now reads a project-level instructions file at the start of a session and injects it into the model’s context before it sees your first message.

The conventions have converged enough to be worth learning even-handedly. Anthropic’s Claude Code reads CLAUDE.md files as persistent project memory — build commands, layout, conventions, “always do X” rules. Cursor stores project rules in .cursor/rules as version-controlled .mdc files with frontmatter that controls when each rule applies: always, applied intelligently based on a description, scoped to file globs, or invoked manually. And a cross-tool standard has emerged in AGENTS.md, described as “a README for agents” — a tool-agnostic, plain-markdown file now used by tens of thousands of open-source projects and supported across a wide range of agents. It is stewarded by the Agentic AI Foundation under the Linux Foundation, with the major coding-tool vendors participating, which is about as close to neutral ground as this space gets.

Whichever file your tools read, the content discipline is the same. Keep it to facts the model should hold in every session, not a novel:

  • Build, test, and run commands. The exact incantations, so the agent verifies its own work instead of guessing.
  • Conventions that are not obvious from the code. “We use our internal Result type, not exceptions, for expected failures.” “Dates are always UTC at the boundary.” “Never add a dependency without flagging it.”
  • Project layout. Where things live, so the model edits the right file instead of creating a near-duplicate.
  • The anti-patterns you keep correcting. If you have told the AI three times not to do something, that correction belongs in the file, not in your short-term memory.

A good rules file is the cheapest quality intervention available, because it converts a recurring conversation into a one-time write. It is also where the GitClear duplication problem gets solved in practice: a rules file that points to existing utilities and says “use these” reorients the model from generation toward reuse. For more on encoding repeatable habits into the workflow itself, see our piece on AI coding workflow patterns.

There is a portability angle worth naming, because it tends to get lost in vendor-versus-vendor arguments. The conventions differ in their syntax, but they agree on the substance: a plain-text file, committed to the repository, that the agent reads before it acts. That overlap is the reason a team should not over-index on any single tool’s format. Most of the value lives in the content — the conventions, the commands, the anti-patterns — not in whether the file is named one thing or another or carries a particular frontmatter block. Write the substance well and you can migrate it to whatever your team standardizes on next with a few minutes of reformatting. Write it badly and no format will save you. The AGENTS.md effort is interesting precisely because it tries to make the substance the standard and the tooling interchangeable, which is the right pressure for an ecosystem this young.

Keep it small, keep it near the top

Because of the lost-in-the-middle effect, a bloated rules file can be worse than a short one — the model may simply not weight the rule that mattered. Treat the file like a tightly edited style guide, not a wiki. When a rule stops being load-bearing, delete it. When a section grows, split it into a scoped rule that only loads for the relevant files. The point is not to document everything; it is to keep the few rules that change behavior where the model will actually read them.

Reusable skills and prompt libraries: stop retyping the playbook

Rules files capture what is always true about a project. The next layer captures what you do repeatedly but not always — the multi-step procedures you would otherwise paste in by hand. The tooling here goes by different names across vendors (skills, custom commands, saved prompts, slash commands), but the shape is the same: a named, reusable unit of instruction that you invoke on demand.

Think about the tasks your team does the same way every time. Cutting a release. Writing a migration. Adding an endpoint with the standard auth, logging, and test scaffolding. Doing a security pass on a diff. Each of these is a playbook that lives in someone’s head and gets re-explained — badly, with variations — every time a new person or a new session runs it. Encoding it as a reusable skill does three things at once: it makes the procedure consistent across the team, it removes the per-invocation cost of explaining it, and it makes the procedure reviewable. A skill in version control can be improved by a pull request like any other artifact.

The discipline of building a prompt or skill library mirrors the discipline of building any shared library: name things well, keep each unit focused, and resist the urge to make one mega-skill that does everything. The same lost-in-the-middle physics applies. A focused skill that does one thing with a tight set of instructions will outperform a sprawling one that tries to encode your entire engineering org. If you are formalizing the human side of this — the prompting craft itself — our guide to AI pair programming covers how to work with the model rather than just at it.

See how developers track their AI coding

Explore LobsterOne

Linters, formatters, and type checkers: automated taste

Here is the part teams under-invest in, and it is the part that scales best. A rules file tells the model your conventions. A linter, formatter, and type checker enforce them — deterministically, for free, on every file, whether the code was written by a human or a machine.

This matters more in the AI era, not less. When a person writes code slowly, a certain amount of taste is applied in the act of writing. When a model generates a hundred lines in two seconds, that human filter is gone. The automated filter has to take its place. A formatter eliminates an entire category of stylistic disagreement by making it non-negotiable. A linter catches the unused variable, the shadowed name, the missing await, the subtly wrong equality check. A type checker catches the contract violation the model confidently introduced because it guessed at a function signature it never actually read.

There is a second, less obvious benefit: these tools produce feedback the model can act on. Run the type checker, hand the errors back to the agent, and it fixes them — often without further instruction. The toolchain becomes a tight correction loop. You are not just catching the model’s mistakes; you are giving it the signal it needs to correct itself. This is the cheapest path away from the kind of accumulating mess we describe in how to prevent AI coding doom loops: when the feedback is automated and immediate, the model converges instead of thrashing.

The configuration belongs in the repo, and the rules file should point at it. “Run lint and typecheck before you consider a task done” is one line that turns your existing toolchain into a guardrail the agent respects every time.

It is worth being precise about what each tool buys you, because teams often run one and assume they are covered. A formatter is purely cosmetic and entirely non-negotiable — it removes debate, not bugs. A linter encodes opinions and catches a class of likely mistakes, but it reasons about one file at a time and cannot see your types. A type checker is the one that catches the interface lies: the model called a function with the wrong shape, returned the wrong thing, or assumed a field that does not exist. For AI-generated code, the type checker is frequently the highest-yield of the three, because the most common failure of a confident generator is not ugly code — it is code that is plausibly wrong at the boundaries. Running all three is not redundancy; each covers a gap the others leave open.

CI quality gates: the line nothing crosses unchecked

Local checks are advisory. The model can skip them, a teammate can forget them, a rushed session can bypass them. The quality gate that cannot be skipped lives in continuous integration, and it is the backstop that makes everything upstream safe to move fast against.

This is well-trodden ground in delivery research, and the conclusions hold regardless of who or what wrote the code. DORA’s work on continuous delivery finds that testing throughout the lifecycle — rather than as a separate phase after “dev complete” — improves software delivery performance and leads to higher quality, measured by the share of time teams spend on rework. High performers, DORA notes, get feedback from their tests in under ten minutes. The mechanism is the same one the linter provides locally, scaled to the whole team and made mandatory: fast, automated signal that catches problems before they compound.

DORA is careful about a trap worth repeating, because it applies directly to AI-assisted work. Modern tooling without the underlying practices “won’t produce the expected benefits.” A pipeline of gates is not a substitute for tests that actually exercise the code, small batch sizes, and a culture that treats a red build as a stop-the-line event. And there is a pointed recent finding in the same body of research: AI adoption can put downward pressure on delivery stability and throughput unless the fundamentals — small batches, robust testing — hold. The gate is what holds them.

For AI-generated code specifically, the gate earns its keep against exactly the failure mode GitClear measured. A duplication check flags the copy-pasted block. A coverage gate refuses the feature that shipped without a test. A type check in CI catches the contract the model violated. None of these care whether a human or a model wrote the line — and that neutrality is the point. We go deeper on designing these gates for an AI-heavy workflow in building an AI code quality gate into CI/CD.

Curated context: feed the right files, not the whole repo

The last piece closes the loop back to where we started. Once you accept that more tokens are not more understanding, the question becomes: what should be in the window for this task?

The honest answer is that it is a skill, and it is the skill that separates teams who get clean output from teams who get confident slop. Pasting the whole repository feels thorough and performs poorly, both because of the lost-in-the-middle degradation and because irrelevant context actively distracts the model from the files that matter. The better instinct is curation: the two or three files the change touches, the interface it must conform to, one representative example of the pattern you want followed, and the rules file. That is usually enough, and it is usually better than ten times the volume.

Curation is also where retrieval and tooling do real work. Letting the agent search the codebase and pull in what it needs — rather than front-loading everything — keeps the window relevant and lets it grow only as the task demands. The skill on the human side is knowing what to point at: the canonical example to imitate, the test that defines the contract, the one adjacent module whose conventions this change must match. Get that selection right and a mid-tier model produces clean, consistent code. Get it wrong and the best model on the market produces something that compiles, passes a glance, and quietly ignores everything your team has decided matters.

This is, ultimately, why context engineering is a discipline and not a setting. It rewards the same judgment good engineering always has: knowing what is relevant, stating it precisely, and verifying the result. None of it is locked to a vendor. A rules file, a skill library, a linter, a CI gate, and a habit of curating context all travel with you across whatever tools your team adopts next — which is exactly how it should be, because the tools will keep changing and the discipline will not.

The Takeaway

The teams getting clean, maintainable code out of AI tools are rarely the ones with privileged access to a better model. They are the ones who stopped treating the model as a mind to be impressed and started treating it as a powerful generator to be constrained. They wrote their conventions down once in a rules file. They encoded their playbooks as reusable skills. They let linters and type checkers apply taste deterministically. They put a quality gate in CI that nothing crosses unchecked. And they learned to feed the right files instead of the whole repo, because the research is clear that volume is not comprehension.

Every one of those moves is available to you today, with the tools you already have, at no model upgrade required. That is the good news hiding inside the Lost in the Middle result and the GitClear churn numbers alike: the lever you control most is the one that matters most. Stop optimizing the prompt and start engineering the context. The output will look like your team wrote it — because, in the way that counts, your team did.

Pierre Sauvignon

Pierre Sauvignon

Founder

Founder of LobsterOne. Building tools that make AI-assisted development visible, measurable, and fun.

Related Articles