Skip to main content

Deterministic architectural drift detection for AI-accelerated Python repositories through cross-file coherence analysis

Project description

Drift

Deterministic architecture erosion detection for AI-accelerated codebases

CI Precision (lenient) Signals codecov SARIF Agent API
PyPI Python versions License Stars

95% precision lenient / 77% strict (single-rater, 286 findings, 5 repos) · 23 signals · deterministic · no LLM in pipeline · full study · docs · FAQ
2 139+ tests · 0 regressions · 88 % mutation recall (15/17 patterns) · validation data

AI coding tools write code that works — but doesn't fit. Error handling fragments across 4 patterns, layer boundaries erode, near-identical utilities accumulate silently. Drift finds exactly that: deterministic structural analysis in seconds, no LLM required.

Drift overview: one splintered behavior becomes one named repair path

The overview above is the model. The analyzer turns that into concrete output like this:

drift analyze demo

Validated on FastAPI · Pydantic · Django · httpx · pytest · requests · click and more study repos


pip install drift-analyzer
drift analyze --repo .

Adopt drift through the path that fits your team: package install from PyPI, a GitHub Action, or the built-in pre-commit hook.

╭─ drift analyze  myproject/ ──────────────────────────────────────────────────╮
│  DRIFT SCORE  0.52  Δ -0.031 ↓ improving  │  87 files  │  AI: 34%  │  2.1s │
╰──────────────────────────────────────────────────────────────────────────────╯

  Module                  Score  Bar                   Findings  Top Signal
  src/api/routes/          0.71  ██████████████░░░░░░       12   PFS 0.85
  src/services/auth/       0.58  ███████████░░░░░░░░░        7   AVS 0.72
  src/db/models/           0.41  ████████░░░░░░░░░░░░        4   MDS 0.61

  ◉ PFS  0.85  Error handling split 4 ways
               → src/api/routes.py:42
               → Next: consolidate into shared error handler

  ◉ AVS  0.72  DB import in API layer
               → src/api/auth.py:18
               → Next: move DB access behind service interface

What drift catches

Drift finds the structural problems AI-generated code introduces quietly: the same error handling done 4 different ways, database imports leaking into the API layer, near-identical helper functions across 6 files. Problems that pass every test but make the codebase harder to change.

Try it now

drift analyze --repo .          # see your top findings
drift explain PFS               # learn what a signal means
drift fix-plan --repo .         # get actionable repair tasks

Add to CI (start report-only)

- uses: mick-gsk/drift@v1
  with:
    fail-on: none               # report findings without blocking
    upload-sarif: "true"        # findings appear as PR annotations

Once the team trusts the output, tighten: fail-on: high.

More: Quick Start · Example Findings · Team Rollout

Discovery Surfaces

Quick install (macOS / Linux / WSL — auto-detects pipx, uv, or pip):

curl -fsSL https://raw.githubusercontent.com/mick-gsk/drift/main/scripts/install.sh | sh

All integration paths:

Path Command / Config Best for
Install script curl -fsSL .../install.sh | sh One-liner, no Python setup
PyPI pip install drift-analyzer Local use, scripts, CI
pipx / uvx pipx install drift-analyzer Isolated CLI (no venv)
Homebrew brew tap mick-gsk/drift && brew install drift-analyzer macOS / Linux devs
Docker docker run -v .:/src ghcr.io/mick-gsk/drift analyze --repo /src Container-based CI
GitHub Action uses: mick-gsk/drift@v1 GitHub CI/CD pipelines
pre-commit repo: https://github.com/mick-gsk/drift Git hooks

Full installation guide: Installation

For questions, rollout feedback, and real-world findings, use GitHub Discussions.

AI-Assisted Workflows

Drift integrates with AI coding sessions (Copilot, Cursor, Claude) and MCP-capable editors:

pip install drift-analyzer[mcp]
drift scan --repo . --max-findings 5   # session baseline for agents
drift diff --staged-only               # pre-commit check
drift fix-plan --repo .                # agent-friendly repair tasks
drift mcp --serve                      # MCP server for IDE integration

To minimise setup work, run drift init --mcp --claude. Drift will scaffold both MCP configs and automatically use the current Python interpreter when no drift executable is on your PATH. The generated pre-push hook still expects drift on PATH.

drift agent workflow: scan → diff --staged-only → fix-plan

Use this when you want drift inside an agent loop instead of as a standalone report.

Full setup: Integrations · MCP · Vibe-Coding Guide

More walkthroughs: demos/README.md

Vibe-Coding Remediation Walkthrough — from findings to verified improvement
  1. Run an initial scan and save the baseline snapshot.
  2. Triage only the top findings by impact and actionability.
  3. Generate a small fix queue and implement one focused change.
  4. Re-scan and confirm that the finding count and/or severity improved.
  5. Update the baseline so future regressions can be caught early.
# 1) Day-0 baseline snapshot
drift analyze --repo . --format json -o drift_day0.json

# 2) Triage high-impact findings first
drift analyze --repo . --sort-by impact --max-findings 5
drift explain PFS

# 3) Create focused remediation tasks
drift fix-plan --repo . --max-tasks 3

# 4) Implement one remediation (example: consolidate connector error handling)

# 5) Confirm improvement
drift analyze --repo . --format json -o drift_after_fix.json
drift trend --repo . --last 30

# 6) Update baseline (new ratchet point)
drift baseline --output .drift-baseline.json

Concrete before/after example (PFS):

  • Before: fragmented error handling in one connector layer appears as a high-severity PFS finding.
  • After: a shared handler reduces fragmentation, lowering the PFS score and total high-severity findings.

Related guides: Quick Start · Finding Triage · Team Rollout

Why teams use drift

Your linter, type checker, and test suite can tell you whether code is valid. They do not tell you whether the repository is quietly splitting into incompatible patterns across modules.

Drift focuses on that gap:

  • Ruff / formatters / type checkers: local correctness and style, not cross-module coherence.
  • Semgrep / CodeQL / security scanners: risky flows and policy violations, not architectural consistency.
  • Maintainability dashboards: broad quality heuristics, not a drift-specific score with reproducible signal families.

Current public evidence: 15 real-world repositories in the study corpus, 23 signal families (15 scoring-active, 8 report-only), and auto-calibration that rebalances weights at runtime. Full study → · Trust & limitations

Use cases

Use case: Pattern fragmentation in a connector layer

Problem: A FastAPI service has 4 connectors, each implementing error handling differently — bare except, custom exceptions, retry decorators, and silent fallbacks.

Solution:

drift analyze --repo . --sort-by impact --max-findings 5

Output: PFS finding with score 0.96 — "26 error_handling variants in connectors/" — shows exactly which files diverge and suggests consolidation.

Use case: Architecture boundary violation in a monorepo

Problem: A database model file imports directly from the API layer, creating a circular dependency that breaks test isolation.

Solution:

drift check --fail-on high

Output: AVS finding — "DB import in API layer at src/api/auth.py:18" — blocks the CI pipeline until the import direction is fixed.

Use case: Duplicate utility code from AI-generated scaffolding

Problem: AI code generation created 6 identical _run_async() helper functions across separate task files instead of finding the existing shared utility.

Solution:

drift analyze --repo . --format json | jq '.findings[] | select(.signal=="MDS")'

Output: MDS findings listing all 6 locations with similarity scores ≥ 0.95, enabling a single extract-to-shared-module refactoring.

Setup and rollout options

Seven integration paths — pick the one that fits your team:

Path Command / Config Best for
Install script curl -fsSL .../install.sh | sh One-liner, no Python setup
PyPI pip install drift-analyzer Local use, scripts, CI
pipx / uvx pipx install drift-analyzer Isolated CLI (no venv needed)
Homebrew brew tap mick-gsk/drift && brew install drift-analyzer macOS / Linux devs
Docker docker run -v .:/src ghcr.io/mick-gsk/drift analyze --repo /src Container-based CI, reproducible runs
GitHub Action uses: mick-gsk/drift@v1 GitHub CI/CD pipelines
pre-commit repo: https://github.com/mick-gsk/drift Pre-commit hooks
Full GitHub Action example (recommended: start report-only)
name: Drift

on: [push, pull_request]

jobs:
  drift:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      security-events: write

    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - uses: mick-gsk/drift@v1
        with:
          fail-on: none           # report findings without blocking CI
          upload-sarif: "true"    # findings appear as PR annotations

Once the team has reviewed findings for a few sprints, tighten the gate:

      - uses: mick-gsk/drift@v1
        with:
          fail-on: high           # block only high-severity findings
          upload-sarif: "true"
pre-commit hook configuration
# .pre-commit-config.yaml
repos:
  - repo: https://github.com/mick-gsk/drift
    rev: vX.Y.Z                  # replace with the latest tag from https://github.com/mick-gsk/drift/releases
    hooks:
      - id: drift-check          # blocks on high-severity findings
      # - id: drift-report        # report-only alternative (start here)

Or use a local hook if you already have drift installed:

# .pre-commit-config.yaml
repos:
  - repo: local
    hooks:
      - id: drift
        name: drift
        entry: drift check --fail-on high
        language: system
        pass_filenames: false
        always_run: true

CI gate (local):

drift check --fail-on none    # report-only
drift check --fail-on high    # block on high-severity findings

More setup paths:

Project operations:

If you want example findings before integrating, start with docs-site/product/example-findings.md.

All 23 signals

Drift scores 23 signal families (15 scoring-active, 8 report-only) — from pattern fragmentation and architecture violations to temporal volatility, security-by-default checks, and co-change coupling. Each finding includes a severity, file location, and concrete next action.

drift explain <SIGNAL> shows what any signal detects and how to fix it.

Signal Reference · Algorithm Deep Dive · Scoring Model

Agent output reference: Negative Context

How drift compares

Data sourced from STUDY.md §9 and benchmark_results/.

Capability drift SonarQube pylint / mypy jscpd / CPD
Pattern Fragmentation across modules Yes No No No
Near-Duplicate Detection Yes Partial (text) No Yes (text)
Architecture Violation signals Yes Partial No No
Temporal / change-history signals Yes No No No
GitHub Code Scanning via SARIF Yes Yes No No
Zero server setup Yes No Partial Yes
TypeScript Support Optional ¹ Yes No Yes

¹ Experimental via drift-analyzer[typescript]. Python is the primary target.

Drift is designed to complement linters and security scanners, not replace them. Recommended stack: linter (style) + type checker (types) + drift (coherence) + security scanner (SAST).

Full comparison: STUDY.md §9 — Tool Landscape Comparison

Is drift a good fit?

Drift is a strong fit for:

  • Python teams using AI coding tools in repositories where architecture matters
  • repositories with 20+ files and recurring refactors across modules
  • teams that want deterministic architectural feedback in local runs and CI

Wait or start more cautiously if:

  • the repository is tiny and a few findings would dominate the score
  • you need bug finding, security review, or type-safety enforcement rather than structural analysis
  • Python 3.11+ is not available in your local and CI execution path yet

The safest rollout path is progressive:

  1. Start with drift analyze locally and review the top findings.
  2. Add drift check --fail-on none in CI as report-only discipline.
  3. Gate only on high findings once the team understands the output.
  4. Ignore generated or vendor code and tune config only after reviewing real findings in your repo.

Recommended guides:

Trust and limitations

Public claims safe to repeat today: Drift is deterministic, benchmarked on 15 real-world repositories in the current study corpus, and uses 23 signal families (15 scoring-active, 8 report-only) with auto-calibration for runtime weight rebalancing and small-repo noise suppression.

What's limited: Benchmark validation is single-rater; not yet independently replicated. Small repos can be noisy. Temporal signals depend on clone depth. The composite score is orientation, not a verdict.

What's next: Independent external validation, multi-rater ground truth, signal-specific confidence intervals.

Drift is designed to earn trust through determinism and reproducibility:

  • no LLMs in the detection pipeline
  • reproducible CLI and CI output
  • signal-specific interpretation instead of score-only messaging
  • explicit benchmarking and known-limitations documentation

Interpreting the score

The drift score measures structural entropy, not code quality. Keep these principles in mind:

  • Interpret deltas, not snapshots. Use drift trend to track changes over time. A single score in isolation has limited meaning.
  • Temporary increases are expected during migrations. Two coexisting patterns (old and new) will raise PFS/MDS signals. This is the migration happening, not a problem.
  • Deliberate polymorphism is not erosion. Strategy, Adapter, and Plugin patterns produce structural similarity that MDS flags as duplication. Findings include a deliberate_pattern_risk hint — verify intent before acting.
  • The score rewards reduction, not correctness. Deleting code lowers the score just like refactoring does. Do not optimize for a low score — optimize for understood, intentional structure.

For a detailed discussion of epistemological boundaries (what drift can and cannot see), see STUDY.md §14.

Drift vs. erosion: Without layer_boundaries in drift.yaml, drift detects emergent drift — structural patterns that diverge without explicit prohibition. With configured layer_boundaries, drift additionally performs conformance checking against a defined architecture. Both modes are complementary: drift does not replace dedicated architecture conformance frameworks (e.g. PyTestArch for executable layer rules in pytest), but catches cross-file coherence issues those tools do not model.

Start with the strongest, most actionable findings first. If a signal is noisy for your repository shape, tune or de-emphasize it instead of forcing an early hard gate.

Further reading:

Test quality & release status

Test quality

  • 2 139+ tests, 0 regressions
  • 88 % mutation recall (15/17 patterns detected across 10 signal types)
    • 100 % recall: MDS, EDS, AVS, DIA, BEM, TPD, GCD
    • Undetected: 1 PFS return-pattern variant, 1 SMS outlier-module below threshold
  • Baseline: benchmark_results/mutation_benchmark.json

Release status

The PyPI classifier is Development Status :: 4 - Beta.

Core analysis and CI workflow are stable; some adjacent surfaces remain intentionally marked as experimental.

Current release posture:

  • core Python analysis: stable
  • CI and SARIF workflow: stable
  • TypeScript support: experimental
  • embeddings-based parts: optional / experimental
  • benchmark methodology: evolving

Full rationale and matrix: Stability and Release Status

Contributing

Drift's biggest blind spots are found by people running it on codebases the maintainers have never seen. Your real-world experience is a direct contribution to signal quality — whether you write code or not.

If Drift surprised you with an unexpected result, that's valuable feedback: open an issue or start a discussion. A well-documented false positive can be more valuable than a new feature.

I want to… Go here
Ask a usage question Discussions
Report a false positive / false negative FP/FN template
Report a bug Bug report
Suggest a feature Feature request
Propose a contribution before coding Contribution proposal
Report a security vulnerability SECURITY.md — not a public issue

New here? Start contributing

You don't need to understand the whole analyzer to help. Start at the level that fits your time:

  1. 15 min: Fix a typo or clarify a docs example → open a PR directly
  2. 30 min: Report an unexpected finding with reproduction steps → FP/FN template
  3. 1 hour: Add an edge-case test → pick a good first issue
  4. 2+ hours: Improve signal logic or finding explanations → see CONTRIBUTING.md
git clone https://github.com/mick-gsk/drift.git && cd drift && make install
make test-fast    # confirm everything passes, then start

First contribution? We'll help you scope it. Open a contribution proposal or ask in Discussions if you're unsure where to start.

Typical first contributions:

  • Report a false positive or false negative with reproduction steps
  • Add a ground-truth fixture for a signal edge case
  • Improve a finding's explanation text to be more actionable
  • Write a test for an untested edge case
  • Clarify docs or add a configuration example

What we value most: reproducibility, explainability, false-alarm reduction. What we deprioritize: new output formats without insight value, comfort features, complexity without analysis improvement.

See CONTRIBUTING.md for the full guide, contributor types, and the contribution ladder. See ROADMAP.md for current priorities.

Documentation map

License

MIT. See LICENSE.

Project details


Release history Release notifications | RSS feed

This version

2.5.3

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

drift_analyzer-2.5.3.tar.gz (1.0 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

drift_analyzer-2.5.3-py3-none-any.whl (336.5 kB view details)

Uploaded Python 3

File details

Details for the file drift_analyzer-2.5.3.tar.gz.

File metadata

  • Download URL: drift_analyzer-2.5.3.tar.gz
  • Upload date:
  • Size: 1.0 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.10

File hashes

Hashes for drift_analyzer-2.5.3.tar.gz
Algorithm Hash digest
SHA256 9fee4b4fe26068974021516f46a3e214eac745f321573ec0ec850b6816b6ac7a
MD5 98e49fc3e1b8efb76942f46364032934
BLAKE2b-256 6987e42277f58bf0a81a9ebc2cb134829263670785638f8201992b09bdac45dc

See more details on using hashes here.

File details

Details for the file drift_analyzer-2.5.3-py3-none-any.whl.

File metadata

  • Download URL: drift_analyzer-2.5.3-py3-none-any.whl
  • Upload date:
  • Size: 336.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.10

File hashes

Hashes for drift_analyzer-2.5.3-py3-none-any.whl
Algorithm Hash digest
SHA256 bb67372bec3b36f2669fd1e7f4403d22b90e31c77db38bf24cad1e97104bcdeb
MD5 430f9c7b510fb8e62c0033bcec9efd2f
BLAKE2b-256 a09814b6306cbf818e27b343b62fcb26b3d08d58d2395f6cfa4f905e9bf69036

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page