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 and skip validation that cannot be trusted while a fence is open. Read-only and guarded modes fail without modifying the file; unguarded write modes warn and continue formatting around the open fence.
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.
With the standard skills CLI:
npx skills add CodeSigils/zero-md-formatter --skill markdown-formatterHermes Agent
Recommended for development — clone the repo and add to external_dirs:
skills:
external_dirs:
- /path/to/zero-md-formatter/skillsEvery commit is immediately reflected without reinstalling.
For end users — install from hub:
# 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 — the hook script ships with the
skill. You just need to register it:
# The script is already at:
# ~/.hermes/skills/markdown-formatter/scripts/check-markdown.sh
# No download needed.Then add the hook to config.yaml:
hooks:
post_tool_call:
- command: ~/.hermes/skills/markdown-formatter/scripts/check-markdown.sh
matcher: write_file
- command: ~/.hermes/skills/markdown-formatter/scripts/check-markdown.sh
matcher: patchThis runs --fix --guard on every written Markdown file — formatting, repairing
adjacent pipes, normalizing fences, aligning tables, and rolling back on
structural drift before they reach git.
Codex CLI
For a repo-specific Codex skill, copy the tap payload into .agents/skills:
mkdir -p .agents/skills
cp -R skills/markdown-formatter .agents/skills/markdown-formatterFor a user-wide Codex skill, copy it to $HOME/.agents/skills instead.
Codex also works directly with the CLI:
npm install -g zero-md-formatter
mdfmt --fix --guard README.mdClaude Code / OpenCode / Gemini CLI
All three can run the formatter as a normal shell CLI:
npm install -g zero-md-formatter
mdfmt --fix --guard README.mdOr clone the source and run the bundled CLI directly:
git clone https://github.com/CodeSigils/zero-md-formatter.git
node zero-md-formatter/src/index.js --fix --guard README.mdFor native Agent Skills support, copy the tap payload to the runtime's documented skill directory:
# Claude Code
mkdir -p .claude/skills
cp -R skills/markdown-formatter .claude/skills/markdown-formatter
# OpenCode
mkdir -p .opencode/skills
cp -R skills/markdown-formatter .opencode/skills/markdown-formatter
# Gemini CLI
mkdir -p .gemini/skills
cp -R skills/markdown-formatter .gemini/skills/markdown-formatterOpenCode and Gemini CLI also discover .agents/skills/markdown-formatter/.
Claude Code also supports $HOME/.claude/skills/markdown-formatter/ for
user-wide installs.
| 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
an unclosed fence is detected, the CLI warns that table and pipe checks are
unreliable and skips them. Read-only modes and write mode with
--guardfail fence validation without modifying the file. Unguarded write modes continue formatting around the open fence. - 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
jq(Hermes shell hook only)
Run mdfmt --doctor to verify runtime readiness.
The shipped runtime payload contains:
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
scripts/check-markdown.sh
The npm tarball also includes package metadata, README.md, and LICENSE.
Repository-only files (test/, .github/) are excluded via the files
field in package.json — scripts/ is not shipped with npm, except
scripts/check-markdown.sh which is included in the Hermes tap payload
(skill install) but not the npm package.
SKILL.md— packaged skill instructionssrc/index.js— CLI entrypointsrc/format-content.mjs— formatter modulescripts/check-consistency.js— repository drift checks
MIT