mdwright
mdwright is a Markdown linter and round-trip formatter for any Markdown project.
Four commitments shape the tool.
Fast. On a 79-file corpus of math-heavy technical prose, mdwright fmt-check runs ≥ 50× faster than
mdformat --check. The multiplier scales with file count and core count; see Performance
for the measurement, host, and reproducer. Design choices that buy this are in
Architecture.
Round-trip safe. mdwright fmt renders to the same HTML before and after; every change in the rendered DOM is
treated as a bug. Whitespace inside a paragraph may shift (a b becomes a b), but word boundaries and the rendered
tree do not. Where the formatter cannot prove equivalence it refuses to rewrite; the deviation table
lists every exception with a reproducer.
Configurable, preserve by default. Source style choices — emphasis delimiters, list markers, thematic breaks,
link-destination angle brackets — pass through untouched. Canonicalisation is opt-in one knob at a time in
.mdwright.toml, or via fmt.profile = "mdformat" for mdformat-compatible spelling where verified rewrites preserve
the parsed document.
Math-resilient. \( … \), \[ … \], and \begin{NAME} … \end{NAME} pass through verbatim. The scanner identifies
math regions before any other pass touches the document, so the formatter never reflows \frac{a}{b} into
\\frac{a}{b} and the linter never flags a backslash inside \begin{align*}. See
Math regions for the design.
Who this site is for
- Users writing Markdown with math, code, or strict formatting requirements: start with Getting started.
- CI operators wiring mdwright into pre-commit, GitHub Actions, or other automation: Integration.
- Rule authors extending mdwright with project-specific lints: Extending → Lint rules.
The narrative pages (concepts, extending) explain the why; the reference pages (rules, CLI, public API, diagnostic schema) are the source-of-truth what.
Stability
mdwright is pre-1.0. The release surface, including public Rust API, CLI, configuration schema, diagnostic JSON, and lint-rule trait, is documented descriptively at Public API; minor versions may include breaking changes until 1.0, patch releases never do. See Semver policy.