Safeguard
Developer Tools•

Upgrade dependencies safely with an AI assistant

Start on a clean branch, upgrade one package at a time, let the assistant run installs and tests only with your approval, then rescan before you commit.

Safeguard Security Team
20 min read

To upgrade dependencies safely with an AI assistant, start on a clean branch with passing tests, find what is outdated and why, upgrade one package at a time by the smallest useful jump, let the assistant run installs and tests only with your approval, rescan for vulnerabilities and licences, then review the diff and commit yourself.

Bring the Claude, ChatGPT or Codex plan you already pay for and use it inside the Safeguard CLI. Safeguard adds no extra charge for that usage; your plan's own usage limits and terms still apply. If you prefer the chat app you use today, connect Claude or ChatGPT to the Safeguard MCP server and ask about your dependencies from there.

This guide covers the rules that make upgrades safe, a step by step routine with real commands for npm, pip, Maven, Gradle and Go, prompts that keep an assistant focused, and how to approve each step from the terminal, the desktop or your phone.

What you will have at the end

After one pass through this guide you will have:

  • A baseline: tests passing and a Safeguard scan of the project before anything changes.
  • A list of outdated packages, sorted so security fixes come first.
  • Each upgrade made on its own, with the manifest and lockfile updated together.
  • Every install and test command approved by you before it ran.
  • A rescan showing which findings the upgrade fixed and confirming nothing new arrived.
  • A reviewed diff and a commit message, with nothing pushed until you push it.
  • A repeatable routine you can run weekly, plus a CI check that holds the line.

You need a project under git, its package manager installed, a test suite you trust, and the Safeguard CLI. The steps work the same on macOS, Linux and Windows.

Why upgrades go wrong, and the five rules that prevent it

Most broken upgrades come from a handful of causes, and an AI assistant can make each of them happen faster if you let it.

Version numbers carry promises that are not always kept. Semantic Versioning says a MAJOR version is for "incompatible API changes", a MINOR version adds "functionality in a backward compatible manner", and a PATCH version is for "backward compatible bug fixes". It also says "Major version zero (0.y.z) is for initial development. Anything MAY change at any time." Many packages follow this closely. Some do not. Treat the version number as a hint about risk, not a guarantee.

Ranges hide changes. In npm, npm update installs "the highest version that satisfies the range" in package.json. A caret range like ^1.1.1 can move you to 1.2.2 without any change to package.json itself. The lockfile records what you really got.

Transitive packages move too. Upgrading one direct dependency can pull new versions of many packages below it. Your diff shows one line in the manifest and dozens in the lockfile.

Tests are the only real check. If the suite does not exercise the code that uses a package, an upgrade can pass every check and still break in production.

An assistant can do more than you asked. Asked to "update dependencies", an assistant may upgrade everything at once, edit code to make tests pass, or run commands you did not expect. That is why approvals matter.

From those causes come five rules that the rest of this guide puts into practice:

  1. One change at a time. Upgrade a single package, or a tightly related group, per commit.
  2. Manifest and lockfile together. Never commit one without the other.
  3. Smallest useful jump. Prefer the patch or minor version that fixes your problem over the latest major.
  4. Tests decide. A failing test stops the upgrade until you understand it.
  5. Scan before and after. An upgrade can fix one vulnerability and introduce another, or change a licence.

Before you start: a safe setup

Ten minutes of setup saves an afternoon of untangling.

  1. Start clean. Commit or stash your work, then create a branch:
git status
git switch -c deps/weekly-upgrades
  1. Prove the baseline. Run your install and test commands before changing anything. If tests already fail, fix that first, or you will not know whether an upgrade broke something.
npm ci && npm test
  1. Commit the lockfile. Check that package-lock.json, gradle.lockfile, go.sum or your pinned requirements.txt is in git.

  2. Open the assistant in the project folder. Start it where the manifest lives, not in your home directory:

cd ~/code/payments-api
safeguard

Type /login the first time to sign in through your browser.

  1. Pick a permission mode. Type /permissions. For planning, choose Plan, which only reads and plans. For the upgrade itself, Ask or Auto. Ask lets reads run and asks before every edit and command. Auto, the default, runs read only commands and what your policy allows, and asks before anything else.

  2. Take a baseline scan. Type /scan . and wait for the results. They land under ./output, including vuln.json and license.json.

Step by step: an upgrade with the Safeguard CLI

1. See what is outdated

Each ecosystem has its own commands. The table collects them, using each project's own documentation where it covers the step.

EcosystemSee what is outdatedUpgrade one packageReproducible installLock record
npmnpm outdatednpm install PKG@VERSIONnpm cipackage-lock.json
pippip list --outdatedpip install --upgrade PKGpip install -r requirements.txtpinned requirements.txt from pip freeze
Mavenmvn versions:display-dependency-updatesedit the version in pom.xmlbuild with exact versionsexact versions in pom.xml
Gradle./gradlew dependencies (resolved tree)./gradlew dependencies --update-locks GROUP:MODULEbuild with locking ongradle.lockfile
Gogo list -m -u allgo get MODULE@VERSIONgo build ./...go.mod and go.sum

A few details from those docs are worth knowing:

  • npm outdated shows Current, Wanted and Latest. Wanted is "the maximum version of the package that satisfies the semver range specified in package.json". Latest follows the latest tag, which the docs say "may or may not be the maximum version". Red rows can be updated within your range; yellow rows need a version outside it, usually a new major.
  • npm update does not change the ranges in package.json unless you pass --save. To go beyond your range, the npm docs say to use npm install.
  • npm ci requires a lockfile, fails if it does not match package.json, deletes node_modules first, and never writes to package.json or the lockfile. That makes it the right command to prove a fix installs cleanly.
  • pip's --upgrade applies to the packages you name. Their dependencies follow the only-if-needed strategy by default, so they move only when they must.
  • Gradle's --update-locks takes a comma separated list of modules and supports wildcards. The docs note that other modules can still change, so read the lockfile diff.
  • Maven's versions plugin prints each dependency with an arrow to its newer version. Add -Dversions.showNewestPerSegment=true to see the newest incremental, minor and major options separately.

You can run these yourself, or ask the assistant: "Run npm outdated and show me the result." Read only commands like these run without a prompt in Auto mode.

2. Put security first

Combine the outdated list with your scan. Ask:

Using output/vuln.json and the npm outdated result, list packages that have a
known vulnerability first, with the version we use and the first fixed version.
Then list the rest, grouped by patch, minor and major upgrades.
Do not change anything yet.

Using Plan mode here guarantees nothing changes. You get an ordered work list: security fixes first, then patch and minor upgrades, then majors.

3. Upgrade one package

Pick the first item and give a narrow instruction:

Upgrade lodash to the first fixed version from the scan. Change package.json
and the lockfile only. Then run npm install and npm test. Stop and ask me
before any other change.

The assistant reads the finding, the files and the advisory, then proposes each command and waits for you. In the recorded session below, you press y or n before each command; it edits package.json to lodash 4.17.21, runs npm install and npm test with approval, and prints a summary with a suggested commit message. It pushes nothing. The session ends with /permissions, /model and /scan ..

Click through it at your own pace, or open it full screen.

4. Read every approval prompt

The prompt is your control, so use it. Before pressing y, check three things:

  • The command. Is it the package and version you agreed? npm install lodash@4.17.21 is fine. npm install with a list of ten packages is not what you asked for.
  • The folder. It should run in the project root.
  • Side effects. Install scripts run during installs. If a command would also touch files outside the project, say no and ask why.

If a test fails, the assistant reads the output and proposes a fix. That proposal also needs approval. Decide whether the failure is a real break caused by the upgrade, or a test that needs updating. When in doubt, say no, and either try a smaller version jump or leave this package for a separate change.

5. Prove it installs cleanly

After the upgrade, run the strict install:

npm ci && npm test

For pip, reinstall from the pinned file in a fresh virtual environment. For Go, go mod tidy then go build ./... and go test ./.... For Gradle, rebuild with locking on. The point is to install from the lock record alone, the way CI and production will.

6. Rescan for vulnerabilities and licences

Type /scan . again, then ask:

Compare this scan with the baseline. Which findings were fixed? Is anything
new, including licence changes in output/license.json?

Upgrades can change a package's licence, or bring in a new transitive package under a licence your policy does not allow. Licence policies themselves are evaluated in the Safeguard platform, so the comparison here is a quick local check before CI runs the real gate.

7. Review the diff

git diff --stat
git diff package.json
safeguard review

safeguard review reviews working tree changes for correctness and security; --base main compares with a branch instead. For a dependency upgrade, the diff should touch the manifest and the lockfile. Any source changes need a careful read. Our guide on reviewing AI generated code before merge has a checklist.

8. Commit, then repeat

Commit with the suggested message or your own, then go back to step 3 for the next package. One commit per upgrade means a bisect or a revert later touches exactly one change.

Prompts that keep the assistant focused

The wording of a request decides how much the assistant does. These patterns work well.

Plan only. "Plan the upgrades for this project. Group them by risk. Do not edit files or run commands that change anything." Pair it with Plan mode.

Bounded change. "Upgrade only PACKAGE to VERSION. Touch only the manifest and lockfile. Ask before any code change." The word "only" and the named files do most of the work.

Explain before acting. "Before upgrading, read @CHANGELOG-excerpt.md and tell me which breaking changes affect our code. List the files." The @ key attaches a file from the folder you started in, so save the release notes there first.

Test focused. "Run only the tests for the billing module after the upgrade, then the full suite if they pass." This shortens the loop on large projects.

Undo ready. "If the tests fail twice, stop and tell me how to revert." The assistant can then suggest /rewind or a git command for you to approve.

Prompts to avoid: "update everything", "make the tests pass", and "fix whatever breaks". Each one invites a large, mixed change that is hard to review.

Handling major version upgrades

Majors deserve their own branch and their own pull request.

  1. Read the release notes first. Save the migration guide into the project folder and attach it with @. Ask the assistant to list the breaking changes that touch your code, with file names.
  2. Plan in Plan mode. Get a file by file list of edits before anything changes.
  3. Upgrade the package alone. Change the version, install, and run the build to see what breaks.
  4. Fix call sites in small batches. Ask for edits one file or one module at a time, approving each.
  5. Use checkpoints. If a batch of edits goes wrong, /rewind puts the files back. From a shell, safeguard checkpoints list and safeguard checkpoints restore do the same, and --dry-run previews the diff. Checkpoints cover files the assistant edits; anything a shell command writes, such as a lockfile rewritten by an install, is not snapshotted, so git covers those.
  6. Rescan and review as in the main routine.

In Go, a new major version is a new module path, such as example.com/lib/v2, so every import changes. In npm and pip the name stays the same, but the API may not. Either way, the routine is the same.

Do the work properly with the Safeguard CLI

You can upgrade dependencies with any terminal. The Safeguard CLI makes the safe routine the easy one, because the assistant that edits your code also knows your vulnerabilities, scans what it changed, and asks before it acts.

Install and first session

On macOS and Linux:

curl -fsSL https://cli.safeguard.sh/install | bash

On Windows, irm https://cli.safeguard.sh/install.ps1 | iex. It is a single static binary with no Node, Python or JVM needed, for macOS, Linux and Windows on x86_64 or arm64 (Windows x86_64 only). Run safeguard, type /login, then /scan .. Ask questions in plain language, such as "how many critical vulns do we have".

Writing and fixing code

The assistant has tools for your local files and your Safeguard data and picks whichever the question needs. It can write files, edit code and run commands, and those actions ask before they act. Use /model to see or switch the model, @ to attach a file, and /resume to continue the last session in the same folder. It also works as a general terminal assistant: find and read files, edit code and run commands, with your approval. More on that in using the Safeguard CLI as an AI assistant on your machine.

For scripted fixes, safeguard fix updates vulnerable packages to safe versions and writes a fix report. Start with a preview:

safeguard fix --dry-run --patch-only --severity high

--dry-run previews without changing files, --patch-only limits it to patch upgrades, and --package targets named packages. Major upgrades are off unless you pass --major-upgrades.

Using your Claude, ChatGPT or Codex plan

Bring the Claude, ChatGPT or Codex plan you already pay for and use it inside the Safeguard CLI. Safeguard adds no extra charge for that usage; your plan's own usage limits and terms still apply. To connect a model, see the CLI docs or type /model.

Approvals that match the job

/permissions offers five modes:

  • Ask: reads run; edits and commands ask first.
  • Accept edits: edits in this folder and read only commands run; other commands ask.
  • Plan: read and plan only.
  • Auto: read only commands and what your policy allows run; anything else asks. This is the default.
  • Strict: pre-approved actions only, for CI.

A --yolo flag approves everything. Keep it for throwaway sandboxes, never for a real project. For upgrades, Plan to build the work list, then Ask or Auto to carry it out.

Approve from your phone or desktop

A CLI session is live: it shows in the web app, the desktop app and the phone app, and those devices can send work to a computer running the CLI. Start in the terminal, continue on the desktop, check findings on your phone. In this recorded Android session, the same conversations appear on the phone, "Work on my computer" picks a computer running the CLI and a folder, and the command waits for Allow once, Allow for turn or Deny on the phone. The answer shows the tests passed.

Click through it at your own pace, or open it full screen.

The phone apps are on the App Store for iPhone and iPad and on Google Play for Android; see our guide to Safeguard on Android phones and tablets. The desktop app runs on Windows, macOS and Linux.

CI with safeguard exec

Your routine is only as good as the check that runs after it. In CI, safeguard ci scan --local --wait --fail-on high scans the checkout on the runner and uploads only the results, failing the step at the severity you choose. safeguard exec "summarise the critical findings in this repository" runs one non-interactive assistant turn whose default mode is strict, so anything not pre-approved is denied. Policies and gates are evaluated in the platform, not by the CLI. See Safeguard CLI in CI with safeguard exec for pipeline files.

Troubleshooting

npm ci fails after the upgrade. The lockfile and package.json disagree. Run npm install once to sync them, review the lockfile diff, and commit both.

The assistant upgraded more than one package. Say no at the approval prompt, then restate the request with "only" and the exact package. If files already changed, /rewind or git checkout the manifest and lockfile.

Tests pass locally but fail in CI. Check that CI installs from the lockfile (npm ci, pinned requirements, Gradle locking), and that the runtime version matches yours.

Peer dependency conflicts in npm. The upgrade needs a matching version of a related package. Upgrade them together as one change, or hold the upgrade. If the lockfile was created with flags such as --legacy-peer-deps, the npm docs say npm ci needs the same flags.

pip resolves a different version than expected. A constraints file may limit what pip can see. Since pip 20.3, constraints act as global limits and do not override requirements. Check for -c files and the PIP_CONSTRAINT variable.

The rescan still shows the finding. Make sure you scanned the same folder, and that the lockfile really changed. For container images, rebuild and scan the image.

Common mistakes

  • Upgrading everything in one commit. When something breaks, you cannot tell which package did it.
  • Committing the manifest without the lockfile. Teammates and CI get a different tree from yours.
  • Jumping to the latest major to fix a vulnerability when a patch release on your current major fixes it.
  • Letting "make the tests pass" become the instruction. Tests that are edited to pass are not tests.
  • Using --yolo on a real project. Approvals exist for exactly this kind of change.
  • Skipping the rescan. A fix can bring a new finding or a new licence.
  • Forgetting the runtime. Some upgrades need a newer Node, Python, Java or Go. Update CI and container images too.

FAQ

Can an AI assistant upgrade dependencies without breaking things?

It can do the mechanical work well: read the finding, change the version, run the install and the tests. Whether it breaks things depends on the routine around it. One change at a time, tests as the gate, and your approval on each command keep the risk small.

Can I use the AI plan I already pay for?

Yes. Bring the Claude, ChatGPT or Codex plan you already pay for and use it inside the Safeguard CLI. Safeguard adds no extra charge for that usage; your plan's own usage limits and terms still apply. You can also connect Claude or ChatGPT to the Safeguard MCP server.

Which permission mode should I use for upgrades?

Plan while you build the work list, then Ask or Auto for the upgrade. Accept edits suits a long series of manifest edits where you still want commands to ask. Strict is for CI.

Should I use npm update or npm install for a fix?

npm update stays within the range in package.json. If the fixed version is outside that range, use npm install PKG@VERSION, which updates the range and the lockfile.

How often should I upgrade?

Security fixes as soon as they are known. Routine patch and minor upgrades on a regular schedule, such as weekly, so each batch stays small.

Does the assistant push or open pull requests on its own?

In the recorded CLI session it prints a summary and a suggested commit message and pushes nothing. safeguard fix can create a pull request only when you pass --create-pr. Pushing yourself keeps a person in charge of what leaves the machine.

How do I undo an upgrade?

/rewind restores files the assistant edited. For lockfiles rewritten by an install command, use git, for example git checkout package.json package-lock.json.

Does my code leave my machine?

Scans build the SBOM locally and upload the SBOM and findings, not your source. The model you choose sees what the assistant reads to answer you.

Try it yourself

This walkthrough shows how to set up the runner on your own machine, pick the platform, start it, approve it with its device code, then use the same CLI to scan from the terminal.

Click through it at your own pace, or open it full screen.

Ready to run your first safe upgrade? Download the Safeguard CLI, read the CLI docs, and start with /scan . in your project.

Quick check

Why upgrade one package per commit?

So that when a test or production build breaks, you know which upgrade caused it, and a revert undoes exactly one change.

Which npm command proves an upgrade installs cleanly from the lockfile?

npm ci. It requires a lockfile, fails if the lockfile and package.json disagree, and never writes to either file.

Why rescan after an upgrade that fixed the finding you wanted?

Because the upgrade may have pulled in other new versions, with new vulnerabilities or a different licence. The rescan compares the whole result, not just one finding.

Sources

Last reviewed: 21 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.