truthlint
Your repository is lying. truthlint finds where.
Find every place where your repository's docs, configs, CI, containers and code contradict each other.
Your README says Python 3.8+. pyproject.toml says >=3.10. The Dockerfile runs 3.9. CI tests a version
users can't even install on. The setup guide tells newcomers to run make lint — a target that was renamed a year
ago. The code reads JWT_SECRET, which is nowhere in .env.example.
Every one of those files is individually "fine". Together they lie.
truthlint reads a repository the way a careful new contributor would — then cross-examines every file against every other file and reports, with evidence, where the project's claims and its reality disagree.
HIGH TL101-406201 Python version contradiction high confidence
README.md says Python 3.8+ is enough, but the project requires >=3.10
(minimum 3.10). Users following the docs on Python 3.8 will be refused by pip.
↳ README.md:8 claims Python 3.8+
↳ pyproject.toml:9 declares requires-python '>=3.10'
Fix: State Python 3.10+ in README.md, or raise the constraint. [auto-fix available]
HIGH TL202-6F78F4 Command runs an undefined make target high confidence
`README.md` documents `make lint`, but target `lint` is not defined in
`Makefile` (defined: format, serve, test).
↳ README.md:28 documents `make lint`
↳ Makefile defines targets: format, serve, test
Why truthlint?
Linters check one file at a time. Type checkers check code. Link checkers check URLs. Nothing checks that the files agree with each other — and that is exactly where onboarding breaks, deployments drift and "works on my machine" is born.
| 🔎 Cross-file analysis | 35 rules compare README, docs, pyproject.toml, requirements*.txt, package.json, lockfiles, Dockerfiles, compose files, GitHub Actions / GitLab CI, Makefiles, .env examples and source code. |
| 🧾 Evidence, always | Every finding cites the exact file and line on each side of the contradiction, a confidence level, and how it was verified. truthlint never reports something it didn't check. |
| 🧭 Onboarding audit | Walks your setup instructions step by step (tracking cd, cp, venv …) and verifies each command statically: does that npm script, make target, file, compose service or pip extra actually exist? |
| 📊 Explainable scores | A 0–100 Repository Truth Score and an Onboarding Reliability Score, with every deduction itemised. |
| 🩹 Reviewable fixes | Suggested fix for every finding; many come with a unified-diff patch. Nothing is written without your explicit confirmation. |
| 🔒 Safe by construction | Fully offline, no API keys, no AI service. Never executes anything from the repository — not even git (a repo's .git/config can make git run commands). |
Installation
Requires Python 3.11+.
pipx install truthlint # recommended: isolated CLI
# or
pip install truthlint
From source:
git clone https://github.com/harshith7002/truthlint.git
cd truthlint
pip install -e ".[dev]"
This installs the truthlint command (python -m truthlint works too).
Quick start
truthlint scan . # investigate the current repository
truthlint scan . --deep # + heuristic checks (unused deps/env vars, stale doc paths, CI coverage)
truthlint explain TL202-6F78F4 # evidence in context, rationale and the proposed patch
truthlint fix # preview every available patch (dry run)
truthlint fix --interactive # review and apply patches one by one
truthlint report --format markdown -o truthlint-report.md
truthlint report --format json -o truthlint.json
Try it on the bundled sample repositories:
truthlint scan examples/drifting-python-api
truthlint scan examples/drifting-node-service --deep
truthlint scan examples/healthy-library # 100/100, zero findings
What truthlint detects
Run truthlint rules for the full list, or truthlint explain TL201 for details on any rule. See docs/rules.md.
| Area | Examples |
|---|---|
| Runtime versions | README / Dockerfile / CI matrix / .python-version / .nvmrc / classifiers / ruff target-version vs requires-python or engines.node; container runtime drifting from the local pin; declared minimum never tested in CI |
| Documented commands | npm run X, yarn X, pnpm X with no such script · make X with no such target · scripts, requirements files, directories and modules that don't exist · pip install ".[dev]" with no dev extra · docker compose up svc with no such service · npm install in a pnpm-locked repo · poetry install in a non-Poetry project · documented CLI never declared as an entry point |
| Documentation | Broken relative links and heading anchors (case-exact, like GitHub) · outdated project-structure trees · inline references to files that no longer exist |
| Environment | Variables read in code (Python AST incl. pydantic-settings, JS/TS, Go, Ruby, Rust, Java, PHP, C#, Elixir, Prisma, shell) but missing from .env.example; documented variables nothing reads; no example file at all |
| Dependencies | Imports not declared in any manifest (works only on the author's machine) · declared deps never imported · runtime code importing dev-only deps — for Python and JS/TS |
| Containers | COPY of missing files or files excluded by .dockerignore · Docker pinning different versions than the manifest · lockfile not copied before install · CMD pointing at missing modules · compose build contexts, Dockerfiles, env_files and depends_on that don't exist |
| CI | Workflow run: steps calling missing scripts/targets/files · missing working-directory · missing local actions |
| Build metadata | Malformed TOML/JSON/YAML · console scripts pointing to missing modules/functions · readme, main, bin files that don't exist |
| Onboarding | No setup instructions · required runtimes/package managers never mentioned · env configuration never explained |
Scores
Repository Truth Score (0–100). Each finding contributes severity weight × confidence
(critical 20 · high 10 · medium 5 · low 1.5; confidence 1.0 / 0.7 / 0.4). Repeats of the same rule count half as
much each time and each rule is capped at 25 points, so one noisy area can't dominate. The score is
100 × e^(−points/90). Every deduction is listed in the Markdown/JSON report.
Onboarding Reliability Score (0–100). Starts at 100: −40 if there are no runnable setup instructions, −15 per
documented step that fails verification (max −60), −8 per required tool the docs never mention, −5 if
environment configuration is never explained. Steps that would need execution to verify (e.g. git clone,
pytest) are reported as unverified and never counted as passing or failing.
Using truthlint in CI
# .github/workflows/truthlint.yml
name: truthlint
on: [pull_request]
jobs:
truthlint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- run: pip install truthlint
- run: truthlint scan . --fail-on high # fail on high/critical contradictions
- run: truthlint report --format markdown -o truthlint-report.md
if: always()
Exit codes: 0 success · 1 a --fail-under / --fail-on gate tripped · 2 usage error.
Configuration
Add a [tool.truthlint] table to pyproject.toml or create .truthlint.toml:
[tool.truthlint]
exclude = ["examples/**", "vendor/"] # gitignore syntax, on top of .gitignore
disable = ["TL402"] # rule IDs to skip
ignore_env = ["MY_CI_ONLY_VAR"] # env vars that never need documenting
min_severity = "low" # hide findings below this severity
Suppress a single finding inline with a comment on the same line (or a comment line directly above):
<!-- truthlint-ignore TL302 -->
Generated files land in `build/output/report.html`.
make docs # truthlint-ignore TL202, TL203
Accuracy principles
truthlint is built to be trusted in CI, so it prefers silence to guessing:
- Evidence or nothing. A finding can't be constructed without at least one file/line citation (enforced in code).
- Unverifiable ≠ broken. Anything that depends on the network or installed tools is reported as unverified.
- Ambiguity is downgraded. If a script exists in another package of a monorepo, or a Makefile uses pattern rules/includes, truthlint reports unverified instead of missing.
- Generated paths are respected. Missing files under
dist/,build/, gitignored paths, or outputs of earlier documented steps (cp,mkdir,python -m venv) aren't reported. - Heuristic rules are opt-in. Rules with a higher false-positive risk run only with
--deep. - Malformed files are reported, not guessed at. If a file can't be parsed, dependent checks are skipped and the file is listed under "Not analysed".
The bundled examples/healthy-library must always score 100 with zero findings — it's part of the test suite.
Architecture
┌──────────────────────────────────────────────────────────┐
repository ─▶ │ discovery own .gitignore engine, no git, no symlink │
│ escapes, size/binary limits │
└───────────────────────┬──────────────────────────────────┘
▼
┌──────────────────────────────────────────────────────────┐
│ RepoContext (lazy, cached) │
│ parsers: markdown · shell · pyproject/requirements · │
│ package.json · Dockerfile · compose · GH Actions · │
│ GitLab CI · Makefile · .env · Python AST · JS/TS │
└───────┬───────────────────────┬──────────────────────────┘
▼ ▼
┌──────────────────────┐ ┌──────────────────────────────────────┐
│ intel: profile │ │ checks → Findings (pydantic models) │
│ languages, tooling │ │ runtime · commands · docs · env · │
└──────────┬───────────┘ │ deps · containers · CI · build │
│ └──────────────┬───────────────────────┘
│ ▼
│ onboarding audit · suppression · scoring
▼ ▼
┌──────────────────────────────────────────────────────────┐
│ ScanResult → terminal (Rich) · Markdown · JSON · patches │
└──────────────────────────────────────────────────────────┘
| Module | Responsibility |
|---|---|
src/truthlint/context.py |
File discovery and the lazily-parsed, cached view every rule reads from |
src/truthlint/ignore.py |
.gitignore / .dockerignore matcher (git semantics, no subprocess) |
src/truthlint/parsers/ |
One parser per format; all line-number aware; none execute code |
src/truthlint/intel.py |
Repository intelligence: languages, frameworks, package managers, CI, key files |
src/truthlint/rules/ |
The checks. commands.py hosts the static command verifier shared by docs, CI, Makefiles and npm scripts |
src/truthlint/onboarding.py |
Setup-instruction audit and onboarding score |
src/truthlint/scoring.py |
Explainable Truth Score |
src/truthlint/fixes.py |
Edit validation, unified diffs, consent-gated application |
src/truthlint/render/ |
Rich terminal UI, Markdown and JSON reports |
src/truthlint/cli.py |
Typer commands |
More detail in docs/architecture.md, including how to write a new rule.
Contributing
Contributions are very welcome — especially new rules, parsers for more ecosystems, and false-positive reports (there's a dedicated issue template). See CONTRIBUTING.md.
pip install -e ".[dev]"
pytest
ruff check src tests
ruff format --check src tests
truthlint scan . # truthlint dogfoods itself
Roadmap
- More ecosystems: Go modules, Cargo, Gemfile, Gradle/Maven version checks
truthlint scan --diff origin/mainto report only findings introduced by a change- SARIF output for GitHub code scanning
- Verifying CLI sub-commands documented in the README against argparse/Typer/Click definitions
License
Metadata
Release files for truthlint 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| truthlint-0.1.0.tar.gz | 111.6 kB | With provenance | Details for truthlint-0.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| truthlint-0.1.0-py3-none-any.whl | Python 3 | none | any | Details for truthlint-0.1.0-py3-none-any.whl |
Total release size: 224.7 kB
Release files / truthlint-0.1.0.tar.gz
| Download URL | truthlint-0.1.0.tar.gz |
|---|---|
| Size | 111.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
de9f4062fd5df4152b9de69686a0586d20f571dcca8b062585f6f03d3f8643e0
|
|
BLAKE2b-256 checksum How to use checksums |
2e6cafd42f4577a819566da236e87fa073a5a850c777dbd2bbc9e0037e899e16
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 11, 2026.
Transparency logRelease files / truthlint-0.1.0-py3-none-any.whl
| Download URL | truthlint-0.1.0-py3-none-any.whl |
|---|---|
| Size | 113.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
4b4facc646916496ae0dc8e1b8987ad61474529d7e5370f6e892bd4a630da2fa
|
|
BLAKE2b-256 checksum How to use checksums |
574a0d02383bbbd8757c7c85bde7f34a6c1b7778c2fe33804150a1de0ba38b12
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 11, 2026.
Transparency logSecurity for truthlint 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
Both files in this release have been uploaded with provenance metadata.
Attestation for truthlint-0.1.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 11, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.