Catalog PyPI
PACKAGE EXPLORERView in registry

adr-drift

PyPI

Deterministic architecture tests: keep the codebase honest about its own ADRs.

Versions collected1
Direct dependencies0From release 0.1.0
Last observed20 Oct, 19:50 UTC

README

Version 0.1.0 documentation

ADR Drift

Deterministic architecture tests for any language. ADRs rot the moment they merge — this keeps them mechanically true. Define layers and constraints once, then adr-drift check fails CI when code drifts from the decisions.

The problem

"The moment an ADR gets merged, it decays into a passive historical record unless something mechanical forces it to stay alive."

Developers — and now AI coding agents — merge boundary violations because nothing checks decisions against code. ArchUnit is Java-only, deptrac is PHP-only. ADR Drift is language-agnostic, repo-local, and CI-friendly.

Install

git clone <repo> && cd adr-drift
pip install .   # provides the `adr-drift` console script

Or run without installing: python3 -m adr_drift from the repo root.

Quick start

cd your-repo
python3 -m adr_drift init      # scaffold arch.yaml + sample ADR from folder layout
# tighten the rules in arch.yaml, add ## Constraints to your ADRs
python3 -m adr_drift check     # verify; exit 1 on violations (CI-ready)
# repo already has legacy violations? grandfather them, then enforce:
python3 -m adr_drift baseline                    # record current violations
python3 -m adr_drift check --baseline .adr-baseline.json

Commands

CommandWhat it does
initInfer layers from folder layout, write arch.yaml + sample ADR + index
checkVerify the repo against arch.yaml + every ADR's ## Constraints (--baseline FILE grandfathers recorded violations)
baselineWrite current violations to .adr-baseline.json (default) for check --baseline
drift --since HEAD~5Report violations introduced since a git ref, plus violations fixed since then (pre-existing ones ignored)
new "title"Create the next-numbered ADR from a template
indexRegenerate the one-sentence-per-ADR index (docs/adr/README.md)

The constraint DSL

Rules live in arch.yaml and in any ADR's ## Constraints section:

forbid-import: handlers -> db.drivers     # layering: handlers may not import drivers
forbid-pattern: src/**.py !~ \beval\(     # no eval() anywhere in src/
require-pattern: src/handlers/**.py =~ authenticate\(   # handlers must authenticate

from/to match layer names or module prefixes (db.drivers matches db.drivers.pg); * wildcards supported. Comments start with #. To-side patterns resolve against layer paths too: in a src/-layout repo both db.drivers and src.db.drivers spellings match a db layer mapped to src/db/**.

How it checks

  • Python is parsed with the real ast — no regex false positives from comments or strings.
  • JS/TS/Go/Rust/Java/Ruby/PHP use a heuristic regex import extractor (documented as such; --strict-py-only disables it).
  • drift compares violations at HEAD against the base ref via git show — it never touches your working tree, and git blame tags each new violation with its introducing commit.

CI

- run: python3 -m adr_drift check --format json --fail-on violations

--fail-on none reports without failing. JSON output is stable for tooling.

Honest limits

  • The regex fallback for non-Python languages is heuristic — it can miss exotic import forms. Python is precise; everything else is best-effort.
  • drift needs a git repo; check works anywhere.
  • Rules are only as good as the constraints you write — init scaffolds, you tighten.

Tests

55/55 pass: python3 -m unittest discover -s tests

Downloads & popularity

Awaiting observations

No metric observations yet

Download counts and popularity will appear here as the collector receives them.

Versions 1

Collected releases
VersionPublishedDirect dependenciesOpen version
0.1.019 Oct 20260

Package advisories

0
No matching advisories collected

This describes our collected data; it is not a security assessment.

Repository

PENDING
calasdan-sketch/adr-drift

Shared repository data · GitHub

License detected in repository
Not collected

Metadata history

Meaningful changes
Current collected state Current

Observed since 20 Oct, 19:50 UTC

No superseded metadata states collected. Unchanged observations do not create new revisions.

Record identity

package:cd72c326568edb07359df4b9f6e1236f6dcae0e6d6fcd11be3bf6619978180e3