Diff Reviewer

An IDE-like /diff — two tabs, a collapsible file tree, and a side-by-side diff pane, without leaving the terminal.

Overview

/diff is a two-tab, side-by-side reviewer:

  • Local Changes — file tree (left) | diff of the selected file (right), collapsed to the changed lines with incremental expand of unchanged context.
  • Log — the git graph/tree (left) | files changed in the selected commit (right).
┌ Diff ─────────────────────────────────────────────────────────┐
│  Local Changes   Log                         (Tab to switch)   │
│  source: working tree ▾   (←/→ when focus on list, only here)  │
│ ┌ Files ─────────────┐┌ Diff: src/foo.ts ───────────────────┐ │
│ │ web  2 files · main ││  12  export function foo() {        │ │
│ │› src/foo.ts  +12 -3 ││ ··· 8 lines ───────────────────────  │ │
│ │  README.md   +4  -4 ││ -18  const x = old()               │ │
│ │ api  1 file  · dev  ││ +18  const x = new()               │ │
│ │  src/bar.ts  +1  -0 ││                                     │ │
│ └────────────────────┘└─────────────────────────────────────┘ │
│  Tab tabs · ↑/↓ files · → diff · ← back · r refresh · Esc close│
└────────────────────────────────────────────────────────────────┘

File tree (Local Changes)

The left pane is a collapsible folder tree, not a flat list. Files nest under their directories; folders sort first, then files; single-child directory chains compact into one row (like VS Code's compact folders). Folder rows show a caret plus an open/closed icon; file rows show the basename with its per-file +/− stat. When more than one repo is in scope, a per-repo group header sits above its files — collapsible too, so you can fold an entire repo's changes out of the way while keeping its header visible.

Keys: ↑/↓ move, Enter toggles a folder or opens a file, → expands a folder or focuses the diff, ← collapses a folder or focuses the list.

The four sources

The source selector on Local Changes cycles with [/] across three kinds, all feeding the same file-list + diff panes:

  • Working tree — uncommitted changes vs HEAD (the default).
  • Per-turn — one entry per agent turn in the current session.
  • Stash — stash@{0}…stash@{n} from git stash list.

Multi-repo / monorepo grouping

When more than one git repo is in scope, the file list groups per project with a colored swatch, the repo name, file count, and branch:

web   2 files changed · main
  src/foo.ts   +12 -3
  README.md    +4  -4
api   1 file changed  · dev
  src/bar.ts   +1  -0

Scope is the cwd's repo, every /add-dir workspace directory, and nested child repos discovered underneath them — the common monorepo shape where sibling folders each carry their own .git and the parent's git status never sees their changes. Discovery is bounded (max depth 3, max 1 500 directories scanned) and skips node_modules/dist/vendor-style noise. A single repo in scope shows no header at all — the flat list you already know.

Collapse & expand

The diff pane shows only changed lines plus 3 lines of context; unchanged stretches collapse to a ··· N lines marker. Activating a marker reveals ±10 more lines, GitHub-style, pulled from the working-tree file. Untracked files no longer show a placeholder — they render as an all-green synthesized diff, syntax-highlighted like any other file.

Nerd-Font file icons

When your terminal font supports it, a per-file-type icon sits next to every filename in both tabs' file lists. On terminals without Nerd Font glyphs, it falls back to plain ASCII markers — no raw glyph is ever emitted unconditionally. Override with CLAUDIN_NERD_FONT=on / off.

Log tab

The left rail is the real branch/merge topology (git log --graph), not a flat list of commits — authors get stable colors, tags render green, branches/HEAD render amber. In a monorepo, [/] cycle which repo's log is shown. The right pane lists the selected commit's changed files with per-file stats and the commit-wide total; drilling into a file (Enter/→) shows its diff at the third level, through the same rendering path as Local Changes, so theme colors and syntax highlighting match exactly.

┌ Diff ─────────────────────────────────────────────────────────┐
│  Local Changes   Log                         (Tab to switch)   │
│ ┌ Log ───────────────────────┐┌ Files in dca77a5 ───────────┐ │
│ │ ○ feat: @-mention nav  main ││  src/components/x.tsx  +20 -4│ │
│ │ ●  chore: bump deps         ││  src/hooks/y.ts        +3  -1│ │
│ │ ├─╮ Merge branch 'fix'      ││                              │ │
│ │ │ ● fix(ink): vacated rows  ││                              │ │
│ │ ●─╯ feat(bridge): remote    ││                              │ │
│ └────────────────────────────┘└──────────────────────────────┘ │
│  main ⟳ ⊗0 ⚠12     Tab tabs · ↑/↓ commits · → files · Esc close │
└────────────────────────────────────────────────────────────────┘

Navigation

KeyAction
Tabswitch tabs (Local Changes ↔ Log)
↑/↓move selection in the left list, or scroll the diff when it's focused
←/→move focus between the left list and the right pane (also collapses/expands a folder on Local Changes)
[ / ]cycle the source (Local Changes) or the project (Log, monorepo)
Enteropen a file / toggle a folder (list focus); grow the next collapsed gap (content focus)
aexpand the whole file (Local Changes)
u / d, g/Gpage / jump to ends (content focused, split layout)
rmanual refresh
Escclose (from content focus, returns to the list first)

Entry points

/diff stays the canonical command. gg opens the same overlay too — but only when the prompt is empty (vim-style), so it never fires mid-typing.

On narrow terminals (under 100 columns) or outside a fullscreen-capable environment, the reviewer falls back to a stacked list-then-detail layout instead of the side-by-side split, so it stays usable everywhere.