Catches structural erosion from AI-generated code — the bugs that pass all your tests
Project description
Drift
Your architecture is drifting. Your linter won't tell you. Drift will.
24 cross-file signals · 100 % ground-truth precision · deterministic, no LLM · ~30 s for a 2 900-file codebase
pip install drift-analyzer
drift setup # 3-question wizard: picks the right profile for your project
drift status # traffic-light health check — your daily entry point
⚡ Try it — zero install
uvx drift-analyzer analyze --repo .
One command. No pre-install. Results in ~30 seconds.
🌐 No install at all? Analyze any public repo in your browser →
Permanent install: pip install drift-analyzer · Python 3.11+ · also via pipx, Homebrew, Docker, GitHub Action, pre-commit →
| Metric | Value | Evidence |
|---|---|---|
| Ground-truth precision | 100 % (47 TP, 0 FP) | v2.7.0 baseline |
| Ground-truth recall | 100 % (0 FN, 114 fixtures) | v2.7.0 baseline |
| Mutation recall | 100 % (25/25 injected) | mutation benchmark |
| Wild-repo precision | 77–95 % (5 repos) | study §5 |
[!NOTE] Drift eats its own dog food. Every release runs
drift selfon its own source — same pipeline, same rules, no exceptions. Results: drift_self.json
🤔 Why drift?
Most linters catch single-file style issues. Drift catches what they miss: cross-file structural drift that accumulates silently during AI-assisted development.
| Without Drift | With Drift |
|---|---|
|
|
🔍 Before —
drift briefanalyses your repo scope and generates structural constraints ready to paste into your agent prompt
🚦 After —drift checkruns 20+ cross-file signals and exits 1 on violations — CI, SARIF, and pre-commit ready
🧠 Over time — Bayesian calibration reweights signals via feedback, git outcome correlation, and GitHub label correlation
⚙️ How it works
Before a session — generate guardrails:
drift brief --task "refactor the auth service" --format markdown
# → paste output into your agent prompt before delegation
After a session — enforce structure:
drift check --fail-on high # local or CI gate
drift check --fail-on none # pre-commit hook (advisory, report-only)
drift analyze --repo . --format json # full report
[!TIP] Best fit: Python repos with 20+ files and active AI-assisted development.
Tiny repos produce noisy scores. Drift does not replace your linter, type checker, or security scanner — it covers the layer they cannot: cross-file structural coherence over time.
🔌 Works with
| AI Tools (MCP) | CI/CD | Git Hooks | Install |
|---|---|---|---|
| Cursor · Claude Code · Copilot | GitHub Actions · SARIF | pre-commit · pre-push | pip · pipx · uvx · Homebrew · Docker |
Bootstrap everything:
drift init --mcp --ci --hooksscaffolds config for all integrations in one command.
GitHub Actions
# Try it — add this to .github/workflows/drift.yml
name: Drift
on: [push, pull_request]
jobs:
drift:
runs-on: ubuntu-latest
permissions:
security-events: write # for SARIF upload
pull-requests: write # for PR comments
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # full history for temporal signals
- uses: mick-gsk/drift@v1
with:
fail-on: none # report-only — tighten once you trust the output
upload-sarif: "true" # findings appear as PR annotations
comment: "true" # summary comment on each PR
Outputs available for downstream steps: drift-score, grade, severity, finding-count, badge-svg
MCP / AI Tools
Cursor, Claude Code, and Copilot call drift directly via MCP server — the agent runs a full session loop:
| Phase | MCP Tool | What it does |
|---|---|---|
| Plan | drift_brief |
Scope-aware guardrails injected into the agent prompt |
| Code | drift_nudge |
Real-time safe_to_commit check after each edit |
| Verify | drift_diff |
Full before/after comparison before push |
| Learn | drift_feedback |
Mark findings as TP/FP — calibrates signal weights |
Copy-paste MCP config
VS Code — add to .vscode/mcp.json:
{
"servers": {
"drift": {
"type": "stdio",
"command": "drift",
"args": ["mcp", "--serve"]
}
}
}
Claude Desktop — add to claude_desktop_config.json:
{
"mcpServers": {
"drift": {
"command": "drift",
"args": ["mcp", "--serve"]
}
}
}
Cursor — add to .cursor/mcp.json:
{
"mcpServers": {
"drift": {
"type": "stdio",
"command": "drift",
"args": ["mcp", "--serve"]
}
}
}
Or auto-generate: pip install drift-analyzer[mcp] && drift init --mcp
pre-commit: Add drift diff --staged-only as a hook — findings block the commit before they reach CI.
🎛️ Configuration profiles
Pick a profile that matches your project — or start with default and calibrate later:
| Profile | Best for | Command |
|---|---|---|
| default | Most projects | drift init |
| vibe-coding | AI-heavy codebases (Copilot, Cursor, Claude) | drift init -p vibe-coding |
| strict | Mature projects, zero tolerance | drift init -p strict |
| fastapi | Web APIs with router/service/DB layers | drift init -p fastapi |
| library | Reusable PyPI packages | drift init -p library |
| monorepo | Multi-package repos | drift init -p monorepo |
| quick | First exploration, demos | drift init -p quick |
Team workflow: Commit
drift.yamlto your repo → CI enforces the same thresholds → team inherits calibrated weights.
📖 Profile gallery with full details → · Configuration reference →
Advanced: Adaptive learning, Negative context library, Guided mode
Adaptive learning & calibration
Drift does not treat all signals equally forever. It maintains a per-repo profile:
- Bayesian calibration engine combines three evidence sources: explicit
drift feedback mark, git outcome correlation, and GitHub issue/PR label correlation. - Feedback events are stored as structured
FeedbackEventrecords and can be reloaded and replayed across versions (record_feedback,load_feedback). - Profile builder (
build_profile) produces a calibrated weight profile thatdrift checkanddrift briefuse to focus on the most trusted signals in your codebase.
CLI surface: drift feedback, drift calibrate, drift precision (for your own ground-truth checks).
Negative context library for agents
Drift can turn findings into a structured "what NOT to do" library for coding agents:
- Per-signal generators map each signal (PFS, MDS, AVS, BEM, TPD, …) to one or more
NegativeContextitems with category, scope, rationale, and confidence. - Anti-pattern IDs like
neg-MDS-…are deterministic and stable — ideal for referencing in policies and prompts. - Forbidden vs. canonical patterns: each item includes a concrete anti-pattern code block and a canonical alternative, often tagged with CWE and FMEA RPN.
- Security-aware: mappings for
MISSING_AUTHORIZATION,HARDCODED_SECRET, andINSECURE_DEFAULTgenerate explicit security guardrails for agents.
API: findings_to_negative_context() and negative_context_to_dict() deliver agent-consumable JSON for drift_nudge, drift brief, and other tools.
Guided mode for vibe-coding teams
If your team ships most changes via AI coding tools (Copilot, Cursor, Claude), drift includes a guided mode:
- CLI guide:
drift startprints the three-command journey for new users:analyze → fix-plan → checkwith safe defaults. - Vibe-coding playbook: examples/vibe-coding/README.md documents a 30-day rollout plan (IDE → commit → PR → merge → trend) with concrete scripts and metrics.
- Problem-to-signal map: maps typical vibe-coding issues (duplicate helpers, boundary erosion, happy-path-only tests, type-ignore buildup) directly to signals like MDS, PFS, AVS, TPD, BAT, CIR, CCC.
- Baseline + ratchet: ready-made
drift.yaml, CI gate, pre-push hook and weekly scripts implement a ratcheting quality gate over time.
📖 Start here if you are a heavy AI-coding user: Vibe-coding technical debt solution →
🔄 Coming from another tool?
From Ruff / pylint: Drift operates one layer above single-file style. It detects when AI generates the same error handler four different ways across modules — something no linter sees.
From Semgrep / CodeQL: Semgrep finds known vulnerability patterns in single files. Drift finds structural erosion across files — pattern fragmentation, layer violations, temporal volatility — that security scanners don't target.
From SonarQube: Drift runs locally with zero server setup and produces deterministic, reproducible findings per signal. Add it alongside SonarQube — not instead.
From jscpd / CPD: Drift's duplicate detection is AST-level, not text-level. It finds near-duplicates that text diff misses and places them in architectural context.
Capability comparison
| Capability | drift | SonarQube | Ruff / pylint / mypy | Semgrep / CodeQL | jscpd / CPD |
|---|---|---|---|---|---|
| Pattern Fragmentation across modules | ✔ | — | — | — | — |
| Near-Duplicate Detection (AST-level) | ✔ | Partial (text) | — | — | ✔ (text) |
| Architecture Violation signals | ✔ | Partial | — | Partial (custom rules) | — |
| Temporal / change-history signals | ✔ | — | — | — | — |
| GitHub Code Scanning via SARIF | ✔ | ✔ | — | ✔ | — |
| Bayesian per-repo calibration | ✔ | — | — | — | — |
| MCP server for AI agents | ✔ | — | — | — | — |
| Zero server setup | ✔ | — | ✔ | ✔ | ✔ |
| TypeScript support | Partial ¹ | ✔ | — | ✔ | ✔ |
✔ = within primary design scope · — = not a primary design target · Partial = limited coverage
¹ Via drift-analyzer[typescript]. 17/24 signals supported via tree-sitter. Python is the primary analysis target.
Comparison reflects primary design scope per STUDY.md §9.
🏷️ Add a drift badge to your README
Show your repo's drift score with a shields.io badge:
drift badge # prints URL + Markdown snippet
drift badge --format svg -o badge.svg # self-contained SVG
Paste the Markdown output into your README:
[](https://github.com/mick-gsk/drift)
Automate in CI: The GitHub Action exposes a badge-svg output — pipe it into your repo or a dashboard.
📚 Documentation
| Topic | Description |
|---|---|
| Quick Start | Install → first findings in 2 minutes |
| Brief & Guardrails | Pre-task agent workflow |
| CI Integration | GitHub Action, SARIF, pre-commit, progressive rollout |
| Signal Reference | All 25 signals with detection logic |
| Benchmarking & Trust | Precision/Recall, methodology, artifacts |
| MCP & AI Tools | Cursor, Claude Code, Copilot, HTTP API |
| Configuration | drift.yaml, layer boundaries, signal weights |
| Configuration Levels | Zero-Config → Preset → YAML → Calibration → MCP → CI |
| Calibration & Feedback | Bayesian signal reweighting, feedback workflow |
| Vibe-coding Playbook | 30-day rollout guide for AI-heavy teams |
| Contributing | Dev setup, FP/FN reporting, signal development |
🤝 Contributing
Drift's biggest blind spots are found by people running it on codebases the maintainers have never seen. 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 |
git clone https://github.com/mick-gsk/drift.git && cd drift && make install
make test-fast
See CONTRIBUTING.md · ROADMAP.md
🔒 Trust and limitations
Drift's pipeline is deterministic and benchmark artifacts are published in the repository — claims can be inspected, not just trusted.
| Metric | Value | Artifact |
|---|---|---|
| Ground-truth precision | 100 % (47 TP, 0 FP) | v2.7.0 baseline |
| Ground-truth recall | 100 % (0 FN across 114 fixtures) | v2.7.0 baseline |
| Mutation recall | 100 % (25/25 injected patterns) | mutation benchmark |
| Wild-repo precision | 77 % strict / 95 % lenient (5 repos) | study §5 |
- No LLM in detection. Same input, same output. Reproducible in CI and auditable.
- Single-rater caveat: ground-truth classification is not yet independently replicated.
- Small-repo noise: repositories with few files can produce noisy scores. Calibration mitigates but does not eliminate this.
- Temporal signals depend on clone depth and git history quality.
- The composite score is orientation, not a verdict. Interpret deltas via
drift trend, not isolated snapshots.
Full methodology: Benchmarking & Trust · Full Study
⭐ Star History
📄 License
MIT. See LICENSE.
Project details
Release history Release notifications | RSS feed
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 drift_analyzer-2.9.14.tar.gz.
File metadata
- Download URL: drift_analyzer-2.9.14.tar.gz
- Upload date:
- Size: 1.8 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
207f4aaefb265ea21f9fa2097e55e11390f3e7f137c39b983788ffdfb93ba42d
|
|
| MD5 |
c9a8fec393e86890d905375c437da70b
|
|
| BLAKE2b-256 |
9b47d2a75bf81593f69b5c141860a2e2e65fabbc36e46e24a0cb6d8713366521
|
File details
Details for the file drift_analyzer-2.9.14-py3-none-any.whl.
File metadata
- Download URL: drift_analyzer-2.9.14-py3-none-any.whl
- Upload date:
- Size: 598.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
046f632071181b5793109cb8a8b0babfe5537458018188d2df24f969d4ae88ec
|
|
| MD5 |
0275762634a1d3fee89d1d5c3bec8035
|
|
| BLAKE2b-256 |
a5c36ea9a86a6ffc663f1391c7eb8ee2d784caf2276854a050d0442713c4e86b
|