Architecture Decision Records (ADRs)
This directory contains Architecture Decision Records - documents that capture important architectural choices made during DaedalusOS development.
What is an ADR?
An ADR documents why a significant technical decision was made. It captures:
- The problem or choice faced
- Alternatives considered
- The decision and rationale
- Consequences and trade-offs
ADRs are lightweight (typically 100-400 lines) and focus on decision rationale, not implementation details.
When to Write an ADR
Write an ADR when:
✅ “Would future-me wonder why this design exists?”
Specific triggers:
- One-way doors: Hard-to-reverse decisions (e.g., target platform, no multi-arch)
- Non-obvious trade-offs: Choices where alternatives had merit (e.g., QEMU version requirement)
- Future-facing design: Adding abstraction/complexity now for future benefit (e.g., NetworkDevice trait)
- Breaking conventions: Deviating from common patterns (with good reason)
- External dependencies: Requiring specific versions/tools (e.g., QEMU 9.0+)
Don’t write ADRs for:
- ❌ Implementation details (those go in module docs)
- ❌ Obvious choices (e.g., “use Rust for Rust project”)
- ❌ Easily reversible decisions (refactorings, minor API changes)
- ❌ Temporary workarounds (comment in code is sufficient)
ADR Template
# ADR-XXX: Decision Title
**Status**: Accepted | Proposed | Deprecated | Superseded by ADR-YYY
**Date**: YYYY-MM-DD
**Decision**: One-sentence summary of the decision.
## Context
What problem are we solving? What constraints exist?
What alternatives were considered?
## Decision
What did we decide to do?
(Keep this section concise - 1-3 paragraphs)
## Rationale
Why this decision over alternatives?
- Reason 1
- Reason 2
- ...
### Alternatives Considered
**Alternative 1: [Name]**
- Pros: ...
- Cons: ...
- Why rejected: ...
**Alternative 2: [Name]**
- Pros: ...
- Cons: ...
- Why rejected: ...
## Consequences
### Positive
- Benefit 1
- Benefit 2
### Negative
- Cost 1
- Cost 2
### Neutral (optional)
- Side effect 1
## Related Decisions
- [ADR-XXX: Related Decision](adr-xxx.md) - How it relates
## References
- [External source 1](https://...)
- [External source 2](https://...)
Best Practices
1. Context Before Decision
Explain the problem and show alternatives before stating what you chose. This prevents “obvious in hindsight” bias.
Good:
## Context
We need to support multiple network devices (Pi 4 GENET, future Pi 5, QEMU mock).
Three approaches:
- A) Direct GENET usage (no abstraction)
- B) Full trait abstraction now
- C) Minimal trait now, implement later
## Decision
Chose option C: Minimal trait now...
Bad:
## Decision
We're using a trait for network devices.
## Context
This lets us support multiple devices...
2. Acknowledge Trade-offs
Good ADRs admit downsides. No decision is perfect.
Good:
### Negative
- Setup complexity: Users must build QEMU from source
- CI build time: ~4 minutes on first run
Bad:
### Consequences
- Better testing
- More accurate emulation
(No admission of downsides)
3. Status Lifecycle
Proposed → Accepted → [Deprecated | Superseded]
- Proposed: Under discussion, not yet implemented
- Accepted: Implemented and active
- Deprecated: No longer recommended, but code remains
- Superseded by ADR-XXX: Replaced by new decision
Update status when circumstances change.
4. Link Related ADRs
Decisions often build on or conflict with previous ones:
## Related Decisions
- [ADR-001: Pi 4 Only](adr-001-pi-only.md) - Why we need raspi4b specifically
- [ADR-003: Network Abstraction](adr-003.md) - Plans for multi-device support
Numbering Convention
ADRs are numbered sequentially with zero-padding:
adr-001-pi-only.mdadr-002-qemu-9.mdadr-003-network-device-trait.md
Numbers are permanent. If ADR-002 is superseded, we create ADR-004 (not rename ADR-002).
File Naming
Format: adr-NNN-short-slug.md
Examples:
- ✅
adr-001-pi-only.md - ✅
adr-002-qemu-9.md - ❌
adr-1-raspberry-pi-4-only-target-platform.md(too long, no zero-padding)
Examples in This Project
ADR-001: Raspberry Pi 4 Only
Type: Platform choice (one-way door) Demonstrates: Clear rationale for rejecting multi-platform, detailed reversal plan
ADR-002: QEMU 9.0+ Requirement
Type: External dependency requirement Demonstrates: “Why Not” alternatives section, multiple implementation options
ADR-003: Network Device Abstraction
Type: Future-facing design (abstraction for 1 implementation) Demonstrates: Three options with honest pros/cons, migration path, design pattern comparisons
ADR-004: Linux Kernel Filesystem Structure
Type: Code organization (maintainability choice) Demonstrates: Practical benefits prioritized over strict conformance, clear deviation policy
ADR-005: Multi-Board Support Strategy
Type: Future-facing architecture (multi-platform preparation) Demonstrates: Hybrid approach reasoning, four alternatives compared, deferred implementation
Anti-Patterns to Avoid
❌ “Implementation Masquerading as ADR”
# ADR-006: UART Driver Implementation
## Decision
The UART driver uses PL011 registers at 0xFE201000...
→ This is implementation detail, belongs in module docs.
❌ “No Alternatives Shown”
## Decision
We use Rust.
→ If there’s no real choice, don’t write an ADR.
❌ “Bias Toward Decision”
## Alternatives
1. Direct GENET usage - terrible, inflexible, bad
2. Trait abstraction - perfect, elegant, future-proof
→ Be honest about trade-offs.
ADR Workflow
- Identify decision: Recognize a significant architectural choice
- Draft ADR: Use template, fill in context/alternatives
- Discuss if needed: For team projects; solo projects can skip
- Implement: Make the change
- Finalize ADR: Update with actual implementation details
- Commit together: ADR and implementation in same PR/commit
For DaedalusOS (solo project), ADRs can be written during or after implementation, as long as rationale is captured while fresh.
References
- Michael Nygard’s ADR article - Original ADR concept
- ADR GitHub organization - Templates and tools
- Documenting Architecture Decisions - ThoughtWorks guide