The Recs Files
The Truth Is In Here
Problem: Agent Drift and the Illusion of Velocity
SCULLY: "Mulder, I’ve reviewed the latest commits. It’s chaotic. It introduced a second retry wrapper, bypassed the authentication middleware we wrote ten days ago, and renamed
AccounttoSubscriberacross four separate modules."MULDER: "It’s agent drift, Scully. A classic case. The codebase isn't just failing to maintain state—it's actively fabricating a new reality."
SCULLY: "There’s a perfectly rational explanation, Mulder. LLMs are non-deterministic, probabilistic prediction engines. As codebases grow, asking an agent to maintain long-term architectural consistency is a fool's errand. Hallucination is baked into the math."
MULDER (staring at the terminal screen): "That’s where you’re wrong, Scully. You’re blaming the engine for failing to navigate chaos. We keep searching for the solution out there, hoping a bigger context window, a smarter model, or a bigger prompt dump will magically fix our engineering."
SCULLY: "And what's your alternative hypothesis?"
MULDER: "Stop treating context like an unstructured chat log and start treating it like an engineered runtime state. The Recs Files, Scully. The truth is in here."
If you’ve spent more than a few weeks building a system alongside AI coding agents, that conversation isn't science fiction. It’s your Tuesday afternoon.
When an agent operates over long-running projects without explicit structural boundaries, all the decisions you haven't made explicit were never made at all. Left unconstrained, the model default-fills architectural ambiguity with plausible, localized guesses. The codebase slowly degrades into a patchwork of competing idioms, duplicate abstractions, and shifted vocabulary.
Two diametrally opposed behaviors eventually trigger this drift:
- Context Flooding ("The Truth is Out There"): Dumping raw pull requests, issue threads, chat histories, and full API docs into a massive context window. This creates prompt pollution, high token burn, and subtle reasoning errors.
- Blind Discovery: Giving the agent a minimal prompt and letting it inspect files haphazardly to "figure it out." This leads to runtime discovery sprawl and unguided guesses.
Both approaches stem from the same flawed premise: treating agent context as an unstructured, growing chat log.
If we want to build complex systems alongside autonomous agents without watching our architecture disintegrate, we must treat context differently. Context is not a conversation history. It is an engineered runtime state. And if we want our software to remain congruent over time, we need a deterministic architecture that keeps humans in firm control of decisions, while directing the agent to execute bounded plans.
Welcome to… The Recs Files (tuuh daah duuh daah dee daah…).
Solution: The Context Architecture
To replace the growing chat log with an engineered runtime state, The Recs Files architecture separates history from active state. Borrowing from Event Sourcing1 and CQRS2, we split our context infrastructure into three distinct artifacts: a root unifying anchor, append-only decision records, and active state projections.
[ VISION.md ]
(Root Unifying Anchor)
│
▼
[ APPEND-ONLY RECORDS ]
(The "Files" in Recs Files)
(docs/adr/, docs/user-workflows/...)
Log of immutable choices & changes
│
│ Trigger: Record added/superseded
▼
[ ACTIVE STATE PROJECTIONS ]
(Read-Only Ground Truth)
Single materialized file per record type
The Root Unifying Anchor (VISION.md)
At the root of the repository sits VISION.md. It is the single, non-negotiable North Star that defines the system's core purpose, target audience, primary capabilities, and non-goals. When individual architectural choices or feature requirements conflict, VISION.md serves as the ultimate tie-breaker across all records, ensuring every automated decision aligns with the software's overarching design intent.
Append-Only Decision Records
The "Files" in The Recs Files are each a decision, captured as an immutable, append-only 3 record under version control (e.g., docs/architectural-decision-records/, docs/user-workflows/, docs/features/).
When a decision changes, we never edit an existing record to alter its historical meaning. We write a new record that explicitly supersedes or amends the old one.
Record files follow a strict naming convention: [TYPE_PREFIX]-[ID]-[descriptive-headline].md 4
ADR-012-use-redis-for-session-caching.mdUW-004-user-initiates-passwordless-login.mdFR-008-stripe-webhook-idempotency-handling.mdADR-019-use-memcached-for-session-caching.md(superseding the above ADR-012)
The Inverted Pyramid - Records follow the inverted pyramid of news writing: the most important information comes first. The title states the decision itself, not a category label. A title like ADR-012-caching.md tells an agent nothing without parsing the document body. A title like ADR-012-use-redis-for-session-caching.md immediately declares the active decision. If you cannot write a single title that states the decision, you either have no decision yet, or you have two.
Humans write the records. An agent can help you think a decision through, but the record itself should be written, and amended, by a human. Records the agent wrote have, in our experience, always come back later as semantic corrections that trickled down into code.
What should be a record
Left to its own devices, your agent will want to make everything into a record. It's on you to stop it. The core rule:
A record is anything worth a team-level decision. If a teammate (or agent) implemented this differently, would you want to have agreed on it first?
- What belongs
- What a user is trying to achieve and what happens at the edges (
UW-); surface area, inputs, outputs and rules (FR-); non-obvious trade-offs, mechanisms and boundaries (ADR-); the exact sentences a user reads when something fails (ERR-); terms with wide reach across modules, messages or records (CURRENT_VOCABULARY.md). - What does not
- Local implementation mechanics such as helper splits or variable names (that is what code review is for); facts about third-party tools (they go in a knowledge base); decisions not made yet (they go in a deferred list, where they bind no code).
Two tests settle where a decision is filed:
- Verb/Sequence: If describing it requires a verb, an argument or a sequence of steps, it is a feature, not an ADR.
- Implementation Survival: If a word survives swapping the implementation, it belongs in the vocabulary. If the swap retires the word (e.g., "middleware"), it belongs in an ADR.
Finally, a record has one reason to change. A record that holds an "or" is two records; split it before one half goes stale while the other stays true.
Active State Projections
While append-only records preserve an accurate audit trail, feeding an agent forty historical ADRs, ten of which are superseded, three abandoned, and two contradictory, wastes context window budget and introduces reasoning errors.
This is where Projections enter the picture.
A Projection is a single, read-only materialized view compiled from all active, non-superseded records of a given type: a short preamble, then one line per active record. There is exactly one projection file per record category:
user-workflows.mdfeatures.mdarchitectural-decisions.mdCURRENT_VOCABULARY.md
When a new decision occurs that supersedes an old one, e.g. ADR-019-use-memcached-for-session-caching.md, the agent updates the projection file, removes ADR-012, and adds ADR-019. We keep the ADR-012 file around because the code may not be up to date yet, and may still have references to ADR-012. ADR-012 indicates it was superseded by ADR-019; when the work to bring the codebase up to date with ADR-019 is finished, we can delete the ADR-012 file.
Operationally, while working in an interactive harness (e.g. Claude Code), the old decision is now going to be in the context window and is going to make the agent slightly worse. So, as soon as a change in record enters the picture, it becomes important to start a new chat with a new context window as soon as possible.
Automated Materialization & The Maintenance Boundary
Projections are maintained by the agent itself, subject to a strict operational invariant: the agent updates projections immediately whenever a record is created or updated5, but during code implementation and review passes, projections are strictly read-only.
Because record titles follow the inverted pyramid, a projection can often be as compact as a bulleted list of active headlines alongside concise summary rules. The agent reads architectural-decisions.md as part of its AGENTS.md, seeding the context window when it starts, gaining unpolluted ground truth without wading through historical dead ends.
Record Precedence & Targeted Context Routing (UW- → FR- → ADR-)
Even with clean projections, a mature repository can accumulate dozens of active state files across different domains. If we dump every projection file into every prompt, we fall right back into context window bloat and reasoning pollution—searching for truth out in the noise.
To keep token spend flat and focus agent reasoning, context assembly in The Recs Files follows a strict Order of Precedence anchored in user value.
[ VISION.md ]
(Root Unifying Anchor)
│
▼
[ CURRENT_VOCABULARY.md ]
(Ubiquitous Language)
│
▼
[ USER WORKFLOW RECORDS ]
(Primary Driver / User Value)
│
▼
[ FEATURE DECISION RECORDS ]
(Implementation Specs & Details)
│
┌───────────────────┴───────────────────┐
▼ ▼
[ ERROR / PERFORMANCE RECORDS ] [ ARCHITECTURAL DECISION RECORDS ]
(Specialized Constraints) (Dynamically Filtered Subset)
Vocabulary: The Words Underneath Everything
Directly under the vision sits the ubiquitous language, CURRENT_VOCABULARY.md. Every record, conversation and line of code is written in its words, so it outranks all of them. No new term enters any file without a human agreeing to it.
User Workflows (UW-): Where Every Session Starts
Every coding session begins with a User Workflow record. User workflows represent the direct, observable value the software delivers (e.g., UW-014-checkout-flow.md).
Because software exists to serve user capabilities, User Workflows take precedence over all other decision records except the vision and the vocabulary. They define what needs to be built and why, establishing the local boundary for the entire task.
Feature Records (FR-): Operational Behavior
User Workflows refer directly to Feature Records (FR-), which supply the operational details, domain boundaries, and edge-case behavior required to execute the workflow.
For instance, UW-014-checkout-flow.md references FR-003-stripe-webhook-handling.md and FR-009-cart-tax-calculation.md. Feature records may in turn attach specialized constraint records, such as error-handling schemas (ERR- ) or latency targets (PERF-).
Architectural Decision Records (ADR-): Dynamic Filtering
Instead of loading the content of all the active architectural decision records into the prompt, the agent performs targeted context routing:
The agent reads the target UW- record and its referenced FR- records.
It analyzes the technical capabilities required by those features (e.g., background job queueing, relational persistence, external API calls).
It scans architectural-decisions.md and selects only the ADR headlines and rules relevant to those capabilities.
If you are implementing an offline batch processing job, the agent selects ADR-005-use-sidekiq-for-background-jobs.md, and ignores ADR-019-use-memcached-for-session-caching.md and ADR-022-oauth2-token-revocation.md.
Context Window Bounding in Practice
Routed this way, the context window holds all of the local intent (the target UW- and its FR- records), all of the active constraints (the filtered ADR- rules), and none of the unrelated noise. Token consumption scales with the task at hand, not with the age or size of the repository.
The Rules of Execution
With our context routed and bounded, we can turn records into production code.
I built my workflow on an evolution of obra/superpowers, and the next article shows how it runs day to day. You can use whatever implementation workflow you want, as long as it respects three rules:
- Records first. No code is generated or modified without first creating or updating the record that governs it. If a requirement changes, or a bug exposes a case nobody considered, you do not ask the agent to "fix the code". You update the record, the agent updates the projection, and only then does work on the code begin.
- Records are read-only during execution. While planning, implementing or reviewing, the agent never modifies records or projections.
- Contradictions halt the work. When the agent finds a conflict or an ambiguity between the task and a record, it stops, surfaces the conflict to the human, and may propose resolutions grounded in
VISION.md. The human decides and updates the record, and work resumes.
The third rule is the circuit breaker: it keeps the agent from quietly inventing architectural workarounds under the hood.
Code Comments as Traceability Anchors
Even with a clean plan, codebases evolve over months of active development. If code becomes detached from its governing records, future agent passes will struggle to understand why specific abstractions exist, leading right back to accidental duplication and architectural drift.
To tie source code to its records permanently, we enforce one last invariant: code comments are citations, and nothing else.
|
|
When an agent (or human) inspects this code months later, there is no need to guess why the logic was structured this way. The anchors point directly to the original design intent and boundary conditions.
A comment that explains what the code does, or which business rule it obeys, is deleted, and the rule goes into the record where it belongs. A comment that explains technical mechanics (an algorithm choice, a concurrency control, a workaround for a third-party bug) moves into a knowledge base, and the code cites it there. The knowledge base is somewhere the explanation can be verified rather than merely asserted: an instruction manual, or an executable notebook (org-mode, Jupyter) that demonstrates the behavior.
Stop Searching the Window: the Truth is in Here
Building software alongside AI coding agents does not require us to choose between two bad choices: flooding prompts with disorganized chat logs or surrendering our architectural authority to an LLM's localized guesses.
By treating context as an engineered runtime state, The Recs Files establish an understandable and maintainable pipeline for software development:
VISION.mdsets the immutable North Star.- Append-Only Records (e.g.
ADR-,UW-,FR-) log every choice explicitly. - Active Projections provide compact, unpolluted ground truth.
- Targeted Context Routing keeps token spend bounded and focused on user value.
- Three Rules of Execution keep humans in control: records first, records read-only while work runs, and every contradiction halted and handed back.
- Traceability Anchors keep source code permanently connected to design intent.
When we build with this architecture, rapid iteration stops being a descent into chaos. Agents execute bounded plans at high speed, while human developers remain in firm, unambiguous control of system design.
The truth about your architecture isn't scattered out in a 200,000-token prompt log or buried in ephemeral chat histories.
The Recs Files. The truth is in here.
Footnotes
Event Sourcing captures every change to an application's state as a sequence of events, so the current state can always be rebuilt by replaying them. See Martin Fowler's Event Sourcing.
CQRS, Command Query Responsibility Segregation, uses a different model to update information than the model used to read it. See Martin Fowler's CQRS.
The key here is immutability of intent; if you must fix a typo, or clarify something, or even add an elment of definition which was intended but that was not identified at creation time, that might be OK. Do what works for your team.
In a team setting, timestamps are recommended over monotonically increasing numbers, to avoid unnecessary conflicts on record files. Here we use numbers for illustrative purposes.
Here again, note, it is about immutability of intent, not immutability of text.