by umputun
TUI for reviewing diffs, files, and documents with inline annotations
# Add to your Claude Code skills
git clone https://github.com/umputun/revdiffLast scanned: 5/19/2026
{
"issues": [],
"status": "PASSED",
"scannedAt": "2026-05-19T07:45:32.976Z",
"semgrepRan": false,
"npmAuditRan": true,
"pipAuditRan": true
}TUI for reviewing diffs, files, and documents with inline annotations. Outputs structured annotations to stdout on quit, making it easy to pipe results into AI agents, scripts, or other tools.
Built for a specific use case: reviewing code changes, plans, and documents without leaving a terminal-based AI coding session (e.g., Claude Code). Just enough UI to navigate diffs and files, annotate specific lines, and return the results to the calling process - no more, no less.
--word-diff or toggle with Wv↪ continuation markers, toggle with w; optional --wrap-indent N for hanging-indent continuations (handy for markdown lists)« / » markers at the edges to signal hidden content off-screen┃ segment on pane right borders indicates the visible portion of long diffs, file trees, and markdown TOCs; thumb size and position track scroll progress automaticallyLNo comments yet. Be the first to share your thoughts!
HEAD@-HEAD~N@--all-filesB/ search within diff with n/N match navigation@): browse all annotations across files, jump to any annotation?) showing all keybindings organized by sectioni) showing launch scope (mode, VCS, ref, filters, file/status counts, aggregate +/- line stats), the optional --description prose, and the commit log subject + body for every commit in the current ref range (git/hg/jj) — useful for restoring narrative context when reviewing PR-style diffs--all-files (git ls-files or jj file list), filter with --include and --exclude--only files outside a VCS repo (or not in any diff) are shown as context-only with full annotation support--stdin, optionally naming it with --stdin-name~/.config/revdiff/history/ on quit as a safety net--dump-keys
git, hg, or jj (used to generate diffs; optional when using --only or --stdin)Homebrew (macOS/Linux):
brew install umputun/apps/revdiff
Arch Linux (AUR):
paru -S revdiff
Debian/Ubuntu (.deb):
# download the latest .deb for your architecture from GitHub Releases
sudo dpkg -i revdiff_*.deb
RPM-based (Fedora, RHEL, etc.):
# download the latest .rpm for your architecture from GitHub Releases
sudo rpm -i revdiff_*.rpm
Binary releases: download from GitHub Releases (deb, rpm, archives for linux/darwin amd64/arm64).
revdiff ships with a Claude Code plugin for interactive code review directly from a Claude session. The plugin launches revdiff as a terminal overlay, captures annotations, and feeds them back to Claude for processing.
The plugin requires one of the following terminals since Claude Code itself cannot display interactive TUI applications - the overlay runs revdiff in a separate terminal layer on top of the current session:
| Terminal | Overlay method | Detection |
|----------|---------------|-----------|
| tmux | display-popup (blocks until quit) | $TMUX env var |
| Zellij | zellij run --floating | $ZELLIJ env var |
| kitty | kitty @ launch --type=overlay | $KITTY_LISTEN_ON env var |
| wezterm | wezterm cli split-pane | $WEZTERM_PANE env var |
| Kaku | kaku cli split-pane (same API as wezterm) | $WEZTERM_PANE env var |
| cmux | cmux new-split + cmux send | $CMUX_SURFACE_ID env var |
| ghostty | AppleScript split + zoom (macOS only) | $TERM_PROGRAM + AppleScript probe |
| iTerm2 | osascript split pane (macOS only) | $ITERM_SESSION_ID env var |
| Emacs vterm | New frame via emacsclient | $INSIDE_EMACS env var |
Priority: tmux → Zellij → kitty → wezterm/Kaku → cmux → ghostty → iTerm2 → Emacs vterm (first detected wins). If none are available, the plugin exits with an error.
Note: cmux is detected before ghostty because cmux also sets
$TERM_PROGRAM=ghostty. The cmux block uses the cmux CLI (new-split+send --surface) instead of Ghostty's AppleScript API.
Note: iTerm2 uses a split pane (vertical or horizontal, auto-detected from terminal dimensions) rather than a full-screen overlay. The iTerm2 AppleScript API does not expose a zoom command, so the split view shares screen space with the invoking session.
Note: Ghostty and iTerm2 launchers use
osascript(Apple Events), which is blocked by Claude Code's sandbox. If you use these terminals with sandbox enabled, add the launcher toexcludedCommandsin your Claude Codesettings.json:{ "sandbox": { "excludedCommands": ["*/launch-revdiff.sh*"] } }Terminals that use CLI tools instead of AppleScript (tmux, Zellij, kitty, wezterm, cmux) are not affected.
Install:
# add marketplace and install
/plugin marketplace add umputun/revdiff
/plugin install revdiff@revdiff
Use with /revdiff command:
/revdiff -- smart detection: uncommitted, last commit, or branch diff
/revdiff HEAD~1 -- review last commit
/revdiff main -- review current branch against main
/revdiff --staged -- review staged changes only
/revdiff HEAD~3 -- review last 3 commits
Use with free text (no slash command needed):
"review diff" -- smart detection, same as /revdiff
"review diff HEAD~1" -- last commit
"review diff against main" -- branch diff
"review changes from last 2 days" -- Claude resolves the ref automatically
"revdiff for staged changes" -- staged only
When no ref is provided, the plugin auto-detects the VCS (git, hg, or jj) and inspects the current repo state to pick what to review:
The plugin includes built-in reference documentation and can answer questions about revdiff usage, available themes, keybindings, and configuration options. It can also create or modify the local config file (~/.config/revdiff/config) on request:
"what chroma themes does revdiff support?"
"switch revdiff to dracula theme"
"what are the revdiff keybindings?"
"set tree width to 3 in revdiff config"
The plugin supports the full review loop: annotate → plan → fix → re-review until no more annotations remain. The bundled launcher treats exit code 10 as success-with-annotations and processes stdout normally.
Custom launchers: both Claude plugins resolve their launcher script through a two-layer chain (user → bundled), so you can drop a custom launcher at ${CLAUDE_PLUGIN_DATA}/scripts/launch-revdiff.sh without forking the plugin. There is no project-level (.claude/...) override layer by design — the planning hook fires automatically on every ExitPlanMode, and a repo-controlled executable layer would let an untrusted repo run arbitrary code on routine Claude actions. See `.claude-plugin/