AI-powered pull request reviewer in your terminal. Review diffs, navigate findings, comment, and submit — without leaving the CLI.
Built with Go and Bubble Tea. Diffs styled by delta.
Download a binary from the latest release.
Or via Go:
go install github.com/andreujuanc/prr/cmd/prr@latestOr build from source:
git clone https://github.com/andreujuanc/prr.git
cd prr
go build -o prr ./cmd/prrOn first run, prr creates ~/.config/prr/config.json:
{
"provider": "gemini",
"api_key": "YOUR_API_KEY",
"model": "gemini-2.5-pro",
"parallel_reviews": 3,
"pipes": []
}Set your API key and you're ready to go. The pipes array is optional — see Pipe Targets for configuration.
If you already have the claude CLI installed and signed in, prr will detect it and offer Claude Opus / Sonnet / Haiku in the model picker without any API key in config.json. Auth is handled by Claude Code itself (subscription, OAuth, or ANTHROPIC_API_KEY), which is useful in environments where you can't easily set an Anthropic API key (e.g. Claude Enterprise).
The provider runs claude -p per request with a curated read-only toolset (Read, Grep, Glob, plus specific read-only git subcommands) and --permission-mode bypassPermissions, so it never edits files and never prompts for permission.
prr 42 # Review PR #42
prr # Pick from open PRs
prr --debug # Enable debug loggingprr has three modes. The interactive TUI is the primary one; the headless modes are for CI integration and scheduled audits.
Interactive TUI (prr <PR#>) — three-pane terminal UI to read diffs, navigate findings, and post review comments without leaving the CLI. See Features and Keybindings.
Headless review (prr review <PR#>) — runs the full multi-pass review pipeline against a single PR and emits a JSON report. Designed for CI: no TUI, no interaction. See Headless review.
Project audit (prr audit) — scans the entire codebase (or a recent slice) for latent issues across configurable categories. Not tied to a PR. See Project audit.
Runs the same review pipeline as the TUI's a key, but headlessly and with JSON export. Typical use: a CI step that uploads the JSON as an artifact or posts findings to a dashboard.
prr review 42 --output=review.json --bug-priors --quiet| Flag | Action |
|---|---|
--output=<path> |
Export report to JSON file |
--no-cache |
Ignore cached deep-review results |
--no-synthesis |
Skip the synthesis pass (only emit raw findings) |
--review-mode=<mode> |
full (default) reviews every file; aoi-only skips files without AOIs |
--bug-priors |
Inject recent fix-shaped commits as known-failure priors |
--quiet, -q |
Suppress terminal output (use with --output) |
--debug |
Print LLM tool calls, prompts, and responses to stderr |
The JSON output has these top-level keys: pr_number, pr_title, files_reviewed, review (the synthesised result — verdict, summary, findings, missing tests, questions for author, and a per-file coverage block), and deep_findings (raw AOI-derived findings). The full schema lives in internal/state/models.go.
Runs a full-project pass without a PR. Useful for periodic codebase health checks, onboarding audits, or measuring the impact of a refactor.
prr audit --focus=security,correctness --audit-recent=30| Flag | Action |
|---|---|
--focus=<cats> |
Comma-separated categories to focus on (default: all) |
--exclude=<globs> |
Additional exclude patterns |
--include=<globs> |
Force-include patterns (override exclusions) |
--max-reviews=<n> |
Cap on Phase 3 review calls |
--concurrency=<n> |
Per-phase parallelism cap (default 5) |
--output=<path> |
Export report (.json or .md) |
--no-cache |
Ignore cached results, re-audit everything |
--no-synthesis |
Skip Phase 4 executive summary |
--file=<path> |
Restrict audit to a single file (relative to repo root) |
--audit-recent=<n> |
Restrict audit to files touched in the last N commits |
--sibling-cluster |
Enable Phase 2.5 sibling-outlier detection (experimental) |
--bug-priors |
Inject recent fix-shaped commits as known-failure priors |
--quiet, -q |
Suppress terminal output (use with --output) |
--debug |
Print LLM tool calls, prompts, and responses to stderr |
Available categories: authentication, authorization, input-validation, data-integrity, cryptography, error-handling, concurrency, external-io, financial, configuration, api-design, resource-management, testing, test-coverage, correctness, design, performance, readability, cross-cutting, observability, web-security, malicious-code.
Cache invalidation. The deep-review and recheck cache keys hash the prompts, the runtime model, and (when --bug-priors is enabled) the bug-priors content. Prompt edits and new fix-shaped commits automatically invalidate stale entries on the next run; no manual cache flush needed.
Three-pane layout — file tree, diff viewer, and AI panel side by side.
AI-powered review — Multi-pass batch review with structured findings. The AI reads diffs, uses tools (grep, git blame, read file), and produces a prioritized list of issues with severity ratings and a recommended verdict.
Inline findings — AI review findings render as severity-colored boxes directly in the diff view, positioned below their target lines. Toggle with F. Findings are sorted by severity (critical first) and support file-level, right-side, and left-side placement.
GitHub Actions status — The file tree shows an "Actions" entry with a live status dot (green/red/yellow). Select it to see workflow runs, jobs, and steps in the diff pane. Active runs poll every 15 seconds automatically.
Publish findings — Post individual findings as GitHub line comments (c), submit all findings as a batch GitHub Review (C), or post as a general PR comment (g). Confirmation modals prevent accidental submissions.
Pipe to external tools — Send findings to external processes (linters, ticket systems, Slack bots) configured in your config file. Pipe targets receive structured JSON, markdown, or plain text via stdin.
Review workflow — Track file review status, navigate between unreviewed files, submit your review to GitHub with approve/comment/request-changes verdicts.
Inline comments — Position cursor on any diff line and press c to leave a review comment directly on the PR.
Chat — Ask follow-up questions about any file or the PR as a whole. The AI has access to the full codebase via tools.
Model switching — Press m to switch between models on the fly. Choice is persisted to config.
Smart caching — Per-file review findings are cached. Re-running a review only re-analyzes changed files. Stale reviews are detected and flagged.
Refresh from origin — Press o to pull the latest changes without restarting.
| Key | Action |
|---|---|
Tab / Shift+Tab |
Cycle panes |
Ctrl+A |
Toggle AI panel |
Ctrl+B |
Toggle file panel |
a |
AI review (file or full PR) |
A |
Force re-review (ignore cache) |
m |
Switch model |
? |
Help |
q |
Quit |
| Key | Action |
|---|---|
j / k |
Navigate files |
Enter |
Select file |
l / h |
Expand / collapse directory |
Space |
Toggle reviewed status |
r |
Hide/show reviewed files |
n / p |
Next / previous unreviewed |
o |
Refresh PR from origin |
| Key | Action |
|---|---|
j / k |
Move cursor |
G / g |
Jump to bottom / top |
Ctrl+D / Ctrl+U |
Half-page down / up |
+ / - |
More / less context lines |
Space |
Toggle reviewed status |
n / p |
Next / previous unreviewed |
c |
Comment on line |
F |
Toggle inline findings |
| Key | Action |
|---|---|
j / k |
Navigate findings |
Enter |
Jump to finding in diff |
c |
Post finding as line comment |
C |
Submit all findings as GitHub Review |
g |
Post finding as PR comment |
| |
Pipe finding to first configured target |
x |
Open action menu (all publish/pipe options) |
Tab |
Switch to Chat tab |
Ctrl+S |
Submit review to GitHub |
| Key | Action |
|---|---|
Enter |
Send message |
Ctrl+K |
Clear chat history |
Tab |
Switch to Review tab |
Add project-specific review instructions that get included in every AI review:
.prr/instructions.md # preferred
.github/prr-instructions.md # alternative
Example:
- This project uses the repository pattern; data access should go through repository interfaces
- Error handling must use wrapped errors with fmt.Errorf("context: %w", err)
- All public functions need doc commentsModel parameters are in ~/.config/prr/models.json:
{
"gemini-2.5-flash": {
"max_output_tokens": 65536,
"temperature": 0.2,
"thinking_budget": 8192
}
}Available models (switchable with m):
| Model | Thinking |
|---|---|
gemini-3.1-pro-preview |
Yes (16K budget) |
gemini-3.1-flash-lite |
Yes (8K budget) |
gemini-2.5-flash |
Yes (8K budget) |
Configure external processes to receive findings via stdin. Add a pipes array to ~/.config/prr/config.json:
{
"provider": "gemini",
"api_key": "...",
"model": "gemini-2.5-pro",
"pipes": [
{
"name": "Create JIRA ticket",
"command": "jira-create",
"args": ["--project", "BACKEND"],
"format": "json"
},
{
"name": "Notify Slack",
"command": "slack-notify",
"args": ["--channel", "#code-review"],
"format": "markdown"
}
]
}Supported formats:
json— structured payload with file, line, severity, category, title, detail, suggestion, repo_rootmarkdown— formatted heading, metadata, and detail sectionstext— compact plain text summary
Pipe targets appear in the action menu (x) and can be triggered directly with number keys (1, 2, ...) when the menu is open.
prr automatically skips files that aren't useful for code review:
- Binary files — images, fonts, archives, compiled artifacts
- Generated files — lock files,
.min.js,.pb.go,.gen.go - Large diffs — files with diffs exceeding 100KB
- Vendored code —
vendor/,node_modules/
Excluded files still appear in the file tree (dimmed with a tag) but aren't sent to the AI.
Review state is stored per-PR at .git/pr-tui/<pr_number>.json. This includes review status per file, cached AI findings, and chat history. State is local to your clone and not committed.
If prr misbehaves — hangs during a phase, returns empty findings, or crashes — the steps below collect the data needed to diagnose it.
Every run writes to ~/.cache/prr/debug.log. It captures cache misses,
batch retries, parse failures with response prefixes, AOI routing, and
any warnings emitted by the pipeline. The file is append-only across
runs, so timestamps matter.
# Last 200 lines of the most recent activity
tail -200 ~/.cache/prr/debug.logFor verbose output, pass --debug on the command line. Extra detail
from the agent loop (per-round LLM calls, tool calls, tool results)
goes to the same file.
If prr appears stuck in a phase, send SIGUSR1 to dump every
goroutine's stack to a file. The process keeps running and the file is
readable while it's open. You can dump as many times as you like —
each dump gets its own timestamp.
# In another terminal:
kill -USR1 $(pgrep -f 'prr')
# Find the latest dump:
ls -ltr ~/.cache/prr/goroutines-*.txt | tail -1The dump shows which goroutine is doing what. The ones to look at:
- A goroutine in
parseSSEStream→http2pipe.Readis actively receiving from the model. - A goroutine in
http2ClientConn.roundTripwith no body read going means we sent the request and never got a response — likely an upstream silent hang. The provider'sResponseHeaderTimeout(90s default) should turn this into a fast retry. - Multiple goroutines parked in
sync.WaitGroup.Waitare the orchestration layer waiting on those workers above.
When the AI's response can't be parsed as JSON, the log records the first 500 chars of the response so you can see what the model actually said. Look for lines like:
Warning: failed to parse batch JSON: invalid character 'm' looking for beginning of value — response prefix: "my analysis ..."
This tells you whether the model went conversational, hit a refusal, returned markdown without code fences, or something else — the fix depends on which.
~/.cache/prr/debug.log(or just the last few hundred lines around the failure).- The most recent
~/.cache/prr/goroutines-*.txtif the run hung. - The exact command you ran (
prr 42 --no-cache, etc.). - Your model selection (
gemini-2.5-pro, etc.) — visible in the first lines of debug.log.
That set is enough to reconstruct what happened without needing your repo content.
Ideas we want to build but haven't yet.
- Incremental re-review on push. When a branch that's already been reviewed gets a new commit, prr re-uses the prior run's findings: marks which ones the new commit resolved, which still stand, and only spends model time on what actually changed plus any newly introduced issues. Needs per-branch finding persistence and stable IDs that survive line shifts.
MIT