Command reference
The adr binary (published as @adrkit/cli) is a small set of deterministic
commands. Run adr with no arguments or adr --help for task-oriented command
discovery and common workflows. Run any command with --help, or
adr help <command>, for its arguments, options, examples, and exit codes.
Compact synopsis:
adr lint [paths...] [--json] [--dir docs/adr]adr migrate --from madr [--dir docs/adr] [--dry-run] [--rename] [--json]adr new <title> [--status draft] [--dir docs/adr] [--json]adr graph [--dir docs/adr] [--format auto|terminal|dot|json|mermaid] [--focus ID] [--kind supersedes|relatesTo|conflictsWith]adr explain <path> [--dir docs/adr] [--json]adr check <files...> [--dir docs/adr] [--json]adr evaluate <proposal-path> --snapshot <bundle.json> --date YYYY-MM-DD [--json] [--dir docs/adr]adr queue [--dir docs/adr] [--as-of YYYY-MM-DD] [--format markdown|json]adr completion <bash|zsh|fish>
adr help [command] Show help, or help for one commandadr --version Print the @adrkit/cli versionadr --color <mode> <command> [options] Colorize human-readable outputFind commands and recover from mistakes
Section titled “Find commands and recover from mistakes”Running adr with no arguments prints the top-level help to stdout and exits
0. The help groups commands by the task they perform, includes common
workflows, and points to this reference. adr help <command> and
adr <command> --help print the same focused command help.
Usage errors stay on stderr and exit 2. Instead of appending the full global
help, a command error prints that command’s usage and points to
adr help <command>. Near-miss command names and long options suggest the
closest documented spelling. The closed value sets for new --status,
graph --format, migrate --from, queue --format, and
completion <shell> do the same:
Error: Unknown option "--jsn". Did you mean "--json"?
Usage: adr lint [paths...] [options]Run 'adr help lint' for more information.Suggestions are conservative: an unrelated command, option, or value is rejected without guessing.
Global color and stable machine output
Section titled “Global color and stable machine output”--color auto|always|never is a global option. Put it before the command for
the clearest invocation:
adr --color always lintBoth --color always and --color=always are recognized anywhere before the
-- argument terminator. After --, --color is an ordinary positional value.
| Mode | Meaning |
|---|---|
auto |
Default. Color each human-readable output stream only when that stream is a TTY and NO_COLOR is unset. |
always |
Force color for human-readable output, including redirects and pipes; this explicit choice overrides NO_COLOR. |
never |
Disable color. |
Stdout and stderr are detected independently, so redirecting one does not
change the other. Color changes presentation only: exit codes and the
stdout/stderr split are unchanged. Machine-oriented output remains ANSI-free
even under --color always, including JSON, DOT, Mermaid, generated completion
scripts, and the canonical queue Markdown format.
adr lint
Section titled “adr lint”Validate the ADR corpus. With no paths, every discoverable record under --dir
is checked.
| Option | Meaning |
|---|---|
--dir <path> |
ADR corpus directory (default: docs/adr) |
--json |
Emit { checked, findings } as JSON |
--help |
Show help and exit |
Exit codes: 0 no error findings · 1 one or more error findings · 2
usage error (invalid invocation or unreachable corpus directory).
adr migrate
Section titled “adr migrate”Migrate a MADR corpus in place, adding adrkit frontmatter and leaving the body untouched. One-way and non-destructive; round-trip sync is unsupported (ADR-0008).
| Option | Meaning |
|---|---|
--from madr |
Source format (required; only madr is supported) |
--dir <path> |
ADR corpus directory (default: docs/adr) |
--dry-run |
Report what would change without writing |
--rename |
Rename each migrated file to <id>-<slug>.md so corpus discovery can see it |
--json |
Emit the migration result as JSON |
--help |
Show help and exit |
Exit codes: 0 migration ran (findings are reported but do not fail the
run) · 2 usage error (missing or unsupported --from, unknown flag,
positional argument, or unreachable corpus directory).
adr new
Section titled “adr new”Scaffold a new ADR record.
| Option | Meaning |
|---|---|
--status <status> |
Initial status (default: draft) |
--dir <path> |
ADR corpus directory (default: docs/adr) |
--json |
Emit { id, path } as JSON |
--help |
Show help and exit |
Exit codes: 0 created · 1 refused to overwrite an existing file · 2
usage error.
adr graph
Section titled “adr graph”Render the decision graph (supersedes, relatesTo, conflictsWith) for the
corpus.
| Option | Meaning |
|---|---|
--dir <path> |
ADR corpus directory (default: docs/adr) |
--format auto|terminal|dot|json|mermaid |
Output format (default: auto) |
--focus <id> |
Keep one ADR, its incident relationships, and their endpoints |
--kind <kind> |
Keep supersedes, relatesTo, or conflictsWith; repeat to include more kinds |
--help |
Show help and exit |
auto selects the compact terminal instrument only when stdout is a TTY. Pipes,
redirects, captured subprocesses, and CI continue to receive deterministic DOT,
so existing adr graph | ... workflows do not change. Explicit formats always
win.
The terminal view shows status and relationship counts. Sparse and focused
graphs include their relationship map; dense corpora show the most connected
decisions and point to --focus/--kind instead of drawing an unreadable
hairball. Large sparse and focused views are bounded as well; select another
kind or a machine format for the complete edge set.
adr graphadr graph --focus 0014adr graph --kind supersedesadr graph --kind supersedes --kind conflictsWith --format jsonadr graph --format mermaid > decisions.mmdadr graph --format dot | dot -Tsvg > decisions.svgDOT, Mermaid, and JSON are deterministic and ANSI-free. The JSON envelope stays
{ nodes: [{ id, title, status }], edges: [{ from, to, kind }] }.
Graph still emits the complete projection of valid records when the corpus also contains invalid records. Those error findings go to stderr.
Exit codes: 0 rendered without corpus errors · 1 rendered with one or
more corpus errors · 2 usage error (invalid invocation, unreachable corpus
directory, unknown focus id, or invalid format/kind).
adr explain
Section titled “adr explain”Report which decisions govern one repo-relative path, and why.
A decision reaches a path in two directions, and explain keeps them apart:
Decisions governing src/services/sync/retry.ts: 0009 [accepted] Resolve affects deterministically via path: src/services/sync/** 0012 [accepted] Bind catalog entities to owned paths declared by src/services/sync/retry.ts:3 (@adr 0012)via is the record reaching out through its own affects pattern.
declared by is the file reaching in with an @adr marker — see
inbound @adr markers below.
| Option | Meaning |
|---|---|
--dir <path> |
ADR corpus directory (default: docs/adr) |
--json |
Emit { path, governedBy, governing, activeProposals, history, markers, findings } |
--help |
Show help and exit |
Exit codes: 0 explained · 1 corpus has error findings · 2 usage error
(invalid invocation or unreachable corpus directory).
Inbound @adr markers
Section titled “Inbound @adr markers”A record declares the paths it governs with affects. That pattern has to be
broad enough to cover a subsystem, and breadth is what costs an agent context.
An inbound marker lets affects stay narrow: any other file opts in with one
line, at zero cost until something reads that file.
// @adr 0012export function syncOnce() { … }- The grammar is
@adrfollowed by whitespace and an ADR id (0012, orpayments:0012for a federated log). A comma continues a list —@adr 0012, 0013. A bare space ends it, so@adr 0012 1234567is one declaration followed by a number, not two declarations. - Any language. adrkit does not parse your file. A marker must be on its own
comment line: after optional whitespace, one of
//,/*,{/*,*,#,--,;,%,<!--,""",'''begins the line and@adris the comment’s first content. A trailing} // @adr 0012does not declare the file. - Not inside a fenced block. A marker between backtick or tilde fences is an example of the syntax rather than a use of it, so documenting the feature does not make your documentation governed by the decision you used as the example. A fence closes only on a line of at least as many of the same character and nothing else, and an unclosed fence runs to the end of the scanned window (ADR-0023).
- In markdown, use a markdown comment. In
.md,.mdx, and.markdownonly<!--and{/*declare.#is a heading and*is a list bullet: they render, so they are content rather than comments, and# @adr 0012does not declare the file. Every other introducer above belongs to a source language and is ignored there. - At most the first 8192 bytes of a file are scanned, and the scan stops at the
last complete line inside that bound —
--jsonreports the extent it reached. A marker is a claim that the file lives under a decision; a mention far down the file is prose about that decision. - At most 64 declarations per file are retained in physical/source order.
--jsonreports the exact total and omitted count, and human output says when declarations were omitted. - Nothing enters the record. The edge is discovered when you run
explainorcheck. There is no schema change and no newaffectsmatcher type (ADR-0021).
A marker naming a record the corpus does not have is a dangling-marker
finding at warn. A log-qualified marker is marker-unresolvable at info —
inert against this corpus, not broken. A marker naming a superseded,
rejected, or deprecated record is a stale-marker warning. It still binds
to that historical record, and a superseded chain names its terminal live
successor when one can be resolved; adrkit never silently substitutes the
successor. None of these marker findings changes the exit code.
The --json output reports what was actually scanned, so an empty result never
has to be guessed at:
"markers": { "state": "scanned", "windowBytes": 8192, "scannedBytes": 1582, "fileBytes": 1582, "truncated": false, "declarationLimit": 64, "totalDeclarations": 1, "omittedDeclarations": 0, "declared": [{ "ref": "0012", "line": 3 }]}state is scanned, absent (no such file), unreadable (not a regular file,
or permission denied), or out-of-tree. truncated is true when the file is
longer than the header window, so a marker below it was never seen — and
truncated: false is what makes declared: [] mean “nothing declares this path”
rather than “we stopped reading first”.
scannedBytes and fileBytes report the observed scan extent. When
truncated is true, use Math.max(0, fileBytes - scannedBytes) to estimate
the unscanned remainder; the values are measured separately and may differ if
the file changes during the scan.
In governedBy, a pattern match carries firedMatchers and a file declaration
carries declaredBy; declaredBy is omitted entirely when nothing declared the
record.
<path> is repo-relative, the same contract affects patterns are matched
against. Absolute and traversing paths are out-of-tree. Every symlink is
refused as unreadable before its target is resolved, including symlinked parent
directories and safe in-tree symlinks, so a fork PR cannot probe target existence
or permissions.
adr check and the governing-decisions Action scan markers from the changed
paths before calling the pure resolver. They normalize, deduplicate, and sort
paths; scan the first 3,000 with at most 16 reads in flight; and expose exact
absent and skipped paths through markerScan. Paths beyond the cap still take
part in affects matching, but their markers are not read. A non-blocking
marker-scan-capped warning makes that loss explicit.
After reads complete, the batch retains at most 10,000 declarations in
code-unit path then physical/source order. markerScan.declarations reports
exact total, retained, per-file-omitted, and batch-omitted counts. Any overflow
collapses into one marker-declarations-capped warning rather than one finding
per dropped declaration.
The cap is GitHub’s own changed-file ceiling. The Action refuses to evaluate a
pull request whose file list hit that ceiling, so every diff it does answer is
scanned completely and only a local adr check can reach the cap.
adr check
Section titled “adr check”Report the decisions governing a set of changed files, and validate any changed records. Deterministic and provider-agnostic — the primitive the CI Action builds on.
| Option | Meaning |
|---|---|
--dir <path> |
ADR corpus directory (default: docs/adr) |
--json |
Emit the CheckOutcome as JSON |
--help |
Show help and exit |
Exit codes: 0 ok · 1 a changed record has an error finding · 2 usage
error (invalid invocation or unreachable corpus directory).
Marker declarations render as declared by, separately from record-authored
via matchers. --json includes markerScan state counts and exact unavailable,
truncated, and skipped path lists. Marker-derived information never changes the
exit code; only validation errors on changed ADR records do.
adr evaluate
Section titled “adr evaluate”Run the deterministic evaluator over one proposal against an offline snapshot
bundle. The evaluator routes; it never approves, persists, or writes. There
is no --write.
| Option | Meaning |
|---|---|
--snapshot <path> |
Snapshot bundle (required) |
--date <date> |
Evaluation date, YYYY-MM-DD (required) |
--dir <path> |
ADR corpus directory |
--json |
Emit the evaluation report as JSON |
--help |
Show help and exit |
Exit codes: 0 evaluated (including warn/info/inert and escalation) · 1
the proposal was returned on a rubric error · 2 usage error, unreachable
corpus directory, or malformed snapshot bundle.
adr queue
Section titled “adr queue”Emit the ARB operations queue report for the local ADR corpus to stdout — a
read-only, deterministic projection of the corpus’s review metadata. Identical
inputs produce byte-for-byte identical output. See Use in CI for the
managed-issue Action.
| Option | Meaning |
|---|---|
--dir <path> |
ADR corpus directory (default: docs/adr) |
--as-of <date> |
UTC calendar date for SLA computation (default: today, UTC). Accepts YYYY-MM-DD or an ISO datetime with an explicit timezone (e.g. 2026-01-08T00:00:00Z); timezone-less datetimes are rejected. |
--format markdown|json |
Output format (default: markdown) |
--help |
Show help and exit |
Exit codes: 0 report, no error findings · 1 report emitted with
error-severity corpus findings · 2 usage error (invalid flag/value or
unreachable corpus directory).
adr completion
Section titled “adr completion”Write a deterministic completion script for Bash, Zsh, or Fish to stdout:
adr completion <bash|zsh|fish>The generated definitions cover top-level commands, each command’s documented
options, and closed value sets such as --format and --status. They register
both adr and the adrkit binary alias where the shell format permits.
| Argument or option | Meaning |
|---|---|
<shell> |
Required; one of bash, zsh, or fish |
--help |
Show help and exit |
Exit codes: 0 script emitted · 2 usage error (missing or unsupported
shell).
Shells commonly lazy-load completion definitions by filename. Install the same
generated script under both the adr and adrkit names so completion works
regardless of which binary you type first.
mkdir -p ~/.local/share/bash-completion/completionsadr completion bash > ~/.local/share/bash-completion/completions/adrcp ~/.local/share/bash-completion/completions/adr \ ~/.local/share/bash-completion/completions/adrkitThis location is loaded by bash-completion. Reload the shell after installing the files. For only the current shell, source the generated script directly:
source <(adr completion bash)mkdir -p ~/.zsh/completionsadr completion zsh > ~/.zsh/completions/_adrcp ~/.zsh/completions/_adr ~/.zsh/completions/_adrkitAdd the directory to fpath before your existing compinit setup, then reload
the shell:
fpath=(~/.zsh/completions $fpath)autoload -Uz compinitcompinitmkdir -p ~/.config/fish/completionsadr completion fish > ~/.config/fish/completions/adr.fishln -sf ~/.config/fish/completions/adr.fish \ ~/.config/fish/completions/adrkit.fishCopying adr.fish to adrkit.fish works too. Fish discovers either file
automatically; no shell restart is required.
adr help · adr –version
Section titled “adr help · adr –version”adr help prints the global synopsis; adr help <command> prints one command’s
help (identical to adr <command> --help). adr --version (or -V) prints the
@adrkit/cli version. Both exit 0.