ADR Writer
Overview
This skill helps you write comprehensive Architectural Decision Records (ADRs) following the MADR (Markdown Architectural Decision Records) format. It enforces consistent structure, thoroughness, and adherence to project conventions.
Prerequisites
- •Understanding of the problem/decision to document
- •Research completed on alternatives and tradeoffs
- •Team discussion completed (if applicable)
- •Clear recommendation ready
Core Rules
- •NEVER use emoji or special characters in ADRs. Use plain ASCII words:
- •Use
CORRECT:for correct examples - •Use
WRONG:for wrong examples - •Use
WARNING:for warnings (not emoji)
- •Use
- •ALWAYS include all required MADR sections (Status, Context, Decision, Rationale, Consequences, Alternatives, References)
- •NEVER reference
AGENTS.mdor.github/copilot-instructions.mdin ADR References section - •ALWAYS use 4-digit numbering (0001, 0002, etc.)
- •ALWAYS update Quick Reference table in
docs/ADR/README.mdafter creating ADR
Workflows
Creating a New ADR
Step 1: Determine ADR Number
Check existing ADRs and use next sequential number:
ls docs/ADR/*.md # If last is 0012, use 0013
Step 2: Create File
Filename format: docs/ADR/XXXX-decision-title-lowercase-hyphenated.md
Example: docs/ADR/0013-graphql-api-strategy.md
Step 3: Follow MADR Structure
Required Sections (in order):
- •Status: Proposed | Accepted | Deprecated | Superseded
- •Context: Problem description, forces, constraints, requirements
- •Decision: Clear statement of what is being decided
- •Rationale: 5-7 reasons why this is the best choice
- •Consequences: Positive, Negative, Neutral impacts
- •Alternatives Considered: 2-4 alternatives with rejection reasons
- •Related Decisions: Links to other ADRs
- •References: Links to docs (NOT AGENTS.md)
- •Notes: Code examples, implementation files, migration paths
Step 4: Write Context Section
Include:
- •Problem Statement: What challenge exists?
- •Technical Requirements: What must the solution provide?
- •Business Requirements: What business value is needed?
- •Design Challenges: What forces are in tension?
- •Related Decisions: Link to ADRs this builds upon
Example:
## Context The application requires object-to-object mapping between domain entities and DTOs. ### Technical Requirements - Domain to DTO mapping for API responses - DTO to Domain reconstruction for requests - Value object conversions (EmailAddress -> string) - Performance: minimal overhead ### Business Requirements - API stability separate from domain changes - Developer productivity (reduce boilerplate) ### Design Challenges - Where to define mappings (Application vs Presentation) - Convention vs explicit configuration - Value object complexity
Step 5: State Decision Clearly
Be specific and actionable:
## Decision Use **Mapster** as the object mapping library with **explicit configurations** defined in module-specific `MapperRegister` classes in the Presentation layer. ### How It Works 1. Each module defines `IRegister` implementation 2. Configure mappings using Fluent API 3. Register via `services.AddMapping().WithMapster()`
Step 6: Provide Strong Rationale
List 5-7 concrete reasons:
## Rationale 1. **Performance**: Mapster generates IL code (10x faster than reflection-based mappers) 2. **Simplicity**: Cleaner API than AutoMapper with less boilerplate 3. **Modern Design**: Built for .NET Core+ with async support 4. **Explicit Control**: MapWith() for value objects is clearer than converters 5. **Predictable**: Less magic, more explicit behavior
Step 7: Document Consequences Honestly
## Consequences ### Positive - Fast IL-generated mappings (minimal overhead) - 100+ lines of manual code eliminated per aggregate - Type-safe compile-time mapping validation - Clear separation between domain and DTOs ### Negative - Learning curve for Mapster API (ForType, MapWith, ConstructUsing) - Explicit configs require more code than pure conventions - Runtime errors if misconfigured (forgot value object conversion) ### Neutral - Requires Mapster NuGet package (stable, maintained) - Configs held in memory (negligible impact)
Step 8: List Alternatives with Rejection Reasons
## Alternatives Considered ### 1. AutoMapper **Description**: Popular object mapper with extensive features. **Pros**: - Mature with extensive documentation - Convention-based auto-mapping **Cons**: - Slower (reflection-based vs Mapster's IL generation) - More complex API with steeper learning curve - Convention magic can be unpredictable **Rejected Because**: Mapster provides better performance with simpler API. ### 2. Manual Mapping (Extension Methods) **Description**: Write ToModel() extension methods manually. **Cons**: - 50-100 lines of boilerplate per entity - Must update manually when properties change - Error-prone (easy to forget new properties) **Rejected Because**: Not maintainable at scale.
Step 9: Link Related Decisions
## Related Decisions - **ADR-0001**: Clean/Onion Architecture - Mapping at Presentation layer boundary - **ADR-0008**: Typed Entity IDs - Mappers convert typed IDs to primitives - **ADR-0011**: Application Logic in Commands/Queries - Handlers use IMapper
Step 10: Add References
## References - [Mapster Documentation](https://github.com/MapsterMapper/Mapster) - [bITdevKit Mapping Extensions](https://github.com/BridgingIT-GmbH/bITdevKit/docs) - Project Documentation: `README.md` (Presentation Layer section) - Module Documentation: `src/Modules/CoreModule/CoreModule-README.md`
IMPORTANT: Never reference:
- •
AGENTS.md - •
.github/copilot-instructions.md
Step 11: Add Implementation Notes
## Notes
### Key Implementation Files
\`\`\`
src/Modules/CoreModule/CoreModule.Presentation/
└── CoreModuleMapperRegister.cs # Mapping configurations
src/Presentation.Web.Server/
└── Program.cs # Registration
\`\`\`
### Usage Pattern
\`\`\`csharp
// In handler
public class CustomerCreateCommandHandler(IMapper mapper, ...)
{
// Map domain to DTO
return mapper.Map<Customer, CustomerModel>(customer);
}
\`\`\`
### Common Patterns
**Value Object Conversion**:
\`\`\`csharp
config.NewConfig<EmailAddress, string>()
.MapWith(src => src.Value);
\`\`\`
**Factory Method Construction**:
\`\`\`csharp
config.ForType<CustomerModel, Customer>()
.ConstructUsing(src => Customer.Create(...).Value);
\`\`\`
Step 12: Use Plain ASCII Characters
CORRECT Usage:
CORRECT: Use typed IDs for type safety WRONG: Use raw Guid everywhere
WRONG Usage (DO NOT DO THIS):
✓ Correct: Use typed IDs ❌ Wrong: Use raw Guid ⚠️ Warning: This is dangerous
Step 13: Update Quick Reference
After creating ADR, edit docs/ADR/README.md and add entry:
| [ADR-0013](0013-graphql-api-strategy.md) | GraphQL API Strategy | Accepted |
Examples
User: "Document the decision to use Entity Framework Core"
Actions:
- •Determine next number: check
ls docs/ADR/*.md(assume 0007) - •Create file:
docs/ADR/0007-entity-framework-core-code-first-migrations.md - •Write comprehensive ADR covering:
- •Context: ORM requirements, code-first vs database-first
- •Decision: EF Core with code-first migrations, DbContext per module
- •Rationale: Type safety, migration system, .NET integration, etc.
- •Consequences: Productivity gains, learning curve, etc.
- •Alternatives: Dapper, NHibernate, manual ADO.NET
- •References: EF Core docs, project README
- •Notes: Code examples, migration commands, file paths
- •Use plain ASCII (CORRECT/WRONG, not emoji)
- •Update
docs/ADR/README.mdQuick Reference table
User: "Create ADR for FluentValidation strategy"
Actions:
- •Check numbering:
ls docs/ADR/*.md(assume 0009) - •Create:
docs/ADR/0009-fluentvalidation-strategy.md - •Write sections:
- •Context: Input validation needs, pipeline integration
- •Decision: FluentValidation in Application layer with nested validators
- •Rationale: Expressiveness, testability, complex rules, separation
- •Consequences: Positive (productivity, fail-fast) and Negative (learning curve, duplication risk)
- •Alternatives: DataAnnotations, manual validation, domain-only
- •Related: Link to ADR-0005 (ValidationPipelineBehavior), ADR-0011/0012 (validation layers)
- •Notes: Validator examples, pipeline order, testing patterns
- •CRITICAL: Use
CORRECT:andWRONG:(NOT emoji) - •Update README Quick Reference
Quality Checklist
Before finalizing, verify:
- • Status is "Proposed" or "Accepted"
- • Context explains problem clearly (2-4 paragraphs)
- • Decision is specific and actionable
- • Rationale has 5+ concrete reasons
- • Consequences include Positive AND Negative
- • At least 2 alternatives shown with rejection reasons
- • Related ADRs linked (if applicable)
- • References included (NOT AGENTS.md)
- • Code examples included in Notes
- • Implementation file paths listed
- • Only plain ASCII used (CORRECT/WRONG, no emoji)
- • Quick Reference table updated in README.md
Common Pitfalls
WRONG:
- •Use emoji or special characters (✅❌⚠️) - use CORRECT/WRONG instead
- •Reference AGENTS.md or .github/copilot-instructions.md
- •Write vague decisions ("use better error handling")
- •Skip Alternatives Considered section
- •Hide negative consequences
- •Make ADRs too short (aim for 7,000-15,000 bytes for technical ADRs)
- •Write implementation docs (belongs in code comments)
CORRECT:
- •Use plain ASCII: CORRECT for correct, WRONG for wrong
- •Write comprehensive context (problem, forces, constraints)
- •Be specific in decision statement
- •List 5-7 rationale points
- •Be honest about tradeoffs (positive AND negative)
- •Show alternatives considered
- •Include code examples in Notes
- •Link to other ADRs and project docs
- •Update README Quick Reference table
Decision Categories
High Priority (Write ADRs)
- •Architectural patterns (Clean Architecture, Modular Monolith)
- •Framework/library choices (EF Core, FluentValidation, Mapster)
- •Cross-cutting concerns (Result Pattern, Validation Strategy)
- •Infrastructure decisions (ORM, messaging, caching)
- •Design patterns (Repository, Outbox, Mediator)
Medium Priority
- •API design decisions (REST conventions, versioning)
- •Security approaches (authentication, authorization)
- •Performance strategies (caching, query optimization)
- •Testing strategies (unit vs integration)
Low Priority (No ADR Needed)
- •Implementation details (specific method logic)
- •Coding style (variable naming, formatting)
- •Trivial/reversible decisions
File Structure
docs/ADR/ ├── README.md # Template + Quick Reference ├── 0001-clean-onion-architecture.md ├── 0002-result-pattern-error-handling.md ├── 0007-entity-framework-core-code-first-migrations.md ├── 0009-fluentvalidation-strategy.md └── 0010-mapster-object-mapping.md
Template Summary
# ADR-XXXX: Title ## Status Accepted ## Context [Problem, challenges, requirements] ## Decision [Clear statement + how it works] ## Rationale [5-7 reasons] ## Consequences ### Positive / Negative / Neutral ## Alternatives Considered [2-4 alternatives with rejection reasons] ## Related Decisions [Links to other ADRs] ## References [Links to docs - NOT AGENTS.md] ## Notes [Code examples, file paths, migration notes]
Validation Rules
Context Section
- •Minimum 2 paragraphs
- •Must include: problem statement, requirements, challenges
- •Should reference related decisions (if building on previous ADRs)
Decision Section
- •Must be specific and actionable
- •Include "How It Works" subsection with implementation approach
- •Use code examples or diagrams where helpful
Rationale Section
- •Minimum 5 reasons
- •Each reason should be a distinct point (not variations)
- •Focus on why not what
Consequences Section
- •Must include both Positive AND Negative
- •Negative consequences cannot be empty (be honest about tradeoffs)
- •Neutral consequences optional
Alternatives Section
- •Minimum 2 alternatives
- •Each alternative must have rejection reason
- •Rejection reasons should be specific (not vague)
Notes Section
- •Must include implementation file paths
- •Should include code examples (2-3 minimum)
- •May include migration path if changing existing code
ASCII Character Usage
ALWAYS use plain ASCII:
CORRECT: Example of correct approach WRONG: Example of wrong approach WARNING: Be careful here NOTE: Important detail
NEVER use emoji or special Unicode:
✓ Correct <- DO NOT USE ❌ Wrong <- DO NOT USE ⚠️ Warning <- DO NOT USE
References
- •ADR Template:
docs/ADR/README.md - •Existing ADRs: Study
docs/ADR/0001-*.mdthrough0012-*.mdas examples - •Project Documentation:
README.md - •Module Documentation:
src/Modules/CoreModule/CoreModule-README.md - •bITdevKit Documentation:
.bdk/docs/