Skip to content
riff logo

riff

Review the diff where you wrote it. PRs, branches, working-copy changes — with vim motions, inline comments, and no browser tab.
Terminal window
brew install candril/tap/riff # or: nix run github:candril/riff
riff # review your uncommitted changes

The README demo

riff takes a target and works out what you meant. A PR number, a revset, a URL, or nothing at all:

Terminal window
riff # uncommitted changes in the working copy
riff pr # the PR for the current branch or bookmark
riff 123 # PR #123 in this repo
riff HEAD~3 # the last three commits
riff main..feature # a branch comparison
riff @- # a jj revset
riff gh:facebook/react#1234

Local and PR mode are the same app. Every motion, every fold, every comment key works in both — PR mode just has GitHub on the other end of it.

The diff with the file tree open

j k h l, w b e, f t ; ,, 0 ^ $, gg G, Ctrl+d/Ctrl+u — the motions are the ones your fingers already know. ]c/[c steps hunks, ]f/[f files, ]u/[u the files you haven’t looked at yet. za/zo/zc fold a file or a hunk, zR/zM do the lot. Ctrl+o/Ctrl+i walk a real jumplist, so every jump is undoable.

c opens the comment panel anchored to the cursor’s line; V first if the comment is about a range. C hands the draft to $EDITOR instead. Comments land in .riff/ in your repo — they are yours until you decide to publish, so half a review survives a closed terminal.

A thread in the comments panel

]r/[r walks every thread in the diff, Enter opens the one under the cursor; ]R/[R skips the resolved ones. gC is a fuzzy picker over every comment in the PR.

Nothing reaches GitHub until you say so. gS opens the review preview — approve, request changes, or comment, with every pending comment batched into one review. gs syncs the smaller stuff: edits to comments you already posted, replies to other people’s threads, resolutions. S posts a single comment immediately when it can’t wait.

The review preview

PR overview

i toggles between the diff and the PR: description, conversation, review threads, checks, approvals, commits, files. l expands a failing check into its annotations; Enter opens the offending line in $EDITOR.

Commit-by-commit

]g/[g filters the diff down to one commit at a time and wraps back to the full diff — the way you’d read a stacked PR without checking anything out.

Viewed tracking

v marks a file viewed and jumps to the next unviewed one. In PR mode the state is GitHub’s own viewed status, so it survives the session and matches the web UI.

Flash jump

s dims the diff and searches what’s on screen as you type; every match gets a one-key label, and pressing it puts the cursor there. Search and jump in one motion.

Search that behaves

/ and ? search the rendered diff, n/N repeat, */# take the word under the cursor. Matches highlight in place; Esc clears them.

Action menu

Ctrl+p lists every action available in the current state with its shortcut — the same list the docs are generated from. Nothing has to be memorised.

Drop into your editor

gf opens the current file at the cursor’s line in $EDITOR, gF in a new tmux window with riff still running, gc checks out the PR branch first.

Links people can follow

gY copies a GitHub permalink for the selection, the line, or the file, pinned to the branch. gy copies the PR URL, y in the comments panel copies a link to that thread.

Claude Code, scoped

Chat about the selection, a file, a folder, a multi-select, or the whole diff. A comment Claude drafts shows up as a notification you copy with gd or dismiss with gD — riff never posts it for you.

Quiet background sync

New replies arrive on a poll that costs one GraphQL point per tick, skipped while the terminal is unfocused and refreshed when you come back to it.

Noise stays hidden

Lock files, generated code and snapshots are folded out of the review by default, and the pattern list is yours to redefine.

git or jj

Both are first-class. Revsets, bookmarks, @- — riff asks whichever tool the repo actually uses.

The action menu

Terminal window
brew install candril/tap/riff # or: nix run github:candril/riff
curl -fsSL https://raw.githubusercontent.com/candril/riff/main/scripts/install.sh | bash

See the installation guide for the Nix flake, the installer’s variables, requirements and first run.