✨ Beautiful and ⚡ BLAZINGLY FAST ✨
Git diff sidebar for herdr: changed files with red/green hunks in a split pane. Click a file to jump, drag to send lines into the agent prompt. Written in Rust 🦀 btw.
Run the toggle action from an agent pane (Diff viewer: toggle git diff sidebar).
Scope is per agent session, never per tab or pane cwd. Two sources feed it:
1. Agent journals (exact). The viewer reads the session's own transcript and adopts every repo the session edited — no cwd assumptions, works even when the agent writes to a repo it was not launched in.
| agent | journal | what counts |
|---|---|---|
| claude | $CLAUDE_CONFIG_DIR (else ~/.claude) /projects/<slug>/<session>.jsonl |
Edit/Write/MultiEdit/NotebookEdit + subagent journals; the root is read from the agent process's own env, and a session id that is not on disk scopes nothing — never another session's newest transcript |
| opencode | ~/.local/share/opencode/opencode.db |
edit/write + apply_patch patch text, plus shell workdir (gated); legacy part and v2 session_message merged, subagent sessions included |
| kilo | ~/.local/share/kilo/kilo.db |
same as opencode |
| codex | ~/.codex/sessions/**.jsonl |
apply_patch / patch_apply_end changes |
| gemini | ~/.gemini/tmp/<project>/chats/session-* |
write_file/replace tool calls |
| qwen | ~/.qwen/projects/<slug>/chats/<session>.jsonl |
edit/write_file tool calls |
| pi | ~/.pi/agent/sessions/<slug>/<session>.jsonl |
edit/write tool calls |
| omp | ~/.omp/agent/sessions/<slug>/<session>.jsonl + every transcript nested under <session>/ (subagents, and subagents of subagents) |
edit/write tool calls in both call shapes — the path argument and the [file#hash] headers of a patch-form call; sessions resolve by transcript path, and a path that no longer exists scopes nothing rather than falling back to a neighbour's transcript |
| antigravity | …/antigravity-cli/brain/<id>/.system_generated/logs/transcript.jsonl |
write_to_file/replace_file_content targets |
| cursor | ~/.cursor/projects/<slug>/agent-transcripts/<conv>.jsonl + ai-tracking.db |
best-effort (no cwd in store) |
| aider | <repo>/.aider.chat.history.md |
> Applied edit to <path> |
2. Shell workdirs (gated). opencode and kilo record the working directory of every shell command; those directories join the scope as candidates and are adopted only once their working tree changes, so a repo the session merely reads stays out.
3. Process fallback (signature-gated). For agents without a journal (and for shell-only edits), a repo is adopted when a new process of the session's own tree runs with its cwd inside it and its working tree changes while the session is alive — so a dirty launch repo that the session never touched stays invisible. Sources marked best-effort above use the same gate. Agents that multiplex every session behind one shared daemon (opencode, kilo) never use the fallback: their pane's process tree spans unrelated sessions, so it is not walked.
The pane's own cwd repo is never assumed. Once a repo is in scope, all of its
uncommitted changes are shown, whoever made them. Session id or agent change
resets the scope; a new session starts empty; a confirmed pane close deletes it.
The viewer follows its own agent pane live — neighbour panes never leak in. The
header shows watching N so you always know the blast radius. Untracked files
included. One broken repo never blanks the view.
Linked worktrees are repos of their own. A session that works in
git worktree checkouts gets one entry per worktree, labelled
<main>⎇<branch> (a detached head falls back to the short sha), and the files
of a linked worktree send absolute paths when dragged — the agent usually runs
in the main checkout, so a repo-relative path would point at the wrong tree. A
removed worktree leaves the view within a tick and is forgotten from state.
Event-driven, not polling. The viewer subscribes to herdr's event stream
(pane.updated/closed/moved, layout.updated, worktree.removed) and runs
two timers: journal + process reads at most once a second while the agent is
working, and a git-signature check every 3s when idle. A dropped socket is
retried every second and the viewer keeps watching on that slow path. Plugin
hooks (pane.agent_status_changed, pane.closed, pane.exited, pane.moved,
tab.closed, workspace.closed) keep the record current even with no viewer
open — toggling afterwards is instant — and prune it when a pane, tab or
workspace goes away. Records are namespaced per herdr server
($HERDR_PLUGIN_STATE_DIR/srv-<socket>/session-<pane>.json), so a named session
never reads or prunes another session's state.
Debug a journal reader from any shell:
diff-viewer journals claude "" <session-id> # cwd + paths the viewer would adopt
CLAUDE_CONFIG_DIR=~/.claude-swap-backup/sessions/<profile> \
diff-viewer journals claude <cwd> <session-id> # same, for a swapped profileLimitations: shell edits that finish between samples and agents with neither a journal nor visible child processes are not detected; cursor/aider/antigravity blob sources are heuristic and always gated.
Toggle resyncs pane sizes after open/close (resize --amount 0 is a no-op that still syncs pty winsizes), so neither the viewer nor the agent renders clipped until the next click.
Click ◑ in the header or press T for a theme menu — applies instantly, persists across toggles. j/k + Enter to pick, Esc to close.
cargo install --path . # once: `diff-viewer` in ~/.cargo/bin
diff-viewer themes # list
diff-viewer theme NAME # set from any shell, picked up live, no re-toggle
diff-viewer theme auto # back to claude-code dark/light auto-detecttransparent = same syntax colors as claude-code-dark, but the gray base stays unpainted (your terminal background / blur shows through) with juicier reds and greens. Also available: dark / light (follow claude-code themes), or any name from diff-viewer themes (catppuccin, dracula, nord, gruvbox, one-dark/light, solarized, kanagawa, rose-pine, vesper, tokyo-night…). Unset = auto-detect from terminal background.
/diff |
diff-viewer | |
|---|---|---|
| Multi-repo scope | ❌ one repo | ✅ own session's repos only, worktrees included |
| Live follow | ❌ snapshot | ✅ events + 1s ticks while the agent works |
| Click-to-jump file list | ❌ | ✅ |
Drag lines into prompt as file:line |
❌ | ✅ |
| Transparent theme | ❌ | ✅ 👻 |
| Speed | fast | ⚡ BLAZINGLY FAST (it's Rust 🦀) |
