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.
.ts files directly, no build stepPATH--path at — a fine-grained token scoped to just that repo is the safer choice.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>
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_..."
}
} | Field | What it's for |
|---|---|
| llm.apiKey | Your API key for whichever provider llm.url points at |
| llm.url | An OpenAI-compatible baseURL — api.openai.com/v1, or a compatible provider like Groq |
| llm.model | Model name at that endpoint |
| codingAgent.command | "claude" for Claude Code, "codex" for Codex — whichever you have installed |
| codingAgent.args | Flags that put that CLI into non-interactive mode — ["-p"] for Claude Code, ["exec"] for Codex |
| github.token | A 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.
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.
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.
--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 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.