pre-commit-readme-enforcer
v1.2.0
Published
Pre-commit hook: stage nearest READMEs with code changes; optional root README reachability over relative Markdown links
Maintainers
Readme
pre-commit-readme-enforcer
Git pre-commit hook: if you stage non-README code, you must also stage the nearest README for each changed path (same directory, then parents). No config required.
Prerequisites: Node.js 18+, npm, and git (Husky 9 needs Node 18). The check-readme-updated script alone may run on older Node if you wire hooks without Husky.
Using the hook in your repo → commands below. Contributing to this project → Development.
Install (npm + Husky)
In your project root:
npm install --save-dev pre-commit-readme-enforcer husky
npx husky
echo "npx check-readme-updated" > .husky/pre-commitOn macOS or Linux you may optionally run chmod +x .husky/pre-commit. On Windows, use the hook line above as-is — see Windows (consumer repos).
Stage code and the README paths the hook names, or the commit stops with a short list of what is missing.
Teams / CI
Add "prepare": "husky" under scripts in your package.json so npm install on a fresh clone keeps Husky’s core.hooksPath wired. In CI or other environments where hooks should not run, set HUSKY=0.
Usage
The hook runs on git commit when Husky is active.
git add src/feature.ts
git commit -m "feature" # fails until required README files are staged too
git add src/README.md # after you edit them (paths the hook prints)
git commit -m "feature" # succeedsOn Windows, use the same git commands from Git Bash, PowerShell, or cmd. See Windows (consumer repos).
Windows (consumer repos)
For developers using this hook in their own project on Windows (not contributing to this package).
Prerequisites: Node.js 18+, npm, and Git for Windows. Run git and npm from your repository root. Husky runs hooks via Git’s shell — installing Git is enough for typical setups.
Install and create the pre-commit hook
npm install --save-dev pre-commit-readme-enforcer huskyPowerShell
npx husky
Set-Content -Path .husky/pre-commit -Value "npx check-readme-updated" -NoNewline
Add-Content -Path .husky/pre-commit -Value "`n"cmd
npx husky
echo npx check-readme-updated> .husky\pre-commitGit Bash / macOS / Linux
npx husky
echo "npx check-readme-updated" > .husky/pre-commitOptional on Unix only: chmod +x .husky/pre-commit.
Add to your app’s package.json so hooks install on clone:
"scripts": {
"prepare": "husky"
}Daily usage
git add src/feature.ts
git commit -m "feature"If the commit fails, the hook lists README paths using forward slashes (e.g. src/README.md). Stage those files, then commit again:
git add src/README.md
git commit -m "feature"Manual check
npx check-readme-updatedIf you copied the script into the repo, use node check-readme-updated.js (not ./check-readme-updated.js in cmd — Windows cmd does not run shebangs).
Opt-in README reachability on Windows
Prefer a CLI flag in .husky/pre-commit (works in every shell):
npx check-readme-updated --enforce-readme-interlinkOne-off manual run with an environment variable:
PowerShell
$env:README_ENFORCE_INTERLINK = "1"
npx check-readme-updatedcmd
set README_ENFORCE_INTERLINK=1
npx check-readme-updatedGit Bash
README_ENFORCE_INTERLINK=1 npx check-readme-updatedCI and disabling hooks
PowerShell: $env:HUSKY = "0"
cmd: set HUSKY=0
bash: export HUSKY=0
Verify on Windows
- Change a tracked file,
git addit, rungit commit— expect failure with listed README paths (forward slashes). - Edit and
git addthose READMEs, commit again — expect success.
Windows troubleshooting
| Issue | What to try |
|--------|-------------|
| Hook never runs | Run npx husky from the repo root; confirm .husky/pre-commit exists |
| node / npm not found | Install Node.js, restart the terminal, check PATH |
| README staged but hook still fails | Upgrade to 1.1.1+ (path normalization fix); ensure paths match what git status shows |
| ./check-readme-updated.js fails in cmd | Use node check-readme-updated.js or npx check-readme-updated |
Verify
- Change a tracked file under your repo,
git addit, trygit commit— expect failure with listed README paths. - Edit and
git addthose READMEs, commit again — expect success.
Run the checker by hand: npx check-readme-updated (from a devDependency install) or node check-readme-updated.js if you copied the script. On Windows, see Windows (consumer repos).
How it works
- Looks at staged non-README files.
- For each, finds the closest README (name starts with
readme, case-insensitive), walking up directories. - Requires every such README to be staged with a change when any of those code paths are staged.
- Prints which README paths to update if the commit would otherwise go through.
Other ways to install
Global CLI + Husky
npm install -g pre-commit-readme-enforcerThen in each repo:
npm install --save-dev husky
npx husky
echo "npx check-readme-updated" > .husky/pre-commitOne-off check (no git hook)
npx pre-commit-readme-enforcerCopy the built script
Clone, build, copy check-readme-updated.js into your project, then point .husky/pre-commit at it, for example:
echo "node check-readme-updated.js" > .husky/pre-commit(Use npm install --save-dev husky and npx husky first if Husky is not set up. On Windows, see Windows (consumer repos).)
Python pre-commit framework
Requires Node on the machine (hook is JS).
repos:
- repo: https://github.com/taidaid/pre-commit-readme-enforcer
rev: main # pin a tag or commit in real projects
hooks:
- id: check-readme-updatedConfiguration
No config is required for the default staged-README check. Optional ignore rules let you skip the nearest-README requirement for certain paths (generated code, lockfiles, vendored deps, and so on). Ignore rules apply only to the staged-README check, not to opt-in README reachability.
Optional: ignore paths (staged-README check)
Define patterns in either or both of:
.readme-enforcerignoreat the repository root — one pattern per line;#starts a comment; blank lines are ignored.package.json—"readmeEnforcer": { "ignore": ["vendor/", "*.lock"] }
When both exist, patterns are merged (union). Invalid package.json (parse error or non-array ignore) is skipped so a broken manifest does not block commits.
.readme-enforcerignore example:
# Vendored and generated code
vendor/
generated/
# Lockfiles
*.lock
# Single file
scripts/codegen.tspackage.json example:
{
"readmeEnforcer": {
"ignore": ["vendor/", "*.lock", "scripts/codegen.ts"]
}
}Supported pattern syntax (repo-relative paths, forward slashes):
| Pattern | Matches | Example |
|---------|---------|---------|
| dir/ or dir | Path equals dir, or starts with dir/ | vendor/ → vendor/foo.ts |
| *.ext | Basename ends with .ext (any depth) | *.lock → yarn.lock |
| anything else | Exact path match | scripts/codegen.ts |
No **, ?, or negation in v1. When staged files match ignore rules, the hook logs how many were skipped and does not require README updates for them.
Default behavior (always on)
- README detection: filenames beginning with
readme(any case). - Matching: nearest README per staged code path; all of them must be staged when any listed code is staged.
Optional: root README reachability (opt-in)
When enabled, the hook also verifies that every tracked readme* file is reachable from a single root README by following relative inline Markdown links [text](relative-path) from file to file (BFS). Cycles and multiple incoming links are allowed; only orphan READMEs (never linked from the root’s component) fail the check.
- Root README: tracked
readme*at the repository root (path with no/). Preference order:README.md, thenreadme.md; otherwise the first path when sorted withenlocale. The hook prints which root was used. - Link sources: only
.md/.markdownreadmes are scanned for outbound links. Otherreadme*files (e.g.readme.txt) can still be targets but do not contribute links. - Graph: nodes are tracked
readme*paths fromgit ls-files. Untracked READMEs are ignored.
Enable in Husky (recommended — all platforms):
npx check-readme-updated --enforce-readme-interlinkEnable with a CLI flag (e.g. Python pre-commit args):
repos:
- repo: https://github.com/taidaid/pre-commit-readme-enforcer
rev: main
hooks:
- id: check-readme-updated
args: [--enforce-readme-interlink]You can combine the flag and env var; either is sufficient.
Enable with an environment variable (bash / Git Bash) in .husky/pre-commit:
echo 'README_ENFORCE_INTERLINK=1 npx check-readme-updated' > .husky/pre-commitOn Windows, prefer the CLI flag in the hook file; see Windows (consumer repos) for PowerShell/cmd one-off runs.
Manual run:
npx check-readme-updated --enforce-readme-interlinkOr with an env var (bash / Git Bash): README_ENFORCE_INTERLINK=1 npx check-readme-updated
If the root-level README rule cannot be satisfied (no tracked root readme*), the reachability check exits with an error when opt-in is on.
Performance: with opt-in, each commit reads every tracked README for link parsing—fine for typical repos; very large documentation trees may prefer running this check in CI instead.
Troubleshooting
command not found: node / npm — Install Node.js (includes npm), restart the terminal.
Permission denied on ./build.sh — chmod +x build.sh then run again.
Hook never runs — Work in the repo root; confirm .husky/pre-commit exists; run npx husky again from that root. On Windows, see Windows (consumer repos).
README staged but hook still fails (Windows) — Use package version 1.1.1+; ensure you use npx check-readme-updated or node check-readme-updated.js, not ./script.js in cmd.
npx husky errors — Run git status in a git repo; run npm install; use Node 18+ for Husky 9.
Hook runs but “no README” — Add a README (e.g. README.md) where the tool expects it, or adjust your layout.
Hook runs but “README reachability failed” — Ensure the root README links (directly or transitively) to every other tracked readme* using relative inline Markdown links. See Configuration.
Still stuck — Open an issue with OS, node --version, the exact error, and commands you ran.
Development
For this repository (not consuming the package elsewhere):
git clone https://github.com/taidaid/pre-commit-readme-enforcer.git
cd pre-commit-readme-enforcer
npm run setupOn Windows, use npm run setup (same as above). On macOS/Linux you may alternatively run ./build.sh, which calls npm run setup and configures the local Husky hook.
npm run setup— install deps, compile TypeScript, run Huskynpm run build— compile TypeScriptnpm run dev— run via ts-nodenpm start/npm test— build, run integration tests, then smoke-run the hook
Releasing to npm
- Update
CHANGELOG.mdand theversionfield inpackage.json(this repo does not runnpm versionautomatically). - From a clean tree, run
npm test(also runs automatically viaprepublishOnlyon publish). npm publish(usesprepackto compile TypeScript before the tarball is built). Usenpm publish --dry-runfirst if you want to inspect the pack without uploading.
License
MIT — see LICENSE.
Last updated: 2026-06-03
