Validate that the shell commands in your docs actually work.
Setup instructions rot. Dependencies change, paths move, tools get renamed — and nobody notices until a new hire spends a day debugging a README written 18 months ago. doc-check finds the breakage automatically.
- Parses your Markdown for
```bash/```sh/```shellcode blocks - Runs each block with
bash -euo pipefail - Reports pass / fail / skip per block with line numbers and section headings
# No dependencies — just Python 3.6+
chmod +x doc_check.py# Check one file
doc-check README.md
# Check multiple files
doc-check README.md CONTRIBUTING.md docs/setup.md
# Dry run — see what would execute, without running anything
doc-check --dry-run README.md
# Only check blocks under "Install" or "Setup" headings
doc-check --include "Install|Setup" README.md
# Skip blocks under "Advanced" headings
doc-check --exclude "Advanced" README.md
# Custom timeout (default 60s)
doc-check --timeout 30 README.md
# Verbose — show stdout for passing blocks too
doc-check -v README.md🔍 Found 4 code block(s) in 1 file(s)
✅ README.md:7 (Prerequisites) [15ms]
❌ README.md:13 (Build) [2ms]
⏭️ README.md:21 (Deploy) — skipped: contains placeholders
✅ README.md:27 (Run Tests) [2ms]
============================================================
📋 DOC-CHECK REPORT
============================================================
✅ PASS README.md:7 (Prerequisites) [15ms]
❌ FAIL README.md:13 (Build) [2ms]
│ bash: nonexistent-tool: command not found
⏭️ SKIP README.md:21 (Deploy)
│ reason: contains placeholders
✅ PASS README.md:27 (Run Tests) [2ms]
------------------------------------------------------------
Total: 4 | ✅ 2 passed | ❌ 1 failed | ⏭️ 1 skipped
💡 Fix the failing blocks, then re-run doc-check.
Blocks are automatically skipped when they contain:
- Placeholders like
<YOUR_SERVER>,${VAR}, or... - Only comments (no executable code)
- Skip markers — add
doc-check:skipanywhere in a block to opt out
Console prompts ($ and > ) are stripped automatically.
# .github/workflows/doc-check.yml
name: Doc Check
on: [push, pull_request]
jobs:
docs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: python3 doc_check.py README.md CONTRIBUTING.md#!/bin/sh
python3 doc_check.py README.md || exit 1| Flag | Description |
|---|---|
--dry-run |
Show blocks without executing |
--workdir DIR |
Run in a specific directory (default: temp dir) |
--timeout N |
Per-block timeout in seconds (default: 60) |
--verbose |
Show stdout for passing blocks |
--include RE |
Only run blocks under matching headings |
--exclude RE |
Skip blocks under matching headings |
- Python 3.6+
- That's it. Zero dependencies.
MIT