Closing the Convention Gap: Structured Context Files as AI Coding Infrastructure
Source: martinfowler
Knowledge priming, as described in Rahul Garg’s article on Martin Fowler’s site from February 2026, is the first of five patterns Garg identified for reducing friction with AI coding assistants. The pattern itself is simple: provide the LLM with structured, upfront context about the project’s conventions, stack, and constraints before asking it to generate anything. The name is useful. The underlying mechanics and the implementation differences across tools are worth examining in more detail.
What the Model Defaults To
LLMs for code are trained on large corpora of public repositories. From that training, they develop strong defaults about what code looks like: console.log for logging in Node.js, try/catch for error handling in most languages, class-based components in pre-hooks React codebases, direct database access in the absence of other signals. These are population-level norms; they represent what most publicly available code does.
A production codebase deviates from those defaults in ways that matter to the team. It uses a specific logging library decided on during a standardization effort two years ago. It has an error-handling convention extracted into a shared utility, a test structure that emerged from team iteration, a set of internal patterns that nowhere appear in public training data. They exist only in the repository and in institutional memory.
Without priming, the model generates generic-correct code, and the developer corrects it to project-correct code. That correction loop is the friction Garg identified. The model is not failing to be intelligent; it simply has no way to learn project-specific conventions unless told them explicitly. Each correction is a micro-cost, and across a day of AI-assisted development, those costs compound.
Why Position Matters
Providing context at the start of a session rather than mid-conversation has empirical support from how transformers process long sequences. Liu et al.’s “Lost in the Middle” study (2023) found that models reliably attend worst to information placed in the middle of long contexts, with performance peaks near the start and end. For priming to work, the constraints and conventions that matter most need to be positioned before the conversation begins, not stated partway through when they compete for attention with everything else in the window.
This is one concrete reason why tool-level context injection (CLAUDE.md, .cursorrules, Copilot instructions) outperforms restating conventions in the first message of each session. Files injected at the system prompt level occupy position zero, where attention is highest, and survive the full session without degradation.
There is also a finding from in-context learning research that shapes how these files should be written. Brown et al.’s GPT-3 paper established that few-shot examples, concrete demonstrations of the desired pattern, outperform instruction-only prompts on most tasks. For knowledge priming, showing the model an example of correct error handling in your codebase will outperform a prose description of the same pattern. The model recognizes a demonstrated pattern and continues it rather than constructing behavior from an abstract specification.
How the Tools Implement It
Every major AI coding tool has converged on some form of persistent context injection, though the implementations differ in important ways.
Claude Code reads CLAUDE.md from the repository root automatically at session start and injects it into the system prompt. It supports layered files: a CLAUDE.md in src/api/ supplements the root file for work in that subtree. The @import directive allows pulling in referenced documents selectively. Anthropic’s documentation recommends keeping the file under roughly 2,000 tokens, since priming tokens and task tokens share the same context budget; every token consumed by the priming file is unavailable for the actual task.
Cursor reads .cursorrules from the project root and applies it as a system prompt prefix for all AI interactions. It also supports a .cursor/rules/ directory with multiple rule files that activate based on glob patterns, so frontend-specific conventions can apply only to *.tsx files without polluting the context for backend work. A community repository, awesome-cursorrules, has collected templates for common stacks, though project-specific conventions require manual authorship regardless.
GitHub Copilot added repository-level custom instructions in late 2024 via .github/copilot-instructions.md. Organizations can layer org-level instructions on top through VS Code settings, and individual users can add a personal layer above that, producing a three-level hierarchy that mirrors Garg’s layered model directly.
Aider approaches the problem differently with its repository map: a compressed structural representation generated by tree-sitter, consisting of file paths plus function and class signatures, fitting within roughly 1,000 to 2,000 tokens. Garg’s priming pattern and Aider’s repo map address complementary gaps; the priming file answers “how should code in this project be written,” while the repo map answers “what does the existing codebase contain.” Both belong early in the context, and tools that combine them produce better outputs than either alone.
Writing a Priming File That Works
The structure that has emerged from community practice across these tools is consistent: project overview, technology stack with explicit versions, directory layout, coding conventions with examples, test strategy, and a section on what not to do. The anti-pattern section matters more than it might appear. A model will generate patterns it was trained on unless given explicit reason to avoid them. Listing “do not use try/catch in the service layer” is not redundant with showing the correct pattern; the model needs both signals, because it has seen both in training data and needs to know which one applies here.
The difference between description-only and example-driven priming is significant. Consider documenting error handling for a service layer. A description-only entry:
## Error Handling
Services return `Result<T, AppError>` from neverthrow.
Only the infrastructure layer converts thrown exceptions to AppError values.
That prose leaves room for inference the model will fill in from training defaults. Pairing it with a concrete code example is more effective:
// Correct - service layer
const result = await this.userRepo.findById(id);
if (result.isErr()) {
return err(new NotFoundError(`User ${id} not found`));
}
return ok(result.value);
// Incorrect - do not use try/catch in the service layer
try {
const user = await this.userRepo.findById(id);
} catch (e) {
throw new Error('User not found');
}
The code example demonstrates the import pattern, the calling convention, and the anti-pattern in a form the model can continue directly. Three paragraphs of prose description accomplishes less.
Token efficiency matters throughout. Bullet lists carry more information per token than prose. One concrete example beats three paragraphs of description. The 2,000-token guidance reflects the real tradeoff: a priming file consuming 4,000 tokens leaves 4,000 fewer tokens for task-level reasoning, which means complex tasks get shorter context budgets and the model reasons with less room.
Priming Rot
A priming file written once and never maintained becomes actively harmful within months. Stale version numbers, removed libraries, superseded conventions, architectural descriptions that predate a significant refactor: all of these direct the model toward code that will fail review. A missing priming file leaves the model at its defaults; a stale one confidently guides it in the wrong direction, which is worse.
The practices that manage documentation rot apply directly. Priming files belong in version control and should be reviewed in PRs that change the conventions they document. The review question is simple: does the priming file accurately describe the project after this PR merges? Some teams have started automating checks that compare the stack listed in the priming file against package.json or go.mod, flagging divergence in CI. The priming file needs the same ownership as the configuration files it sits alongside, not the same ownership as the README.
Context Engineering as a Discipline
The broader framing that has consolidated in the industry is “context engineering”: the deliberate design of what occupies an LLM’s context window, treated as a software engineering discipline rather than an ad hoc practice. Garg’s knowledge priming pattern is one component of this, covering always-relevant project-level context. Other components include retrieval-augmented approaches for codebases too large for full injection, and session-level context management for specific tasks.
The Thoughtworks Technology Radar flagged CLAUDE.md and equivalent files as recommended practice for teams using AI coding tools, and multiple engineering teams working with AI assistance at scale have published accounts of reduced correction overhead after adopting structured priming. The practices have been independently rediscovered by enough teams that they represent something real about the problem space.
What Garg’s article contributes through Martin Fowler’s platform is a named, teachable pattern for something that had mostly been spreading as informal habit. A team can adopt “knowledge priming” as shared vocabulary, discuss whether their priming file needs updating, and review it systematically in ways that individual convention does not support. The named pattern is the mechanism by which informal discovery becomes deliberate infrastructure, and that transition is the more durable value of the work.