review reads a change before you commit it and says what a careful reviewer would. Static checks first, narrow model readings second. Built for agent loops. The command is review.
## Install
```sh
curl -fsSL https://mordaunt.dev/code/review/install.sh | sh
```
```sh
curl -fsSL https://mordaunt.dev/code/review/install.sh | sh
```
```powershell
irm https://mordaunt.dev/code/review/install.ps1 | iex
```
Each one downloads the release for your machine, checks every hash before
installing anything, and puts `review` and its three language sidecars in
`~/.local/bin`.
Then, in any git repository with something staged:
```sh
review
```
## What it looks at
Your compiler, linter and tests already say whether the code builds and
runs. review asks what they cannot:
- Does the repository already state this somewhere else?
- Could this test ever fail?
- Does the name say what the thing is?
- Does anything support what this comment claims?
- Does the commit message describe the commit?
Each question is its own narrow job, sent only the part of the change it
needs. A job that reads less costs less, and is harder to distract into
reporting what another job owns.
## Made to converge
An agent's loop is review, fix, review again. Everything here exists to make
that loop end.
- **Comparisons before judgement.** Twenty-seven checks of its own, and the repository's own compilers and linters, run before any model is asked, and still run when none can be.
- **Every finding cites a rule.** A finding that cites none is dropped before you see it. `review rules ` prints what it was judged against.
- **A second reading.** Each finding is read again with its evidence. One that falls is reported as retracted, with the reason, never silently dropped.
- **The same answer twice.** Answers are cached by the exact question asked, so an unchanged change replays and costs nothing. Ids hash what a finding is about, not where it sits, so they survive edits.
- **Progress you can read.** `--baseline last.json` names which findings resolved, which persist, and which are new.
- **Dismissals live in the source.** `//review:ignore ` beside the code it justifies, not in a config file. One added by the change under review is itself a must-fix.
- **Advisory unless asked.** It never fails a build or blocks a commit until `--exit-code` says it should.
- **Any model.** The console API, the `claude` or `pi` CLIs, or any command that reads a prompt and prints an answer.
- **Keeps itself current.** `review update` fetches a signed release. It never updates unasked.
## What a review costs
The static checks cost nothing: they compare, they do not ask. The readings
are what cost money, measured over one job on a seven-file commit:
| provider | one job |
|----------|--------:|
| `claude`, default model | $0.19 |
| `claude`, smallest model | $0.06 |
| `api` | a fraction of a cent |
| replayed from the cache | nothing |
A whole change, all five jobs, is a few times that. The gap between `claude` and `api` is the assistant's own harness, about
22,000 tokens a call, which these jobs do not use. The default model is the
middle one on purpose: the smallest found about two thirds of the wanted
duplicates, and never both halves of a pair in one reading.
A check that fires on everything is noise, so each one's fire rate is
measured rather than assumed. `review bench -n 500` runs them over your last
500 commits; `-rule ` lists the commits one rule fired on.
## Use
```
review the staged change
review HEAD^..HEAD the last commit
review --json one JSON object, for an agent
review --show what each job would be sent, and what the checks found
review --fresh ask again rather than replay the cache
review --exit-code exit 1 when a must-fix finding stands, for a hook
review --baseline last.json which findings resolved, persist, or are new
review --message-file "$1" the staged change with a commit-msg hook's message
review rules [job | rule] what a finding was judged against
review rules -dismissed each rule's dismissals in this tree, and why
review bench [-n 200] each check's fire rate over recent commits
review hook install the commit-msg hook that makes review a gate
review agent what an agent's instructions should say
review version which release this is
review update fetch the latest release
```
Flags go before the revision. `--provider` and `--model` pick who answers;
`REVIEW_PROVIDER` and `REVIEW_MODEL` set the defaults.
## Give it to your agents
```sh
review agent >> AGENTS.md
```
That appends the paragraph an agent needs: run `review --json`, fix every
`must-fix`, weigh each `consider`, dismiss a wrong finding in the source,
and stop when nothing must-fix persists.
To make it a gate rather than advice:
```sh
review hook install
```
That writes a commit-msg hook that refuses a commit while a must-fix finding
stands, and prints the stanza that does the same for Claude Code before any
`git commit` it runs.
## Languages and tools
Go and Odin are read through their own parsers, shipped as sidecars.
TypeScript, JavaScript, Python, Rust and shell are read through
[ast-grep](https://ast-grep.github.io) when it is installed. Any other
language still gets its comments, its commit message and its history
checked.
Whatever the repository already uses is run for it, at its strictest, and
kept to the lines the change touched: `go vet`, `staticcheck`, `odin check`,
`tsc`, `ruff`, `mypy`, `cargo clippy`, `semgrep`, `shellcheck`, `actionlint`
and `zizmor`. Each runs only when it is on PATH, and a skip is said on
stderr, so a check that is not running can be told from one that found
nothing.
## Releases
Releases are tagged by calendar, as Odin's are: `dev-2026-10`, then
`dev-2026-10a` for a second that month. A `dev-2026-10-rc1` tag is a release
candidate; the installers and `review update` never offer one unless it is
asked for by name:
```sh
curl -fsSL https://mordaunt.dev/code/review/install.sh | REVIEW_VERSION=dev-2026-10-rc1 sh
```
At a terminal, review checks once a day and says when a newer release is
out. Hooks, agents and pipes never see the check; `REVIEW_NO_UPDATE=1`
turns it off.
## Build from source
Needs [Odin](https://odin-lang.org), [Go](https://go.dev) and
[just](https://just.systems). CI builds with the Odin commit named by
`ODIN_PIN` in `.github/workflows/release.yml`; other versions may not link.
```sh
git clone --recursive https://mordaunt.dev/code/review && cd review
just install
```
## Learn more
[ARCHITECTURE.md](ARCHITECTURE.md) explains every check and job, the JSON
contract, the cache, the providers, how releases are signed, and what each
directory in this repository is for.
## Licence
Apache-2.0; see [LICENSE](LICENSE) and [NOTICE](NOTICE).