Skip to content

markdown-contract

Teams keep decision records, runbooks, and planning docs in markdown — but nothing guarantees those documents keep the shape your team and tooling rely on. markdown-contract lets you declare a contract per document type (frontmatter fields, section structure, table shapes, custom rules) and gives you back two things from one parse:

  • Validation — findings with path:line positions, as human text, JSON, or SARIF, with CI-ready exit codes.
  • A typed model — the contract that checks a document also types it: doc.frontmatter.status, doc.body.summary.text(), iterable typed table rows.
import { contract, sections, section } from "markdown-contract";
import { z } from "zod";
const decision = contract({
frontmatter: z.object({ status: z.enum(["proposed", "accepted"]) }),
body: sections({ allowUnknown: true }, [section("Summary"), section("Decision")]),
});
decision.validate(src, { path: "D-0001.md" }); // findings with path:line positions
decision.read(src, { path: "D-0001.md" }); // typed Doc: frontmatter + body model

Contracts can also be pure YAML — no code at all — and a declarative config maps directories and globs to contracts, so validating a whole docs tree is configuration. See Getting started.

  • Why markdown-contract — the gap it fills and the design drivers.
  • How it works — one parse, three validation planes, one finding shape, and the typed model.
  • Getting started — validate a folder from the terminal, then author a contract in YAML or TypeScript.

The example catalog is a curriculum: eight short ladders of small, runnable examples, each rung building on the one before it. Every shipped artifact is regression-checked against the real CLI and library, so what you read is what the tool actually does.

  1. CLI Quickstart: Validate from the Terminal — 12 rungs, starting with CLI-01: Validate one clean file, see exit 0.
  2. Scaffold and Guard: init, Inference, and Drift Checks — 10 rungs, starting with INFERENCE-INIT-01: Scaffold a contract from a folder of notes.
  3. Declarative YAML: Contracts and Corpus Config, No Code — 20 rungs, starting with DECLARATIVE-YAML-01: Validate one required frontmatter field by type.
  4. Authoring Contracts in Code: Structure, Content, and Custom Rules — 17 rungs, starting with VALIDATION-PLANES-01: Parse markdown into a DocTree.
  5. Consume as Typed Data: Reading the Document as a Model — 11 rungs, starting with CONSUME-AS-DATA-01: Open the read() door for typed frontmatter.
  6. Dialect: Anchors, Wikilinks, and Vault References — 11 rungs, starting with DIALECT-01: Anchor a block, resolve it with byAnchor.
  7. Embed and Automate: the Runner Library and CI Gates — 11 rungs, starting with EMBED-AND-CI-01: Run the corpus in-process.
  8. Real-World Schemas: Document Templates and Cross-Document Governance — 16 rungs, starting with REAL-WORLD-SCHEMAS-01: ADR: require the four sections in order.