Migrations you can merge.
Uptide is an open-source CLI that shows which dependency upgrades matter in your repo, what each one breaks in your code, and opens a verified migration branch or PR. It runs locally on your repo. Nothing to sign up for.
npx uptide list --html --openNo API key. No account. Node 20 or newer.
$ npx uptide check zod stripe uptide check · storefront · pnpm · 8.5s zod 3.25.76 → 4.6.5 major · latest on npm verified ✗ 28 breaking in 7 files 24 auto-fixable · 4 need the agent (LLM) stripe (packages/api) 14.25.0 → 23.0.0 9 majors behind · latest on npm verified ✗ 4 breaking in 3 files 1 auto-fixable · 3 need the agent (LLM)
Major upgrades sit for months because nobody knows what they'll break.
Version bots open the PR. The version changes, the build goes red, and the code that breaks is still on you. So the PR waits, and the next major lands on top of it.
- Bumps the version and the lockfile.
- Links the changelog.
- Decide which upgrades matter first.
- Find every line the new version breaks.
- Rewrite those lines and prove the rest still compiles and passes its tests.
list, check, fix, pr.
Every outdated dependency in seconds, grouped into packages that move together and ranked by priority with a reason: known advisories with the smallest fixing version, deprecated versions, unsupported major lines, version drift across workspaces, runtime before dev. In the terminal, or as an HTML report with filters. No LLM, no API key.
npx uptide list --html --openCompiles your code against the new version and states the verdict, 28 breaking · compiled against 4.6.5: 28 new type errors, with every call site. No LLM, no API key.
npx uptide check zod --html --openMigrates on a new branch in an isolated clone of your local HEAD, in two passes:
- Deterministic rules first. When the dependency has a verified pack, it rewrites every site it covers, the same way on every run. No LLM, no key.
- Then AI, only for what rules can't do. It needs your API key in the environment:
ANTHROPIC_API_KEY,OPENAI_API_KEYorGEMINI_API_KEY(experimental). Without one, the rules still run and the remaining sites are listed for you; a dependency with no pack has no rules, so it needs the key.
Then it verifies with your compiler, the related tests, and your linter and formatter. With --pr --yes it pushes the branch and opens a draft PR once verification passes; without them it never pushes.
npx uptide fix zod --pr --yesFor a branch fix left local: opens the pull request with the evidence, summary first. It prints the plan and pushes only when you add --yes.
npx uptide pr --branch uptide/zod-4.6.5Real runs. Numbers as printed.
check and fix on fixtures/repos/storefront, a small pnpm workspace in the repository written to exercise Uptide: two packages on zod 3 and stripe 14, with a few tests. Every block below is a run published in the uptide README and docs, and the site build checks it against them.
check. What breaks, where, and who can fix it.$ npx uptide check zod stripe uptide check · storefront · pnpm · 8.5s zod 3.25.76 → 4.6.5 major · latest on npm verified ✗ 28 breaking in 7 files 24 auto-fixable · 4 need the agent (LLM) stripe (packages/api) 14.25.0 → 23.0.0 9 majors behind · latest on npm verified ✗ 4 breaking in 3 files 1 auto-fixable · 3 need the agent (LLM) zod 28 breaking · compiled against 4.6.5: 28 new type errors compiled 11 of 11 files in 2 workspaces with the repo's TypeScript 5.9.3 ✗ New error API (required_error → error) 24 sites auto-fixable ✗ ZodTypeDef removed 1 fix, 3 errors needs the agent (LLM) ✗ .ip() removed monitoring.ts:6 needs the agent (LLM) ! 15 deprecated calls (.uuid, .datetime, .email, ...) 8 auto-fixable stripe 4 breaking · compiled against 23.0.0: 4 new type errors compiled 7 of 7 files in 1 workspace with the repo's TypeScript 5.9.3 ✗ Test fixture casts widened renewal.test.ts:7 auto-fixable ✗ Subscription billing period moved to items 2 sites needs the agent (LLM) ✗ apiVersion no longer matches the SDK client.ts:9 needs the agent (LLM) 1 API change since 2023-10-16 affects your code Next npx uptide fix zod migrate on a new branch, verify, no push npx uptide fix stripe migrate on a new branch, verify, no push npx uptide plan --only 'zod,stripe' the order to upgrade in, with the effort npx uptide check zod stripe --details every site and reason
fix, one dependency at a time, each on its own verified branch.$ npx uptide fix zod uptide fix · zod 3.25.76 → 4.6.5 (latest on npm) · verification passed · 36s Risk Medium: request validation in webhooks Changes 29 sites in 8 files · 25 auto-fixed · 4 fixed by the agent (LLM) Types ✅ 29 errors after the bump → 1 (1 pre-existing) Behavior ✅ 9 schemas identical · 2 not checked · 21/21 custom-message assertions Tests ✅ 5 tests in 3 files passed
- expect(parsed.error?.issues[0]?.message).toBe('Required');+ expect(parsed.error?.issues[0]?.message).toBe('Invalid input: expected string, received undefined');
$ npx uptide fix stripe uptide fix · stripe 14.25.0 → 23.0.0 (latest on npm) · verification passed · 41s Risk High: behavior changes Changes 6 sites in 3 files · 3 auto-fixed · 3 fixed by the agent (LLM) Types ✅ 5 errors after the bump → 1 (1 pre-existing) Behavior ⚠️ 1 of 570 API changes affects your code · 47 touch resources you use (8 breaking) Tests ✅ 3 tests in 2 files passed · the test script of packages/api
subscriptionPeriod helper and migrated the code that read the old fields.- renewsAt: new Date(subscription.current_period_end * 1000),+ renewsAt: new Date(period.end * 1000),
The compiler decides. The diff explains.
A change in a package's API is a reason to look, not a verdict. A site is breaking when your own compiler, or the new version loaded at runtime, says so.
Verified packs and generic mode
A verified pack holds rules written for that dependency, a guide for the agent, behavior checks, and ground truth from public repositories that made the upgrade, which the pack is scored against. The packs below are verified.
Every other dependency runs in generic mode. A finding is breaking only when your compiler or the runtime probe confirms it, or when it is a require() of an ESM-only package or an import of a removed export. Everything else is listed as unconfirmed under --details. A generic fix uses the agent alone, under the same verification, and its pull request says no pack covers the package.
When it can't verify, it says so
If the compiler could not run, the verdict says why instead of guessing: N breaking · types not verified: <reason>. A package whose analysis fails is named with its reason and never called clean.
A fix that does not verify exits 1 and lists the sites left for you. Unfinished sites stay manual and cannot pass the publish gate. Passing compilation does not prove runtime equivalence, so the report says what was verified, what was not, and what to review.
Risk levels
Why stripe is High on purpose
Types and tests pass, but a new Stripe API version changes what Stripe sends. Server API changes are never rewritten by rule, and the pull request asks what only you can answer, such as which item's period counts when a subscription has several.
5 verified packs
Precision and recall are for breaking findings on each pack's ground truth, as uptide pack test recorded them in the pack's verification.json. A pack is verified with two or more public repositories and no false positive. This table is built from those files on every deploy, the same way as the uptide README.
| Package | Range | Precision | Recall | Ground-truth repositories | Status |
|---|---|---|---|---|---|
ai | 6.x → 7.x | 100% | 36% | vercel/chatbot, miurla/morphic | verified |
react | 18.x → 19.x | 100% | 69% | excalidraw/excalidraw, tldraw/tldraw | verified |
stripe | 14 and newer | 100% | 90% | unkeyed/unkey, nextjs/saas-starter | verified |
vitest | 4.x → 5.x | 100% | 50% | votingworks/vxsuite, vitorvasc/opentelemetry-ecosystem-explorer | verified |
zod | 3.x → 4.x | 100% | 71% | ugurkocde/AwesomeIntune, howardyang2009/PATH, band-ai/band-sdk-typescript | verified |
Built to run on code it didn't write.
listandcheckexecute nothing from your repository. Configs are read as data;checkcompiles against the target in memory.fixworks in an isolated clone of the commit you have checked out, never in your checkout and never from the remote. Uncommitted changes are left out and listed. Your branch, files, git hooks and git config are compared before and after and must be identical.- Lifecycle scripts are disabled for every install, and git hooks are disabled for every git command it runs.
- Lockfile check: a lockfile change outside the upgraded dependency's subtree is rejected.
- Services are opt-in. Tests that need a database, cache or queue run only with
--with-services --yes, after it prints what they connect to. - No PR from a dirty or diverged tree. With
--prit stops before any work when the working tree has uncommitted changes or the base branch onorigindoes not contain your commit.uptide prchecks the branch is still at the verified commit. - No push without you. The branch stays local until you run
uptide pr --yesor passfix --pr --yes. - Secrets stay out of child processes. Install and test commands do not receive your LLM API key or GitHub token.
Not a sandbox for your own code. fix runs your repository's tests with your user's permissions, the way you would. Run it on code you would run yourself. The full model is in SECURITY.md.
The agent runs on your key, only when rules run out.
Never call an LLM.
Rules first. Only sites no rule covers go to the agent, one at a time, and a patch is kept only if it removes its compiler error and introduces none.
Anthropic by default (claude-sonnet-5-5), OpenAI (gpt-6.1-sol) or Gemini, experimental (gemini-3.8-flash), with your own key from ANTHROPIC_API_KEY, OPENAI_API_KEY or GEMINI_API_KEY. Keys are read only from the environment. Pick with --provider and --model.
--max-cost defaults to $1 per package. Uptide reserves the worst-case cost before every call, and a call that would exceed the budget is never sent.
--no-llm turns the agent off. Rules still apply, and the remaining sites are listed for you.
What leaves your machine, exactly.
The same statement the CLI prints in uptide --help:
Privacy: Analysis runs locally. Code snippets go to your chosen LLM provider (Anthropic, OpenAI or Gemini), only for assisted fixes in `uptide fix`, and only with your own API key from ANTHROPIC_API_KEY, OPENAI_API_KEY or GEMINI_API_KEY: for each site the rules cannot migrate, the finding, the enclosing function and the compiler error. `uptide fix --no-llm` turns assisted fixes off. No account. `check` and `verify` load the `typescript` package your repository installs (resolved from its node_modules) to compile with, and never run your repository's scripts or other code outside `fix`'s verification step. Anonymous telemetry is off by default and asks for consent in an interactive terminal. Set UPTIDE_TELEMETRY=0 to disable it. No IP, code, paths or repo names are collected. Other network use: your npm registry for package metadata and tarballs, npm's advisory endpoint from `list` (public package names and installed versions; `--no-advisories` turns it off), PostHog EU only after telemetry opt-in, and GitHub when you pass `fix --pr` or run `pr` / `pr-body`.
| Command | What leaves your machine (telemetry off, the default) |
|---|---|
list | Package names and versions requested from your npm registry, and the names and installed versions of public packages sent to npm's advisory endpoint. Off with --no-advisories. |
check | Nothing of yours. It downloads package tarballs from your npm registry. |
fix | Nothing of yours for rules and verification. For each site no rule covers: the finding, the enclosing function or declaration, and the compiler error, to the provider you chose, with your key. |
pr | The branch and the pull request, to GitHub through your own gh, when you say so. |
Telemetry is anonymous, off by default and opt-in: the first interactive run asks once, and Enter means no. CI never sends without UPTIDE_TELEMETRY=1. The exact fields are in docs/telemetry.md.
What works now.
npm, pnpm and Yarn with the node-modules linker. Not Yarn Plug'n'Play.
Workspaces and pnpm catalogs. One row per package across workspaces, with version drift called out.
TypeScript, and JavaScript in the project (allowJs). In JavaScript the compiler type-checks (checkJs or // @ts-check) the compiler decides; elsewhere a site is breaking only when the runtime confirms it.
ai 6.x → 7.x, react 18.x → 19.x, stripe 14 and newer, vitest 4.x → 5.x and zod 3.x → 4.x.
Every other dependency: list, check, and fix with the agent.
For version-bot pull requests: detects zod and stripe upgrades and keeps one findings comment. With fix enabled, it pushes one verified commit to the bot's branch. Setup.
Node 20 or newer.
Packs are how Uptide learns a library.
A pack holds what Uptide knows about one dependency: deterministic rules applied only at sites check reported, a guide and validator for the agent, findings the compiler cannot see, and review material for the pull request. Every rule ships with a before-and-after test and a case it must leave alone, and every claim is backed by ground truth from a real upgrade.