Review an AI-generated pull request from your terminal.
GitHub tells you which lines changed. Cutplane tells you which components changed, what else in the system those changes reach, and — for every sentence it prints — the evidence it was computed from.
$ npx cutplane analyzethis branch against the default branch$ npx cutplane analyze --pr 482a pull request, by number$ npx cutplane analyze --jsonthe whole report, for another programPublished on npm as cutplane, MIT licensed.
What a report looks like
cutplane zermmi-app a859dfc1..6e9e3126
base is the merge-base with origin/main
58 files changed 7 components changed 9 components reached
0 routes added/removed 22 schema statements 0 dependencies added
WHAT CHANGED
src/features/invoicing/ (Invoicing) 34 files schema, 8 dependents
Invoicing changed in 34 files, 3729 lines added or removed.
…
CHANGE IMPACT — 9 components, 65 files reached
src/features/invoicing/ 36 files 1-4 hops precise
…
6 further component(s) reached — ranked lower or held backWhen it is uncertain, it shows less
When Cutplane is uncertain, it shows less — not something plausible.
A wrong architecture diagram is considerably worse than an incomplete one. So every list that stops early says how many it left out, every reach it declines to trace says why, and the footer says whether the sentences were written by a model or by templates. There is a section headed “Not stated” whose entire job is to name what the engine computed and chose not to claim.
Every command and flag
cutplane analyze [--repo <path>] [--base <ref>] [--head <ref>] [--pr <n>]
[--full] [--json] [--offline]
[--print-llm-payload] [--depth <n>]
cutplane new-files [--repo <path>] [--base <ref>] [--head <ref>] [--pr <n>] [--json]
cutplane doctor [--repo <path>]
cutplane version- no --base
- the merge-base with the default branch, and the report says so
- no --head
- HEAD
- --pr <n>
- gh pr view if you have it, then the GitHub REST API with GITHUB_TOKEN, then an error naming both. gh is never required. The base is the merge-base, which is the diff the PR page shows
- --full
- every count, every claim, every withheld sentence — the short report is the default
- --json
- the whole report, including the configuration every threshold came from
- --offline
- make no network call at all — the structural report, and it says so at the top
- --no-source
- make the calls, and send no file contents with them
- --depth <n>
- how far the impact walk may travel
- doctor
- everything the other commands assume, checked and named
Cutplane reads git objects locally and never downloads a diff. If --pr names a commit your clone does not have, it tells you the git fetch that gets it.
The drawn report
The architecture diff, the impact cascades and every claim under the thing it is about are at cutplane.dev, which runs this same engine on a server and gives each run a link you can send. There used to be a --html flag that rendered it into one self-contained file; it was retired once that page existed, because two renderers of one report are two pages that can disagree about the same change. Here, --json is the whole report and the thing to hand another program.
What leaves your machine
Source files are sent. Up to 12 changed files, whole, at most 156 KB in all: the highest-priority changed files of the components this change touched, so the report can say what the change does and not only what it touched. Structural metadata goes with them — paths, symbol names, component names, counts and relationships — and a path can itself name an internal service or a customer.
- default
- structure, plus the key files above
- --no-source
- structure only — what every version before 0.2 sent
- --offline
- nothing
--print-llm-payload prints the exact bytes of both, so none of the above has to be taken on trust.
Two calls are made, and OPENAI_API_KEY is required — from the environment or a .env at the repository root. One phrases the report's sentences and names its components, and sends no source at all. The other reads the key files and writes what the change does, at the top of the report.
Without a key, analyze stops and names the fix. --offline is how you ask for the structural report on purpose — every count, every claim and every citation, and a block at the top saying the report is structure only.
What Cutplane does not claim
It is not a linter and not a test runner.
It says what changed and what that reaches. Whether the change is correct is your job.
Dynamic dispatch is invisible to it.
getattr, DI containers, Django's app registry and duck typing are invisible to any static tool; nothing is claimed about them.
Line numbers are valid at one commit.
Every citation carries the sha it was taken at.
The thresholds are tuned against a twelve-unit corpus, not proven.
They are in --json under config, versioned, so a number that moved is traceable to the run that moved it.
Requirements
Node ≥ 20 and git. TypeScript and Python are parsed; nothing is installed, run or evaluated from the repository being analysed.