· 8 min read ·

The Config File That Finally Explains Itself

Source: martinfowler

Software projects grow a configuration layer over time that nobody designs in advance. A tsconfig.json for the TypeScript compiler. An .eslintrc for the linter. A .prettierrc for formatting. An .editorconfig for whitespace conventions. A pyproject.toml encoding package metadata and tool settings. Each file serves the same structural role: it records project decisions in a machine-readable form so that tools apply them consistently without being told each time.

What unifies all of these files is what they contain. Settings. Rules. Targets. Each tells a tool what to do. Not one of them records why the decision was made.

The .eslintrc that bans console.log in production code does not explain the incident that prompted the rule. The tsconfig.json with strictNullChecks: true does not document the class of runtime errors that made the migration cost worthwhile. The .prettierrc does not mention the three-week argument that ended in “just pick a style and commit.” The files hold decision outcomes. The context behind those decisions lives in a Slack thread nobody will find, in a commit message with insufficient detail, or in the memory of whoever was in the room when it happened.

This has been tolerable. The tools that consume these configuration files are deterministic: given the same settings and the same input, a linter always produces the same output. Deterministic tools do not need to understand why a rule was created to apply it correctly. They need the rule, and they have it.

The Judgment Call Problem

AI coding tools are not deterministic in this sense. When Claude Code generates a data access layer, it makes judgment calls: whether to use a query builder, how to handle errors, when to introduce an abstraction, which of several reasonable approaches to prefer given the project’s constraints. When it implements a new feature, it has to decide whether existing patterns generalize or whether something new is needed. These are not rule applications. They are contextual judgments, and contextual judgments require context.

This is where conventional configuration files fall short. A CLAUDE.md that says “use the repository pattern for all database operations” gives the model enough to avoid writing direct SQL in the service layer. It does not give the model enough to handle adjacent questions correctly: whether to add a caching layer between the repository and service, whether to abstract over multiple data sources, whether a particular read-heavy query warrants bypassing the pattern for performance reasons. The model has the rule but not the principle behind it, and principles are what generalize.

Rahul Garg’s Context Anchoring, published in Martin Fowler’s series on reducing friction with AI, addresses this directly. The pattern is to maintain a living document alongside AI sessions that captures not just the decisions made but the reasons behind them. It is the first systematic treatment of what is genuinely a new category of project artifact: configuration that explains itself.

What the Reasoning Layer Looks Like

A conventional project anchor might read:

## Data access
- Repository pattern for all database operations
- No direct SQL from service layer

With decision context added:

## Data access
- Repository pattern for all database operations.
  Reason: database migration planned for Q3; direct SQL would require
  touching every service file during migration. Constraint expires post-migration.
- No new ORM dependencies.
  Reason: evaluated three ORMs last year, all introduced N+1 query
  problems difficult to debug through the abstraction layer.
  pg directly has been stable and well-understood by the team.

The difference is not cosmetic. The first version tells the model what to avoid in cases the rule explicitly covers. The second version gives the model what it needs to handle cases the rule does not enumerate: whether a proposed caching layer would complicate the migration timeline, whether a read-heavy query warrants temporary deviation from the pattern, whether the Q3 constraint is still active. The reasoning generalizes to adjacent situations in a way that the bare rule cannot.

For a Discord bot I have been developing with Claude Code for over a year, this shows up concretely in command handling architecture. The bot uses deferred replies for all slash commands that touch the database. A rule stating that convention is useful. What makes it actionable across new commands I had not anticipated when writing the rule is that the anchor document explains the underlying constraint: Discord’s interaction acknowledgment window is three seconds, and any command that makes a database call before acknowledging risks hitting that timeout under load, producing a failed interaction that cannot be recovered. A new command that needs a database lookup gets designed correctly the first time because the model understands what it is protecting against, not just that protection is required.

Why the Reasoning Has Always Been Missing

If captured rationale is this useful, the obvious question is why it has been absent from project configuration files for decades.

Part of the answer is that traditional tools simply never needed it. Linters, compilers, and formatters are stateless with respect to reasoning: they apply rules without needing to understand their origin. The format of configuration files was shaped by what tools could use, and deterministic tools cannot use prose rationale. Including reasoning in an .eslintrc would be ignored by ESLint and would only benefit a human reader, making it documentation overhead with no payoff for the consuming tool.

Part of the answer is documentation decay. Written rationale requires maintenance. The reason a rule was added becomes inaccurate as projects evolve. An outdated reason entry is worse than no reason at all if it leads future readers to the wrong conclusion about whether a constraint still applies. Without a mechanism that surfaces staleness quickly, rationale documentation tends to drift quietly into misinformation.

AI development changes the economics of both problems. The model actively uses the reasoning, so a well-maintained anchor document with decision context produces measurably better outputs than one without it. And when the reasoning goes stale, the AI’s suggestions in the current session reveal the inconsistency. The mismatch surfaces within the hour rather than in a code review six months later. The feedback loop that makes documentation discipline hard to sustain in traditional settings is compressed to a timescale where the benefit is visible to the same person who paid the cost.

The Architecture Decision Record Comparison

Architecture Decision Records, introduced by Michael Nygard and formalized in tooling like adr-tools, have been the standard mechanism for capturing decision rationale since around 2011. An ADR records the context, the decision, and the consequences in a short structured document committed alongside the code it describes.

Context anchoring and ADRs are addressing related problems with different operational characteristics. ADRs are a pull-based archive: a human reads them when trying to understand a decision made in the past. They are written once per decision, for readers who can fill in gaps from domain knowledge, and they are never meant to be consumed automatically by a tool at the start of every session.

A context anchor is push-based: it gets actively provided to the AI at the start of each session. It is written to be complete enough that a stateless reader with no project history can reason correctly from it. And unlike an ADR, it reflects current state rather than historical record. An ADR is marked “superseded” when a decision changes; a context anchor is updated in place, keeping only the reasoning that is currently active.

The two practices complement each other well. A project with mature ADRs has the rationale already written somewhere; building a context anchor document becomes curation rather than reconstruction. A complex session that produces a well-maintained anchor provides a natural draft for a permanent ADR once the work is complete. The reasoning is already articulated, the alternatives already documented, the constraints already identified. Teams that have struggled with ADR adoption sometimes find that context anchoring provides the discipline, because the feedback loop is in the current session rather than deferred to a future review.

Maintenance and the Stale Reason Problem

Garg emphasizes that the anchor document must be a living document, not a project snapshot. This is where most implementations drift. Teams build a useful anchor document during initial setup and stop updating it as the project evolves.

Stale rationale is the specific failure mode to guard against. A context anchor that says “this constraint expires post-migration” when the migration completed four months ago causes the model to restrict its suggestions unnecessarily. An anchor citing a performance concern from a library version that has since resolved the issue prevents the model from suggesting a cleaner approach that would now be appropriate. The document has to reflect current state because the model reasons from it as if it is current.

A practical approach that keeps the document accurate without significant overhead: at significant decision points during a session, ask the model to update the anchor before continuing implementation. The model does the writing; you review for accuracy. This captures decisions at the moment they are made rather than requiring end-of-session reconstruction, and it costs a short pause per significant decision rather than an extended reconstruction effort later.

The anchor document should also stay short by design. When a constraint has been resolved, the reasoning behind it belongs in a commit note or a permanent ADR, not in a document that gets re-injected into every session. A long anchor document is a sign that closed decisions are accumulating alongside open ones, and it means the model is being asked to attend to information that is no longer decision-relevant. Short and current beats comprehensive and stale.

A New Category of Project File

The broader observation from Garg’s article is that context anchoring describes a category of project file that has not existed before: one that carries reasoning rather than just settings.

Every tool in the conventional project configuration stack captures outcomes. Version targets. Rule sets. Naming conventions. Package metadata. Build targets. These all encode the what of project decisions in formats that deterministic tools can apply without needing to understand the why behind them. The format was adequate because the consuming tools were adequate to it.

AI tools make the why load-bearing in a way that deterministic tools never did. A tool that makes judgment calls cannot apply a rule correctly to unanticipated cases without understanding what the rule is protecting against. The context anchor is the file format that delivers that understanding, and the entire AI development ecosystem has been converging on it independently because the alternative, re-explaining the same reasoning session after session, is the most predictable waste in AI-assisted development.

The tooling will formalize this further. Several AI coding tools are already building session memory and decision tracking into their core scaffolding. When that infrastructure matures, some of the manual discipline behind context anchoring will be automated. What will remain is the underlying principle: configuration for a judgment-making tool needs to capture more than rules. It needs to capture the reasoning that makes those rules coherent. Writing that down, keeping it current, and treating it as a first-class project artifact is the practice. The format is just markdown.

Was this interesting?