1 unstable release
| 0.1.3 | May 20, 2026 |
|---|
#208 in Development tools
750KB
17K
SLoC
ggr
Review GitHub pull requests commit-by-commit in your terminal.
A PR is a stack of commits. ggr treats it that way: open a PR by number or
URL, walk each commit's diff oldest-to-newest, draft inline comments locally,
then submit everything as a single GitHub review. No browser required.
ggr is part of the
local-review workspace alongside
jjr (pre-push stack review). Both share the same TUI, comment model, and
anchoring engine. The difference is the source of truth (gh instead of jj)
and the submission target (GitHub PR review API instead of Claude).
Install
brew install ericbmerritt/jjr/ggr
cargo install ggr will work once the crate is published to crates.io; the
binary is not on crates.io yet. To install from source meanwhile:
cargo install --path crates/ggr --locked
Requires gh authenticated to GitHub (or GitHub
Enterprise Server).
Usage
# Auto-detect repo from the current directory's git remote
ggr 42
# Explicit repo — works from any directory
ggr acme/myrepo#2429
# GitHub Enterprise Server
ggr --url https://github.example.com acme/myrepo#2429
# Paste a full pull URL from the browser
ggr https://github.com/owner/repo/pull/2429
Review workflow
-
Open a PR.
ggr 42fetches the PR, re-anchors any drafts from your last session, and opens the description page. Existing GitHub review threads render inline below their anchor lines. -
Walk the commits.
n/pmove between commits (oldest first) and the description page.Tab/Shift-Tabjump between files.fopens the file picker. -
Draft comments. With the cursor on a diff line:
corEnter— line-scoped commentm— commit-scoped comment (goes in the review body as an attribution block)P— PR-scoped comment (goes in the review body verbatim)r— reply to an existing GitHub review thread (cursor must be on a thread)e— edit a draft you wrote earlier- In the composer,
Ctrl-Xsaves,Ctrl-Ddeletes,Esccancels. - Severity:
M-rrequired ·M-ssuggestion ·M-nnote (default)
-
Submit.
Sopens a verdict modal:a— Approver— Request changescorEnter— Comment (requires at least one non-stale draft or reply)Esc— Cancel
On submit,
ggrposts onePOST /reviewscall covering all inline comments, then fans out reply calls serially. Stale drafts are excluded. On full success all drafts are cleared; on partial failure (a reply failed) the posted drafts are cleared and the remaining stay on disk for retry. -
Re-review after force-push. Press
Rto re-fetch the current PR state and re-anchor your drafts. Drafts whose commit SHA is gone from the PR are re-anchored via commit-subject matching; if no unique successor exists they go stale. The stale panel lists them with reasons;ddeletes a stale draft,Escdismisses.
CLI subcommands
# List all local drafts for a PR
ggr drafts 42
ggr drafts acme/repo#42
# Clear all local drafts (use --stale to clear only stale ones)
ggr clear 42
ggr clear 42 --stale
Keybindings
Main view
| Key | Action |
|---|---|
↑ ↓ / j k |
Scroll line |
PgUp PgDn |
Scroll page |
Home g / End G |
Top / bottom |
Tab / Shift-Tab |
Next / previous file |
n / p |
Next / previous commit (or description) |
c / Enter |
New line-scoped comment |
m |
New commit-scoped comment |
P |
New PR-scoped comment |
r |
Reply to thread on current line |
e |
Edit draft on current line |
T |
Toggle thread expand/collapse |
S |
Submit (opens verdict modal) |
R |
Refresh — re-fetch PR state and re-anchor drafts |
f |
File picker |
| |
Cycle diff layout (auto / unified / side-by-side) |
? |
Help |
q |
Quit |
Composer (when writing a comment)
| Key | Action |
|---|---|
M-l |
Scope: line (default when on a diff line) |
M-c |
Scope: change / commit |
M-k |
Scope: PR (same as P from main view) |
M-r |
Severity: required |
M-s |
Severity: suggestion |
M-n |
Severity: note (default) |
Ctrl-X |
Save |
Ctrl-D |
Delete (when editing an existing draft) |
Esc |
Cancel |
Comment scopes and severity
Scopes:
- Line — anchored to a specific line in a specific file in a specific commit. Renders inline below the anchor line.
- Commit — anchored to a whole commit. Folded into the review body as a
quoted attribution block:
> Commit abc1234 — "commit title". - PR — anchored to the whole PR. Rendered verbatim in the review body.
Severity becomes the first line of the submitted comment body, matching
jjr's format for cross-tool consistency:
[REQUIRED]— must be addressed[SUGGESTION]— should be addressed when safe[NOTE]— informational
Draft storage
Drafts live in ~/.local/share/ggr/<host>/<owner>/<repo>/<pr>/ and are never
shared or committed. Nothing reaches GitHub until you press S.
License
MIT OR Apache-2.0
Dependencies
~14–22MB
~428K SLoC