Zero-dependency GFM and MDX formatter with structural guardrails — trailing whitespace removal, table alignment, fence normalization, pipe-safety checks, column-count enforcement, and drift detection.
Designed for AI-agent workflows but works anywhere Node.js >=24 runs.
npm install -g zero-md-formatter
mdfmt --fix README.md
The CLI and formatter module have zero npm runtime dependencies. Installable on any system with Node.js >=24.
npm install -g zero-md-formatter
mdfmt --fix README.mdRequires Node.js >=24. Zero runtime npm dependencies — no config file, no plugin system.
npx zero-md-formatter --fix README.mdimport { formatContent } from 'zero-md-formatter';
const result = formatContent(rawMarkdown);
console.log(result);git clone https://github.com/CodeSigils/zero-md-formatter.git
cd zero-md-formatter
node src/index.js --fix --guard README.mdFormatter-owned behavior:
- Remove trailing whitespace
- Ensure a final newline
- Normalize leading-tab indentation outside fenced code blocks
- Align GFM table columns when the table has no empty-cell ambiguity
- Normalize tilde fences to backtick fences, escalating the backtick count when nested content requires it
Guard-owned behavior:
- Fence closure and malformed fence info strings
- Table column counts (header vs delimiter vs data row alignment)
- Unescaped inline-code pipes in table rows
- Adjacent-pipe table hazards (
||→| |) - Pre/post structural drift detection and rollback when
--guardis used
- No formatting config file — no
.prettierrc,.markdownlintrc, or similar. No plugin system. Zero runtime dependencies means no extension points. - No dialect extensions — no Obsidian wiki-links, Mermaid, Pandoc, or frontmatter semantics.
- No JSX/MDX validation — formats Markdown containers only; JSX inside is passed through unchecked.
mdfmt [options] <path...>| Flag | Description |
|---|---|
--check |
Read-only pipe-safety and format check (exit 0 if clean) |
--fix |
Format files in-place after pipe-safety preflight (default) |
--all |
Process directories recursively |
--guard |
Pre/post structural check; rollback on drift; clean snapshots |
--verify |
Run formatting, idempotence, and structural checks without writing |
--fences |
Validate fenced code block info strings |
--validate |
Run all structural validations |
--doctor |
Check runtime prerequisites without modifying files |
--dry-run, -n |
Run pipe-safety preflight, preview changes without writing |
--audit-tables |
Print table row cell counts and pipe hazards without writing |
--no-repair |
Report repairable table issues instead of modifying them |
--version |
Print version number and exit |
--help, -h |
Display help message |
Create .mdfmtignore in the project root to exclude files from --all and explicit path processing. One pattern per line; # for comments. Patterns ending with / match directory prefixes; * matches any non-/ characters.
# Skip vendored docs and generated output
vendor/
docs/generated/
*.generated.md
# Check formatting (read-only, CI-safe)
mdfmt --check README.md
# Format with rollback-safe structural guards
mdfmt --fix --guard docs/
# Validate structure across a directory
mdfmt --validate --all docs/
# Diagnose installed readiness
mdfmt --doctorGFM tables are notoriously fragile in agent-generated Markdown. This formatter includes guard scripts that catch the most common failure modes before formatting:
- Adjacent pipes (
||) create empty cells per GFM. Write modes automatically insert a space (| |), preserving empty-cell semantics. Read-only modes block with a clear error. - Inline-code pipes (
|cmd | opt| title |) look like extra columns to naive formatters. Guard scripts detect them and block formatting before corruption. - Column drift — rows with mismatched column counts are detected and, in write mode, repaired by padding short rows or rolling back on structural drift.
- Empty-cell tables that remain ambiguous are preserved by skipping the full formatter pass. The delimiter row is still normalized to GFM-canonical width.
- Unclosed-fence preflight — all modes detect unclosed fences before running table/pipe checks, skipping unreliable validation when fences are open.
Table-shaped content inside fenced code blocks is always left untouched.
The formatter ships as a standard agentskills-compatible skill via
SKILL.md. It works with any agent that supports
agentskills.io-formatted skills.
Hermes Agent
# Add repo as skill tap (one-time), then install
hermes skills tap add CodeSigils/zero-md-formatter
hermes skills install CodeSigils/zero-md-formatter/markdown-formatter --yesThen use the formatter via npm (recommended — gives mdfmt binary):
npm install -g zero-md-formatter
mdfmt --fix --guard README.mdOr run from source (no npm install):
node src/index.js --fix --guard README.mdFor auto-wiring on every write_file or patch call, add to config.yaml:
hooks:
post_tool_call:
- command: mdfmt --check
matcher: write_fileThis runs --check (read-only) on every written file, blocking pipe hazards,
fence errors, and formatting drift before they reach git. Use --fix instead
of --check for auto-repair.
Claude Code / Codex CLI / OpenCode / Gemini CLI
# Clone the repo or copy the skill directory
git clone https://github.com/CodeSigils/zero-md-formatter.git
# Point at the source directory
node zero-md-formatter/src/index.js --fix --guard README.mdOr install via npm globally and use the mdfmt binary directly.
| Component | Portable? |
|---|---|
CLI (src/index.js) |
Pure Node.js, no agent runtime required |
| SKILL.md | agentskills.io base frontmatter |
| Guard scripts (4) | Node.js, no agent tools referenced |
| Post-write hook config | Hermes-specific (platform feature) |
Reference spec: GitHub Flavored Markdown Spec.
check-tables.jsenforces formatter-safe table column counts and pipe consistency, including unescaped pipes inside inline code spans. Stricter than GFM body-row parsing because autonomous formatting should not guess table intent.check-pipes.jsdetects adjacent pipes in table rows, which create valid empty cells per GFM. Write modes repair them by inserting a space between the pipes. Read-only modes block with a clear error.- All CLI modes run pipe-safety preflight checks before table operations. When unclosed fences are detected, the CLI warns that table and pipe checks are unreliable and skips them while continuing with fence validation and formatting.
- Write-mode
--guardruns structural snapshots before and after formatting. If post-format structure doesn't match the pre-format snapshot, the original content is restored.
.md.markdown.mdx
- Node.js >=24
Run mdfmt --doctor to verify runtime readiness.
The shipped package contains only:
zero-md-formatter/
SKILL.md
src/index.js
src/format-content.mjs
guard/check-structure.js
guard/check-fences.js
guard/check-tables.js
guard/check-pipes.js
Repository-only files (test/, scripts/, .github/) are excluded from the npm
tarball via the files field in package.json.
SKILL.md— packaged skill instructionssrc/index.js— CLI entrypointsrc/format-content.mjs— formatter modulescripts/check-consistency.js— repository drift checks
MIT