Documentation and ADRs
Overview
Document decisions, not just code. The most valuable documentation captures the why — the context, constraints, and trade-offs that led to a decision. Code shows what was built; documentation explains why it was built this way and what alternatives were considered. This context is essential for future humans and agents working in the codebase.
Workflow notes: For an active track, read docs/tracks/<track-id>/notes.md at phase entry or resume and update it when useful context changes or before handoff. Capture observations, tentative ideas, outcomes, blockers, and next actions with evidence links. Follow the memory-management running-note and document-metadata protocols; honor explicit read-only or file-scope limits and keep writes outside pinned verification or release targets.
When to Use
- Making a significant architectural decision
- Choosing between competing approaches
- Adding or changing a public API
- Shipping a feature that changes user-facing behavior
- Onboarding new team members (or agents) to the project
- When you find yourself explaining the same thing repeatedly
- Authoring or updating capability specs, track documents, saved briefs, or review reports
When NOT to use: Don't document obvious code. Don't add comments that restate what the code already says. Don't write docs for throwaway prototypes.
Document Authoring Workflow
- Resolve ownership before writing. Accepted requirements belong in
docs/specs/<capability>/spec.md; proposals, bugs, plans, tasks, notes, and revision-scoped evidence belong in the activedocs/tracks/<track-id>/. Saved discovery briefs retain their established home. Use the artifact's owning skill for requirements and acceptance criteria; link existing sources instead of duplicating them. - Choose the format for that owner. Capability specs, track documents, and saved workflow briefs or standalone reports use the memory-management document-metadata profile: one YAML header with non-empty string
type,title, anddescription, followed by the existing Markdown sections. Use its descriptive artifact types, such asCapability Specification,Change Specification,Bug Report,Implementation Plan,Task List,Working Notes,Review, orVerification Report. - Keep lifecycle meanings distinct. OKF
statusis document maturity (draft,stable,deprecated); new unreviewed documents start asdraft. Workflow progress may useworkflow_status. ADR decision status, approval evidence, task checkboxes, review verdicts, and evaluated revisions retain their separate meanings. A stable document does not prove that its proposed work is complete or approved. - Preserve evidence while editing. Add optional
sources,generated, orverifiedonly from actual evidence, following memory-management's OKF rules. Preserve unknown fields and historical revision claims; a header migration preserves the body and does not reverify it. Read older headerless documents permissively and honor explicit file-scope, read-only, and pinned-target limits. - Verify the authored result. Parse the header, check required string fields and local source links, and review the diff against the requested scope. Reconcile verified requirement changes through the capability-spec workflow; do not promote a track proposal merely because it now has metadata.
Knowledge concepts inside an OKF bundle follow its concept and index rules: ADRs use Architecture Decision, runbooks use Playbook, and reserved indexes/logs keep their special formats. Established ADR and runbook homes retain their existing format unless a migration is authorized. READMEs, changelogs, general guides, API schemas, rules files, skill/command configuration, and raw evidence retain their native formats. Inline report sections and task entries inherit the containing document's metadata; do not insert extra frontmatter blocks into them.
Architecture Decision Records (ADRs)
ADRs capture the reasoning behind significant technical decisions. They're the highest-value documentation you can write.
When to Write an ADR
- Choosing a framework, library, or major dependency
- Designing a data model or database schema
- Selecting an authentication strategy
- Deciding on an API architecture (REST vs. GraphQL vs. tRPC)
- Choosing between build tools, hosting platforms, or infrastructure
- Any decision that would be expensive to reverse
Match the existing convention first
Before creating an ADR, inspect the available repository context for an established convention — existing ADRs, project instructions, and ADR-related configuration or tooling (e.g. an .adr-dir file). An established convention overrides the defaults below. Match:
- Location and format — e.g.
docs/adr/*.md,Documentation/Decisions/*.rst, a MADR layout, or anadr-toolssetup. Match the existing directory, file extension, and markup (Markdown vs reStructuredText). - Numbering and naming — continue the existing sequence and filename pattern (
ADR-004-Title.rst,0004-title.md, …); don't restart at 001 or introduce a second scheme. - Section headings — reuse the project's heading set rather than imposing this template's.
An established OKF decision collection is also a convention: use its existing bundle location, numbering, type: Architecture Decision, and discovery index. When an ADR home is outside the bundle, preserve that home and link to it rather than creating a competing copy in the bundle.
If the available evidence conflicts, surface the conflict rather than silently introducing another scheme. Only when no convention can be established do you apply the default below.
ADR Template
Store ADRs in docs/decision-records/ with sequential numbering (unless the project already uses another location — see above):
# ADR-001: Use PostgreSQL for primary database
## Decision Status
Proposed | Accepted | Superseded by ADR-XXX | Deprecated
## Date
[Actual decision date, if known]
## Context
We need a primary database for the task management application. Key requirements:
- Relational data model (users, tasks, teams with relationships)
- ACID transactions for task state changes
- Support for full-text search on task content
- Managed hosting available (for small team, limited ops capacity)
## Decision
Use PostgreSQL with Prisma ORM.
## Alternatives Considered
### MongoDB
- Pros: Flexible schema, easy to start with
- Cons: Our data is inherently relational; would need to manage relationships manually
- Rejected: Relational data in a document store leads to complex joins or data duplication
### SQLite
- Pros: Zero configuration, embedded, fast for reads
- Cons: Limited concurrent write support, no managed hosting for production
- Rejected: Not suitable for multi-user web application in production
### MySQL
- Pros: Mature, widely supported
- Cons: PostgreSQL has better JSON support, full-text search, and ecosystem tooling
- Rejected: PostgreSQL is the better fit for our feature requirements
## Consequences
- Prisma provides type-safe database access and migration management
- We can use PostgreSQL's full-text search instead of adding Elasticsearch
- Team needs PostgreSQL knowledge (standard skill, low risk)
- Hosting on managed service (Supabase, Neon, or RDS)
For an ADR authored inside an OKF bundle, prefix the body with the bundle's document header and update its collection index:
---
type: Architecture Decision
title: Use PostgreSQL for the primary database
description: Record the constraints and trade-offs behind the datastore choice.
status: draft
---
The body records whether the decision was proposed or accepted and the evidence for that state. Add provenance only when known; the example date and decision content must be replaced with the actual facts. An established external ADR format remains authoritative for documents in that home.
ADR Lifecycle
PROPOSED → ACCEPTED → (SUPERSEDED or DEPRECATED)
- Don't delete old ADRs. They capture historical context.
- When a decision changes, write a new ADR that references and supersedes the old one.
Inline Documentation
When to Comment
Comment the why, not the what:
// BAD: Restates the code
// Increment counter by 1
counter += 1;
// GOOD: Explains non-obvious intent
// Rate limit uses a sliding window — reset counter at window boundary,
// not on a fixed schedule, to prevent burst attacks at window edges
if (now - windowStart > WINDOW_SIZE_MS) {
counter = 0;
windowStart = now;
}
When NOT to Comment
// Don't comment self-explanatory code
function calculateTotal(items: CartItem[]): number {
return items.reduce((sum, item) => sum + item.price * item.quantity, 0);
}
// Don't leave TODO comments for things you should just do now
// TODO: add error handling ← Just add it
// Don't leave commented-out code
// const oldImplementation = () => { ... } ← Delete it, git has history
Document Known Gotchas
/**
* IMPORTANT: This function must be called before the first render.
* If called after hydration, it causes a flash of unstyled content
* because the theme context isn't available during SSR.
*
* See ADR-003 for the full design rationale.
*/
export function initializeTheme(theme: Theme): void {
// ...
}
API Documentation
For public APIs (REST, GraphQL, library interfaces):
Inline with Types (Preferred for TypeScript)
/**
* Creates a new task.
*
* @param input - Task creation data (title required, description optional)
* @returns The created task with server-generated ID and timestamps
* @throws {ValidationError} If title is empty or exceeds 200 characters
* @throws {AuthenticationError} If the user is not authenticated
*
* @example
* const task = await createTask({ title: 'Buy groceries' });
* console.log(task.id); // "task_abc123"
*/
export async function createTask(input: CreateTaskInput): Promise<Task> {
// ...
}
OpenAPI / Swagger for REST APIs
paths:
/api/tasks:
post:
summary: Create a task
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateTaskInput'
responses:
'201':
description: Task created
content:
application/json:
schema:
$ref: '#/components/schemas/Task'
'422':
description: Validation error
README Structure
Every project should have a README that covers:
# Project Name
One-paragraph description of what this project does.
## Quick Start
1. Clone the repo
2. Install dependencies: `npm install`
3. Set up environment: `cp .env.example .env`
4. Run the dev server: `npm run dev`
## Commands
| Command | Description |
|---------|-------------|
| `npm run dev` | Start development server |
| `npm test` | Run tests |
| `npm run build` | Production build |
| `npm run lint` | Run linter |
## Architecture
Brief overview of the project structure and key design decisions.
Link to ADRs for details.
## Contributing
How to contribute, coding standards, PR process.
Changelog Maintenance
For shipped features:
# Changelog
## [1.2.0] - 2025-01-20
### Added
- Task sharing: users can share tasks with team members (#123)
- Email notifications for task assignments (#124)
### Fixed
- Duplicate tasks appearing when rapidly clicking create button (#125)
### Changed
- Task list now loads 50 items per page (was 20) for better UX (#126)
Documentation for Agents
Special consideration for AI agent context:
- CLAUDE.md / rules files — Document project conventions so agents follow them
- Capability specs — Keep accepted requirements in their canonical specs, with track proposals and reconciliation recorded separately
- Workflow documents — Keep descriptive metadata current and distinguish document maturity from task progress, approval, and evidence
- ADRs — Help agents understand why past decisions were made (prevents re-deciding)
- Inline gotchas — Prevent agents from falling into known traps
Common Rationalizations
| Rationalization | Reality |
|---|---|
| "The code is self-documenting" | Code shows what. It doesn't show why, what alternatives were rejected, or what constraints apply. |
| "We'll write docs when the API stabilizes" | APIs stabilize faster when you document them. The doc is the first test of the design. |
| "Nobody reads docs" | Agents do. Future engineers do. Your 3-months-later self does. |
| "ADRs are overhead" | A 10-minute ADR prevents a 2-hour debate about the same decision six months later. |
| "Comments get outdated" | Comments on why are stable. Comments on what get outdated — that's why you only write the former. |
Red Flags
- Architectural decisions with no written rationale
- Public APIs with no documentation or types
- README that doesn't explain how to run the project
- Commented-out code instead of deletion
- TODO comments that have been there for weeks
- No ADRs in a project with significant architectural choices
- Documentation that restates the code instead of explaining intent
- A document header that converts a workflow or decision status into OKF maturity
- A header migration that rewrites historical evidence or invents authorship or verification
- An existing ADR/runbook home displaced by an unnecessary second convention
Verification
After documenting:
- Authored workflow documents have valid YAML with the appropriate type and non-empty title and description
- Document maturity, workflow progress, decision status, and report verdicts remain distinct
- Metadata and source links reflect actual evidence; unknown fields and historical bodies/revisions are preserved during header adoption
- Existing ADR/runbook conventions and reserved OKF index/log formats remain intact
- ADRs exist for all significant architectural decisions
- README covers quick start, commands, and architecture overview
- API functions have parameter and return type documentation
- Known gotchas are documented inline where they matter
- No commented-out code remains
- Rules files (CLAUDE.md etc.) are current and accurate