Rust Apache-2.0

mado

A fast Markdown linter written in Rust.

A

akiomik

Dernière activité 29 sept. 2026
akiomik/mado

413

étoiles

12

forks

43

issues ouvertes

github-actionslintermarkdownrust

Ce README est souvent en anglais.

Mado

CI codecov

A fast Markdown linter written in Rust. Compatible with CommonMark and GitHub Flavored Markdown (GFM).

Usage

mado check .
mado check path/to/*.md

Performance

Approx. 49-60x faster than existing linters (e.g. markdownlint).

---
config:
    xyChart:
        height: 200
        titleFontSize: 14
        chartOrientation: horizontal
        xAxis:
            labelFontSize: 12
            titleFontSize: 14
        yAxis:
            labelFontSize: 12
            titleFontSize: 14
---
xychart-beta
    title "Linting ~1,500 Markdown files (Lower is faster)"
    x-axis ["mado (rust)", "markdownlint-cli (node.js)", "markdownlint (ruby)", "markdownlint-cli2 (node.js)"]
    y-axis "Time (seconds)" 0 --> 10
    bar [0.129, 6.381, 6.609, 7.817]
Loading

This benchmark was conducted on a MacBook Pro (2021, M1 Max) using hyperfine with GitLab documentation as the dataset.

Installation

Homebrew (macOS and Linux)

brew tap akiomik/mado https://github.com/akiomik/mado.git
brew install mado

Nix (macOS and Linux)

nix profile install github:akiomik/mado

Arch Linux (Linux)

pacman -S mado

Scoop (Windows)

scoop install https://raw.githubusercontent.com/akiomik/mado/refs/heads/main/pkg/scoop/mado.json

WinGet (Windows)

# For security reasons, installing from local manifest files requires that this feature be enabled by an administrator.
# For more details, see https://learn.microsoft.com/en-us/windows/package-manager/winget/install#local-install
winget settings --enable LocalManifestFiles

curl.exe -o mado.yml https://raw.githubusercontent.com/akiomik/mado/refs/heads/main/pkg/winget/mado.yml
winget install -m mado.yml

Manually

Pre-built binaries are available for download from the release page.

Supported Rules

Mado supports most markdownlint rules.

  • ✅ Stable support
  • 🔨 Unstable support
  • ⚠️ Unsupported option(s)
  • ❌ Not supported
Rule Support Note
MD001 ✅
MD002 ✅
MD003 🔨
MD004 ✅
MD005 ✅
MD006 ✅
MD007 🔨
MD009 ✅
MD010 ✅
MD012 ✅
MD013 ✅
MD014 ✅
MD018 ✅
MD019 ✅
MD020 🔨
MD021 ✅
MD022 ✅
MD023 ✅
MD024 ✅
MD025 ✅
MD026 ✅
MD027 🔨
MD028 ✅
MD029 ✅
MD030 ✅
MD031 ✅
MD032 🔨
MD033 ✅
MD034 ✅
MD035 ✅
MD036 ✅
MD037 ✅
MD038 ✅
MD039 ✅
MD040 ✅
MD041 ✅
MD046 ✅
MD047 ✅

Configuration

Mado can be configured via mado.toml or .mado.toml file in the current directory. You can also use global configuration files located in:

  • Linux: ~/.config/mado/mado.toml
  • macOS: ~/.config/mado/mado.toml
  • Windows: ~\AppData\Roaming\mado\mado.toml

For more details, see the example mado.toml and the JSON Schema for mado.toml.

Ignore files

respect-ignore decides whether .ignore files exclude what they list. respect-gitignore decides when .gitignore files do:

value .gitignore files are read
"never" not at all
"repository-only" (default) inside a Git repository, as Git does
"always" whether or not the tree carries Git metadata

A repository here is a .git directory, the .git file a worktree or a submodule carries, or a .jj directory, which the ignore crate stops at as well.

"always" suits a tree that arrives without its Git metadata — a source archive, or a Docker context copied without .git. It stops mado looking for a repository at all, for every tree rather than only those without one, which is what the ignore crate offers and what rg --no-require-git does. So .gitignore files apply from every parent directory, above a clone's own repository root included, and a repository below the path being linted does not bound the search.

The global Git ignore file and .git/info/exclude are never read. Neither travels with the tree being linted, so reading them would have one source lint differently on another machine.

GitHub Actions

Mado is compatible with GitHub Actions.

# Basic usage (runs `mado check .`)
- uses: akiomik/mado@v0.3.2

# Custom usage (runs `mado` with specified arguments)
- uses: akiomik/mado@v0.3.2
  with:
    args: '--config path/to/mado.toml check path/to/*.md'

The action downloads the mado release it was published with. Setting the version input names a different release to run; a pin from before the input was added ignores it.

Development

just is required.

Running Tests

just test

Linting Code

just lint

Acceptance Testing

Compares what mado and mdl report for markdownlint's own rule fixtures. This needs mdl, cargo and git on PATH.

# Download the fixtures and set aside the ones written against their own style
./scripts/acceptance/setup.sh

# Write each tool's findings to tmp/mdl.txt and tmp/mado.txt
./scripts/acceptance/test.sh

diff tmp/mdl.txt tmp/mado.txt

That diff is not expected to be empty. Some of it is the two tools disagreeing and some of it is the two configurations differing, which is being worked out in #401.

Benchmarking

This needs hyperfine, mdl, node, npm, cargo and git on PATH.

# Download Markdown dataset
./scripts/benchmarks/setup.sh

# Install the markdownlint commands the comparison runs against
npm --prefix scripts/benchmarks ci

# Benchmark mado, mdl and markdownlint-cli using hyperfine
./scripts/benchmarks/comparison.sh

Profiling

First, install flamegraph:

cargo install flamegraph

Then run:

just flamegraph

Fuzz Testing

First, install cargo-fuzz:

cargo install cargo-fuzz

Then run:

just fuzz

Projets similaires

Fast Markdown linter and formatter written in Rust

Rustclideveloper-toolsformatter
Rrvben
1,5 k étoiles88

Static analysis for GitHub Actions

Rustgithub-actionssecuritysecurity-tools
Zzizmorcore
6,6 k étoiles259

Markdown lint tool

Rubymarkdownmarkdownlintruby
Mmarkdownlint
2,1 k étoiles248