How ADRs Helped Us (and our AI Agents) Turn Chaos into Collective Architecture
It started the way many cross-team projects do: with good intentions and too many opinions. Another team was brought in to work on a major part of our system. We shared the same repository, but not the same habits. Our skills, standards, and philosophies of “good architecture” were miles apart.
We were told to document everything in Confluence. But Confluence quickly became what it often becomes: a graveyard of process. Nobody checked it when making decisions, and the few who did couldn’t tell which pages were current or who had agreed to what.
Decisions happened everywhere, in meetings, pull requests, hallway chats, and late-night messages. Everyone had partial context, and nobody owned the full picture. The misalignment had become both technical and cultural.
When Shared Repositories Aren’t Shared Understanding
That’s when we brought decisions closer to the work itself, into the repository. We introduced Architecture Decision Records (ADRs): short documents that capture the reasoning behind technical choices. Traditionally used for high-level calls, we started applying them to small, everyday choices too. Those micro decisions, about naming, structure, testing, or boundaries, were exactly where alignment was lost. Capturing them brought clarity back to collaboration.
Later, when AI tools entered our workflow, the same ADRs became useful in a second way: they gave agents something better than code to read. They gave them a sustainable memory.
The farther documentation gets from the work, the faster it loses authority. AI only makes that gap more visible.
The Problem: Documentation Too Far from the Work
On paper, we already had documentation. There were pages for architecture, diagrams, and standards. They followed a familiar pattern: a burst of activity followed by slow decay.
The problem wasn’t laziness; it was distance. By the time a decision reached Confluence, it had already lost context. The page was an echo of a conversation that had happened somewhere else. Over time, those echoes grew fainter. New engineers couldn’t tell what still applied. Veterans stopped trusting the documentation altogether.
Confluence had become a museum of past decisions rather than a place where current decisions could continue to evolve. We needed something closer to the code, documentation that lived where the consequences lived.
That problem becomes sharper with AI. A human developer can sometimes compensate for weak documentation by asking around, reading between the lines, or remembering past conversations. An AI agent needs that context to be written down, retrievable, and close to the work. Without a clear architectural memory, it optimizes locally. It sees patterns, but not intent. It can reproduce a convention without knowing whether the convention is deliberate, deprecated, accidental, or contested.
That is how teams end up with AI-generated code that looks plausible while violating the architecture. The agent may follow the local pattern it sees, while missing the decision that explains whether that pattern should exist at all.
Architecture became easier to discuss once the reasoning lived beside the code.
How We Brought Decisions Closer to the Code
We moved architectural documentation into the repository itself, as simple markdown files stored beside the code. Each ADR captured one decision: its context, tradeoffs, and outcome. No ceremony, no management templates. Just structured thinking in plain sight.
At first, we used ADRs for big design calls: patterns, data models, and integrations. The real friction often lies in smaller choices. Those were the invisible edges where style, intent, and ownership collided. So we began writing micro-ADRs: short records for local conventions, naming patterns, testing strategies, API boundaries, folder structures, and dependency rules. They took minutes to write and saved hours of debate.
What Makes an ADR Useful
A bad ADR is usually just a decision with the thinking removed.
Decision: Use repository pattern for data access.
Status: Accepted.
Reason: It is cleaner.
That kind of ADR looks like documentation, but it does very little. It records the outcome while losing the tension that made the decision useful. A new developer can see what was chosen, yet they still have to guess why. An AI agent has the same problem. It can follow the instructions, but it cannot understand the architectural pressure behind it.
A better ADR keeps the reasoning visible:
Title: Use focused repositories for write-heavy domain operations.
Status: Accepted.
Context: Controllers were mixing validation, persistence, and transaction logic. This made write flows harder to test and caused repeated bugs around partial updates.
Options considered: Keep persistence in controllers, hide all persistence behind generic repositories, or introduce focused repositories for write-heavy operations.
Decision: Use focused repositories for complex writes, while keeping simple reads in query services.
Consequences: Write flows become easier to test. Simple reads stay lightweight. Avoid repositories that only wrap basic ORM calls.
Review trigger: Revisit if repositories become pass-through abstractions.
The second version preserves the judgment behind the choice. It explains where the pattern applies, where it does not apply, and when the team should revisit it. That is useful for people, and it is exactly the kind of context an agent needs before generating code.
To keep decisions alive, we built a lightweight loop:
- Architecture Syncs: Open weekly design sessions focused on understanding before agreement.
- Informal Chats: Early ideas could stay informal, then resurface as ADRs once they affected the system.
- Draft & Review: One author drafted the decision, and the team reviewed the reasoning.
- Acceptance: Accepted ADRs were merged. Old ones were deprecated, never deleted.
Over time, the practice became a rhythm rather than another layer of process. Decisions became visible, reviewable, and continuous because they lived in version control alongside the work they affected.
Once we started using AI assistants more often, ADRs also became part of the development context we wanted agents to read. A coding agent could be instructed to consult the ADR folder before proposing a refactor. A review assistant could flag pull requests that contradicted accepted decisions. An onboarding chatbot could explain why the system uses a particular pattern by citing the relevant ADR rather than hallucinating a confident explanation.
That changed how we thought about documentation. ADRs became context we could actually use during development. A decision is easier to reuse when it preserves the pressure, constraints, and tradeoffs behind it.
ADRs as On-Demand Memory for Agents
Here, “agent” means any AI-assisted tool that can read project context and act on a task: a coding assistant, review bot, documentation helper, or onboarding chatbot.
AI tools often begin each task with a narrow view of the system. That may be enough for small changes, but architecture depends on memory: past constraints, rejected options, accepted tradeoffs, and the reasons a boundary exists.
Architecture accumulates judgment over time. Why we avoided a framework. Why we split a service. Why we tolerate duplication in one place and forbid it in another. Why an abstraction was rejected. Code rarely preserves this kind of reasoning on its own.
ADRs turn that missing judgment into retrievable memory. This memory is not hidden inside a model. It is plain text in the repository: versioned, reviewable, and owned by the team.
A good ADR gives an agent the reasoning that code usually leaves implicit. It explains the context behind a decision, names the constraints that mattered, records the alternatives considered, captures the trade-offs the team accepted, and states the current decision clearly enough to be followed.
Three agent behaviors became especially useful.
1. Retrieve before changing
Before touching persistence, API boundaries, testing strategy, or service structure, the agent searches accepted and deprecated ADRs for relevant decisions. It can summarize the constraints before proposing code. The agent is no longer guessing from nearby files. It is retrieving the team’s decision history before acting.
2. Surface conflicts
During the review, the agent compares a proposed change with existing ADRs and identifies any drift.
This implementation introduces persistence logic in the controller. ADR-014 recommends keeping write-heavy persistence behind focused repositories because controller-level persistence caused repeated transaction bugs. Consider moving this logic into the existing write repository, or update the ADR if the team wants to change this convention.
That kind of comment is useful because it is specific, grounded, and reviewable. Sometimes the code should change. Sometimes the ADR is outdated. The important part is that the conflict becomes visible.
2. Draft the missing record
When a pull request introduces a new convention, reverses an old one, or exposes a decision that was only discussed informally, the agent can suggest a draft ADR. It can summarize the context, list the tradeoffs, and ask the author to confirm the reasoning. This lowers the cost of documentation while keeping ownership with the team.
Agents can also help detect staleness. If an ADR says the system follows one pattern and the implementation has clearly moved elsewhere, the agent can flag the mismatch. The team can then decide whether to update the code, update the ADR, or formally deprecate the old decision.
Used this way, the ADR folder becomes part of the team’s working context. Developers and agents can retrieve intent, challenge assumptions, and keep architectural decisions connected to the code they affect.
The Outcome: Shared Standards, Shared Ownership
The first few weeks felt slow. Writing ADRs for small design choices seemed excessive, a kind of paperwork creeping into engineering.
Then something shifted.
Conversations that once looped endlessly began to resolve faster. Code reviews got easier. Disagreements felt less personal because the reasoning was already written down. New developers onboarded faster because “why do we do it this way?” had a durable answer. Junior engineers learned from reading past ADRs. Senior engineers refined their arguments in writing instead of relying on authority.
When another external team joined later, the difference was obvious. They didn’t need to guess how we worked. The ADRs made our standards transparent and framed them as open conversations rather than fixed commandments. They even added their own ADRs, blending their experience with ours.
AI amplified that effect. Instead of treating the repository as code plus scattered documentation, we could treat it as a repository that contained both code and rationale. The code showed the system's current shape, while the ADRs explained the reasoning behind it. The agent could navigate both.
This made AI assistance safer and more useful. Prompts became simpler because we could point the agent to the right memory rather than re-explaining the whole system each time. “Follow the accepted ADRs.” “Check whether this conflicts with our testing strategy.” “Find the decision that explains this boundary.” Those instructions worked because the memory was already there.
For example, when a developer asked an agent to add a new endpoint, the agent could first retrieve the ADR on API conventions. It would see that we preferred explicit request objects over loose parameter bags, that validation belonged near the boundary, and that domain logic should stay out of controllers. The generated code was closer to our standards because the agent had access to the rationale behind them.
When someone proposed a new integration pattern, an agent could find the older ADR explaining why a similar approach had been rejected. That did not automatically end the conversation. It made the conversation better. The team could ask whether the old constraints still apply, rather than rediscovering the same trade-off from scratch.
In review, the most useful comments were grounded in accepted decisions rather than personal preference. Instead of debating whether a pattern “felt clean,” we could point to the ADR, examine the original tradeoff, and decide whether the current change still fits.
That was the cultural shift. Architecture was no longer only a matter of APIs, data flows, and dependencies. It became a shared way of making sense of complexity. Teams repeat mistakes when memory is weak. Disagreement turns political when reasoning is hidden. ADRs gave us a place to preserve both the decision and the debate around it.
ADRs changed more than our documentation habits. They changed how we made decisions. The repository held the code and the collective reasoning behind it. AI then made that reasoning easier to retrieve, reuse, and test.
The Smallest Useful ADR for Humans and Agents
The smallest useful ADR doesn't need to be long. It only needs to answer a few questions clearly:
- What decision did we make?
- Why did this decision matter?
- What alternatives did we consider?
- What tradeoff did we accept?
- Where does this decision apply?
- When should we revisit it?
That last question is especially important. A decision without a revisit condition can become dogma. A decision with a revisit condition remains alive.
For AI-assisted teams, I would add one more field:
Agent guidance: When generating or reviewing code in this area, follow this decision unless the team is explicitly revisiting it. If a change appears to conflict with this ADR, surface the conflict before suggesting an implementation.
That simple addition turns the ADR into something an agent can act on. It translates architectural reasoning into operational behavior. A full template can live separately as an appendix or starter file in the repository. The article itself only needs the principle: useful ADRs preserve enough reasoning for both people and agents to act responsibly.
Conclusion
Start small, one decision at a time. Keep ADRs close to the work so they can preserve the reasoning around the system. Write them clearly enough for a new developer to understand and concretely enough for an agent to use.
In an AI-assisted engineering culture, vague documentation becomes a liability. Agents act on whatever context we give them, and silence becomes a kind of context, too. ADRs give teams a way to make intent explicit, durable, and available when decisions need to be made.
A well-tended ADR folder keeps decisions alive for the people maintaining the system today and for the tools increasingly helping them change it tomorrow.
Example of an Agent-Readable ADR
ADR-018: Keep domain logic out of controllers
Status: Accepted
Context
Controllers in the billing service had started accumulating validation, authorization checks, persistence logic, and domain rules. This made endpoints faster to write at first, but harder to test and modify. Several bugs came from small differences between controllers that were supposed to enforce the same rule.
Decision
Controllers should handle transport concerns: request parsing, authentication context, response formatting, and delegation. Domain rules should live in application services or domain objects, depending on the complexity of the flow.
Alternatives considered
Keep logic in controllers for speed. This was rejected because behavior was already drifting between endpoints.
Move all logic into domain entities. This was rejected because some flows coordinate external systems and do not belong inside entities.
Use application services for orchestration and domain objects for core rules. This was accepted because it keeps controllers thin while avoiding oversized domain entities.
Consequences
New endpoints may require slightly more structure. Tests become easier to target because behavior lives outside the transport layer. Code reviews should flag business rules added directly to controllers.
Review trigger
Revisit this decision if application services become procedural dumping grounds or if simple endpoints require excessive ceremony.
Agent guidance
When generating endpoint code, keep controllers thin. Place orchestration in application services and core business rules in domain objects where appropriate. During review, flag business rules inside controllers and cite this ADR. If the user asks for a simpler implementation, explain the tradeoff before changing the structure.
Accelerate Delivery Through AI
Don't just integrate tools. Nexapp powers your engineering practices with AI-assisted programming.
Continue reading
How ADRs Helped Us (and our AI Agents) Turn Chaos into Collective Architecture
AI Doesn't Learn: How to Build Its Memory to Get the Most Out of It
Legacy Systems vs. Innovation: A Persistent Challenge