dv
A terminal diff viewer for reading and reviewing pull requests, with Helix keys, rust-analyzer, and GitHub review comments.
- Diff: unified or side-by-side (
Ctrl-w v), with review comments in the right margin on wide windows (Ctrl-w cputs them inline), syntax highlighted, changed words emphasised, context expandable per hunk (+/-,Zfor the whole file). - Helix-style: the cursor/selection model, motions (
w b e,f t,gw,mm, …), and your Helix theme,cursorline,line-number, andjump-label-alphabet. - rust-analyzer:
gd/gr/gy/giand hover (Space k) from the diff. - GitHub: the PR's description, conversation, checks and review threads inline, rendered like github.com. Comment on selected lines, suggest changes, reply, edit, delete, resolve, mark files viewed, and submit reviews.
Install
Or download a binary for Linux or macOS from the
releases, or build from a checkout with
cargo install --path ..
Needs git. For PRs: gh, logged in (gh auth login).
Optional: rust-analyzer (go to definition, references, hover), hx (opening files and
writing comments; $VISUAL/$EDITOR is used for comments if set), xdg-open/open
(opening links). Inside zellij, hx, editors and Claude Code open in a pane to
the right, and dv keeps working while hx is open.
Usage
# Tab lists the PRs you have worktrees for (D D removes one);
# m marks PRs and a a has Claude review them in the background;
# filter by #N to open a PR that isn't listed
On a branch with an open PR, plain dv loads it too.
The mouse works too: scroll, click to move, drag to select (dv --no-mouse leaves it to your
terminal; most select text with Shift held either way). Press ? in dv for every key (/ searches the list). SPEC.md has the full key
table and design notes.
Reviewing a PR
dv 2258(ordv 2258 -wto keep your checkout as it is).- Read:
]g/[ghop between hunks,]f/[fbetween files,Space fpicks a file,Space tlists the threads.Space vmarks a file viewed and moves on. - Comment: select lines (
x,v), thencto comment orsto suggest a change. On a thread,rreplies (quoting the comment under the cursor). These go into your pending review;Space plists them. - Submit:
S, then Comment / Approve / Request changes.
C posts a comment immediately instead of adding it to the review. Space e / Space d
edit / delete a comment, Space r resolves a thread, gf opens a link, R refreshes.
Reviewing with Claude Code
Claude Code writes a review, and dv shows it inline next to the lines it's about. You reply to Claude from dv, Claude answers (or changes the code), and you copy the comments you agree with into your GitHub review. The two talk through a review file that dv reloads whenever it changes, so you can keep dv open while Claude works.
Setup (once): dv install-skill installs the dv-review skill to
~/.claude/skills/dv-review/. Restart any running Claude Code session so it picks it up.
-
Get the PR:
dv 2258 -w(ordv list -w, then Enter). -
Ask for a review: press
Space ain dv and pick "Ask Claude to review this".$EDITORopens for anything it should focus on; leave it empty to just go. (Or, in Claude Code in that checkout, ask it to "review this PR for dv".) Inside zellij, Claude Code opens in a pane on the right, where you can watch it and approve what it asks to do; if that PR's Claude pane is already open, dv asks there instead of opening another; elsewhere it runs in the background, allowed to edit files and run only thedv review-*and read-onlygitcommands it needs, and the status bar says when it's done. It runsdv review-info(the review file's path, and the base commit:git diff <base>is the diff dv shows), writes its review, and runsdv review-check, which checks every line reference against the diff and records the commented code. -
Read it in dv: Claude's summary sits in the top section; its comments are threads by claude under their lines (
]c/[cto step through them,Space Alists them), tagged with how much each matters ([bug],[nit], …).[waiting]marks a thread where you spoke last (Claude's turn),[answered]one where Claude has answered you (yours); type either inSpace Ato list just those.[new]marks a thread with comments you haven't seen yet (Claude's or anyone's on GitHub; seen once your cursor has been on it):]n/[nstep through those,Space nlists them. -
Act on each comment:
Key ccopy it into your pending GitHub review (edit it in $EDITOR, or keep it as is)Csame, but post it now rreply to Claude: it answers right away, in the background (nothing goes to GitHub) Space rresolve it, so Claude leaves it alone Space ddismiss it To ask Claude something yourself, select lines and press
a: your comment goes into the review file and Claude answers it like a reply.A comment copied to GitHub is removed from the review file, so it doesn't show twice.
-
Claude answers: as soon as you reply, Claude Code answers in the background, resuming the same session each time so it keeps the review in mind; its answer shows up under your reply ("Claude is answering…" meanwhile). Replies you write while it's busy are answered in one more run. (
Space a→ "answer your replies", or asking Claude Code to "answer my dv replies", does the same by hand.) For each unresolved comment where you spoke last, it replies, or makes the change you asked for, says what it changed and resolves the thread. Its answers appear in dv as it writes them. Repeat 4–5 as needed. -
Have Claude make the changes (optional):
Space a, "Ask Claude to make the changes". You can add your own instructions in$EDITORfirst (leave it empty to just go; with no open comments, they're the request: "Ask Claude to make a change"). Claude makes the change each open comment asks for, its own and the ones you left it (not the resolved, dismissed or outdated ones), replying on each with what it changed and resolving it. Resolved threads fold: unfold one (Tab) to check the change, andSpace rreopens it if it isn't right. On someone else's PR this is "suggest the changes": Claude doesn't touch the code, it puts GitHub suggestion blocks in its comments for you to post withc.Then
Space g: "Show only what isn't committed" to check just Claude's changes, "Commit" (the message starts from what Claude said it changed), and "Push" to the PR's branch. After a push, "Update Claude's review" looks at just what's new. -
Submit:
Ssubmits your pending review, holding whatever you queued withc. Claude never posts to GitHub; only you do, from dv.
When the code changes (Claude's edits, yours in hx, a new push), Claude's comments follow
their code: one whose lines moved moves with them; one whose code changed or is gone shows
[outdated], folded and dimmed near its old line, and can't be copied to GitHub. Claude
re-anchors outdated comments that still apply when it next runs dv review-check. After new
commits on top of the one Claude reviewed, "Update Claude's review" asks it to review just
those. New files show in the diff before they're committed (marked untracked).
Good to know
- The review file is
~/.local/share/dv/<repo>/reviews/pr-<N>.json(branch-<name>.jsonwithout a PR;$XDG_DATA_HOMEif set): outside the repo, so never committed, and shared by its worktrees. (Not in.git: Claude Code won't edit files there.) A new review replaces it (the skill keeps comments that still apply, with your replies). - It works on a local branch before there's a PR, but
c/Cneed one. - Like dv's own comments,
c/Cneed the checkout at the PR head with no local changes. While Claude's changes are uncommitted you can reply and resolve, but copy comments to GitHub only once they're pushed.
Layout
| File | |
|---|---|
src/main.rs |
arguments, PR checkout, worktrees |
src/diff.rs |
git diff parsing, hunks, word diffs |
src/list.rs |
dv list: the open-PR picker |
src/claude.rs |
Claude review files: format, checks, replies |
skills/dv-review/ |
the Claude Code skill (dv install-skill) |
src/gh.rs |
GitHub via gh: PR info, threads, review mutations |
src/lsp.rs |
a minimal rust-analyzer client |
src/highlight.rs |
syntect highlighting mapped to Helix scopes |
src/md.rs |
GitHub-flavoured markdown rendering |
src/theme.rs |
Helix theme and settings |
src/view/ |
the TUI: state (mod.rs), keys, motions, rendering, review actions, rust-analyzer |
cargo test runs the tests.
License
MIT or Apache-2.0, at your option (LICENSE-MIT, LICENSE-APACHE). Releasing: RELEASING.md; changes: CHANGELOG.md.