#10210·jj

Choose a Markdown linter and formatter

Author: joshkaCreated Sep 16, 2026Updated Sep 17, 2026

Following wrapping feedback from @josephlou5, I propose adopting markdownlint with the 20 rules that already pass across all 114 documentation inputs. That needs no initial formatting cleanup.

This should be tool + config, not doc + best intentions. Contributors should have a command or editor setup that produces the formatting we expect, without choosing settings themselves or waiting for review feedback.

Commit the configuration, pin the version, and make installation easy through mise and Nix. Local installation stays optional; CI runs the checks either way. Then enable more rules in small changes toward the defaults or an agreed subset. Revisit Rumdl once it handles our conflict examples correctly.

Requirements

  1. Preserve code examples, links, and MkDocs syntax during the migration, and support MDX for Starlight.
  2. Start with rules that pass today; review further rules and their cleanup separately.
  3. Check line lengths. Rewrapping every existing paragraph is optional.
  4. Share one configuration between the CLI, editors such as VS Code and Vim/Neovim, and GitHub Actions.
  5. Keep installation optional and simple. Prefer Rust or a standalone binary over another runtime dependency.

I've used both markdownlint and Panache and found their configuration straightforward. Both projects have responded quickly to issues and PRs.

markdownlint-cli2 (Node.js)

Pros: individual rule selection, line-length checks, automatic fixes, and VS Code, Vim/Neovim, and GitHub Actions integrations. We have a verified configuration that passes without changing files.

Cons: requires Node.js for the CLI and does not rewrap paragraphs. Some autofixes break MDX, so we should test each additional rule before enabling it.

Rumdl (Rust)

Pros: no Node.js dependency; markdownlint-style rules plus additional checks; MkDocs/MDX modes; VS Code and Neovim/LSP support and a GitHub Action.

Cons: Rumdl fails on four valid pages containing conflict examples, even with every lint rule disabled. I’ve reported this in rumdl#887; we should fix it before adopting Rumdl. Some wrapping and link checks also need work.

Its similar rule set makes a later switch plausible, but we should check the behavior differences against our configuration.

Panache (Rust)

Pros: no Node.js dependency; full formatting and wrapping; VS Code and Neovim support; dedicated GitHub Action.

Cons: more formatting changes than we need now, no advertised MDX support, and changes to rendered admonitions, tabs, code, and links in the tested configurations. Its Pandoc/Quarto support is useful, but doesn't justify adopting it for this first step. See its tool comparison.

Prettier (Node.js)

Pros: MDX support, prose wrapping, editor integrations, and CLI checks for CI.

Cons: requires Node.js, applies broader formatting changes, and broke Starlight builds in both tested wrapping configurations.

Other options

Remark-lint can use the site's MDX and directive parsers, but requires Node.js and several plugins.

Mdformat uses Python and has MkDocs plugins. I haven't established an MDX setup for it.

Investigation notes

The investigation covered all 113 distinct Markdown/MDX source files, plus the generated CLI reference shared by both sites. This includes MkDocs, Starlight, root documents, templates, and other READMEs. Symlinks count once; Rustdoc comments were outside the investigation.

Both unchanged sites build locally. The initial markdownlint configuration enables 20 rules, passes all 114 inputs, and changes no files with --fix.

Tested configuration Files changed Lines added / removed
markdownlint, proposed 20-rule configuration 0 +0 / −0
markdownlint, default autofixes 46 +657 / −904
Rumdl, default rules with MkDocs/MDX settings 55 +1,584 / −1,766
Panache, GFM preserving existing wrapping 53 +1,123 / −891
Panache, GFM with 80-column wrapping 107 +4,548 / −4,214
Panache, Pandoc with 80-column wrapping 107 +7,840 / −7,592
Prettier, preserving existing wrapping 76 +5,695 / −5,771
Prettier, prose wrapping at 80 columns 106 +9,974 / −9,190

Panache used custom settings and skipped MDX files and the generated CLI reference. Rumdl skipped four pages containing conflict examples.

Specific failures in the tested versions:

  • markdownlint-cli2 0.23.2: broad fixes broke an existing MDX page. A separate test deleted a link definition used inside an MDX component.
  • Rumdl 0.2.73: the conflict safeguard reports Unresolved merge conflict; formatting skipped until conflict markers are removed. The line-length check missed prose inside a <TabItem>; broad checks produced false anchor errors, and fixes damaged an include path.
  • Panache 3.11.0: the GFM preserve configuration passed both builds but changed rendered admonitions, tabs, code, and links.
  • Prettier 3.9.7: prose wrapping broke a caution block and both MDX pages. Preserving wrapping also left a Starlight build failure.

Prepared with Codex assistance, including validation against saved test results. I reviewed the evidence, confirmed the recommendation, and chose the wording.