How it works
Every change travels the same steps. Nothing runs on a schedule against your
repositories; Upseam works from events. In the auto mode the approval step
is skipped, except for the kinds of pull requests that
always ask.
vendor change
│
┌────▼────┐
│ detect │ what changed
└────┬────┘
┌────▼────┐
│ match │ which lines it touches
└────┬────┘
┌────▼────┐
│ approve │ ask mode: Slack buttons
└────┬────┘ or the dashboard issue
┌────▼────┐
│ patch │ your model, then gates
└────┬────┘
┌────▼────┐
│ PR │ your CI runs, you review
└─────────┘
Detect
Upseam starts work from four events:
- A vendor publishes a change. Once an hour Upseam reads the providers' changelogs and deprecation pages and records new change events. Each event carries its type, the official breaking flag, the symbols to search for and a link to the vendor's page.
- You install the App or add a repository. Upseam scans the default branch once.
- A push to the default branch changes a manifest or lockfile,
.github/upseam.ymlor a source file Upseam reads. Other pushes are ignored. - Dependabot or Renovate opens a pull request that bumps the SDK of a tracked provider.
For each repository Upseam records its surface: the provider SDK, the SDK version from the lockfile or manifest, and the API version from the pin in code. Without a pin, the API version is inferred from the SDK version where Upseam knows the default for that SDK release; otherwise it is unknown. Only breaking vendor events reach repositories: for versioned APIs, repositories whose recorded version is below the event's version; for AI model retirements, every repository using that provider. Because the recorded version may be inferred, a repository can be reached by a change that does not apply to it, or missed by one that does.
Match
Upseam downloads the repository at its current commit and searches it for the
symbols of the breaking changes newer than your version. Matching is textual
and word-bounded. It skips comments and lines that start with import or
from, and ignores node_modules, dist, vendor and similar directories.
Model ids match only as whole ids: a neighbouring letter, digit or hyphen
makes a different id, and ids made only of letters and digits, such as
davinci, match only inside quotes. Each match is a file and a line. No match, no action.
Matched breaking changes are grouped. One group becomes at most one pull request:
| Change | Group |
|---|---|
| Versioned API | repository, provider, target API version |
| AI model retirement | repository, provider, notice date |
| Internal contract | consumer repository, backend repository, spec path |
A group can be fixed automatically when every change in it is mechanical (a removal, a rename or a type change) and the target version works with the SDK you have. If any change in the group is not, the whole group is listed under Needs you with a reason, for example "Bump SDK" when the change needs a newer SDK.
Patch
The patch is written by your model, with your key (Connect a model). The model receives only the change data and the files with matches, and answers with whole files. Before anything is pushed, deterministic gates check the answer: only the matched statements may change, only the changed symbol may be renamed, and no new imports, URLs, network calls or environment access may appear. A patch that fails a gate is not pushed; the finding goes to Needs you. The full list is in the Security model.
Until you connect a model or your own agent, Upseam writes no fixes; fixable findings are listed as ready to fix instead. See Without a model.
Pull request
Upseam pushes one commit to a branch upseam/<group> through the GitHub API,
so GitHub marks it Verified, and opens a pull request against the default
branch. The body has these sections:
- What changed at the vendor, for example "What changed at Stripe": the change, its date and a link to the vendor's page.
- Changes: the lines Upseam changed.
- Not changed: needs you: matches Upseam left alone, with file and line.
- New in the vendor's API version, for versioned APIs: additions between your version and the target version, listed from the vendor's changelog. Upseam does not use them in your code. The list is left out when New capabilities is off.
- Verification: which files and how many lines changed, and the result of your CI on the pull request.
- How this was made: the model that wrote the patch, with your key.
Your own CI runs on the pull request as on any other. Upseam reads the result and shows it in the pull request, and in the Slack message when the pull request came from an approval there.
- No duplicates. A group has one branch and at most one open pull request. A newer change in the same group updates the branch, but only while its head is the last commit Upseam pushed. If someone else committed to it, Upseam does not touch the branch and moves the finding to Needs you.
- Closed means ignored. A pull request closed without merging switches its group off. The next target version is a new group.
- Limit. At most five open Upseam pull requests per repository.
The dashboard issue
When a repository has its first finding that waits for approval or needs you, or a setup notice (for example a missing workflow for generation in your Actions), Upseam opens one issue, Upseam watches this repository, and keeps it up to date:
- Waiting for approval: findings in the
askmode, and successor-model and Dependabot or Renovate findings in any mode, with a checkbox to open the pull request. - Needs you: changes Upseam will not patch, with file and line.
- Watching: the providers, SDKs and versions Upseam found.
- Setup: shown when fixes are generated in your GitHub Actions and the
upseam-generateworkflow is missing, with what to add.
Snoozed findings leave Waiting for approval until the snooze ends. A closed dashboard issue is not reopened. With Slack connected, findings waiting for approval also arrive in your channel with Open PR, Snooze 7 days and Ignore buttons. Code review stays in GitHub.
Successor models
When a vendor retires a model and names exactly one replacement for each
retired model your code uses, the pull request switches the model id to the
replacement. Its body has a "Needs your review" section, because the successor
may accept different parameters and behave differently. These pull requests
always wait for approval, even in the auto mode. When the vendor names
several replacements, the finding goes to Needs you with the choices.
The New capabilities switch on the settings page, per installation or per repository, turns successor-model pull requests on or off. When it is off, those retirements are listed under Needs you instead.
Internal contracts
List an OpenAPI or GraphQL spec and its consumer repositories in the backend's
.github/upseam.yml. When a push to the backend's default
branch changes the spec, Upseam compares the two versions, searches every
consumer for the changed operations, types and fields, and opens a pull
request in each affected consumer. Consumers must be in the same App
installation.