turboreview is a terminal code-review tool for git repositories. Review the
working tree or browse the branch's commit history, with a file tree on the left
and the selected diff (syntax-highlighted, adjustable context) on the right.
Stage files, mark them reviewed, leave line comments — and let an AI coding agent
read those comments, fix the code, and respond. It can also debug straight
from the diff (breakpoints, stepping, variable inspection, even debugging a past
commit) and overlay test coverage.
Prerequisites:
- A recent stable Rust toolchain (
cargo) andgit. Install Rust via rustup:curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh. - A C compiler / build toolchain —
git2(libgit2) andlibzare built from source. macOS: Xcode Command Line Tools (xcode-select --install). Linux:build-essentialandpkg-config. - Linux only: X11 clipboard libraries for copy support (
arboard), e.g. on Debian/Ubuntu:libxcb1-dev libxcb-render0-dev libxcb-shape0-dev libxcb-xfixes0-dev. - A Nerd Font set in your terminal for the file-type glyphs.
- Optional: the pi coding agent,
only for the Pi chat popup (
P). Everything else works without it. See Pi chat.
cargo install turboreviewThe turboreview binary lands in ~/.cargo/bin — make sure that's on your
PATH.
git clone https://github.com/nmbr7/turboreview.git
cd turboreview
cargo install --path . # installs the release binary to ~/.cargo/bincargo run -- [REPO_PATH] # run against a repo (defaults to .)
cargo test # run the test suite
cargo fmt && cargo clippy # format + lintUpdating later: re-run cargo install turboreview (add --force to overwrite
an older build).
turboreview [REPO_PATH] # defaults to the current directory
turboreview --skill # print the AI-agent guide and exit
turboreview --watch # stream review comments as JSON lines (for an agent)
turboreview --watch --replay # ... including comments already open
Run inside (or point at) any git repository.
Two views, toggled with [ / ]:
- Changes — the working tree. Left pane has two sections,
▌ Unstaged (N)and▌ Staged (N), each a collapsible directory tree. - Commits — the branch history. Left pane lists commits (short hash, summary,
author, date, and per-commit diff stats
N files +ins -del). Diff stats are computed lazily for the rows in view. The list loads 50 commits at a time; scroll to the bottom and pressLto load the next page. PressEnteron a commit to drill into its changed files (diff vs the commit's first parent);Escsteps back out.
In both views:
- Left pane — Files. Each file row shows a colored status letter
(
Aadded,Mmodified,Ddeleted,Rrenamed), a review tick (✓reviewed /○not), and a Nerd Font file-type icon. The pane can be resized or hidden entirely (see keys). - Right pane — Diff. Syntax-highlighted code with a line-number gutter.
Added/removed lines are bright with a green/red background; unchanged context
lines are dimmed so changes stand out. A line cursor (highlighted row) marks
where comments attach. The title shows
(ctx N)or(full file). Pressvfor a side-by-side (split) view — old on the left, new on the right — which is remembered across sessions. - Comments pane (toggle with
C). An optional third column listing the current scope's comments grouped by status (Open / NeedsInfo / Wontfix / Resolved). PressEnteron a comment to jump to its file and line.
Press ? at any time for an in-app keybinding overlay.
| Key | Action |
|---|---|
[ / ] |
switch view (Changes ⇆ Commits) |
Tab |
switch focus across the visible panes |
↑/↓ j/k |
move selection / commit / line cursor in the focused pane |
⇧↑/⇧↓ J/K |
jump (fast scroll) in the focused pane |
| mouse wheel | move the focused pane's cursor |
gg / G |
jump to top / bottom of the focused pane |
L |
load more commits (Commits view, when more history exists) |
Enter |
open commit (straight to its first file's diff) · focus a file's Diff · fold dir · jump to comment |
W |
switch to another worktree of this repo (type to filter, Enter switches) |
Ctrl-T |
review timer: type a duration (up to 99h) and optional label (25 comments, 1 min review, 90s, 1h 30m, 10:00, 1:30:00) or pick a preset (5–45 min). Tab moves to Remind: comma-separated reminders, 5 or 5m left (5 min before the end), every 5 (every 5 min in, at most every 10s: a 15-min timer reminds at 10:00 and 5:00 left), after 10 (10 min in); each rings the bell and shows a notice under the countdown for a few seconds, and new timers start with the last reminders set. The countdown shows at the top middle of the screen (red in the last minute); when it runs out an alarm pops up with a terminal bell (Enter dismiss, r restart, s snooze 5 min; while you are typing a comment, a Pi prompt or a search only Esc dismisses it, and your typing goes on). Ctrl-T while it runs: Space pause, +/- 5 min, r restart, x stop, n new. It keeps running across worktree and repository switches |
Ctrl-P |
find a file or folder (fuzzy; changed files first) and open it: a changed file in its diff, an unchanged one in the all-files list, a folder unfolded in the file list. A query starting with / or ~ browses the whole disk instead (Tab goes into a folder); Enter opens the pick in its own git repository, switching to it |
* |
pin / unpin the selected file (see Pinned files) |
' |
open the Pinned tab: pinned files of every repo, with open comments and changes per repo (Enter opens, d unpins); again closes the right pane |
C |
open the comment-list pane (again closes the right pane): the open view's comments, then those on other reviewed commits (Enter jumps to any of them) |
Space / a |
in the comment pane: resolve / reopen the selected comment · archive it (asks first) |
c (comment pane) |
reply to the selected comment; a reply on a closed comment reopens it |
o |
in the diff: preview the comment on the cursor line, with the code it was originally written against |
p |
show / hide agent responses in the comment pane |
u |
hide / show resolved comments, in the diff and the comment pane |
S |
hide / show outdated comments in the diff (pane still lists them) |
Esc |
step back (Diff → files → commit list) / focus the Files pane |
h/l ←/→ |
scroll the diff horizontally (Diff pane) |
+ / - |
increase / decrease diff context (step 5; + at max → full file) |
F |
toggle full-file view (shortcut; also reachable via +) |
v |
toggle side-by-side (split) vs unified diff (persisted) |
d |
cycle diff style: dim → bright → plain (persisted) |
w |
toggle wrapping of long diff lines (persisted) |
H |
file-history overlay for the selected file's diff |
{ / } |
step to older / newer revision (in the history overlay) |
/ |
search within the current diff |
n / N |
jump to next / previous search match |
a |
fold / unfold all directories in the file tree |
O |
view all tracked files / changed files only |
e |
toggle macro-expanded view of the selected file |
z |
hide / show the file pane (diff goes full-width) |
< / > |
narrow / widen the focused pane (files or the right pane) |
c |
comment on the cursor line (opens a modal input box) |
E |
edit the cursor line / V selection in the file (unstaged only); Ctrl-S writes |
←→↑↓ Home End |
move the cursor in the comment / edit box |
s |
stage the selected file or folder (Unstaged) / unstage it (Staged) |
s (Diff pane) |
stage / unstage the hunk under the cursor, or every hunk a V selection touches |
Space |
toggle the reviewed checkbox on the selected file |
R |
toggle hiding reviewed files |
A |
archive resolved comments in the current scope (asks y / n first) |
r |
refresh everything from disk / git (also applies agent updates) |
% |
toggle test-coverage highlight (LCOV) |
M |
run the configured coverage command, then show it |
P |
open the Pi chat popup (needs pi; see Pi chat) |
? |
show the keybinding help overlay (type to search it) |
qq / Ctrl-C |
quit (press q twice to avoid accidental exits) |
Debugging (right pane Debug tab; see Debugging):
| Key | Action |
|---|---|
b |
toggle a breakpoint on the cursor line (Diff pane) |
D |
launch a debug session (a selected commit in Commits, else worktree) |
[ / ] |
right pane: switch the Comments / Pinned / Debug tab (when focused) |
t |
Debug tab: switch the Vars / Breakpoints view |
c/n/i/o |
continue / step over / step in / step out (Debug focused) |
Enter |
Vars: expand a variable · Breakpoints: jump to it |
Space / d |
Breakpoints tab: enable-disable / delete a breakpoint |
h / l |
scroll the Debug pane horizontally |
Ctrl-D |
in the comment box: attach the stopped call stack to the comment |
X |
end all debug sessions (asks y / n first) |
In the comment input box: type freely, Enter for a newline, Ctrl-S to save, Esc to cancel. Saving an empty comment deletes it.
s on a file in the Unstaged section stages it; on a file in the Staged
section it unstages it. Staging only moves changes into or out of the git index —
your working-tree files are never modified. (Hunk-level staging is not yet
supported.)
Press c on a diff line to attach a comment. Comments render in a bordered box
directly under their line.
Each comment is anchored to its line's content plus the surrounding lines, so
it follows the line when the file shifts (e.g. lines inserted above). If a comment
can no longer be confidently placed, it is shown as ⚠ outdated rather than lost.
Comments carry a status (open, resolved, wontfix, needs_info) and an
optional response. An AI coding agent can close the loop:
- Run
turboreview --skillto print a guide describing the on-disk schema and workflow. The guide has the agent ask whether to save a pointer to it — as a skill in the agent's skills folder if it has one, otherwise in the repo'sCLAUDE.md/AGENTS.md— so later sessions know to read it. - The agent reads the open comments, makes the requested changes, then writes a
responseand sets thestatusin the relevantcomments.json. - Reopen turboreview — each comment box shows the agent's status badge
(
✓ resolved,✗ wontfix,? needs-info) and its response inline. - The agent leaves its fixes unstaged and stops there. You review the diff and approve before anything is staged or committed — the agent never commits its own fix on your behalf.
Ask the agent to "review my past comments" and it will distil recurring feedback into
.turboreview/lessons.md, then read that file at the start of later fix loops so the
same review note doesn't have to be written twice.
You don't have to quit and reopen. While turboreview is running it watches the
current scope's comments.json, so when an agent responds you get a notification
in the comment pane and the status bar:
● agent resolved 2, needs info on 1 — press r to reload
Nothing moves until you press r — the view never shifts under you mid-read. The
banner says only what changed; r applies it.
There is no daemon and no socket: both sides poll the same file. turboreview stats
comments.json every ~500ms while you are idle (mtime and length, so two writes in
one timestamp tick are still caught).
For the other direction, an agent runs:
turboreview --watch # one JSON object per line, as comments arrive
turboreview --watch --replay # plus comments already open when it startsIt streams every scope (the worktree and each reviewed commit) and keeps running, so the agent reads a line at a time instead of polling by hand:
{"kind":"new","scope":"worktree","path":"/repo/.turboreview/comments.json",
"file":"src/a.rs","line":42,"orig_line":40,"text":"use a const here",
"line_text":"let x = 2;","hunk":"@@ -1,4 +1,4 @@","stale":false}kind is new, edited (you reworded it) or reopened (you rejected the fix —
the line carries the agent's previous_response). Replies the agent writes are not
echoed back, so answering cannot loop. path names the file to write the reply
into, which matters because a comment left on a commit belongs to that commit's
store, not the worktree's.
An agent can review your changes and leave its findings as comments you read in turboreview:
turboreview comment add --file src/a.rs --line 42 --severity bug --author claude --text "…"
turboreview comment list [--commit SHA | --all] [--status open] [--author claude]
turboreview comment reply --id c7f3a1 --status resolved --text "…"
Findings show the agent's name and severity, bugs first. Reply from the
comment pane with c; the agent sees your reply (turboreview --watch
reports it as replied) and answers in the same thread.
Press H on a file's diff to enter the history overlay — it walks the
commits that touched that file (newest first). { steps to an older revision,
} to a newer one; } past the newest returns to the live diff, and Esc
exits. While stepping, the cursor stays on the same line number, the view
scrolls to keep it centered, and context is expanded (up to full file) if needed
to show that line. Comments made on a past revision are stored in that commit's
scope (.turboreview/commits/<sha>/).
Press / to search within the current diff (case-insensitive substring).
n and N jump to the next and previous match.
turboreview can drive a debugger straight from the diff, using the Debug Adapter
Protocol (any DAP adapter:
lldb-dap, codelldb, debugpy, …). Configure it under debug in
.turboreview/config.json (see docs/debug-config-example.md):
-
Press
bon a diff line to set a breakpoint (a●shows in the gutter), thenDto build + launch. The right pane's Debug tab shows the call stack and the selected frame's variables;▶marks the stopped line. -
Tabto focus the Debug pane, then step withc/n/i/o.Enterexpands a structured value (String/Vec/struct/map) to its contents; each variable shows its type and memory address. -
tswitches the Debug pane between Vars and Breakpoints (the breakpoint list:Enterjumps,Spaceenables/disables,ddeletes). -
Press
Dto open the launch picker: debug the working tree, a selected commit, attach to a running process, or attach to a remote target. -
Attach to a process: pick process to open a filterable list of running processes (type to filter by name or pid,
Enterto attach). -
Debug a past commit: pick commit in the Commits view — turboreview checks it out in a throwaway
git worktree, builds it there, and debugs that historical binary (cleaned up when the session ends). -
Remote attach (gdbserver / Docker): pick remote to attach to a running target. Configure it under
debug.remote(and usesource_mapto map the remote source paths to your local checkout):"debug": { "remote": { "host": "localhost", "port": 1234 }, "source_map": [["/build/src", "/local/repo/src"]] }
host/portrungdb-remote host:port; for other setups setremote.attach_commandsto raw adapter commands instead. -
Attach a snapshot to a comment: while stopped, press
cto comment, thenCtrl-Dto attach the current call stack + locals. It's saved with the comment and shown inline, so a reviewer keeps the exact runtime state. -
Otoggles view all files (every tracked file, not just changed ones) so you can open and breakpoint anywhere in the codebase.Xends the session.
Press % to overlay coverage from an LCOV file: a ▌ bar in the gutter is
green for covered lines, red for uncovered. The footer shows overall and
current-file percentages. Configure the file (and, optionally, a command that
generates it) in .turboreview/config.json:
"coverage_file": "coverage/lcov.info",
"coverage_command": "cargo llvm-cov --lcov --output-path coverage/lcov.info"Press M to run the command and reload. Any tool that emits LCOV works
(cargo llvm-cov, tarpaulin, nyc, gcov, …).
Press e to replace the diff with the macro-expanded source of the selected
file (read-only, syntax-highlighted); e again restores the diff. It runs a
configurable command and shows its stdout. The {module} and {file}
placeholders are substituted (module path derived from the src/-relative path):
// crate with both a lib and a bin needs an explicit target:
"expand_command": "cargo expand --lib {module}"Default is cargo expand {module} (needs nightly + cargo-expand). Switching
files leaves the expanded view.
Configure several named commands to get a picker on e:
"expand_commands": [
{ "name": "lib", "command": "cargo expand --lib {module}" },
{ "name": "example", "command": "cargo expand --example $(basename {file} .rs)" }
]With one (or none) configured, e runs it directly; with several, it opens a
selection popup.
Documents you are reviewing across several repositories can be pinned, and every turboreview instance lists them in the right pane's Pinned tab, grouped by repository.
*on a file (Files or Diff pane) pins it;*again unpins it.'opens the Pinned tab (and focuses it).'while the Pinned tab shows, orCwhile the Comments tab shows, closes the right pane; either key on the other tab switches to its own.Enteron a pin opens it. A pin from another repository switches this instance into that repository first (asWdoes for worktrees), so its comments, reviewed flags and agent handoff all use that repository's.turboreview/.Enteron a repository header just switches there.dunpins (asks y / n first, as does*on a pinned file). The open file is marked▶; a pinned file gone from disk is red.- Each repository header shows what is waiting there:
● N opencomments (over every view: working set, commits, ranges, branches),? N needs info, and± N changedfiles with uncommitted changes (.turboreview/itself left out), orclean. A pin shows its own pending comments (● N) andMwhen the file has uncommitted changes. The counts are read in the background and refresh every few seconds while the tab shows.
From a shell:
turboreview pin add docs/design.md ../other-repo/RFC.md
turboreview pin # list, one absolute path per line
turboreview pin rm docs/design.mdPins live in ~/.turboreview_root/root_config.json (set TURBOREVIEW_ROOT to
use another folder), one entry per file with its repository root and its path
inside it. Writes are locked, and running instances pick up changes made
elsewhere within a second.
P opens a chat with pi, a coding
agent turboreview runs as pi --mode rpc in the open repository. pi is not
bundled: install it separately (it needs Node.js 22.19+; tested with pi 1.0.4):
curl -fsSL https://pi.dev/install.sh | sh
# or: npm install -g --ignore-scripts @earendil-works/pi-coding-agentWithout pi, the popup says so and how to get it; nothing else changes.
- Each prompt starts with a
[turboreview context]block describing the screen: the repo, the view and the focused pane; in the commit list the commits around the selection (with stats, anyVrange) and the selected commit's message and files; an opened commit or range with its commits, message and files; the Branch tab's branch, base and files; the Changes list; File History's revision; an active search; the comment or pin selected. Then the open file: itsgitdiff command, the display mode, the hunk at the cursor, the cursor line orVselection, and its comments. Pi is told how to useturboreview commentto read and answer comments. - Replies render as markdown. Tokens show per prompt, with context / session totals and cost in the title.
Entersends,Ctrl-Por/modelpicks the model (with context size and price per 1M tokens, from pi's catalog),Ctrl-Lor/clearstarts a new conversation,Esccloses.
Privacy and safety. Prompts, with the code and comments above, go to the
model provider pi is set up with. By default pi has all its tools, so it can
run shell commands and edit files in the repository; set pi_tools to keep
it read-only.
Settings, in ~/.turboreview_root/root_config.json (shared by every instance):
| Key / variable | Meaning |
|---|---|
pi_model |
model for pi --model (set by the picker); unset: pi's default |
pi_tools |
pi --tools allowlist, e.g. "read,grep,find,ls" for read-only |
pi_command |
the pi executable, when it is not pi on PATH |
TURBOREVIEW_PI |
environment variable; overrides pi_command |
PI_CODING_AGENT_DIR |
pi's own folder (default ~/.pi/agent), read for the model catalog |
Reviewed flags and comments persist under <repo>/.turboreview/:
| Path | Holds |
|---|---|
.turboreview/comments.json · reviewed.json |
working-tree review (Changes view) |
.turboreview/commits/<sha>/comments.json · … |
per-commit review (Commits view) |
.turboreview/comment-log.jsonl |
append-only activity log (newest last) |
.turboreview/archive/comments-archive.jsonl |
archived resolved comments (repo-wide) |
.turboreview/lessons.md |
recurring review lessons (agent-written) |
The comment log records one JSON object per comment add/edit
({path, line, scope, date, action}, where date is a YYYY-MM-DD HH:MM:SS
timestamp), so an agent can read the tail to find the latest review activity. Add .turboreview/ to your .gitignore if you don't
want it tracked. R hides reviewed files to declutter the list.
File-type icons use Nerd Fonts — install a Nerd Font in your terminal for the glyphs to render correctly (otherwise you'll see fallback boxes). Code highlighting uses the bundled Catppuccin Mocha–style dark theme.
