Local terminal diff review for humans.
Open rv on your local changes. Approve the changes you like, and comment on the changes you have feedback on. Tell your agent to address your rv comments. Reload with r and continue until you are happy with the changes.
Linux and macOS. No Windows builds yet.
mise use -g github:Zooce/rvA specific release. Drop the leading v from the tag (2.6, or an older tag such as 2.2.0):
mise use -g github:Zooce/rv@2.6curl -fsSL https://raw.githubusercontent.com/Zooce/rv/master/install.sh | shPuts rv in ~/.local/bin. A specific release (v2.6, or an older tag such as v2.2.0):
curl -fsSL https://raw.githubusercontent.com/Zooce/rv/master/install.sh | RV_VERSION=v2.6 shIf ~/.local/bin is not on PATH:
export PATH="$HOME/.local/bin:$PATH"Install the agent skill after either method above:
npx skills add Zooce/rv -gZig 0.17.0.
zig build -Doptimize=ReleaseSafe --prefix ~/.local
npx skills add Zooce/rv -grv --version prints major.minor (zon 2.6.0 prints rv 2.6).
Load, paint, present, and approve timings: mise run bench. Compare a run to bench/baseline.json with --compare. How timings are taken, and how to attach samply or perf, is in bench/README.md.
Changed words are colored on the line. Unchanged words on that line stay grey. A whole line that was added or deleted stays green or red.
t shows the same review as a unified diff.
i opens the comment box under the diff. The box grows as the comment wraps.
Space then c lists open comments. Enter jumps to that comment.
Space then a lists approved hunks. Approving stages a hunk and hides it from the diff. Enter puts that hunk back on the diff and leaves it staged.
/ searches the diff. Enter jumps to the match.
Space then f lists the files in this review.
Space then p switches among saved work trees.
rv # local changes (staged, unstaged, untracked)j and k move the current line. gg and ge jump to the first and last row. A click jumps to that line. The scroll wheel moves the window and leaves that line selected. h and l, Shift+wheel, or a sideways trackpad scroll, pan the hunk. e grows the hunk's context.
a approves the hunk at that line and A approves the whole file. Approving stages the change and hides it from the diff. gs, gu, and gd stage, unstage, and discard the hunk. gS, gU, and gD do the same for the file.
i, c, or Enter comments on the new side of the current line. I and C comment on the old side. d and D dismiss that comment. / searches the diff, and n and N move through the matches.
Space then f lists files, c lists open comments, a lists approved hunks, and rv starts from any directory and restores that list. rv path opens that work tree and adds it to the list. Tab in the add prompt cycles matching directories. Type / and Tab again to go into the one on the line.
Press ? for every key, and q to quit.
Tell your agent to address your rv comments. The skill from the install step reads those comments, edits the code, and resolves each comment it has handled. What you approved stays staged and stays out of the next diff.
r reloads the diff and the comments. Continue until you are happy with the changes.
rv HEAD # one commit
rv main...HEAD # a range
rv ~/src/other # open that work tree and remember itrv status # comment count, approved count, and store paths
rv list # open comments
rv show <id> # one comment
rv export # those comments as markdown on stdout
rv export --format json -o review.json
rv resolve <id> [id…]
rv approved # hidden hunks and files
rv unapprove <n>rv keeps your approvals and your comments. Your agent changes the code.
Display defaults are read once, before the first paint.
The user file is $XDG_CONFIG_HOME/rv/config. When XDG_CONFIG_HOME is unset or empty, it is ~/.config/rv/config. The same directory holds projects: one absolute path per line, in the order projects were added, plus an optional current line for the last live project. The repo file is .rv/config, in the same directory as comments and approvals. A key in the repo file overrides that key in the user file. A missing file leaves the compiled default in place: side-by-side, line numbers on, wrap off.
layout = uni
line_numbers = false
wrap = true
layout is side-by-side, sbs, unified, or uni. line_numbers and wrap are true or false. An invalid file prints its path and the reason, and rv does not start.
t, #, and w change layout, line numbers, and wrap for this session. They do not write either file. The next rv reads the files again.
rv list, rv export, and the other headless commands do not read these files.
Pushing a git tag v<major>.<minor> (zon 2.3.0 is tag v2.3) publishes a GitHub Release with Linux and macOS tarballs (x86_64 and aarch64) and SHA256 checksums. The Linux binaries are musl builds. The release name is the tag. The tag message is the release notes.
mise use github:Zooce/rv installs those tarballs: rv-linux-x86_64.tar.gz, rv-linux-aarch64.tar.gz, rv-macos-x86_64.tar.gz, and rv-macos-aarch64.tar.gz. Each archive contains bin/rv.
- Bump
.versioninbuild.zig.zontomajor.minor.0(for example2.3.0). - Commit that change.
- Tag
v<major>.<minor>:git tag -a v2.3 - Push the tag:
git push origin v2.3
The release action checks that the tag matches build.zig.zon and rv --version, then publishes the Release.
MIT. See LICENSE.