mdv check

Validate Markdown documents against their contracts: in a terminal, in CI, or on stdin.

MOTHER, the Nostromo's computer, never sleeps. She doesn't argue, doesn't editorialize — she scans what's in front of her and reports exactly what's wrong. mdv check is your MOTHER for Markdown: point it at a file, get back a verdict and an exit code.

Usage

mdv check [files...] [options]
cat doc.md | mdv check - --schema schema.mdv.md
mdv check --pr body.md

Arguments

  • [files...] — Markdown documents or directories to check; default: every auto-discovered contract and the documents it governs. A *.mdv.md file or a GitHub template is checked as a contract.
  • - — Read one document from stdin (--schema or --pr required).

Output

  • -f, --format FORMAT — stylish (default), compact (one finding per line; what the VS Code $mediva problemMatcher reads), json, sarif, github (GitHub Actions inline annotations; a clean run prints one ✓ line), pr-comment, or issue-comment. The comment formats render a Mediva CI comment; set its marker and grace period with the config comment key.
  • --list — Print every checked document and its contract, not only failures.
  • --fail-on LEVEL — error (default): a gate fails on an error; warning: on any finding; never: exit 0 even when a gate failed (JSON still names the gate that failed; a check that could not run still exits 2). Heuristic (advisory) findings never count as errors.

Scope

  • --new — Only check the documents this branch changed, or whose contract it changed: shorthand for --changed against the merge base with the default branch (GITHUB_BASE_REF, else origin/HEAD, else main). --new=REF picks the branch. Picks files; each is checked in full.
  • --staged — Only check staged Markdown (git index), read as it will be committed. For pre-commit hooks. Picks files; each is checked in full.
  • --changed REV-RANGE — Only check documents that changed in git diff REV-RANGE, or whose contract did (e.g. origin/main...HEAD). Picks files; each is checked in full. Not the same as --change-set.

Contract selection

  • --schema FILE — Use an explicit contract instead of discovering one.
  • --pr — Use the repository's pull request template (.github/pull_request_template.md) as the contract — mdv check --pr body.md.
  • --title TEXT — Supply the PR, issue, or document title validated by title rules.

Context

  • --context FILE — Load JSON title, issue, and value context.
  • --now DATE — Inject the ISO date or datetime read by freshness rules; an explicit context values.now wins.
  • --change-set REV-RANGE — Data, not scope: feed the files and refs changed over REV-RANGE to contracts that check against @change/paths or @change/refs. Does not pick files - that is --changed.
  • --change-set-file FILE — The same change-set data from a JSON file instead of git (mutually exclusive with --change-set).

Sources and resolution

  • --source NAME=FILE[,...] — Pin a declared logical source NAME to a local FILE for this run; wins over the config loader and over a snapshot replay.
  • --resolver URL — Override the config's external-reference resolver endpoint.
  • --resolver-snapshot FILE — Replay an existing resolver snapshot, or resolve live and write one.
  • --source-snapshot FILE — Replay an existing contract-source capture; if FILE is missing, note it and record instead.

Examples

mdv check                                            # check every auto-discovered *.mdv.md → *.md pair
mdv check README.md                                  # check one file against its README.mdv.md sibling
mdv check --schema schema.mdv.md doc.md              # check a file against an explicit contract
mdv check schema.mdv.md                              # check a contract as its own worked example
cat doc.md | mdv check - --schema schema.mdv.md      # check a document piped via stdin
mdv check --pr body.md                               # check a pull request description against .github/pull_request_template.md
gh pr view --json body -q .body | mdv check --pr -   # check an open pull request's description
mdv check -f pr-comment body.md --schema pr.mdv.md   # render findings as a Mediva CI pull-request comment
mdv check --new                                      # only the documents your branch changed (merge base with the default branch)
mdv check --staged                                   # in a pre-commit hook: the staged Markdown, as it will be committed
mdv check --changed main...HEAD -f github            # in CI: annotate the documents a pull request changed

stdin

echo "## Summary" | npx mediva check - --schema pr.mdv.md

- needs --schema or --pr and must be the only target.

The zero-config scan

Run mdv check with no files and it walks the tree, validating every document a contract governs.

ContractChecks
X.mdv.mdthe X.md beside it
_template.mdv.mdevery other *.md in its folder
.mediva/contracts/<path>.mdv.mdthe document at <path>
GitHub template with mdv: rulesitself, compile-checked

Most specific wins: mirror, sibling, then _template.mdv.md.

Skipped by the walkDetail
node_modules, dist, hidden directoriesalways
A directory whose .mdvignore contains a * linethe whole subtree; no usable patterns (empty, comment-only) prunes nothing and says so
A pattern .mdvignoregitignore-style patterns; the walk keeps walking
npx mediva check .git/HOOKS.md --schema h.mdv.md   # an explicit path reaches a pruned area
npx mediva check docs                              # a directory runs the same scan rooted there

When nothing gets checked

CaseWhat you get
Every section of a contract misses the documentunmatched-contract
The scan pairs nothinga note naming what .mdvignore excluded
nothingToCheck: "fail" in configan empty run exits 2
A file you name that no contract governsthe lint gate alone and a no-contract warning; exit 0 unless lint fails

Output

README.md
  State: what the document claims; clear it by doing the work or saying it is not done
  3  error  "Installation" is empty  empty-section
            help: Write the section's content, or "Not specified." if there is none

✖ 1 problem (1 error, 0 warnings)
  mdv explain <rule-id> for details

Every rule id links to the diagnostics reference.

The gates run in order: lint (markdownlint's rules, set by config lint, plus the fence check), shape, then state. Only the first that fails is reported. Lint findings are always errors.

Colour

SettingEffect
terminalcoloured
pipe or fileplain, no escape bytes
FORCE_COLOR=1coloured through a pipe (set it in CI)
NO_COLOR=1plain; FORCE_COLOR wins if both are set
--color / --no-coloroverride all

Output formats

FormatFor
stylishpeople (default)
compactone line per finding (the VS Code $mediva matcher)
jsontooling, stable codes
sarifSARIF 2.1.0 for code scanning
githubinline annotations on the pull request
pr-comment, issue-commenta Mediva CI comment (config comment key)
npx mediva check README.md --schema readme.mdv.md -f json | jq '.results[].diagnostics[].code'
npx mediva check README.md --schema readme.mdv.md -f sarif > mediva.sarif
npx mediva check body.md --schema pr.mdv.md -f pr-comment > comment.md

-f json gives each file's gate (the first gate that failed, null when none did, or "could-not-run"), failed (whether the file fails the run), its diagnostics, and readout once shape passed. --fail-on never changes only the exit code: a file whose gate failed still says failed: true, and a check that could not run still exits 2.

github prints ::error, ::warning or ::notice (advisory) per finding:

::error file=docs/guide.md,line=7,col=1,title=mdv(placeholder-text)::Placeholder "TBD" left in "Notes"%0Ahelp: Write the real content, or "Not specified." if unknown

Only what a change touched

npx mediva check --changed origin/main...HEAD -f github   # CI
npx mdv check --new                                       # locally, includes uncommitted work
FlagDoes
--changed REV-RANGEonly documents in git diff REV-RANGE, or whose contract changed
--new--changed against the default branch's merge base
--stagedonly staged documents, read from the git index
--change-setnot scope: feeds @change/paths and @change/refs rules

These pick which documents run, and nothing else: each picked document is checked in full, its old problems with its new ones.

Pre-commit hooks

npx mdv check --staged

Reads the git index. See the pre-commit recipe.

Blocking and advisory findings

--fail-onExits 1 on
error (default)a blocking error
warningany warning; a gate fails on its warnings, so a shape warning stops state
nevernothing

Heuristic rules (vague-evidence, @agent/chatter, truncated-output, …) are advisory: they never fail under --fail-on error.

Checking a contract

npx mediva check pr.mdv.md

Naming a *.mdv.md checks the contract itself: it compiles, its body passes as its own example, and every exemplar value occurs in it.

Exit codes

CodeMeaning
0no errors
1errors (any finding with --fail-on warning)
2could not run: bad option, unreadable file, broken config, broken contract

CI recipes: PR bodies, issue forms, monorepo, changelogs.

External context

{ "issues": [{ "number": 123, "state": "open" }], "title": "Ship the docking checklist" }
npx mediva check PR.md --schema pr.mdv.md --context context.json

issue.state=open reads it, else missing-context. --title "..." sets context.title; there is no H1 fallback.

Configuration

What blocks, severity overrides, plugins: Configuration.

On this page