A minimal CLI for an append-only, JSONL-backed architecture decision record.
Records form a directed acyclic graph through optional supersedes edges.
The CLI is the only sanctioned writer, so the file's invariants
(monotonic IDs, valid edges, status consistency) hold by construction.
go install github.com/jryio/adr/cmd/adr@latestadr add \
--title "Use SQLite for local cache" \
--context "Need an embedded store for offline reads" \
--decision "SQLite with WAL mode" \
--consequences "Single-writer; readers concurrent; no networked queries"
adr add \
--title "Switch to BoltDB" \
--context "SQLite write contention from worker pool" \
--decision "BoltDB key/value store" \
--consequences "Lose SQL queries; gain ACID kv" \
--supersedes 1
adr list
adr show 1
adr validateThe ADR file is scoped to the current git repository: from any subdirectory, adr walks up to the nearest .git and uses <git-root>/adr.jsonl. CWD must be inside a git repo unless --file or $ADR_FILE is set.
| Command | Purpose |
|---|---|
add |
Append a new decision; flips any --supersedes IDs |
edit |
Update fields of an active record (--id) |
list |
One line per record: id<TAB>status<TAB>title |
show <id> |
Pretty JSON for one record |
validate |
Schema, ID density, and DAG integrity check |
where |
Print the resolved file path (useful for scripts) |
Every command resolves the ADR file with this precedence (first match wins):
--file <path>flag$ADR_FILEenvironment variable<git-root>/adr.jsonl— the nearest ancestor of CWD containing a.gitentry
If none of these yield a path (CWD is not inside a git repo and no flag/env override is set), the command errors out — no implicit fallback.
adr where prints the resolved path without touching the file. Useful for cat $(adr where) or for confirming which repo you're targeting.
Each line is a single JSON object with these fields:
| Field | Type | Set by | Notes |
|---|---|---|---|
id |
int | tool | monotonic, dense, 1..N |
title |
string | author | free text, ≤80 chars |
context |
string | author | why this came up |
decision |
string | author | what was decided |
consequences |
string | author | trade-offs, follow-ups |
supersedes |
int[] | author | DAG edges, default [] |
status |
enum | tool | active | superseded |
created_at |
RFC3339 | tool | set at add |
updated_at |
RFC3339 | tool | bumped on edit + status flip |
superseded_at |
RFC3339|null | tool | set when flipped |
- File is append-only except (a) tool-driven
status/superseded_at/updated_atwrites, and (b)editonactiverecords. - The CLI takes a sidecar
<file>.lockwhile writing, so twoadrinvocations against the same file are safe. - Hand edits bypass these guarantees. Don't.
See AGENTS.md for engineering conventions.
task tools
task # lint + vet + test
task ci # full pipelineMIT