CLI Reference
md-validate validate
Validate a Markdown file or directory against a rule set.
md-validate [--verbose] [--quiet] validate TARGET --rules RULES [options]
Arguments
| Argument | Description |
|---|---|
TARGET |
Path to a .md file or directory (recursive) |
Options
| Option | Default | Description |
|---|---|---|
--rules / -r |
required | Path to the rule-set JSON file |
--output / -o |
— | Directory to write report files |
--format / -f |
text |
Output format: text, json, or csv |
--workflows / --no-workflows |
enabled | Run workflow chains after evaluation |
--verbose / -v |
off | Enable DEBUG logging |
--quiet / -q |
off | Suppress all non-error output |
Exit codes
| Code | Meaning |
|---|---|
0 |
All Required rules passed |
1 |
One or more Required rules failed |
The exit code is what CI systems use to gate a build. Suggested-level rule failures
are reported but do not change the exit code.
Examples
# Basic validation
md-validate validate article.md --rules rules/tutorial.json
# JSON output
md-validate validate article.md --rules rules/tutorial.json --format json
# Validate directory, save CSV reports
md-validate validate docs/ --rules rules/tutorial.json --format csv --output reports/
# Verbose debug output
md-validate --verbose validate article.md --rules rules/tutorial.json
Sample text output
Validating: docs/tutorial-deploy-app.md
Rule set: rules/tutorial.json
✓ [1] topic-must-be-tutorial
✓ [2] must-have-h1
✓ [3] h1-must-start-with-tutorial
✗ [4] description-must-exist
→ Add a description field to the front matter.
✓ [5] ms-date-must-be-fresh
✗ [6] title-under-60-chars
→ Title must be under 60 characters.
✓ [7] must-have-prerequisites-h2
✓ [8] must-have-next-steps-h2
Score: 6/8 FAILED (2 Required rules failed)
When all rules pass:
Score: 8/8 PASSED
CI integration
GitHub Actions
name: Validate docs
on:
pull_request:
paths:
- 'docs/**/*.md'
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install markdown-validator
run: |
pip install markdown-validator
python -m nltk.downloader punkt_tab averaged_perceptron_tagger_eng
- name: Validate docs
run: md-validate validate docs/ --rules rules/tutorial.json --format json --output reports/
- name: Upload reports
if: failure()
uses: actions/upload-artifact@v4
with:
name: validation-reports
path: reports/
The step exits with code 1 if any Required rule fails, blocking the PR merge.
Uploading reports as artifacts makes it easy for authors to see which rules failed
without reading the raw log.
Using JSON output in scripts
result=$(md-validate validate docs/ --rules rules/tutorial.json --format json)
failures=$(echo "$result" | jq '[.results[] | select(.passed == false)] | length')
echo "Failed rules: $failures"
md-validate repl
Start the interactive REPL for rule development.
md-validate repl
The REPL lets you load a Markdown file, inspect its metadata and HTML, run XPath queries, and evaluate rule JSON objects interactively. Use it to author and debug rules before committing them to a rule-set file.
REPL commands
| Command | Description |
|---|---|
load <path> |
Load a Markdown file |
dump metadata |
Print the loaded file's metadata as JSON |
dump html |
Print the rendered HTML |
query <xpath> [flag] |
Run an XPath query (flags: text, count, dom) |
get <key> |
Get a metadata value by key |
eval <json-rule> |
Evaluate a rule JSON object against the loaded file |
quit / exit |
Exit the REPL |
REPL example session
> load docs/article.md
Loaded: /abs/path/docs/article.md
Metadata keys : ['title', 'ms.topic', 'ms.date', 'author']
> get ms.topic
ms.topic: tutorial
> query /html/body/h1 text
Result: ['My Tutorial Title']
> query /html/body/h2 count
Result: [3]
> eval {"id":1,"name":"topic-check","type":"header","query":"ms.topic","flag":"value","operation":"==","value":"tutorial"}
PASS: rule id=1 name='topic-check'
> query /html/body/h2 text
Result: ['Prerequisites', 'Deploy the app', 'Clean up resources']
> quit
Workflow for authoring a new rule:
loadthe document you are writing the rule for.queryyour XPath expression with the relevant flag (text,count,dom) to confirm it returns what you expect.evala complete rule JSON object to see pass/fail before adding it to the rule-set file.- Repeat with
loadon a document that should fail the rule to confirm the rule catches the problem.