Dependency updates, checked against your code
Your dependency updated.
Did it break your code?
Drift checks the update against the code that uses it. You get the changed API, exact call sites, and a fix you can review.
83.9% precision against 16,168 negative controls16 package ecosystemsEvery number, and every one refused
Why this exists
A green update PR can still break your build.
Version rules describe what maintainers intended. Drift checks what they shipped, then looks for that change in your repository.
88.42 of every 100 updates, unaffected11.58 broke a client, per the same study
Not an update bot
Three tools, three different questions.
Dependabot · Renovate
“A newer version exists.”
Opens the PR. Says nothing about whether it breaks you.
OpenRewrite · Moderne
“I will rewrite your code for this migration.”
Only where somebody wrote a recipe. Needs a build to parse.
Drift
“Here is what changed, where it lands, and what I could not check.”
Any version pair, computed from the published artifacts.
OpenRewrite is the better tool once you have decided to migrate — it rewrites the code, and Drift does not. Drift answers the question before that one: which of these upgrades can I take, and what will the rest cost me?
For coding agents
Your agent recalls what a package changed. Drift makes it check.
Ask an agent to upgrade a repository and it answers from memory — about a version pair it never looked at. Drift gives it the computed diff instead, and a verdict it is told not to soften.
check_upgrades— every pending upgrade, by verdictexplain_upgrade— what changed, and the exact linescheck_installed— names imported that the installed version does not export- Runs locally over stdio. No Drift service or account; evidence comes directly from upstream registries.
Real output
A real repository. A real dependency change.
Recorded run · linked commit
supabase/supabase-js — The official Supabase client for JavaScript and TypeScript.
What the recordings found
270 exact call sites, linked to files and lines. Missing evidence is shown as a gap, not softened into a pass.
How Drift performs on public data
100.0%
recall on 267 hand-labelled Java API changes, with 99.0% precision.
Read the method and every miss →
Run it yourself
Try Drift in your browser, on your ecosystem.
Each demo is a small project pinned to an old version of a real dependency, using an API the newer version breaks. Opening it upgrades the manifest and leaves the code alone, so Drift analyses an ordinary uncommitted change — and has no idea it is a demo.
- JavaScript / TypeScriptnpm— axios 0.21.4 → 1.7.7, opens a Codespace
- Pythonpypi— werkzeug 2.0.3 → 2.1.0, opens a Codespace
- Gogo— golang.org/x/exp 20230522 → 20231006, opens a Codespace
- Rustcargo— clap 2.34.0 → 4.5.4, opens a Codespace
- Java / Kotlin / Scalamaven— com.google.guava:guava 20.0 → 21.0, opens a Codespace
- Rubyrubygems— rack 3.0.0 → 3.1.0, opens a Codespace
- .NETnuget— AutoMapper 8.1.1 → 9.0.0, opens a Codespace
- PHPpackagist— monolog/monolog 2.9.3 → 3.5.0, opens a Codespace
- Elixir / Erlanghex— plug 1.13.6 → 1.15.0, opens a Codespace
- Dart / Flutterpub— dio 4.0.6 → 5.0.0, opens a Codespace
- Swiftswift— Alamofire 4.9.1 → 5.9.1, opens a Codespace
- CocoaPodscocoapods— Alamofire 4.9.1 → 5.9.1, opens a Codespace
- OCamlopam— lwt 4.5.0 → 5.7.0, opens a Codespace
- C / C++ (Conan)conan— fmt 9.1.0 → 10.2.1, opens a Codespace
- C / C++ (vcpkg)vcpkg— catch2 2.13.9 → 3.5.2, opens a Codespace
- Arduino / PlatformIOarduino— bblanchon/ArduinoJson 5.13.5 → 6.21.3, opens a Codespace
Opens a GitHub Codespace on your own account — nothing to install, and the free tier covers it. The extension and the drift CLI are both already set up: the panel analyses the change as the editor opens, and the terminal runs drift analyze next to it.
How a Finding Gets Made
- Dependency movedmanifest + lockfile
- API changedrelease notes + API diff
- Your code uses itimports + exact call sites
- Verifybuild / test
- Fixcodemod → fix plan → agent
Real example: w3lib 2.1.1 → 2.4.1 in Scrapy, from the recording above. Each stage below opens to the artefact it actually produced.
- 1
Read What MovedManifests and lockfiles, not guesses.
Drift parses the manifest, then checks the lockfile for the version actually installed — a range only says what's permitted. Workspace members are read as separate packages, since a bump in one is a fact about that one.
package.jsongo.modGemfile.lockpyproject.tomlCargo.tomlpom.xmlDirectory.Packages.propsconanfile.txtvcpkg.jsonplatformio.inipyproject.toml1 changed dependency@@ pyproject.toml — [project.dependencies] @@ 25 "tldextract", 26 - "w3lib>=2.1.1", 26 + "w3lib>=2.4.1", 27 "zope.interface>=5.1.0", - 2
Gather EvidenceThree independent sources, each with a link you can open.
Every record carries a URL or a local locator — the difference between Drift and asking a model what it remembers about a library.
Registry metadata
The package's own index entry
Deprecation notices, yanked releases, publish dates, the maintainer's own 'latest' tag, and known advisories from OSV for both versions.
GET pypi.org/pypi/w3lib/json
GET api.osv.dev/v1/query ← both versions
Release notes & changelog
What the maintainers said changed
Every GitHub release between the two versions, the CHANGELOG, and any migration guide it points to — matched by explicit rules, not a model's recollection.
GET api.github.com/repos/scrapy/w3lib/releases
GET raw…/w3lib/master/CHANGELOG.rst
Computed API surface
What actually changed, whatever they said
Both versions are fetched and their public surfaces compared symbol by symbol — nothing is installed, no build script runs. Drift's strongest signal, and the only one that catches a break nobody wrote down.
.d.ts · Go AST · rustdoc JSON
japicmp · ECMA-335 · C headers · stubs
Sources are independent on purpose. A missing changelog entry is caught by the surface diff; a behavior change with no signature change is caught by the changelog. Agreement raises confidence, and disagreement is reported rather than resolved by picking a favorite.
- 3
Decide What BreaksA finding without a citation is not a finding.
Computed diffs already know which symbol changed and how, so Drift reads structure rather than prose. Changelog lines go through rules that recognize a removal or a rename. Every breaking change points back at the evidence that justified it, and anything it couldn't establish is recorded as a gap.
drift / analyzew3lib · 6 breaking changesbehaviour-changeconfidence: 60/100 — Fairly confidentcites: GitHub release notescanonicalize_urlno longer applies lowercase to the userinfo URL component.Review call sites for assumptions that no longer hold. Make any dependency on lowercased userinfo explicit instead of silently relying on the previous canonicalization behavior.
@@ w3lib v2.2.1 — release notes @@ canonicalize_url() no longer applies lowercase to the userinfo URL component. - 4
Find It in Your CodeOnly the files that import it are searched.
A file that never imports w3lib can't be broken by a w3lib change, however often the word url appears in it. Within files that do, Drift matches the symbols the evidence named — skipping comments and strings, so a word in a docstring is never mistaken for a call. Each site gets its own confidence, highest when the file provably bound that symbol from that import.
import graph#include graphAST-aligned indexper-site confidencesymbol: canonicalize_url4 results · 3 filesscrapy/linkextractors/lxmlhtml.py
57 return canonicalize_url(link.url, keep_fragments=True) high confidence · 1 of 4 sites
This file directly binds
canonicalize_urlfrom an import of w3lib, so the name here is provably that function — not a local one that shares its spelling. These are the four places that call the API whose behavior changed; whether a particular caller depends on lowercased userinfo is what the review step must determine.scrapy/linkextractors/lxmlhtml.py
399 link.url = canonicalize_url(link.url) scrapy/utils/request.py
100 url = canonicalize_url(request.url, keep_fragments=keep_fragments) tests/test_linkextractors.py
794 return canonicalize_url(url, *args, **kwargs) - 5
Know What To ReviewThe finding includes its remediation.
Drift keeps the recommended next step attached to the finding, so the evidence, affected code, and remediation stay together.
Structured context like this measurably helps automated repair — the strongest tested model in a peer-reviewed study fully repaired 27% of breaking builds when given the erroneous line and the API diff.
remediationfrom DriftBehaviour changed:
canonicalize_urlno longer applies lowercase to the userinfo URL component. Review call sites for assumptions that no longer hold. Prefer making the assumption explicit over silently adapting to the new behaviour.
Verification rules & confidencewhat counts as a gap, six silenced patterns, three confidence levels
When a Source Can’t Be Reached
It’s recorded as a gap and the package is reported as not verified — never as clean. Zero findings from a complete check and zero findings from a check that never ran are different facts, and you need to know which one you have.
Drift found nothing it could check this version against.
What Drift Refuses to Report
Six lines that match a changed symbol and get no comment — each rule exists because a real run got it wrong without it.
scrapy/core/downloader/tls.pyno comment
from twisted.internet.ssl import CertificateA symbol this file got from somewhere else. Certificate here is Twisted's, whatever cryptography did to a class of the same name. A name has one binding in a scope, and the import says whose it is.
components/ui/button.tsxno comment
const Comp = asChild ? Slot : "button";A mention, when the change is a change of signature. A changed argument list is a fact about calls. Storing the name, re-exporting it, or asking for its type passes no arguments and has nothing to update.
scrapy/utils/conf.pyno comment
"""To define format set a colon at the end of the o…"""A word inside a comment, a docstring, or a string. An English sentence containing the word define is not a call to define. Comments are stripped and string contents blanked before any identifier is matched.
w3lib/url.pyno comment
+ def add_or_replace_parameters(url, new_parameters)Anything additive. A new export, a widened parameter, a new optional field. It cannot break a caller, so it appears in the reasons to upgrade and never in the risks.
openapi.yamlno comment
+ responses.200.content.schema.properties.regionChanges that break the server, not you. In an API diff only the consumer-breaking direction is reported. A response gaining a field is not your problem, and a report you have to filter is a report nobody reads twice.
zlib.hno comment
#define ZLIB_VERSION "1.3.1"A version constant that moves every release. ZLIB_VERSION changes on every single tag. A guaranteed finding at the top of every upgrade teaches people to skim past the ones that matter.
What the Confidence on a Finding Means
Two separate questions underneath. Did this happen upstream? is answered by the evidence — a computed diff starts high, prose starts medium, and agreement between sources promotes it. Does it land here? is answered per line. Drift keeps them apart internally — a certain upstream diff is not a reason to call a repository affected on its own — but rolls them into one score on the report, so the question “how sure is Drift, overall?” has a plain answer without hiding the breakdown that produced it.
High
The file bound that exact symbol from an import of this dependency. There is an edge from the declaration to this line.
Medium
The file imports the dependency and the symbol appears in it. Also the ceiling for C and C++, where #include binds no names and only a compiler could say more.
Low
The symbol appears but no import link could be established — a dynamic import, a re-export barrel, or a package whose module name differs from its own.
AI-pass findings are capped at medium by construction, so they can never alone clear the bar to open a pull request. They assist recall — they don’t get a vote.
And when Drift isn’t sure a change lands in your code, it says so in the verdict itself — “may affect your code”, not “affects your code”, for anything short of a directly imported match. Being wrong with the same confidence as being right is the failure mode this whole model exists to avoid.
Ecosystem coverage
16
ecosystems — evidence · static analysis · verify · fix
On every dependency change
AnalyzeAskPR
See the full run
main.github/workflows/drift.yml·push · pyproject.toml
Set Up Job
2sTriggers only on manifest and lockfile changes, not every push.
1on: push
2paths: **/package.json, **/go.mod, **/vcpkg.json, …
3permissions: contents: write · issues: write · pull-requests: write · checks: write
Run trydrift/drift@v0
—Post the Check Run
—Ask Before Acting
—Verify the Approval
—Open the Pull Request
—
What should Drift build next?
Public roadmap
Drift is early. Tell us what is missing, vote on ideas, or follow what has shipped.
Try it on your next update