Documentation · 日本語ドキュメント · Getting started · Rules
For AI agents: llms.txt indexes the docs; llms-full.txt has the full text in one fetch; the AI agents guide covers the ready-made adopt-madr-lint / new-adr skills.
A fast, configurable linter for MADR (Markdown Architectural Decision Records). It validates the things a plain Markdown linter can't: required sections, a valid status, ISO-8601 dates, filename convention, and cross-file integrity like unique numbering and non-broken links — across MADR v2, v3, and v4.
MADR ships no official linter, and the general-purpose tools each cover only part of what an ADR collection needs:
| Tool | Markdown style | Inter-doc links | ADR numbering | Status enum | Date format | Supersedes graph | v2 bold-list | Autofix |
|---|---|---|---|---|---|---|---|---|
| markdownlint-cli2 | ✅ | — | — | — | — | — | n/a | ✅ |
| lychee | — | ✅ | — | — | — | — | n/a | — |
| adrs (rust) | — | — | ✅ (init) | — | — | ~ | — | — |
| madr-lint | —¹ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ~ (3/8 rules) |
¹ Deliberately not Markdown style — pair it with markdownlint-cli2 if you want both. madr-lint owns the ADR-specific semantics.
- MADR v2 / v3 / v4 aware — reads YAML frontmatter and v2 body-list metadata (both
- **Status**:and canonical* Status:), or auto-detects per file. - ESLint-style rules — named
madr/*rules witherror/warn/offand per-rule options validated by a JSON Schema. - Per-file & cross-file — fast single-pass checks plus project rules for unique numbering, the supersedes graph, and link rot.
- CLI, library & CI —
text/json/sarif/githubreporters, a programmatic API, and a drop-in GitHub Actions step. - Autofix —
--fix/--fix-dry-runmechanically repair the violations that have a safe, unambiguous correction (3 of 8 rules today); everything else still reports with asuggestion. - Gradual adoption — inline suppression comments for one-off exceptions and a baseline file to snapshot legacy debt so only new violations fail the build.
npm install --save-dev madr-lint # or: pnpm add -D madr-lint / yarn add -D madr-lintNode.js 22+. ESM-only. Ships TypeScript types.
# Scaffold a config — detects your ADR directory and MADR version
npx madr-lint init
# Lint the configured adrDir (default: docs/adr)
npx madr-lint
# Auto-repair what's mechanically fixable, then re-lint
npx madr-lint --fix
# Explicit paths (files or directories; directories are searched recursively)
npx madr-lint docs/adr libs/x/adr
# Machine-readable output for CI
npx madr-lint --format sarif > madr-lint.sarifExit code: 0 clean · 1 on error-level diagnostics or an exceeded --max-warnings threshold · 2 on a config problem.
A madr-lint.config.ts (or .madrlintrc.json) at your project root:
import { defineConfig } from 'madr-lint';
export default defineConfig({
extends: ['madr-lint:recommended'],
madrVersion: 'auto',
adrDir: 'docs/adr',
ignorePatterns: ['**/template.md', '9999-*'],
rules: {
'madr/filename-format': ['error', { pattern: '^[0-9]{4}-.+\\.md$' }],
'madr/no-numbering-gap': 'off',
},
});Rule values are a severity ('error' | 'warn' | 'off') or a [severity, options] tuple. Options are validated — an invalid option fails fast with exit code 2. Full reference: Configuration.
8 rules — 7 enabled by recommended, 1 opt-in. 🔧 marks the 3 rules --fix can repair. Each page documents its options, examples, and MADR-version compatibility.
| Rule | Type | Default | Checks |
|---|---|---|---|
madr/required-sections |
per-file | error |
Required heading sections are present |
madr/status-enum 🔧 |
per-file | error |
status is one of the allowed values |
madr/date-iso8601 🔧 |
per-file | error |
date is a valid ISO-8601 calendar date |
madr/filename-format |
per-file | error |
Filename matches the ADR convention |
madr/no-broken-links |
project | error |
Relative links resolve to existing files |
madr/no-duplicate-numbering |
project | error |
ADR numbers are unique |
madr/supersedes-bidirectional 🔧 |
project | error |
supersedes / superseded-by agree |
madr/no-numbering-gap |
project | off |
ADR numbers are contiguous (opt-in) |
madr-lint ships a composite GitHub Action that annotates the PR diff directly:
# .github/workflows/adr-lint.yml
jobs:
madr-lint:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 22 } # madr-lint requires Node ≥22
- uses: knktkc/madr-lint@v0
with: { path: docs/adr }The floating
v0tag tracks the latest v0.x release; for stricter reproducibility, pin an exact tag like@v0.4.0.
Or run it via npx in any CI provider:
- uses: actions/setup-node@v4
with: { node-version: 22 }
- run: npx madr-lintThe sarif reporter integrates with GitHub code scanning — see GitHub Action.
import { runRulesOnFile, buildProjectFile, rules } from 'madr-lint';
const diagnostics = runRulesOnFile(
[rules.requiredSections, rules.statusEnum],
{ path: '0001-x.md', content },
{ severity: 'error' },
);Full surface: Programmatic API.
madr-lint intentionally skips Markdown style — compose it:
markdownlint-cli2 'docs/adr/**/*.md' # Markdown style
lychee 'docs/adr/**/*.md' # external link rot
madr-lint docs/adr # ADR structure + inter-ADR linksAlpha. Self-dogfooded (this repo lints its own ADRs) and validated against an external repository. Until 1.0, treat each minor bump as potentially breaking; the 1.0 gate is adoption feedback.
Issues and PRs welcome. See CONTRIBUTING.md for the dev setup, rule-shape guide, and TDD/changeset workflow. The project dogfoods its own linter against its own ADRs in docs/adr/.
MIT © t.kaneko