Usage
What happens on every pull request: how a review is triggered and routed, what a PURA review looks like, and how re-reviews and skips behave.
The review lifecycle
PRs from any branch are eligible. When one opens or receives a push, PURA runs a deterministic pipeline — there is no LLM in the routing hot path:
PR opened / new commit pushed
│
▼
1. Classify → hydrate the pr.* context (paths, lines,
CODEOWNERS, labels, author type) at the head SHA
│
▼
2. Route → Engine evaluates rules.yaml (CEL, no LLM) and picks
(provider, model, thinking); org-cap overlay applies
│
▼
3. Review → Reviewer Agent reads the diff, uses read_file / glob /
grep, and returns structured findings (your BYO key)
│
▼
4. Post → exactly ONE line-anchored GitHub review, as the PURA appDeterministic by design.Two runs at the same head SHA route to the same model (budget permitting). The reviewer is agentic — it's handed the diff and tools and decides what to fetch — but routing is pure CEL evaluation.
Anatomy of a review
PURA posts exactly one Pull Request Review per run. It opens with a transparency header showing what was routed and why, then carries line-anchored inline comments.
The summary header:
**pura Review** • routed to `claude-opus` (high thinking) • matched rule `payments-critical`
3 findings: 1 P1, 2 P2 • estimated cost $0.34 • 2.1s
<summary prose from the agent>Each finding is a line-anchored inline comment: severity tag, an imperative title, a short body that backticks every identifier, and an optional one-click suggestion block:
🟠 **P2 · Close popover before hiding Changes/Price pills**
Wrapping the Changes and Price pills behind `showAllFilters` introduces a
state mismatch: if `showAllFilters` is false and a user clears one of these
filters, the pill unmounts but `activeFilter` is not reset, leaving a
floating popover with no anchor pill.
```suggestion
{(filters.maxChanges !== null || showAllFilters) && (
```Suggestion blocks are conditional.A one-click fix is emitted only when it is ≤ 25 lines, a single contiguous range matching the comment's line and side, and free of embedded triple-backticks. Otherwise the comment stays prose-only.
Severity tags & the review event
| Tag | Meaning | Examples |
|---|---|---|
| 🔴 P1 — must fix | Correctness, security, breaking change | Data loss, auth bypass |
| 🟠 P2 — should fix | Robustness, missing coverage, perf | Unhandled edge case |
| 🔵 P3 — suggestion | Polish, alternative approach | Naming, minor cleanup |
The orchestrator derives the GitHub review event from the severity distribution — the agent never sets it:
- Any P1 →
REQUEST_CHANGES - Only P2 / P3 →
COMMENT - No findings →
APPROVE(the header is still posted)
Re-review on every push
A new commit re-runs the full pipeline against the new head SHA — re-classify, re-route (the budget may have shifted, so the model can differ), re-review. The prior PURA review is dismissed and superseded: the new review links back with Supersedes review #<id>.
Each re-review is a billable reviewed commit. The PR opening counts as 1, and every push that triggers a re-review counts as 1 more. A re-review happens even if the previous run ended in a manual-review-needed comment.
Drafts & skips
When the routing decision is skip, PURA posts nothing on the PR — the skip is recorded in the audit log with the matched rule name, and it is not counted as a reviewed commit.
- Drafts are skipped by default. The Translator emits a synthetic
skip-draftsrule when yourpura.mddoesn't handle drafts; you can opt drafts in. - Explicit skips come from a rule with
action: skip(e.g. skip docs-only PRs). When both a skip rule and a use rule match, the use rule wins. - Empty diffs skip the agent run entirely — no review, no comment.