RealityLint
Your README says it works. RealityLint checks if it actually does.
Static, deterministic README-vs-repository verification — without executing README commands, without an LLM, and without sending your code anywhere.
by @voonterr
local-first · no API key · no LLM · CI-ready · safe static analysis
The problem
README files drift.
A command gets renamed. A file moves. .env.example disappears. The project switches from Yarn to npm. AI-generated documentation confidently describes a script that never existed.
Most Markdown linters can tell you whether the document is formatted correctly. RealityLint asks a different question:
Do the locally verifiable claims in this README still match the repository?
It stays deliberately conservative: if a claim cannot be proven from local repository evidence, RealityLint skips it instead of guessing.
30-second demo
realitylint examples/broken-project --fail-on never
RealityLint v0.1.3 — by @voonterr
RealityLint score: 34/100
✗ README.md:3 ERROR RL002 Documented local link target "docs/setup.md" does not exist.
! README.md:6 WARNING RL004 README uses yarn, but the repository has only an npm lockfile.
✗ README.md:7 ERROR RL001 Documented package script "dev" is not defined in package.json.
✗ README.md:8 ERROR RL003 Documented environment template ".env.example" does not exist.
✗ README.md:9 ERROR RL005 Documented Python entry file "scripts/start.py" does not exist.
4 error(s), 1 warning(s), 0 notice(s).
Why RealityLint?
| RealityLint | |
|---|---|
| Deterministic | Same repository → same result. No model randomness. |
| Safe by design | Parses commands from docs but never executes them. |
| Private | Your repository never leaves the machine. |
| CI-friendly | Text, JSON, Markdown and SARIF output. |
| Low false-positive bias | Ambiguous claims are skipped instead of guessed. |
| Monorepo-aware | Understands common working-directory forms such as cd frontend && .... |
What it checks
| Rule | Verification |
|---|---|
RL000 |
Repository/README scan preconditions are safe and readable |
RL001 |
npm/pnpm/yarn/bun package scripts exist in the relevant package.json |
RL002 |
Relative Markdown links and images point to real local paths |
RL003 |
Documented .env.example / .env.sample files exist |
RL004 |
Package-manager commands agree with the detected lockfile family |
RL005 |
Python entry-file commands point to real files |
RL006 |
Documented Make targets exist in GNUmakefile/makefile/Makefile |
RL007 |
Pinned self-install versions agree with [project].version |
RL008 |
A claimed common license has a real LICENSE/COPYING file |
RL009 |
Obvious inline repository paths still exist (notice) |
RL010 |
Malformed/unreadable package metadata is reported instead of crashing |
RealityLint also understands common cd subdir && ... flows, npm --prefix, yarn --cwd, pnpm --dir / pnpm -C, bun --cwd, make -C, nested README link bases, Windows-style path separators/prompts, backtick/tilde shell fences and inline shell commands.
Quick start
Requires Python 3.10+.
git clone https://github.com/voonterr/realitylint.git
cd realitylint
python -m pip install -e .
realitylint .
Or run it from the source checkout without installing the console script:
python -m realitylint /path/to/repository
Try the intentionally broken fixture:
realitylint examples/broken-project --fail-on never
GitHub Actions
Add this to .github/workflows/realitylint.yml in another repository:
name: README reality check
on: [pull_request]
permissions:
contents: read
jobs:
realitylint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: voonterr/realitylint@v1
with:
fail-on: error
The action emits inline annotations and a Markdown job summary.
Note:
voonterr/realitylint@v1becomes usable after the firstv1tag is published. See PUBLISH.md for the release checklist.
Output formats
realitylint . --format text
realitylint . --format json
realitylint . --format markdown
realitylint . --format sarif
CI failure policy:
realitylint . --fail-on error
realitylint . --fail-on warning
realitylint . --fail-on never
Machine-readable formats keep stdout clean — the by @voonterr banner does not corrupt JSON or SARIF output.
Security model
RealityLint is intentionally a static checker, not a sandbox.
- README commands are parsed, never executed.
--readmecannot escape the repository root.- Symlink/path resolution is contained before files are read.
- README and metadata files have size limits to reduce memory/regex abuse.
- GitHub Action inputs are passed through environment variables instead of direct shell interpolation.
- GitHub annotations escape workflow-command control characters.
- Third-party Actions used by this repository are pinned to immutable commit SHAs.
- No network access is required for the scanner itself.
Found a security issue? Please read SECURITY.md instead of opening a public exploit report.
Project philosophy
- Evidence over vibes. Every finding should point to repository evidence.
- No arbitrary execution. Documentation commands are parsed, never run.
- Prefer silence to a false accusation. Ambiguous syntax is skipped.
- Local-first. Source code and docs stay on the user's machine.
- Small rules, easy contributions. Ecosystem checks should remain isolated and testable.
Roadmap
Near-term priorities:
- Go:
go run, module path and toolchain claims - Rust:
cargo run --bin, features and MSRV claims - Docker Compose service/port verification
-
.envvariable drift: code ↔ template ↔ docs - pre-commit hook
- ignore directives for intentional examples
- CLI flag verification from generated
--helpsnapshots
See the detailed ROADMAP.md.
Contributing
Bug reports, rule ideas and pull requests are welcome.
python -m unittest discover -s tests -v
Start with CONTRIBUTING.md. New contributors can also open a rule request using the repository issue template.
Status
RealityLint is currently alpha software. Its checks are intentionally narrow and deterministic. It will not understand every shell expression or every documentation style — and it should not pretend to.
Author
Created and maintained by @voonterr.
If RealityLint saves you from a broken README, consider ⭐ starring the repository — it helps other developers discover the project.
License
MIT License. Copyright © 2026 voonterr. See LICENSE.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file realitylint-0.1.3.tar.gz.
File metadata
- Download URL: realitylint-0.1.3.tar.gz
- Upload date:
- Size: 24.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b4710c0a900e562fc24b660f0fccb24002fe279309c35366c259475ebb831f2b
|
|
| MD5 |
5b7d2378695f5b2111540fae30fd2606
|
|
| BLAKE2b-256 |
0282167eb301df1268e1e18a131042efd13ae978e7a114283a538cee27d6fc92
|
Provenance
The following attestation bundles were made for realitylint-0.1.3.tar.gz:
Publisher:
publish-pypi.yml on voonterr/realitylint
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
realitylint-0.1.3.tar.gz -
Subject digest:
b4710c0a900e562fc24b660f0fccb24002fe279309c35366c259475ebb831f2b - Sigstore transparency entry: 2465469974
- Sigstore integration time:
-
Permalink:
voonterr/realitylint@bb0e3b8474d6b7dbeb7fb7cae9ca3991ed06828a -
Branch / Tag:
refs/heads/main - Owner: https://github.com/voonterr
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@bb0e3b8474d6b7dbeb7fb7cae9ca3991ed06828a -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file realitylint-0.1.3-py3-none-any.whl.
File metadata
- Download URL: realitylint-0.1.3-py3-none-any.whl
- Upload date:
- Size: 17.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b55af560a75d386a0bf56d9e32625844ca98c593a3c3d80f19095fb285865b2a
|
|
| MD5 |
361d2150013735a18137cc02e5139324
|
|
| BLAKE2b-256 |
3f735c1b12c4dc14f00a881e237150c90b29990b9778a43ab770565eb07520a8
|
Provenance
The following attestation bundles were made for realitylint-0.1.3-py3-none-any.whl:
Publisher:
publish-pypi.yml on voonterr/realitylint
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
realitylint-0.1.3-py3-none-any.whl -
Subject digest:
b55af560a75d386a0bf56d9e32625844ca98c593a3c3d80f19095fb285865b2a - Sigstore transparency entry: 2465470018
- Sigstore integration time:
-
Permalink:
voonterr/realitylint@bb0e3b8474d6b7dbeb7fb7cae9ca3991ed06828a -
Branch / Tag:
refs/heads/main - Owner: https://github.com/voonterr
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@bb0e3b8474d6b7dbeb7fb7cae9ca3991ed06828a -
Trigger Event:
workflow_dispatch
-
Statement type: