In projects that live for more than a few years, there is one question that comes up surprisingly often:
“Why did we build it this way?”
Maybe it was the decision to choose PostgreSQL instead of MongoDB. Maybe the team decided to use messaging, adopt microservices, keep a modular monolith, introduce distributed caching, or standardize an observability strategy.
The code usually tells us what was implemented.
Git tells us when it changed.
But neither necessarily explains why the decision was made.
That is exactly where Architecture Decision Records, or simply ADRs, come in.
The problem is not forgetting the technology. It is forgetting the context
Architectural decisions rarely happen in a vacuum.
Imagine that, a few years ago, a team decided not to use a particular technology. Someone joining the project today might look at the architecture and think:
“This doesn’t make sense. We could simplify all of this by using X.”
Maybe they could.
But perhaps X had been rejected because the system needed to satisfy a regulatory constraint. Maybe the team did not yet have enough operational maturity. Maybe licensing was a problem. Or perhaps, at the time, the technology simply did not meet an important requirement.
Without that context, old decisions can look arbitrary.
Michael Nygard helped popularize ADRs around this exact idea: useful architecture documentation does not have to be a massive document describing the entire system. Small, independent records that explain individual decisions have a much better chance of remaining understandable and useful over time.
An ADR is essentially a snapshot of architectural reasoning at a particular point in time.
It does not try to explain the entire architecture.
It explains one decision.
What goes into an ADR?
There are several ADR templates, but one of the best-known formats is intentionally simple.
Context explains the problem, constraints, and forces that created the need for a decision.
Decision records what was decided.
Consequences describe what changes because of that choice, including benefits, costs, and trade-offs.
There is usually also a Status, indicating whether the decision is being proposed, has been accepted, has been deprecated, or has been superseded by another decision.
AWS, for example, recommends using ADRs for architecturally significant decisions involving system structure, non-functional requirements, dependencies, interfaces, and construction techniques.
That distinction matters because an ADR should not become a development diary.
“We upgraded a library version” probably does not need an ADR.
“We standardized every service in the organization on a specific authentication strategy” probably does.
A useful question is:
Does this decision significantly affect how the system will be built, operated, or evolved?
If the answer is yes, there is probably an architectural decision worth recording.
ADRs are less about documentation and more about institutional memory
As ADRs accumulate, they form what is often called a decision log.
That history becomes especially valuable as people join and leave teams.
Instead of depending on the one developer who “remembers why we did that in 2023,” the context becomes part of the repository itself.
There is another benefit that is less obvious: ADRs reduce repeated discussions.
Without a record, a team can debate the same architectural question multiple times over the years. Someone proposes a technology, the team discusses it, decides against it, and six months later someone else reopens exactly the same discussion because the original reasoning was never documented.
With an ADR, the conversation can start several steps ahead:
“We made this decision for these reasons. Have any of those assumptions changed?”
That is a much better discussion.
When the ADRs themselves become a problem
Adopting ADRs sounds easy: create a docs/adr directory, add a few Markdown files, and you are done.
In practice, small inconsistencies begin to appear over time.
One file is called 0003-use-redis.md, another is called adr4-rabbitmq.md. One ADR uses the status Approved, another uses Accepted. Some decisions have no consequences section. Two files accidentally reuse the same ID. One ADR says it was superseded by another decision, but the referenced file no longer exists.
And perhaps the most common problem: someone creates a manually maintained ADR index that stops being updated after a few months.
Individually, none of these problems seems particularly serious.
Together, however, they slowly make the documentation less trustworthy.
That is exactly the space ADR Guard is designed to address.
ADR Guard: treating ADRs as verifiable artifacts
ADR Guard is a .NET command-line tool for validating and indexing Architecture Decision Records.
The idea is straightforward: if certain conventions matter to your architectural documentation, they do not have to remain informal recommendations buried in a README.
They can become automatically verifiable invariants.
By default, ADR Guard expects files such as:
0001-use-postgresql.md
0002-adopt-opentelemetry.md
And a structure based on the classic ADR format:
# Use PostgreSQL
## Status
Accepted
## Context
We need a relational database.
## Decision
Use PostgreSQL.
## Consequences
The team will need operational knowledge of PostgreSQL.
The command:
adr-guard check docs/adr
analyzes the records and validates filenames, IDs, titles, statuses, required sections, and relationships between ADRs.
The tool currently exposes stable validation codes from ADR001 through ADR009, covering problems such as duplicate IDs, broken relative references, missing required sections, and Superseded ADRs that do not correctly reference the decision that replaced them.
That may sound like a small detail, but stable validation codes make the tool especially useful for automation.
The real benefit appears in CI
Running ADR Guard manually is useful.
Running it in the pipeline is where things become more interesting.
- name: Validate ADRs
run: adr-guard check docs/adr
At that point, architectural documentation conventions become part of the same quality workflow already used for source code.
A pull request that breaks a link between architectural decisions can fail.
An incomplete ADR can fail.
Two ADRs using the same identifier can fail.
Of course, this does not turn architecture into code. ADR Guard cannot tell you whether Kafka is a better architectural choice than RabbitMQ.
But it can verify something much more objective:
Is the record of that decision still structurally consistent?
That separation matters.
Automate what is mechanical so that human attention can remain focused on what actually requires judgment.
The index no longer has to be maintained manually
ADR Guard also provides:
adr-guard index docs/adr
The command validates the ADR set first and only then generates a deterministic Markdown index.
That order is intentional.
ADR Guard itself contains an ADR explaining this choice: generating an index from invalid documents could make an inconsistent set of decisions look authoritative.
If validation fails, the existing index is left untouched.
If nothing has changed, the file is not rewritten unnecessarily.
The result may seem small, but it removes one more manual maintenance task that would otherwise eventually be forgotten.
And then AI enters the picture with clear boundaries
One of the more interesting capabilities added to the project is the draft command.
ADR Guard can use OpenAI, Anthropic, Gemini, or an OpenAI-compatible endpoint to help generate an initial ADR draft.
But there is an important architectural principle behind the implementation:
AI does not make architectural decisions on behalf of the team.
Every AI-generated ADR is forced to use the Proposed status.
ADR Guard owns the final document structure, validates the generated result, and leaves the transition to Accepted under human control.
That distinction is increasingly important.
Using AI to accelerate documentation is very different from delegating architectural authority to a model.
The project also deliberately avoids silently ingesting the entire repository.
Additional context must be explicitly provided, and existing ADRs are only sent to the configured AI provider when --include-existing-adrs is enabled.
There is also a preview mode:
--dry-run
which allows the tool to generate, assemble, and validate the ADR without writing anything to disk.
It is a sensible approach to AI in engineering:
assistance rather than unrestricted autonomy.
What ADR Guard deliberately does not do
Understanding what a tool does not do can be just as important as understanding what it does.
ADR Guard does not automatically analyze a Git diff and decide that a change requires an ADR.
It does not scan the entire source tree looking for architectural decisions.
It does not perform RAG over the repository.
It does not automatically accept architectural decisions.
And it does not attempt to judge whether the recorded decision is architecturally sound.
That means one responsibility remains firmly with the team:
recognizing when a decision is significant enough to be recorded.
ADR Guard starts helping after that human decision has been made.
And that is a healthy division of responsibility.
An interesting detail: ADR Guard uses ADRs to build ADR Guard
The project keeps its own architectural decisions under docs/adr.
Among the decisions currently documented are:
- using conventional Markdown ADRs;
- keeping the CLI free of third-party runtime dependencies;
- validating ADRs before generating the index;
- keeping AI-assisted draft generation provider-agnostic.
In other words, the project applies its own rules to itself.
Beyond being a good example of dogfooding, this illustrates an important point about ADRs: they are not only for giant decisions such as “monolith versus microservices.”
Choosing to keep a CLI dependency-free can also be an architectural decision when that choice affects distribution, maintenance, and future evolution.
ADRs should not prevent change
This may be the most important point of all.
An ADR does not exist to say:
“We decided this once, so we can never change it.”
Architecture has to evolve.
When assumptions change, a new decision can replace the previous one. What matters is preserving the history.
Instead of rewriting the past until it appears consistent with the present, create a new decision and record that it supersedes the previous one.
That sequence tells a far more useful story about the architecture than any isolated diagram.
Key takeaways
- Code records implementation; ADRs record intent and context.
- A collection of ADRs creates architectural memory and reduces repeated discussions.
- Even simple documentation can suffer from drift, inconsistencies, and broken relationships exactly the kind of problems automation can help prevent.
- ADR Guard turns ADR conventions into checks that can run locally and in CI while also keeping the decision index consistent.
- AI can accelerate the creation of an initial draft, but architectural decisions remain a human responsibility.
Perhaps that combination is exactly what makes ADRs so useful.
They are simple enough to remain human-readable documentation, but structured enough for tools to help keep them healthy.
ADR Guard follows that philosophy.
It is not intended to replace architects, code reviews, or technical discussions.
Its goal is much more pragmatic:
once a team decides to record its architectural decisions, help ensure that this history remains readable, consistent, and trustworthy as the project grows.
Further reading
A great place to start is Michael Nygard's “Documenting Architecture Decisions,” the article that helped popularize the modern ADR format.
The Architectural Decision Records community maintains a useful collection of concepts, templates, and examples, including alternatives such as MADR for teams that want slightly more detailed records.
The AWS Prescriptive Guidance. Using architectural decision records to streamline technical decision-making is also worth reading, especially for its discussion of ADR adoption, lifecycle, and team workflows.
Another useful reference is The GDS Way, Documenting architecture decisions, from the UK Government Digital Service, which presents a pragmatic approach to keeping architectural decisions close to the code.
And, of course, you can explore ADR Guard itself. Beyond the implementation, the ADRs maintained inside the repository provide small real-world examples of how to document not only what was decided, but also the context and consequences behind each decision.
References
Michael Nygard — Documenting Architecture Decisions
https://cognitect.com/blog/2011/11/15/documenting-architecture-decisionsArchitectural Decision Records
https://adr.github.io/AWS Prescriptive Guidance — Architectural Decision Records
https://docs.aws.amazon.com/prescriptive-guidance/latest/architectural-decision-records/welcome.htmlThe GDS Way — Documenting architecture decisions
https://gds-way.digital.cabinet-office.gov.uk/standards/architecture-decisions.htmlADR Guard — GitHub
https://github.com/rodri-oliveira-dev/adr-guard
Top comments (0)