Skip to content

How it works

miu-cr splits a review into a deterministic shell and a single LLM pass. The shell handles everything where correctness matters — selecting files, assembling context, anchoring findings to real line numbers, gating, and dedupe. The LLM is used only for judgment: spotting bugs and proposing fixes.

GetDiff ──▶ SelectFiles ──▶ AssembleContext ──▶ Agent.Review ──▶ ResolveLineNumbers ──▶ drop drift ──▶ dedupe ──▶ gate
(staged= (ext / include/ (hunks + new- (one LLM pass, (re-anchor from (Line==0 (file+line+ (max
index) exclude globs) content windows) file_read/grep) quoted code) rejected) category) severity)

Each stage is deterministic except Agent.Review. An empty diff set yields an empty findings list, not an error.

One of three modes produces the reviewable diffs:

  • --staged reads the index (what you are about to commit), not HEAD.
  • --from/--to diffs two refs.
  • --commit diffs a commit against its parent.

The reviewed revision travels with the diff so later stages read the exact same content the diff came from.

SelectFiles filters changed files by --ext, --include, and --exclude (doublestar globs). Only selected files reach the model.

AssembleContext builds the exact text the model sees — deterministic for a fixed diff set. Per file it emits the diff hunks plus a line-numbered new-content window around each change (--expand lines on each side).

When --token-budget is set and the full context exceeds it, assembly degrades down a truncation ladder, recording the level it landed on in stats.truncation_level:

LevelContents
fullDiff hunks + expansion windows.
hunks_onlyDiff hunks, no expansion windows.
filenames_onlyJust the list of changed files.

This makes truncation visible instead of a silent miss.

A single structured pass reviews the assembled context. The model has two read-only tools to gather more context before deciding:

  • file_read — read a line range of a file at the reviewed revision.
  • grep — search the reviewed revision for a fixed string.

The model returns JSON findings without line numbers — instead it quotes the exact source it refers to (existing_code). Severities are constrained to info|low|medium|high|critical; categories are short kebab-case tags (bug, security, performance, error-handling, concurrency, resource-leak, maintainability, …).

This is the core trick. Any line number a model emits is discarded; the engine recomputes every finding’s line from its quoted code against the reviewed revision:

  1. Match the quote against each hunk’s new side (context + added → new-file line numbers).
  2. Then the old side (context + deleted → old-file numbers).
  3. Then scan the full new-file content as a fallback.

Matching normalizes whitespace and diff markers and drops blank lines, so a quote with interior blanks still anchors. A finding whose quote no longer matches resolves to line 0 and is dropped (findings_dropped in stats). That single rule kills position drift — the classic failure of diff-only and bare-agent review where a finding points at the wrong line.

Surviving findings are de-duplicated on file + line + category plus a short hash of rationale + suggested_patch, then sorted by file then line. Two genuinely distinct findings on the same line/category both survive.

Finally the gate: severities rank info(1) < low(2) < medium(3) < high(4) < critical(5). If the worst surviving severity reaches --gate, the run exits 2. An unrecognized gate fails loudly (treated as a failure) so a misconfigured run never silently passes.

When a SQLite store is wired, each review is saved (mode, head SHA, findings, stats) and addressable by id — that id is what the MCP review_get tool fetches. The store is pure-Go (modernc.org/sqlite, no cgo). It holds review records only; credentials are never part of a record. See Credentials.