// Tools

CLI

The upseam CLI runs the same detector as the App, locally or in your CI, with no account and no server. It is published as the @upseam/cli npm package with the first release; the installed command is upseam:

upseam inspect stripe ../your-repo

It needs Node.js 22 or later.

Commands

Command What it does
upseam inspect <provider> [path] [--api-version <v>] SDK, API version, changes since, matched lines.
upseam inspect internal --spec <path> --from <ref> [--to <ref>] [--repo <path>] [consumer...] Diff your OpenAPI or GraphQL contract and search the consumer paths.
upseam report [path] (--dry-run | --github <owner/repo>) Print the issue body, or create or update it with GITHUB_TOKEN.
upseam fix [path] (--dry-run | --github <owner/repo>) Patch one mechanical change with your model: print the diff or open a pull request.
upseam fix [path] --group <key> --sha <sha> [--head <sha>] (--dry-run | --github <owner/repo>) Write the patch for one App group and push upseam/<group>, as the Action does when generating in your GitHub Actions.
upseam init [path] Set up Upseam in a repository; see below.
upseam agent route "<task>" Rate a coding task and pick a model tier. Needs TYPESAFE_API_KEY.
upseam agent prune --task "<task>" <fragments.json> Drop context fragments irrelevant to the task. Needs TYPESAFE_API_KEY.

<provider> is one of stripe, shopify, hubspot, twilio, github, openai, anthropic, gemini and mistral. --api-version overrides the detected version for stripe, shopify, hubspot, github and twilio; openai, anthropic, gemini and mistral have no API version, and --api-version exits with code 2 for them. When the provider's SDK is not found in the repository, --api-version has no effect.

upseam init

upseam init prepares a repository for the App without a model, the same way the coding agent setup does:

upseam init
  1. Checks that the path (default: the current directory) is a git repository with a GitHub remote, and lists the supported vendor SDKs and the OpenAPI and GraphQL files it finds. With neither, it says "Upseam has nothing to watch in this repository yet", asks nothing and writes nothing.
  2. Proposes .github/upseam.yml with only internal and ignore, checked with the same parser as the App. It asks for consumer repositories and never guesses them. When nothing is needed, it writes no file and says so.
  3. Asks how fixes are written: by the model you connect on the settings page, or by your GitHub Actions with the upseam-generate workflow and upseam/action pinned to a commit SHA you give. Without a SHA it writes no workflow.
  4. Shows every file before writing it and asks to confirm. It never commits or pushes; it prints the git commands instead.
  5. Lists what is left in the browser: install the App, connect a model or choose Actions, optionally connect Slack. While the App is in private beta, it says so instead of printing an install link.
Flag Meaning
--dry-run Ask nothing and write nothing; print what would be written.
--yes Ask nothing and write the proposed files: the stored-key method, no consumers, nothing ignored.
--json Print one JSON object with the findings, files, notes and next steps. Needs --yes or --dry-run.
--force Replace an existing file whose content differs. Without it the file is kept.
--internal <spec>=<owner/repo>[,<owner/repo>...] An internal entry; repeat per contract.
--ignore-provider <id>, --ignore-path <pattern> ignore entries; repeat for more.
--method model|actions How fixes are written.
--action-sha <sha>, --vendor anthropic|openai, --model <id>, --base-url <url> For Actions: the upseam/action commit and the model the workflow uses. --vendor openai needs --model.

Run by an agent, without a terminal, it needs --yes or --dry-run. It refuses to read or write .github/upseam.yml or .github/workflows/upseam-generate.yml through a symbolic link or a non-regular file. It reads no environment variables or secrets, makes no network calls and sends no telemetry.

Contract checks

upseam inspect internal also takes:

  • --consumer-repo <owner/repo[@ref][:path]>, repeatable, to search other repositories;
  • --fail-on breaking|matched|never, which exits with code 3 when it triggers;
  • --dry-run to print the pull request comment, or --github <owner/repo> --pr <number> to create or update it with GITHUB_TOKEN.

The --spec extension picks the format: .yaml or .yml is OpenAPI in YAML, .graphql, .graphqls or .gql is a GraphQL schema, anything else is OpenAPI in JSON. --from and --to are git refs or file paths; --to defaults to HEAD.

upseam inspect internal --spec api/openapi.yaml --from v1.4 --to HEAD ../frontend ../mobile

Options and exit codes

  • inspect and agent take --json. upseam --help prints the commands grouped by task, with examples. upseam --version, -v or upseam version prints only the package version.
  • inspect in a terminal lists the changes matched in code first, then the first 10 unmatched breaking changes; --all lists every breaking or matched change. --all changes only this terminal output: plain and --json output always list everything. A retirement date shows a countdown, for example retires 2026-10-23 (in 26 days).
  • fix also takes --vendor, --model and --base-url. The Action runs it as separate steps with --pulls <file>, --stage <dir> and --publish <dir> --manifest <sha256>, so the token and the model key are never in the same step. --verify is refused: code the model wrote never runs in a job that can push, so your tests run in your usual pull request workflow with contents: read.
  • Exit codes: 0 done, 1 error, 2 usage, 3 --fail-on triggered.

Terminal output

In an interactive terminal the output has colour, links you can click and, while inspect, report, init or fix scan the repository, a progress bar on stderr. The percentage counts the files read; the other steps show their name only. The bar appears only after a quarter of a second and is cleared before the result is printed.

  • NO_COLOR with any value, or TERM=dumb, turns colour off; the bar stays in black and white, except with TERM=dumb, where there is none.
  • When stdout is not a terminal or CI is set, the output is plain text, one line per fact, without colour, links or a progress bar. The GitHub Action and your CI logs get this form.
  • --json output never changes with the terminal.
  • Text taken from the repository, the change data or a model reply (file names, code lines, titles, versions, contract keys, error messages from parsing a spec, and the fix diff) is cleaned before it is printed: control characters, escape sequences, bidirectional and zero-width characters and line breaks inside a value are removed, a line that would start with :: gets a zero-width space between the colons and every ##[ gets one after ##. So it cannot change your terminal or run a GitHub Actions workflow command. --json output is not changed; a JSON string can still contain ##[. Links are clickable only for plain http and https addresses.
  • In the GitHub Action every step that runs the CLI also turns workflow commands off (::stop-commands:: with a random token) while it runs; the Action itself prints the warnings about skipped consumers afterwards.
  • Ctrl-C clears the progress bar and exits with code 130. During a step that does not yield, such as reading the change data or matching, it takes effect when that step ends, usually within a second.

Data and privacy

  • inspect and report read the change database that ships inside the package and fetch no change data at run time.
  • Local only: init, inspect <provider>, inspect internal without --consumer-repo and --github, and report --dry-run.
  • GitHub, with your token: inspect internal --consumer-repo downloads each consumer repository as an archive, using UPSEAM_CONSUMERS_TOKEN or GITHUB_TOKEN. --github on inspect internal and report sends the rendered comment or issue body to the GitHub API. fix --pulls looks up Upseam's pull requests through the GitHub API.
  • Your model vendor, with your key: fix sends the change and the matched files, except with --pulls, --publish, or --group with --edits. fix --github then pushes one branch to your origin and opens a pull request. With --stage <dir> it only writes the patch to that directory and pushes nothing; the separate --publish step pushes and opens the pull request. With --group it only pushes the branch, and the App opens the pull request.
  • agent route and agent prune send the task and the fragments to TypeSafe, with your TYPESAFE_API_KEY. Keep secrets out of them.