semantic-diff
A terminal diff viewer with AI-powered semantic grouping. Built with Rust and ratatui.
Groups your git changes by meaning — not just by file path. Designed to run as a cmux split pane alongside Claude Code, giving real-time visibility into what's being changed and why.
Why
AI coding agents like Claude Code, Cursor, and Copilot generate code faster than you can review it. The bottleneck has shifted from writing code to understanding what changed.
"Claude Code has absolutely zero features that help me review code or do anything else than vibe-coding and accept changes as they come in" — Hacker News
"You can't review code being generated faster than you can read it" — Hacker News
"The diff shows what changed, but not why" — Hacker News
"CLI based tools (eg. git diff) are just generally inferior to visual integrated code review tools" — Hacker News
Developers moving to terminal-first workflows (Ghostty + tmux + Claude Code) gain speed but lose the review capabilities IDEs provide. semantic-diff fills that gap — a terminal-native TUI that groups your changes by intent, not just by file.
How semantic-diff is different
| Tool | Semantic grouping | Terminal TUI | AI-powered | Review-time |
|---|---|---|---|---|
| semantic-diff | Yes | Yes | Yes | Yes |
| Difftastic | No | Yes | No | Yes |
| Delta | No | Yes | No | Yes |
| Deff | No | Yes | No | Yes |
| Crit | No | Yes | No | Yes |
| Gnosis | Yes | No (Electron) | Yes | Yes |
| VibeGit | Yes | No | Yes | No (commit-time) |
| LightLayer | Yes | No (web) | Yes | Yes |
| Plandex | No | Yes | Yes | Yes |
No other tool combines semantic grouping by intent + terminal-native TUI + AI-powered analysis at review time.
Demo
https://github.com/user-attachments/assets/49f7f3cf-a72c-47f6-9313-fdf0e2000db8
Features
- Hunk-level semantic grouping — AI clusters related hunks across files by intent (e.g. "Auth refactor", "Test coverage"), not just file-level grouping
- Multi-backend AI — Supports Claude CLI and GitHub Copilot CLI (
copilot --yolo), with configurable preference and automatic fallback - Configurable —
~/.config/semantic-diff.jsonwith JSONC comment support, model selection, and intelligent cross-backend model mapping - Grouping cache — Cached in
.git/semantic-diff-cache.jsonkeyed by diff hash; instant reload when nothing changed - Syntax-highlighted diffs — Powered by syntect with word-level inline highlighting
- Collapse/expand — Toggle files, hunks, and semantic groups
- File tree sidebar — Changed files organized by semantic group with per-hunk stats
- Group-aware diff filtering — Select a file or group in the sidebar to filter the diff view to only those changes
- Hook-triggered refresh — Auto-updates when Claude Code edits files (via SIGUSR1)
- cmux integration — Auto-opens in a right split pane
- Help overlay — Press
?to see all keybindings - Text wrapping — Long diff lines flow with the terminal width
- Progressive enhancement — Shows ungrouped diff immediately, regroups when AI responds
- Graceful degradation — Works without any AI CLI (falls back to ungrouped view)
Install
Homebrew (macOS)
Cargo (crates.io)
Build from source
# Binary at target/release/semantic-diff
Usage
# Run in any git repo with uncommitted changes
Keybindings
| Key | Action |
|---|---|
j/k, ↑/↓ |
Navigate up/down |
Enter |
Sidebar: select file/group · Diff: toggle collapse |
Tab |
Switch focus between tree sidebar and diff view |
/ |
Search/filter files |
n/N |
Next/previous search match |
g/G |
Jump to top/bottom |
Ctrl+d/u |
Page down/up |
? |
Show shortcut help |
Escape |
Clear filter / quit |
q |
Quit |
Configuration
On first run, a default config is created at ~/.config/semantic-diff.json:
{
// Which AI CLI to prefer: "claude" or "copilot"
// Falls back to the other if preferred is not installed
// "preferred-ai-cli": "claude",
"claude": {
// Model: "sonnet", "opus", "haiku"
// Cross-backend models mapped automatically (gemini-flash → haiku)
"model": "sonnet"
},
"copilot": {
// Model: "sonnet", "opus", "haiku", "gemini-flash", "gemini-pro"
"model": "sonnet"
}
}
Claude Code Integration
semantic-diff is designed to work as a live diff viewer alongside Claude Code.
Setup
- Copy the hook script (an example is provided in
.claude/hooks.example/):
- Add to your Claude Code settings (
~/.claude/settings.local.json):
Note: Add this to your global (
~/.claude/settings.local.json) or user-level settings, not the project-level.claude/settings.local.json. Adding it to the project settings will cause the hook to trigger within the semantic-diff repo itself, repeatedly opening new semantic-diff instances.
How it works
- Claude Code edits a file (Edit/Write tool)
- PostToolUse hook fires
refresh-semantic-diff.sh - If semantic-diff is running: sends SIGUSR1 to refresh the diff
- If not running: opens a cmux right-split pane and launches semantic-diff
- AI groups the changed hunks by semantic meaning
- You see real-time, grouped changes without leaving the terminal
Changelog
v0.4.0
- Adaptive dark/light theme — Auto-detects terminal background color via OSC 11 protocol (supports iTerm2, Ghostty, kitty, WezTerm, Alacritty, xterm, VS Code terminal). Falls back to
COLORFGBGenv var. Override with"theme": "dark"or"light"in config. - Light theme — Full light-background palette with pastel diff colors, dark text, and blue accents for readability on white/light terminals.
- Terminal detection guards — Skips background detection in CI, piped stdin, and
TERM=dumbenvironments for zero startup overhead.
v0.3.0
- Security hardening — Secure PID file management with atomic writes and ownership validation, path traversal protection in diff parser and config/cache paths, bounded LLM response reading with validated deserialization, UTF-8 safe truncation.
- Stdin-piped LLM invocation — Prompts sent via stdin instead of command-line arguments to prevent process table exposure.
- Secure log file location — Log file moved to a secure directory with restricted permissions.
- Integration test suite — Added diff rendering, SIGUSR1 signal handling, large diff stress tests, and LLM integration tests.
v0.2.3
- Fix — Resolve clippy warnings in config and LLM modules.
v0.2.2
- Fix — Account for line wrapping in scroll offset calculation.
- Badges — Added crates.io and Homebrew version badges to README.
v0.2.1
- Fix — Remove non-functional cmux resize-pane call from hook.
- Docs — Embed demo video in README.
v0.2.0
- Hunk-level semantic grouping — Groups related hunks across files by intent, matching GitHub Copilot's content-level approach. A single file's hunks can appear in different groups.
- Multi-backend AI support — Added GitHub Copilot CLI (
copilot --yolo) as a fallback when Claude CLI is not available. - Configuration file —
~/.config/semantic-diff.jsonwith JSONC comment support. Configure preferred AI backend, model per backend, with intelligent cross-backend model mapping (e.g.gemini-flash→haiku). - Grouping cache — Results cached in
.git/semantic-diff-cache.jsonkeyed by diff hash. Instant startup when diff hasn't changed. - Group-aware diff filtering — Selecting a file in the sidebar filters the diff to its entire group. Selecting a group header toggles the filter.
- Help overlay — Press
?to see all keybindings in a centered popup. - Text wrapping — Long diff lines wrap with the terminal width instead of being truncated.
- Improved key responsiveness — Accept
Repeatkey events on macOS for smooth held-key navigation. - Scroll-to-top on file select — File header pinned to top of viewport when selected from sidebar.
v0.1.0
- Initial release with file-level semantic grouping, syntax highlighting, collapse/expand, file tree sidebar, and Claude Code hook integration.
Requirements
- Rust 1.75+
- Git
- Claude CLI or GitHub Copilot CLI (optional, for semantic grouping)
- cmux (optional, for auto-split pane)
License
MIT