FAQ

Does it block merges?#

No. It posts comments. The CLI exits non-zero only on an actual error — a bad config, a git failure, a cost ceiling — not because it found something. If you want findings to block a merge, gate on the JSON output in a step of your own.

Will it work on a monorepo?#

Yes, and the design assumes it. Review cost scales with the files a pull request changes, not with how large the repository is. The caller search walks the tree, which is where repository size shows up, and it skips vendor directories and anything over 2 MB.

What happens on a 200-file pull request?#

Stage 4 makes one call per changed file, so that is 200 review calls plus one skeptic call per surviving candidate. That is exactly the situation max_cost_per_run exists for. The reason it is not one giant call: a single pass over a huge diff reports a few obvious things and stops looking, so the fiftieth file would get no real attention.

Does it re-comment on every push?#

No. Every finding gets a fingerprint built from the file, the surrounding code and the category — deliberately not the model's wording, so rephrasing the same finding does not make it look new. Fingerprints already posted are carried in the summary comment and passed back on the next run.

What happens if I push twice quickly?#

There is no queue, so both pushes can trigger a review that runs at the same time. Each one reads the pull request's summary comment for the fingerprints already posted, adds its own, and writes the result back — and if both reads happen before either write, the second write can overwrite the first one's additions. The cost is narrow: a finding that is still present can get re-posted once on a later push, never a finding that no longer applies. The sample workflow sets GitHub's concurrency so a second push cancels the review still running for the same pull request rather than racing it; GitLab's equivalent is interruptible: true plus the project's auto-cancel setting. Bitbucket Pipelines has no equivalent primitive, so the fingerprint marker is the only protection there.

Does it ever post a finding without asking a second model?#

Yes, for one kind. When a Python function's signature changes and a caller can no longer satisfy it, the parser proves that from the two syntax trees, and the finding is posted with the evidence attached and no skeptic call. It still has to pass the free checks: the quote must exist, the line must be changed, and it must not repeat an earlier comment. Anything a model proposes still goes through the second model. --no-proofs turns the parser's findings off. See what it proves, and what it declines to say.

Can I run it with no API cost at all?#

Yes. Set model: ollama/<model> and every call goes to a local endpoint. No key, no spend, and no code leaves the machine. Review quality then depends on the local model you run.

Does it store my code anywhere?#

No. There is no database, no cache and no service operated by this project. See what gets sent to the model for exactly what leaves the repository and where it goes.

How is this different from a linter?#

A linter matches patterns it was taught in advance, which is why it is fast and deterministic and why it cannot notice that a function's new required argument broke a caller three files away. Groundtruth is built for that second kind of finding. They are complements — run both.

Why no vector database?#

Because retrieval guesses. Similarity search returns code that looks related, and a wrong snippet produces a confident, wrong finding — the exact failure this tool is built to avoid. Parsing the actual function and searching for actual callers is exact, repeatable and free.

Is it deterministic?#

The context is: the same diff assembles the same context every time. The model calls are not, which is the reason the verification stages are ordinary code rather than more model calls. The quote check, the location check, the fingerprint and the ranking give the same answer on every run.

Which model should I use?#

Start with one strong model everywhere, then split the tiers once you see the bill: a strong model on stage 4 where the reasoning happens, a cheap one on stages 5 and 6. A finding that was never proposed cannot be recovered downstream, while a finding that was proposed still has to get past the gate.

Should the verifier be a different model from the reviewer?#

If you can, yes — ideally from a different provider. Review with Claude and verify with GPT, or the reverse. The verifier's whole job is to doubt the first model, and a model is a poor judge of mistakes it would make itself. Nothing in the code prefers one arrangement; each stage takes its own model string. See verify with a different provider, and note that it needs both providers' keys.

How mature is this?#

Honestly: alpha. The pipeline, the CLI, the eval harness and three platform adapters are implemented and covered by 370 tests that run offline against fake model clients, plus labeled cases replayed on every build. What that does not prove is behaviour against a live model on your codebase at scale — no test can. Start it on one repository, read what it posts, and tune min_confidence before you turn it on everywhere.

What is still missing?#

Publication to PyPI, so installing stops meaning a git URL; and a self-hosted server mode for Bitbucket Data Center, which is the one platform with no free per-pull-request CI container. The scoped design for the second is in docs/server-mode-design.md. Letting feedback tune the reviewer automatically is also not built, on purpose.