mordaunt.dev/code

code / review

review

a hybrid review gate for agentic loops: static checks and narrow model readers give fast, converging feedback on every change before it is committed

  • Odin
  • Go
  • AI
  • LLM
  • Code-Review
  • Claude
  • Anthropic
  • Git
  • CLI
  • Developer-Tools
clone
https://mordaunt.dev/code/review
release
dev-2026-10d2026-10-2969 commits
license
Apache-2.0
activity
69 commitsthis year, since 2026

review

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

Linux
curl -fsSL https://mordaunt.dev/code/review/install.sh | sh
macOS
curl -fsSL https://mordaunt.dev/code/review/install.sh | sh
Windows
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:

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. Deterministic 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 <rule> 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 <rule> <why> beside the code it justifies, not in a config file. A reasoned, rule-specific addition is reported as consider; blanket or unexplained dismissals are 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, grok, codex, 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 runs several jobs and costs 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 <id> lists the commits one rule fired on.

Odin reviews also check that main packages live under cmd/ and that command-line parsing belongs to one cli package. A focused odin job judges avoidable allocations, temporary strings that can use stack buffers, entry points that should delegate their logic, and allocator parameters that make allocation visible and caller-controlled. It also checks that allocation and release use matching allocators, respecting containers that retain theirs. Borrowed-memory checks catch local array slices and strings that escape their storage, with inference for other proven lifetime violations. Owning-copy checks catch two local headers freeing the same explicitly heap-allocated container; inference covers other established ownership violations. Partial-construction checks catch heap storage lost on later failure returns; inference covers other resources with established acquisition and cleanup contracts. Container checks catch local borrows used after potentially reallocating growth, with inference for established mutations through helpers. A 512-byte environment buffer is a use-case assumption; replacements must preserve overflow handling and keep borrowed strings within the buffer’s lifetime.

Use

review                          the staged change
review HEAD^..HEAD              the last commit
review --json                   one JSON object, for an agent
review --repo "/path/to/repo"    review from outside the repository
review doctor --json            local paths and capability diagnostics
review external prepare --repo DIR  export jobs without a provider
review external submit --repo DIR   accept an answer object from stdin
review external report --repo DIR --run ID  inspect a saved external run
review mcp --repo /absolute/repo    serve the same jobs over stdio MCP
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.

--json keeps progress on stderr and returns a single error object for setup failures, preserving the command’s exit code. doctor --json reports the canonical repository root, executable paths, and API credential presence without printing credentials or probing authentication. Shipped sidecars are found beside the review executable first, then on PATH. Run python3 tests/cli.py build/review after building to check these contracts without a provider or network.

Use a connected assistant

review external prepare --repo DIR runs the existing static checks and exports bounded review jobs without contacting a provider. Add --rev REV for a revision or --jobs LIST to select jobs. Submit each answer with review external submit --repo DIR < answer.json; the input has version: 1, run_id, source_id, job_id, schema, and answer (the answer JSON encoded as a string). Copy the identities and schema from the exported run and packet, then answer any returned verification jobs. review external report --repo DIR --run ID returns the run’s current jobs and nested v1 report. Pending answers, missing verification, faults and unread source remain incomplete; an empty findings list alone is not a pass.

review mcp --repo /absolute/path/to/repository exposes that engine to a local assistant over stdio. See Desktop setup and protocol limits. It supports MCP 2025-11-25 initialization; actual Desktop UI compatibility has not been tested.

These commands are additive. Ordinary CLI reviews, providers, hooks and their answer cache retain their existing behavior. A connected Desktop assistant supplies answers for external runs; its subscription does not authenticate the ordinary provider-backed review or commit hook. External answers stay outside the provider answer cache.

Give it to your agents

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:

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 and Grok 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, Java and shell are read through ast-grep when it is installed. Any other language still gets its comments, its commit message and its history checked. The artifacts job reads build instructions (justfile, Makefile, Dockerfile), patches, fixtures and golden outputs from their actual diff, including embedded source code. Stored source fixtures are reviewed as test inputs rather than compiled as standalone packages. Unsupported source languages still report missing parser coverage.

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:

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, Go and just. CI builds with the Odin commit named by ODIN_PIN in .github/workflows/release.yml; other versions may not link.

git clone --recursive https://mordaunt.dev/code/review && cd review
just install

Offline regression checks need Python 3 and Git on a POSIX host:

just test-desktop

This builds the release binaries, then runs tests/cli.py, the offline Grok schema contract in tests/grok.py, and tests/desktop.py. The CLI fixture uses POSIX printf and executable permissions; this recipe does not establish Windows runtime or Desktop UI compatibility. The release workflow runs it on native Linux and macOS targets; Windows still runs the package and installer tests.

Learn more

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 and NOTICE.

Changelog

full log
dev-2026-10d2026-10-29

dev-2026-10d

  • 995617ereview: cover artifacts and reduce false positives
dev-2026-10c2026-10-24

dev-2026-10c

  • b5a0b2cprovider: build the expected grok home with path.join
  • b060696job: cap stanza findings at consider in code
  • 1b43636tests: resolve the cli fixture root
  • 5e50171review: enforce blank lines between stanzas
  • 6871249provider: pass over an unset API key without warning
  • c22add1check: spare side programs from odin-main-location
  • and 2 more
dev-2026-10b2026-10-21

dev-2026-10b: external inference and Claude Desktop integration

  • bb56355external: canonicalize fixture repository paths
dev-2026-10a2026-10-21

dev-2026-10a: external inference and Claude Desktop integration

  • 9a918dcreview: integrate external inference and Desktop workflows
  • 67b0d68mcp: validate busy requests and honor response allocators
  • 2c62dc8mcp: expose external review jobs over stdio
  • c616152review: add explicit repositories and JSON diagnostics
dev-2026-102026-10-21

dev-2026-10

  • 1df585echeck: detect borrows invalidated by Odin container growth
  • ceebfd3check: track Odin container storage and borrowed references
  • fd2bd4acheck: enable and test partial construction leak detection
  • 498e878check: detect heap storage lost on construction failure
  • 81cd484check: detect copied Odin owners being destroyed twice
  • e5c4c73check: detect Odin borrowed storage escaping its lifetime
  • and 4 more
dev-2026-092026-10-01

initial release

  • 0d4e028check: merge odin-destroy-incomplete beside odin-temp-in-loop
  • 4be0788check: report an owning field an Odin destroy procedure never frees
  • 3e8c122check: report temp allocations a loop never gives back
dev-2026-09-rc22026-09-30

dev-2026-09-rc2

  • 76bf268release: strip ./ from checksum names in sha256sum's binary mode too
  • f81abfcanalyser: compare the resolved collections one by one
  • f283e7banalyser: give the tests a root Windows reads as absolute
  • 811f3e3tree: name a materialised tree by its real path, and read Windows separators
  • 7f3a1abrelease: run the tests with their sidecars, on an Odin that fails cleanly on Windows
  • 86c4d79release: keep the sqlite defines when the read hits end of input
dev-2026-09-rc12026-09-30

dev-2026-09-rc1

  • 6a2cc07licence: release under Apache-2.0
  • 38ccc5breadme: lead with install and what review is for
  • 732c790release: build, test and sign tagged releases on every platform
  • acd2cf5review: add version and update commands through jm:selfupdate
  • 1a9ccbcjustfile: give build outputs the .exe extension on Windows
  • 73d08e7justfile: take the jm collection path from JM
  • and 30 more

Mirrored to sourcehut and GitHub.