mdsmith

module
v0.23.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 21, 2026 License: MIT

README ΒΆ

πŸ”¨ mdsmith

Build Quality Coverage

A fast, auto-fixing Markdown linter and formatter for docs, READMEs, and AI-generated content. Checks style, readability, structure, and cross-file integrity. One static Go binary.

One static Go binary checks 523 Markdown files in about 0.2 s. That is roughly 10x faster than Node markdownlint. It does more per file than the Rust linters; closing the rest of that gap is active work.

Numbers above come from a reproducible benchmark, not hand-typed copy.

mdsmith demo

Why mdsmith

mdsmith is one rule engine behind every surface: the CLI, the LSP server, and the VS Code extension all run the same checks. Neovim and other LSP-aware editors plug in through the same server; a Claude Code plugin is available for users of that editor. This page is the shared overview. The README includes it; the website renders it and links each card to a fuller page.

Core (every repo)

These features pay off on a single README and scale up to a docs monorepo.

Auto-fix Markdown formatting. mdsmith fix rewrites whitespace, headings, code fences, bare URLs, list indentation, and table alignment in place. It loops until edits stabilize. mdsmith check is the read-only CI sibling.

Live diagnostics wherever you write. mdsmith lsp emits diagnostics, quick-fixes, and navigation. Any LSP-aware editor can consume it. The VS Code extension and the Claude Code plugin surface the same data.

Rename without breaking links. Rename a heading and every workspace anchor link to it is rewritten in one atomic edit. Link-ref 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, or what depends on it. The LSP call-hierarchy walks the same <?include?>, <?catalog?>, <?build?>, and link graph in your editor.

Cross-file integrity. Built-in rules flag broken links and missing anchors, enforce per-file section schemas, and keep Markdown in the right folders. Schemas can be inline on a file kind or shared via proto.md files.

Scale (large docs sites)

These features show up when the repo grows past a handful of files: includes, catalogs, dependency graphs, release gates, and size budgets.

Size and readability limits. Cap file, section, and token-budget size. Enforce reading grade and sentence count. Flag verbatim copy-paste across files. Three rules ship on by default; two are opt-in.

Self-maintaining sections. On mdsmith fix, <?toc?> rebuilds a heading TOC, <?catalog?> generates an index from front matter, and <?include?> splices in another file. A Git merge driver resolves conflicts in those blocks.

Gate releases on doc status. mdsmith list query selects files by a CUE expression on front matter. mdsmith metrics rank ranks files by any shared metric. Both pipe straight into a release script.

Fast on every run. A single static Go binary with no runtime to boot. The workspace walk runs in parallel and embeds are linted once, so CI and editor feedback stay instant.

Quality you can verify. The build, Go Report Card, and coverage badges at the top of the README report live project health. mdsmith lints its own docs with the rules it ships, and a coverage gate blocks merges that drop below the line.

File kinds and schemas. Tag each file with a kind, then validate its headings and front matter against a schema declared inline on the kind or shared via a proto.md template. A whole directory obeys one contract.

Conventions and flavors. Pin a convention to get a curated rule preset and a target renderer flavor in one switch. MDS034 flags syntax the flavor will not render. A placeholder vocabulary spares template tokens.

Build artifacts in sync. <?build?> declares an artifact and a recipe. mdsmith fix keeps the section body in sync with the recipe output. MDS040 shell-safety-checks the recipe without running it.

Git-native, conflict-free. A merge driver auto-resolves conflicts inside generated blocks. 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 overrides. --explain and mdsmith kinds resolve show which layer set each effective value.

Editors and agents. A bundled VS Code extension and Claude Code plugins drive the same mdsmith lsp server, so diagnostics, fix-on-save, and navigation reach your editor and your coding agent unchanged.

Installs everywhere. One version-stamped Go binary ships through go install, npm, pip, uvx, mise, asdf, and GitHub Releases. No postinstall network call, so locked-down CI installs offline.

πŸ†š How does it compare? See:

πŸ”— Link handling internals. See:

πŸ“¦ Installation

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

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)

Any LSP-aware editor (Neovim, Helix, JetBrains via the LSP plugin) works by pointing at mdsmith lsp.

Claude Code plugin (inline diagnostics plus definition, references, symbol search, and call-hierarchy queries across your docs):

/plugin marketplace add jeduden/mdsmith
/plugin install mdsmith-lsp@mdsmith
/reload-plugins

More: the install guide covers direct downloads and mise (asdf pending). VS Code integration covers settings, code actions, and troubleshooting.

πŸš€ Usage

mdsmith <command> [flags] [files...]
Commands
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.
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.
version Print the mdsmith build version and exit.

Files can be paths, directories (walked recursively for *.md and *.markdown), or glob patterns. Directories respect .gitignore by default; use --no-gitignore to override. Explicitly named files are never filtered by .gitignore.

Examples
mdsmith check docs/            # lint a directory
mdsmith fix README.md          # auto-fix in place
mdsmith check -f json docs/    # JSON output
mdsmith metrics rank --by bytes --top 10 .

See the CLI reference for shared flags, exit codes, output format, and configuration merge semantics. Individual subcommand pages above cover their own flags and examples.

βš™οΈ Configuration

Run mdsmith init to generate a .mdsmith.yml with every rule and its defaults. Without a config, rules run with built-in defaults.

rules:
  line-length:
    max: 120
  fenced-code-language: false

ignore:
  - "vendor/**"

overrides:
  - glob: ["CHANGELOG.md"]
    rules:
      no-duplicate-headings: false

Rules are true (defaults), false (off), or an object with settings. overrides apply per file pattern; later entries take precedence. Config is discovered by walking up to the repo root; --config overrides.

Commit .mdsmith.yml so contributors share the same rule settings and mdsmith upgrades become an explicit, reviewable change. Run mdsmith version to see the build you have installed.

πŸ“š More

πŸ“„ License

MIT

Directories ΒΆ

Path Synopsis
cmd
corpusctl command
mdsmith command
mdsmith-release command
mdsmith-release is the internal CLI the GitHub Actions release pipeline invokes.
mdsmith-release is the internal CLI the GitHub Actions release pipeline invokes.
cue
types
Package types embeds the canonical mdsmith field-type-shortcut library so schema parsing can resolve `created: date` and friends without touching the network.
Package types embeds the canonical mdsmith field-type-shortcut library so schema parsing can resolve `created: date` and friends without touching the network.
docs
guides/directives
Package directives embeds the directive guide Markdown files so the LSP hover provider can serve them from the compiled binary without requiring the source tree to be present at runtime.
Package directives embeds the directive guide Markdown files so the LSP hover provider can serve them from the compiled binary without requiring the source tree to be present at runtime.
internal
archetype/gensection
Package gensection provides a reusable engine for marker-based generated-section rules.
Package gensection provides a reusable engine for marker-based generated-section rules.
concepts
Package concepts provides embedded concept-page documentation for mdsmith topics that span multiple rules or subsystems.
Package concepts provides embedded concept-page documentation for mdsmith topics that span multiple rules or subsystems.
convention
Package convention owns the convention and flavor data shapes independent of any rule.
Package convention owns the convention and flavor data shapes independent of any rule.
discovery
Package discovery finds Markdown files by expanding glob patterns from config.
Package discovery finds Markdown files by expanding glob patterns from config.
explain
Package explain attaches per-leaf rule provenance to lint diagnostics.
Package explain attaches per-leaf rule provenance to lint diagnostics.
export
Package export implements the source-to-source transform behind `mdsmith export`.
Package export implements the source-to-source transform behind `mdsmith export`.
extract
Package extract projects a schema-conformant Markdown document into a data tree whose shape mirrors the composed schema hierarchy.
Package extract projects a schema-conformant Markdown document into a data tree whose shape mirrors the composed schema hierarchy.
extract/encode
Package encode serialises an extracted data tree into one of the supported wire formats.
Package encode serialises an extracted data tree into one of the supported wire formats.
fieldinterp
Package fieldinterp provides {field} placeholder interpolation with CUE path resolution for nested front-matter access.
Package fieldinterp provides {field} placeholder interpolation with CUE path resolution for nested front-matter access.
fix
githooks
Package githooks provides utilities shared between the mdsmith CLI and the git-hook-sync rule for managing the pre-merge-commit hook, merge-driver assignments in .gitattributes, and discovery of files that contain generated-section directives.
Package githooks provides utilities shared between the mdsmith CLI and the git-hook-sync rule for managing the pre-merge-commit hook, merge-driver assignments in .gitattributes, and discovery of files that contain generated-section directives.
globpath
Package globpath provides glob matching and pattern utilities for mdsmith config surfaces: ignore:, overrides:, kind-assignment:, and rule settings (allowed:, include:, exclude:, budgets[].glob).
Package globpath provides glob matching and pattern utilities for mdsmith config surfaces: ignore:, overrides:, kind-assignment:, and rule settings (allowed:, include:, exclude:, budgets[].glob).
index
Package index builds and maintains the symbol graph that powers mdsmith's LSP navigation methods (documentSymbol, definition, references, workspace/symbol, callHierarchy).
Package index builds and maintains the symbol graph that powers mdsmith's LSP navigation methods (documentSymbol, definition, references, workspace/symbol, callHierarchy).
kindsout
Package kindsout renders the output of the 'mdsmith kinds' subcommand surface: declared-kind bodies, per-file resolutions, and per-rule merge chains.
Package kindsout renders the output of the 'mdsmith kinds' subcommand surface: declared-kind bodies, per-file resolutions, and per-rule merge chains.
linkgraph
Package linkgraph extracts Markdown links and heading anchors so the link-validity rule (MDS027) and the `backlinks` subcommand share one implementation of the link walk, anchor slug rules, and target parsing.
Package linkgraph extracts Markdown links and heading anchors so the link-validity rule (MDS027) and the `backlinks` subcommand share one implementation of the link walk, anchor slug rules, and target parsing.
log
lsp
Package lsp implements a minimal Language Server Protocol surface for mdsmith.
Package lsp implements a minimal Language Server Protocol surface for mdsmith.
placeholders
Package placeholders provides a shared vocabulary of placeholder tokens that rules can opt into to treat template content as opaque rather than content violations.
Package placeholders provides a shared vocabulary of placeholder tokens that rules can opt into to treat template content as opaque rather than content violations.
profiling
Package profiling adds an env-gated CPU/heap profiler to the mdsmith CLI.
Package profiling adds an env-gated CPU/heap profiler to the mdsmith CLI.
punkt
Package punkt is a forked, allocation-clean subset of the trained Punkt sentence tokenizer from neurosnap/sentences v1.1.2 (https://github.com/neurosnap/sentences).
Package punkt is a forked, allocation-clean subset of the trained Punkt sentence tokenizer from neurosnap/sentences v1.1.2 (https://github.com/neurosnap/sentences).
release
Package release: the cross-tool benchmark harness.
Package release: the cross-tool benchmark harness.
rename
Package rename is the workspace rename engine shared by the LSP server and the `mdsmith rename` CLI.
Package rename is the workspace rename engine shared by the LSP server and the `mdsmith rename` CLI.
rules/all
Package all is a blank-import barrel that registers every production rule with the rule registry.
Package all is a blank-import barrel that registers every production rule with the rule registry.
rules/ambiguousemphasis
Package ambiguousemphasis implements MDS047, which flags emphasis runs whose meaning a human cannot predict at a glance.
Package ambiguousemphasis implements MDS047, which flags emphasis runs whose meaning a human cannot predict at a glance.
rules/blockquotewhitespace
Package blockquotewhitespace implements MDS059, which flags two blockquote defects: more than one space after the > marker (MD027) and a blank line between two adjacent sibling blockquote nodes (MD028).
Package blockquotewhitespace implements MDS059, which flags two blockquote defects: more than one space after the > marker (MD027) and a blank line between two adjacent sibling blockquote nodes (MD028).
rules/build
Package build implements MDS039, which validates <?build?> directive parameters and keeps the body in sync with the recipe's body-template.
Package build implements MDS039, which validates <?build?> directive parameters and keeps the body in sync with the recipe's body-template.
rules/duplicatedcontent
Package duplicatedcontent implements MDS037, which flags substantial paragraphs that also appear verbatim in another Markdown file in the project root after whitespace and case normalization.
Package duplicatedcontent implements MDS037, which flags substantial paragraphs that also appear verbatim in another Markdown file in the project root after whitespace and case normalization.
rules/fencepos
Package fencepos answers "where in the source does a fenced code block's opening and closing fence line sit, and what fence character did the author use?" The helpers here let any rule reason about the raw fence delimiters of a *ast.FencedCodeBlock without owning that scanning logic itself.
Package fencepos answers "where in the source does a fenced code block's opening and closing fence line sit, and what fence character did the author use?" The helpers here let any rule reason about the raw fence delimiters of a *ast.FencedCodeBlock without owning that scanning logic itself.
rules/forbiddenparagraphstarts
Package forbiddenparagraphstarts implements MDS055, which flags paragraphs whose plain text begins with any configured prefix.
Package forbiddenparagraphstarts implements MDS055, which flags paragraphs whose plain text begins with any configured prefix.
rules/forbiddentext
Package forbiddentext implements MDS056, which flags paragraphs whose plain text contains any configured substring.
Package forbiddentext implements MDS056, which flags paragraphs whose plain text contains any configured substring.
rules/githooksync
Package githooksync implements MDS048, the git-hook-sync rule.
Package githooksync implements MDS048, the git-hook-sync rule.
rules/linkvalidity
Package linkvalidity implements MDS062, which flags links that silently do not work: the reversed (text)[url] form (markdownlint MD011) and links or images whose destination is empty/`#` or whose visible text is empty (markdownlint MD042).
Package linkvalidity implements MDS062, which flags links that silently do not work: the reversed (text)[url] form (markdownlint MD011) and links or images whose destination is empty/`#` or whose visible text is empty (markdownlint MD042).
rules/listmarkerspace
Package listmarkerspace implements MDS061, which enforces a consistent number of spaces between a list marker and item text, configurable per single-line vs multi-paragraph items and ordered vs unordered lists.
Package listmarkerspace implements MDS061, which enforces a consistent number of spaces between a list marker and item text, configurable per single-line vs multi-paragraph items and ordered vs unordered lists.
rules/listmarkerstyle
Package listmarkerstyle implements MDS045, which pins the bullet character for unordered lists.
Package listmarkerstyle implements MDS045, which pins the bullet character for unordered lists.
rules/markdownflavor
Package markdownflavor implements MDS034, which validates Markdown against a declared target flavor (commonmark, gfm, goldmark, pandoc, phpextra, multimarkdown, myst, or any) and flags syntax the target renderer will not understand.
Package markdownflavor implements MDS034, which validates Markdown against a declared target flavor (commonmark, gfm, goldmark, pandoc, phpextra, multimarkdown, myst, or any) and flags syntax the target renderer will not understand.
rules/markdownflavor/ext
Package ext implements detection-only goldmark extensions used by MDS034 (markdown-flavor) to flag syntax that varies across Markdown flavors.
Package ext implements detection-only goldmark extensions used by MDS034 (markdown-flavor) to flag syntax that varies across Markdown flavors.
rules/noreferencestyle
Package noreferencestyle implements MDS043, which forbids reference-style links and footnotes.
Package noreferencestyle implements MDS043, which forbids reference-style links and footnotes.
rules/nospaceincodespans
Package nospaceincodespans implements MDS052, which flags inline code spans with leading or trailing whitespace inside the backticks.
Package nospaceincodespans implements MDS052, which flags inline code spans with leading or trailing whitespace inside the backticks.
rules/noundefinedreferencelabels
Package noundefinedreferencelabels implements MDS054, which flags reference-style links and images whose label has no matching link reference definition in the file.
Package noundefinedreferencelabels implements MDS054, which flags reference-style links and images whose label has no matching link reference definition in the file.
rules/nounusedlinkdefinitions
Package nounusedlinkdefinitions implements MDS053, which flags link reference definitions that are never used by any reference-style link or image, and definitions that duplicate an existing label.
Package nounusedlinkdefinitions implements MDS053, which flags link reference definitions that are never used by any reference-style link or image, and definitions that duplicate an existing label.
rules/orderedlistnumbering
Package orderedlistnumbering implements MDS046, which pins how ordered list items are numbered in the source: literal sequential (1.
Package orderedlistnumbering implements MDS046, which pins how ordered list items are numbered in the source: literal sequential (1.
rules/propernames
Package propernames implements MDS050, which checks that proper names (e.g.
Package propernames implements MDS050, which checks that proper names (e.g.
rules/recipesafety
Package recipesafety implements MDS040, which validates every command in build.recipes for shell-safety at lint time.
Package recipesafety implements MDS040, which validates every command in build.recipes for shell-safety at lint time.
rules/requiredmentions
Package requiredmentions implements MDS058, which flags heading-bounded sections whose body text does not contain every configured substring.
Package requiredmentions implements MDS058, which flags heading-bounded sections whose body text does not contain every configured substring.
rules/requiredtextpatterns
Package requiredtextpatterns implements MDS057, which flags heading-bounded sections whose body text does not match a configured regex.
Package requiredtextpatterns implements MDS057, which flags heading-bounded sections whose body text does not match a configured regex.
rules/settings
Package settings provides shared helpers for coercing rule-configuration values decoded from YAML/CUE into Go types.
Package settings provides shared helpers for coercing rule-configuration values decoded from YAML/CUE into Go types.
rules/tablefmt
Package tablefmt answers "what does the canonical aligned form of a pipe-table look like for these source lines?" Callers ask the package to format a string of markdown, to spot non-conforming tables in a parsed line list, or to rewrite the source bytes in place.
Package tablefmt answers "what does the canonical aligned form of a pipe-table look like for these source lines?" Callers ask the package to format a string of markdown, to spot non-conforming tables in a parsed line list, or to rewrite the source bytes in place.
rules/toc
Package toc implements MDS038, the <?toc?> generated-section directive that emits a nested heading list linked to GitHub-style anchors.
Package toc implements MDS038, the <?toc?> generated-section directive that emits a nested heading list linked to GitHub-style anchors.
rules/tocdirective
Package tocdirective implements MDS035, which flags renderer-specific table-of-contents directives that render as literal text on CommonMark and goldmark.
Package tocdirective implements MDS035, which flags renderer-specific table-of-contents directives that render as literal text on CommonMark and goldmark.
schema
Package schema models the document-structure schemas that drive MDS020 (required-structure).
Package schema models the document-structure schemas that drive MDS020 (required-structure).
testcorpus
Package testcorpus holds shared text corpora for tests and benchmarks across mdsmith's internal packages.
Package testcorpus holds shared text corpora for tests and benchmarks across mdsmith's internal packages.
testutil
Package testutil holds small helpers shared across test binaries.
Package testutil holds small helpers shared across test binaries.
yamlutil
Package yamlutil provides safe YAML parsing and marshaling helpers.
Package yamlutil provides safe YAML parsing and marshaling helpers.
pkg
markdown
Package markdown is mdsmith's public Markdown parse/produce surface.
Package markdown is mdsmith's public Markdown parse/produce surface.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL