Reviews
A review is one run of the Anvil agent over a pull request. This page covers when reviews run, what they look at and what they post.
When a review runs #
A review is queued when a pull request is opened, reopened, pushed to or marked ready for review. Anvil waits 15 seconds before starting, and a newer push replaces a review that's still waiting, so a burst of pushes produces one review of the latest commit. A push while a review is already running stops that review (its commit gets a "Review cancelled: superseded by a newer push" status) and the new commit is reviewed next.
Closing a pull request cancels its review: a running agent is stopped, a waiting review is dropped, and the commit status becomes a warning, "Review cancelled: the pull request was closed".
A queued review is skipped when:
enabled: falseorauto_review.enabled: falseis set in.anvil.yaml;- the PR is a draft, or its title starts with
WIP,[WIP]orDraft:(unlessauto_review.drafts: true); - the title contains one of
auto_review.ignore_title_keywords("wip" and "do not review" by default); - the author is in
auto_review.ignore_authors; - the base branch doesn't match
auto_review.base_branches(when set); - reviews are paused on the PR with
@anvil pause; - the head commit was already reviewed.
@anvil review and @anvil full review always run, regardless of these rules.
What gets reviewed #
Anvil works on a fresh clone of the repository with the PR checked out. It gets the diff, the commit messages, the PR title and description, your .anvil.yaml instructions, the repository's guideline files, the issues the PR closes, any learnings for the repository, and the CI results recorded so far for the head commit. It then reads whatever else it needs with read-only tools (read a file, search, list files), so it can check callers, types and tests outside the diff.
Some files are never reviewed: lock files (pnpm-lock.yaml, package-lock.json, yarn.lock, bun.lock, Cargo.lock, poetry.lock, uv.lock, go.sum), minified files and source maps, build output (dist/, build/, .next/), node_modules/, vendor/ and snapshot files. Add your own with path_filters. The walkthrough footer says how many files were filtered.
Very large diffs are truncated before they reach the model; Anvil is told which files were cut and can still open them.
Guideline files #
Anvil loads the instruction files coding agents and editors read, so a review holds the change to the same house rules:
AGENTS.md,CLAUDE.mdand.cursorrules, in every directory that contains a changed file and in each of its parents up to the root;.github/copilot-instructions.mdat the root.
They're read from the base branch, like .anvil.yaml, so a PR can't add a guideline that relaxes its own review. The nearest directory comes first. Each file is cut at 8,000 characters and all of them together at 24,000. The walkthrough's Review details lists the files used. Turn this off with reviews.guideline_files: false.
Linked issues #
When the PR description says Closes #12, Fixes #12 or Resolves #12 (also closed, fixes, resolved and the other forms, lists such as Closes #12, #13 and #14, and owner/repo#12 for another repository on the same host), Anvil fetches up to five of those issues and judges whether the PR does what each one asks. The walkthrough gets a Linked issues table with ✅ met, 🟡 partly or ❌ not met and a sentence on what's missing. References inside code blocks and quotes are ignored. On GitHub, an issue in another repository is read only if Anvil's app is installed there.
Full and incremental reviews #
The first review of a pull request is a full review of everything between the base branch and the head.
After that, each push gets an incremental review: only the commits since the last reviewed commit. Anvil is shown its own open comments so it doesn't repeat them, and the rest of the PR's files are listed for context. The review body then says "No new issues in the latest commits." when there's nothing new.
A full review happens instead when:
- the branch was force-pushed or rebased, so the last reviewed commit is no longer in its history;
auto_review.incremental: falseis set;- you comment
@anvil full review.
Findings #
Each finding has a severity and a category.
| Severity | Meaning |
|---|---|
critical |
Will break something or open a security hole. Fix before merging. |
major |
A real bug or risk in a likely path. |
minor |
Worth fixing, low risk. |
nit |
Style or polish. |
Categories: bug, security, performance, data-loss, concurrency, api-contract, error-handling, maintainability, tests, docs, style.
Findings are posted as one pull request review with an inline comment per finding, critical first. Each comment has the explanation, an optional suggested change shown as a diff, and a collapsed "Prompt for AI agents" you can paste into a coding agent. The review is a plain comment; set request_changes_on_critical: true to make it Request changes when there's a critical finding.
If the code host rejects an inline comment (for example, a line that moved), all findings go into the walkthrough instead, so nothing is lost.
Profiles #
profile sets how picky Anvil is.
chill(default): bugs, security problems and real risks. Nits are dropped.assertive: also maintainability, naming, missing tests, docs and nits.
With assertive, nits are collected in one collapsed Nitpicks section of the walkthrough instead of inline comments, so they don't crowd the diff. reviews.nitpicks: inline posts them inline; off drops them.
Merge and security risk #
Every review rates two risks on five levels, each with a one- to three-sentence explanation:
| Level | Merge risk | Security risk |
|---|---|---|
| trivial | Docs, comments, tests only, or an obviously safe one-liner | No security-relevant surface |
| low | Small, contained, well covered | Touches input handling or permissions in a contained, safe way |
| moderate | Shared code or user-visible behaviour; a mistake would be noticed and fixed quickly | Changes auth, permissions, secrets, validation or external calls; needs a careful look |
| high | Data model, migrations, money, auth, concurrency or wide refactors; costly or hard to undo | A plausible path to unauthorised access, injection, data exposure or leaked secrets |
| critical | Will very likely break production or lose data as written | An exploitable vulnerability in the diff |
Add your own rules with merge_risk_instructions and security_risk_instructions. Reviews from before the five levels showed one risk (low, medium, high); they're shown as low, moderate and high merge risk.
Replies in review threads #
Reply to one of Anvil's inline comments and Anvil answers in the same thread, without @anvil: it agrees when you explain why the comment doesn't apply, shows the fix when you ask for one, and saves lasting rules as learnings. It stays out of replies that start with someone else's @mention, never answers its own comments, and stops after five replies in one thread. Turn it off with chat.auto_reply: false.
Budgets and limits #
Every agent run has a cost cap. On this server the ceiling is $3 per run; max_budget_usd in .anvil.yaml can lower it but not raise it. Questions in PR comments and the Ask panel are capped at $1. A run also stops after 80 turns or 20 minutes.
Each review is routed by size and risk: docs, formatting and bot PRs get a light review on a small model (capped at $0.50 and 8 turns), small low-risk diffs a standard one, and large or risky changes (migrations, auth, CI config and the like) the strongest model. See Model routing.
Each account also has a monthly budget for the repositories it owns ($25 unless an admin changes it). Reviews, questions, thread replies, CI diagnoses and code-changing agents all count. Once it's used up, Anvil skips new runs until the 1st: a review says so in the walkthrough, a question gets a reply saying so, and a CI diagnosis is skipped. Settings → Repositories shows this month's spend against the budget, per repository and per review tier.
When a run fails or times out it's retried; if it still fails, the walkthrough says so, the Anvil status ends as a warning ("Review failed: …", or failure with reviews.fail_commit_status: true), and @anvil review tries again. A review never leaves the status pending: any error on the last attempt sets a final status. Cost, tokens and duration of every run are shown on Agent runs in the dashboard and in the walkthrough footer.
The walkthrough comment #
Each PR has one walkthrough comment, created on the first review and edited in place after that. It contains:
- Summary of the change;
- the change stack as a table: each layer, what it does, the files, and which layers it builds on, plus a link to the workspace;
- a sequence diagram (Mermaid, rendered in the pull request), unless
walkthrough.sequence_diagram: false; - Review effort (1 to 5, from about 5 minutes to 2 hours or more) unless
walkthrough.estimate_effort: false, the merge risk and security risk with their explanations, and the finding counts; - Linked issues: whether the PR does what each issue it closes asks;
- Pre-merge checks with pass, fail or inconclusive per check;
- Comments outside the diff: findings about lines the PR didn't change;
- Nitpicks, collapsed, when
reviews.nitpicksisfolded; - Review details, collapsed: the config file and the branch it was read from, the guideline files used, the files skipped by path filters and the commits reviewed;
- a warning if
.anvil.yamlhad errors and was ignored; - a footer with the reviewed range, full or incremental, the number of inline comments, the model with its routing tier and the reason for it, the cost, the duration and the commands.
Anvil commit status #
Each review sets a commit status named Anvil on the head commit:
| State | When |
|---|---|
| pending | "Reviewing…" while the review runs |
| success | Review done. The description gives the finding count, e.g. "3 findings (1 critical)", or "No issues found" |
| failure | A pre-merge check in error mode failed, or the review failed with reviews.fail_commit_status: true |
| warning | The review failed ("Review failed: …"), or was cancelled because the PR closed or a newer push superseded it. Doesn't block merging. On GitHub, which has no warning state, this shows as success |
Findings alone never fail the status. To block merges on Anvil, use pre-merge checks in error mode and make anvil a required status in the branch protection rules. Setting statuses needs the bot to have Write access (see Connect a repository).