Markdown, smithed.
Markdown as a single source of truth
Write content; mdsmith keeps your Markdown neat and consistent โ fast enough to stay out of your way. Auto-fix on save, instant navigation, cross-file integrity, and generated sections that keep a single source of truth in sync across files and pipelines.
One static Go binary checks this whole repository in well under a second. That is an order of magnitude faster than Node markdownlint. It does more per file than the Rust linters. The figures are re-measured on every merge and refreshed each release. See the latest cross-tool benchmark for the current per-tool ratios on both corpora.
mdsmith is a Markdown linter and formatter written in Go. It checks style, readability, structure, and cross-file integrity, and auto-fixes what fixes cleanly. Where markdownlint-compatible linters stop at per-file style, mdsmith adds the cross-file graph, generated sections, structure schemas, and readability budgets. Together they keep a whole docs tree consistent as it grows, so the same Markdown can drive your README, your docs site, and downstream pipelines.
Already on markdownlint? mdsmith init --from-markdownlint
converts your config and notes whatever needs review.
One rule engine runs everywhere you work: in CI, in your editor
through mdsmith lsp, and in your coding agent through a Claude
Code plugin. The check that blocks a merge is the same one you see
as you type, so feedback never depends on which tool you opened.
Catch style, formatting, and readability problems on every file.
mdsmith fix rewrites the ones with a single correct fix;
mdsmith check is the read-only gate for CI.
Auto-fix Markdown formatting.
mdsmith fix rewrites whitespace, headings, code fences, bare
URLs, list indentation, and table alignment in place, looping
until edits stabilize. mdsmith check runs the same rules
read-only for CI.
Conventions and flavors.
Pin one convention to apply a curated rule preset and a target
renderer flavor together. MDS034 flags syntax the flavor will
not render; a placeholder vocabulary leaves template tokens like
{name} alone.
Size and readability limits. Cap file, section, and token-budget size, enforce a reading grade and sentence count, and flag verbatim copy-paste between files. Three rules ship on by default; two are opt-in.
The same engine runs in CI, in your editor, and in your coding agent, from one fast static binary you can install through any channel.
Editors and agents.
A bundled VS Code extension and a Claude Code plugin drive the
same mdsmith lsp server, so diagnostics, fix-on-save, and
navigation reach your editor and your agent with no separate
install. The .vsix is republished to Open VSX for Cursor,
VSCodium, and Theia.
Live diagnostics wherever you write.
mdsmith lsp serves diagnostics, quick-fixes, and navigation
(definition, references, symbol search, and a call hierarchy) to
any LSP-aware editor over stdio.
Fast on every run. One static Go binary, no runtime to start. The workspace walk runs across all cores, and includes are linted once. A full check of this repository's Markdown takes about 0.5 s, an order of magnitude faster than Node markdownlint.
Installs everywhere. The same version-stamped binary ships through go install, npm, pip, uvx, Homebrew, mise, asdf, and GitHub Releases. No postinstall network call, so locked-down CI installs offline.
mdsmith reads the links, includes, and headings that tie your files together, so a rename or a move never strands a reference.
Cross-file integrity.
MDS027 flags broken links and missing anchors across the
workspace, MDS020 validates each file against its section
schema, and MDS033 keeps files in their allowed folders.
Rename without breaking links. Rename a heading and mdsmith rewrites every workspace anchor link that resolved to its slug in one atomic edit. Link-reference labels rename with their uses; a colliding slug fails loudly instead of breaking links.
See the dependency graph.
mdsmith deps lists what a file pulls in (includes, catalogs,
build inputs, and links), or every file that points at it with
--incoming. The editor walks the same graph as a call hierarchy.
File kinds and schemas.
Tag each file with a kind, then validate its headings, section
order, and front matter against a schema. Declare the schema
inline on the kind or share it from a proto.md template, so a
whole directory obeys one contract.
Each file stays the single source of truth. mdsmith keeps the generated parts in sync, and can project the file out as JSON, YAML, or msgpack.
Self-maintaining sections.
On mdsmith fix, <?toc?> rebuilds a heading table of contents,
<?catalog?> generates an index from front matter, and
<?include?> splices in another file. A Git merge driver resolves
conflicts inside those blocks.
Agent-ready docs index.
A <?catalog?> in CLAUDE.md keeps one summary line per
tracked doc, so an agent reads a few thousand tokens of metadata
up front and opens only the files a task touches. mdsmith's own
CLAUDE.md is the live example.
Build artifacts in sync.
The <?build?> directive declares an artifact and a recipe;
mdsmith fix rebuilds only the targets whose inputs, recipe, or
outputs changed, tracking freshness in
.mdsmith/build-cache.json. MDS040 shell-safety-checks the
recipe without running it.
Markdown as a data source.
mdsmith extract projects a schema-conformant file to a JSON,
YAML, or msgpack tree, and <?include extract:?> reads one value
back into another file. mdsmith export writes a portable,
directive-free copy that renders on any Markdown tool.
Release gates, a Git merge driver, transparent config, and a coverage-gated build make mdsmith safe to wire into a shared repository.
Gate releases on doc status.
mdsmith list query 'status: "โ
"' plan/ selects files by a CUE
expression on front matter, and mdsmith metrics rank orders
files by any shared metric. Both print plain lines ready to pipe
into a release script.
Git-native, conflict-free.
A Git merge driver re-runs the directive and keeps the regenerated
body when two branches both touch a generated block. A
pre-merge-commit hook re-runs mdsmith fix and re-stages the
result, so generated content never blocks a merge.
Config you can explain.
Config layers deep-merge rule by rule: defaults, convention,
kinds, then per-glob overrides. mdsmith check --explain and
mdsmith kinds resolve show which layer set each effective value.
Quality you can verify. The CI, Go Report Card, and Codecov badges report live project health. mdsmith lints its own docs with the rules it ships, and a coverage gate blocks any merge that drops below the line.
go install github.com/jeduden/mdsmith/cmd/mdsmith@latest # or npm / pip / brew (see Installation)
mdsmith check . # lint every Markdown file; non-zero exit on failure (CI-ready)
mdsmith fix . # auto-fix what fixes cleanly, in placecheck prints each problem โ location, rule, and a source snippet
with a caret under the offending column โ then a summary, exiting non-zero:
docs/guide.md:1:81 MDS001 line too long (89 > 80)
1 | # This heading runs deliberately long so that it spills well past the eighty-column limit
ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท^
stats: checked=1 fixed=0 failures=1 unfixed=1
CLI:
go install github.com/jeduden/mdsmith/cmd/mdsmith@latest
npm install -g @mdsmith/cli # or: npx @mdsmith/cli
pip install mdsmith # or: uvx mdsmith / pipx install mdsmith
brew install jeduden/mdsmith/mdsmith # macOS / Linux (Homebrew)Editor extension (LSP-backed; runs mdsmith lsp):
code --install-extension jeduden.mdsmith # VS Code, Codespaces (Marketplace)
codium --install-extension jeduden.mdsmith # Cursor, VSCodium, Theia, Gitpod (Open VSX)Claude Code plugin (diagnostics + cross-file navigation in your agent):
/plugin marketplace add jeduden/mdsmith
/plugin install mdsmith-lsp@mdsmith
/reload-plugins
More: the install guide covers asdf, mise, and direct downloads; VS Code setup covers settings and troubleshooting.
mdsmith <command> [flags] [files...]
| Command | Description |
|---|---|
check |
Lint Markdown files for style issues. |
deps |
List a file's dependency-graph edges (includes, links, catalogs, builds). |
export |
Write a portable, directive-free copy of a Markdown file. |
extract |
Emit a schema-conformant Markdown file as a JSON/YAML/msgpack data tree. |
fix |
Auto-fix lint issues in Markdown files in place. |
help |
Show built-in documentation for rules, metrics, and concept pages. |
init |
Generate a default .mdsmith.yml config in the current directory, or convert an existing markdownlint config with --from-markdownlint. |
kinds |
Inspect declared file kinds and resolve effective rule config per file. |
list |
Selection-style commands that walk the workspace and emit matches. |
list backlinks |
List workspace links that point at a file. |
list query |
Select Markdown files by a CUE expression on front matter. |
lsp |
Run a Language Server Protocol server on stdio for editor integrations. |
merge-driver |
Git merge driver that resolves conflicts inside generated sections. |
metrics |
List and rank shared Markdown metrics (file length, token estimate, readability, โฆ). |
pre-merge-commit |
Install / manage a pre-merge-commit hook that runs mdsmith fix after a merge. |
rename |
Rename a heading or link-reference label and rewrite every dependent edit. |
trust |
Review the .mdsmith.yml diff since it was last trusted and update the build trust marker on this clone. |
version |
Print the mdsmith build version and exit. |
That command table and the feature list above are generated by mdsmith's own directives.
Files can be paths, directories (walked for *.md/*.markdown), or
globs; directories respect .gitignore (--no-gitignore overrides).
The CLI reference covers shared flags, exit
codes, output, and merge semantics; each page has its own examples.
mdsmith init writes a .mdsmith.yml of all rules at their defaults;
without one, built-in defaults apply.
rules:
line-length:
max: 120
fenced-code-language: false
overrides:
- glob: ["CHANGELOG.md"]
rules:
no-duplicate-headings: falseEach rule is true (default), false (off), or an object of settings.
overrides apply per glob; later entries win. Config is found by walking
up to the repo root. Commit it so contributors share one ruleset and
upgrades stay reviewable.
- How mdsmith compares to other linters
- Guides โ directives, structure, migration
- Rule directory โ every rule with status
- CLI reference
- Contributor guide โ Go 1.25+, build, test, style