doc-drift
Find the docs that lie. docdrift reports the environment variables and CLI flags your documentation promises that the code no longer has, and the ones the code has that nobody documented.
$ docdrift check
Docs that are wrong now
stale-env LEGACY_TOKEN README.md:41
the docs promise it and the code never reads it: rename the doc, or read the variable
Code nobody is told about
undocumented-flag --secret-mode src/cli.py:22
the flag exists and no one can find it
1 stale in docs, 1 missing from docs (3 docs, 11 source files)
Why this exists
Docs drift in a specific, boring way: someone renames a variable or deletes a flag, the code stays green, and the README keeps instructing people to use something that no longer exists. Nothing catches it, because tests exercise code and nothing exercises prose.
The usual version of this tool greps. Grep lies in both directions: it finds DATABASE_URL inside a comment or a deleted branch, and it misses a name that appears with different spacing. docdrift reads the source with ast, so a variable inside a comment is not a variable, and a renamed function is really renamed.
Install
pipx install doc-drift-py
The distribution is doc-drift-py because PyPI refused doc-drift as too similar to an
existing project. The command stays docdrift: nothing you type changes.
Use
docdrift check # README.md + docs/ against src/ (or .)
docdrift check --docs docs --src app # explicit paths
docdrift check --fail-on stale # only fail on docs that are wrong, not gaps
docdrift check --symbols # also check backticked function/class names
docdrift check --json # machine-readable
docdrift check --ignore LEGACY_* # skip a name, exact or prefix
Exit codes are the contract:
| code | meaning |
|---|---|
| 0 | nothing drifted |
| 1 | drift found (the useful failure) |
| 2 | usage or configuration problem: bad path, no docs, no source |
In CI:
- name: Docs tell the truth
run: pipx run --spec git+https://github.com/mgkvibez/doc-drift.git docdrift check --fail-on stale
What counts as a claim
Precision matters more than coverage here, because a checker that cries wolf gets deleted. So a documentation mention only counts when it is written the way a user would read it:
- an environment variable in backticks, after
export, insideos.environ.get(...), or anywhere inside a fenced code block
- a
--flagwritten as a flag, not a hyphenated word and not a version range like1.0--2.0
Plain uppercase prose is ignored on purpose: This speaks HTTP and JSON over TCP is not a claim about your environment.
On the code side, only real reads count: os.environ["X"], os.environ.get("X"), os.getenv("X"), argparse.add_argument("--flag"). Files that fail to parse are skipped silently and cannot create findings.
Suppressing a false positive
Some docs legitimately discuss names they do not promise: a migration guide, an example of another tool's command, a paragraph about how the check works. Two markers handle that, and both keep line numbers honest by blanking rather than deleting.
<!-- docdrift: ignore-next-line -->blanks the line that follows it- a fence tagged
docdrift-ignore(```console docdrift-ignore) is treated as an illustration, never as a claim
argparse's own -h, --help and --version are excluded automatically, because no project documents those.
What it deliberately does not do
- Not every framework. Flags are read from
argparse. Click, Typer and docopt are not parsed yet, and a project using them will report its flags as undocumented. That is a known gap, not a silent one. - Not every language. Source scanning is Python only. Markdown, RST and plain text docs are read.
- A flag in an example may not be yours.
gh run view --log-failedin your README is a flag ofgh, not of your project, and it will be reported. Use--ignoreor tag that fencedocdrift-ignore. Found by running this on its own sibling project. - Not a prose checker. It says a name is missing, not that a sentence is wrong.
- Symbols are opt-in. Backticked
function_namereferences are heuristic, so they are behind--symbolsand off by default.
Dogfooding
This repo runs docdrift on itself in the gate, so the README above cannot quietly drift from the code that ships it.
License
MIT
Metadata
Release files for doc-drift-py 0.1.1
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 |
|---|---|---|---|---|
| doc_drift_py-0.1.1.tar.gz | 13.1 kB | With provenance | Details for doc_drift_py-0.1.1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| doc_drift_py-0.1.1-py3-none-any.whl | Python 3 | none | any | Details for doc_drift_py-0.1.1-py3-none-any.whl |
Total release size: 25.2 kB
Release files / doc_drift_py-0.1.1.tar.gz
| Download URL | doc_drift_py-0.1.1.tar.gz |
|---|---|
| Size | 13.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
55f018fdabbb8480929b289ed4d29ac64987770067b214c960108e435dba37d7
|
|
BLAKE2b-256 checksum How to use checksums |
43ec21e33be7615e7a7cb7aea30898c5129ee80bbf0145900df1947771841bf9
|
| 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 Oct 31, 2026.
Transparency logRelease files / doc_drift_py-0.1.1-py3-none-any.whl
| Download URL | doc_drift_py-0.1.1-py3-none-any.whl |
|---|---|
| Size | 12.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
9f1e333086048292408c57c64fb5cd17ab8cb4c9e1ad3ee449e4c8c59669177b
|
|
BLAKE2b-256 checksum How to use checksums |
8d1d46439befcc90c5d184c46b2f18e6e253d68deae37b260716083dd387182e
|
| 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 Oct 31, 2026.
Transparency logSecurity for doc-drift-py 0.1.1
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
All 2 files in this release have been uploaded with provenance metadata.
Attestation for doc_drift_py-0.1.1.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 Oct 31, 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.