# How we keep dependencies up to date

The upgrade agent we run on Kortix — a weekly cron that opens dependency PRs, runs the full suite in a sandbox, and only opens the PR when it's green.

Canonical page: https://kortix.com/use-cases/dependency-upgrades

Dependencies drift. Left alone, a project falls months behind, security patches
pile up, and the eventual upgrade turns into a large, risky change nobody wants
to own. The usual bots open a PR for every bump and leave a human to work out
whether each one is safe, which mostly means the PRs sit unreviewed.

We run an upgrade agent on Kortix that does the checking before it asks for a
review. A weekly cron proposes upgrades, applies them in an isolated sandbox,
runs the full suite, and only opens a PR when the change is green. This write-up
covers how the setup works: the trigger, the session model, and the guardrails.

- **Team:** Kortix
- **Runs on:** A weekly cron
- **Connected systems:** GitHub · CI
- **Mode:** Cron-driven · PR opened only when green

## The problem

Keeping dependencies current is work no one schedules. A version-bump bot opens a
PR per package, but it can't tell whether the bump breaks anything — that check
still falls to a person, so the PRs queue up and the project drifts anyway.

The common fixes are incomplete. Ignoring upgrades until something forces the
issue turns a routine bump into a migration. Merging bot PRs on green CI trusts
whatever tests already exist, not that the upgrade is actually safe. Doing it by
hand is reliable but slow, and it's the first thing dropped when the team is busy.

## What we built

On Kortix, a weekly cron triggers an upgrade agent. Each run spawns an isolated
session (a cloud sandbox) with scoped access to the repository and CI. The agent
checks which dependencies are behind, applies the upgrades on a branch, installs
clean, and runs the full suite inside the sandbox. It opens a PR only when the
change is green; a human merges.

## How it works

### Connect a weekly cron as the trigger

A scheduled **trigger** fires the project once a week. Each firing spawns a fresh
**session** in its own sandbox, seeded with a clean checkout of the default
branch. One run, one disposable machine, so nothing carries over between weeks and
independent upgrade sets can run in parallel.

### Give the agent the upgrade playbook

How we handle upgrades lives as **skills** and **memory** that travel with the
agent: which packages are pinned on purpose, how to run the suite, the order to
apply major versions in, and migrations that have bitten us before. When an
upgrade needs a manual step, we write it down and the agent applies it on the next
run.

### Connect the systems the upgrade needs

Through scoped **connectors**, brokered server-side so no raw token reaches the
model, the agent can:

- **Read the manifests** — resolve which dependencies are behind and how far,
separating patch and minor bumps from majors.
- **Apply and install in the sandbox** — update the lockfile and install clean on
a branch, with the resolution output captured in full.
- **Run the full suite** — unit, integration, and e2e inside the sandbox, so a
bump that breaks a path fails here rather than in review.
- **Open a PR on GitHub** — the branch, the changelog for each bump, and the green
result post as a pull request.

### Set the guardrails

The agent opens a PR only when the suite passes; a failing upgrade is dropped or
split, not pushed for a human to debug. It never merges — the merge is a **human
approval gate**. Credentials are encrypted in the secrets manager and injected at
runtime, scoped to the agents you grant them to.

### Let the weekly run happen

With that in place, each week the agent finds what's behind, applies the upgrades,
runs the suite in the sandbox, and opens a PR that's already been proven green —
with the bumps grouped and the changelog attached. A bump that breaks a test never
becomes a PR; it comes back flagged with the failure instead.

> **The pattern**
> A weekly **trigger** spawns a session with scoped **connectors** into the repo
> and CI. The upgrade playbook is encoded as **skills** and **memory**. The agent
> proves the change green in its sandbox and a human owns the merge.

## Guardrails

The agent changes dependencies and runs code, so the access is scoped and
contained:

- **Isolation.** Every run happens in its own isolated sandbox on its own branch.
  The session can install, resolve, and run the suite to prove an upgrade; only
  the branch and result are written back out.
- **Scoped secrets.** The GitHub and CI credentials are encrypted in the secrets
  manager and injected into the sandbox at runtime, scoped to the agents you grant them to or
  the logs.
- **PR-gated.** The agent opens a pull request and stops. It never merges and
  never pushes to the default branch; a human owns the merge.
- **Everything is code.** The agent's configuration, skills, and permissions are
  files in the repo, versioned and changed through a reviewed **change request**
  rather than a dashboard setting.

## The outcome

- **Weekly:** Upgrades proposed on a schedule, not when something breaks
- **Green-only:** PRs opened only after the full suite passes
- **Human merge:** The agent proves the change; the team decides

Dependencies stay current without anyone scheduling the work, and the upgrade PRs
that land in review have already been run against the full suite. Reviewers see a
green change with the changelog attached instead of a bump they have to check out
and test by hand.
