Docs

apiweiser-cli is a long-running local process: point it at a repo once, and it keeps watching that repo's dependencies for breaking updates — opening a PR when a coding agent has built and tested a fix.

Prerequisites

  • Node.js 22+ — runs .ts files directly, no build step
  • git, on PATH
  • A coding agent CLI, already installed and logged inClaude Code or Codex. apiweiser-cli shells out to it; it doesn't set up an account for you.
  • A GitHub personal access token with Contents and Pull requests write access on whatever repo you point --path at — a fine-grained token scoped to just that repo is the safer choice.
  • An LLM API key from any OpenAI-compatible provider (OpenAI itself, or a compatible endpoint like Groq)

Install

Installs the CLI globally and sets up the codemod skill for whichever coding agent is on your PATH, in one step:

curl -fsSL https://apiweiser-cli-fe.vercel.app/install.sh | sh

Or do both manually:

npm install -g apiweiser-cli
npx codemod ai --harness claude --user --no-interactive   # swap claude for codex if that's what you use

Or run it without installing:

npx apiweiser-cli --path <path-to-repo>

Or clone the repo and run it from source (no build step needed):

git clone https://github.com/enismustafaj/apiweiser-cli.git
cd apiweiser-cli
npm install
node src/main.ts --path <path-to-repo>

Configure

Every run needs ~/.apiweiser-cli/config.json filled in — even a plain scan, since the process always starts three daily background schedulers alongside it. Run the CLI once with no config and it creates a template for you there, then exits with an error telling you to fill it in:

{
  "llm": {
    "apiKey": "sk-...",
    "url": "https://api.openai.com/v1",
    "model": "gpt-5"
  },
  "codingAgent": {
    "command": "claude",
    "args": ["-p"]
  },
  "github": {
    "token": "ghp_..."
  }
}
FieldWhat it's for
llm.apiKeyYour API key for whichever provider llm.url points at
llm.urlAn OpenAI-compatible baseURL — api.openai.com/v1, or a compatible provider like Groq
llm.modelModel name at that endpoint
codingAgent.command"claude" for Claude Code, "codex" for Codex — whichever you have installed
codingAgent.argsFlags that put that CLI into non-interactive mode — ["-p"] for Claude Code, ["exec"] for Codex
github.tokenA PAT with Contents + Pull requests write access on the repo you point --path at

codingAgent also needs the codemod skill installed for it (the one-line installer above does this automatically) — without it, your coding agent won't know how to build a codemod package.

Usage

apiweiser-cli is two subcommands. scan is the default, so the original invocation still works unchanged — point it at exactly one of a local path or a git URL:

apiweiser-cli --path <path-to-repo>
apiweiser-cli scan --repo <git-url>
# the first is short for: apiweiser-cli scan --path <path-to-repo>

--repo clones the URL (or pulls latest, if a previous run already cloned it) into ~/.apiweiser-cli/repos/<owner>-<repo>/ and scans that instead — no need to git clone a repo yourself first just to point apiweiser-cli at it. Everything after this point behaves identically either way.

Scans the repo once — generates its SBOM, records its dependencies, finds every call site, and queues anything brand new for a changelog-source lookup — then settles into a long-running process running three daily schedulers, in order: draining the changelog-lookup queue, classifying releases as breaking or not, and checking Renovate for version update suggestions — including security fixes Renovate surfaces via OSV.dev's vulnerability database, not just version bumps you'd have found anyway. Whenever a suggestion turns out to already be classified as breaking, a coding agent builds and tests a codemod for the migration, applies it, and opens a PR — no further action needed from you beyond reviewing it. Safe to re-run — unchanged dependencies are skipped entirely, so it's fast even on a large repo. Leave the process running.

All state lives in ~/.apiweiser-cli/ — the sqlite db, the config file, SBOM/Renovate caches, clones made via --repo, and generated codemod packages — separate from whatever repo is actually being scanned.

Dashboard

A local, read-only web view over that same sqlite db — every package it's found, every suggestion Renovate has raised, and every PR it's opened so far:

apiweiser-cli dashboard --port 3000   # default 3000, --port is optional

A foreground command, not a scheduler — it binds the port and runs until you Ctrl+C it, same as any local dev server. It only reads ~/.apiweiser-cli/db.sqlite, so it reflects whatever the scan process has already written and never scans or writes anything itself — run it alongside a running scan, or on its own against state from an earlier run.

What to expect

  • The first scan of a large repo can take a few minutes, dominated by the SBOM/dependency-scanning tooling; re-scans are fast since only new or version-changed dependencies get re-processed.
  • Not every breaking update gets a PR. If your repo's actual call sites don't touch whatever part of the API changed, the generated codemod correctly makes no changes, and no PR is opened — that's expected, not a bug.
  • A change request can take several minutes. Building and testing a codemod is a real coding-agent session, not a single API call.
  • PRs are opened directly on the scanned repo — whether it was given via --path or cloned via --repo (from a branch named apiweiser-cli/<package>-<version>), not a fork. Point this at a repo you (or your token) actually have write access to.

Docker

docker build -t apiweiser-cli .
docker run --rm \
  -v "$(pwd)":/repo:ro \
  -v apiweiser-cli-state:/root/.apiweiser-cli \
  apiweiser-cli --path /repo

The repo being scanned is mounted read-only at /repo. The named volume persists ~/.apiweiser-cli/ (db, config, caches) across runs — drop it and you lose scan history/config. Every run is long-running, so add -d to run detached rather than blocking the terminal.