Agent-generated code arrives differently than human commits. A coding agent writes 15 files in 30 seconds, embeds reasoning inline, and expects a human to approve or reject the batch. Traditional git diff shows line-by-line changes but offers no structure for multi-file review, no space for agent annotations, and no way to watch a directory as an agent writes.
Hunk is a terminal diff viewer built for this workflow. It treats agent changesets as review units, not individual commits. The tool sits between agent output and human acceptance, providing split/stack layouts, inline AI notes, watch mode for live file updates, and Git difftool integration. At 5,361 stars and trending #11 on GitHub for TypeScript, it exposes the plumbing gap between agent-generated code and the review interfaces developers actually need.
Why Agent Changesets Break Traditional Diff UX
Human developers commit incrementally. Agents produce multi-file batches with embedded reasoning. The mismatch creates three problems:
-
Batch review scope: An agent might touch 20 files to implement a feature. Reviewing each file in isolation loses context. Reviewing all 20 in a single pager scroll loses structure.
-
Inline annotations: Agents often explain their changes in comments or metadata. Traditional diff tools strip this context or bury it in commit messages.
-
Live updates: When an agent runs in watch mode or iterates on feedback, files change rapidly. Reloading
git diffmanually breaks flow.
Hunk addresses these by treating the changeset as the atomic unit. It provides a sidebar for file navigation, inline rendering of AI annotations, and a watch mode that reloads the diff when files change.
Architecture: OpenTUI + Pierre Diffs + Layout Engine
Hunk is built on two libraries:
- OpenTUI: A terminal UI framework that handles keyboard, mouse, and pager integration. Provides the event loop and rendering primitives.
- Pierre diffs: A diff library that parses Git diffs, file pairs, and patches into structured data. Handles unified diff format, hunk metadata, and line-level changes.
The core architecture has three layers:
- Input layer: Watches file system events, Git working tree changes, or Jujutsu/Sapling revsets. Feeds raw diffs to the parser.
- Layout engine: Decides whether to render split view (side-by-side), stack view (vertical), or responsive auto layout based on terminal width and file count.
- Render layer: Streams diff hunks to the terminal, injects inline AI annotations, and handles scrolling, selection, and navigation.
Layout Decision Tree
Hunk chooses layout based on terminal dimensions and changeset size:
| Terminal Width | File Count | Layout Choice | Rationale |
|---|---|---|---|
| < 120 cols | Any | Stack | Side-by-side unreadable |
| ≥ 120 cols | 1-5 files | Split | Full context visible |
| ≥ 120 cols | 6+ files | Split + sidebar | Navigation needed |
| Watch mode | Any | Previous choice | Preserve state on reload |
The layout engine recalculates on terminal resize events. If width drops below 120 columns mid-review, it collapses split view to stack view without losing scroll position.
Watch Mode: File System Events and Diff Reload
Watch mode monitors the file system for changes and reloads the diff automatically. This is critical when an agent writes files in rapid succession or iterates on feedback.
The implementation uses fs.watch (or equivalent) to monitor:
- Working tree files in Git mode
- Specific file paths in raw file mode
- Commit objects in
hunk showmode (watches.git/refsfor new commits)
When a change event fires, Hunk:
- Debounces events (100ms window to batch rapid writes)
- Re-parses the diff using Pierre
- Preserves scroll position and selected file in the sidebar
- Re-renders only changed hunks
This avoids full-screen flicker and keeps the review context stable. If the agent deletes a file mid-review, Hunk removes it from the sidebar and advances to the next file.
Handling Rapid Agent Writes
Agents often write files faster than humans can review. If an agent writes 10 files in 2 seconds, watch mode:
- Batches all 10 changes into a single reload
- Updates the sidebar file list atomically
- Highlights new files in the sidebar
- Does not auto-scroll unless the current file was deleted
This prevents the UI from jumping around while the agent is still writing.
Inline AI Annotations: Embedding Agent Reasoning
Hunk renders inline annotations beside code changes. These annotations come from:
- Comments in the diff (e.g.,
// AI: Refactored for clarity) - Metadata in commit messages (parsed from structured formats)
- External annotation files (JSON or YAML sidecar files)
The annotation format is flexible. Hunk looks for markers like AI:, Agent:, or Note: in comments and renders them in a separate column. For structured metadata, it expects:
{
"file": "src/handler.ts",
"line": 42,
"annotation": "Replaced callback with async/await to avoid nested promises"
}
Annotations appear in the right margin in split view or inline in stack view. They scroll with the code and can be toggled on/off with a keybinding.
Annotation Rendering Trade-offs
| Approach | Pros | Cons |
|---|---|---|
| Inline comments | No external files needed | Clutters code, hard to strip later |
| Sidecar JSON | Clean separation, structured | Requires agent to write extra file |
| Commit message metadata | Git-native, version-controlled | Limited space, hard to parse |
Hunk supports all three. The default is inline comments because most agents already write them.
Git Difftool Integration: Replacing git diff in Workflows
Hunk registers as a Git difftool, so you can replace git diff with hunk diff in existing workflows:
git config --global diff.tool hunk
git config --global difftool.hunk.cmd 'hunk diff "$LOCAL" "$REMOTE"'
git difftool HEAD~1
This works with:
git difftoolfor staged changesgit difftool --cachedfor index vs. HEADgit difftool <commit>for historical diffs
Hunk also supports Jujutsu and Sapling revsets. Inside a jj workspace, hunk diff @ shows changes in the current revision. Inside a Sapling workspace, hunk show . shows the current commit.
The tool auto-detects VCS type by checking for .git, .jj, or .sl directories. You can override this with a config file:
# ~/.config/hunk/config.toml
vcs = "git" # or "jj" or "sl"
Performance Boundaries: Reviewing 50+ File Changesets
Hunk is fast for typical agent changesets (5-20 files). Performance degrades when:
- File count exceeds 50: Sidebar rendering slows. Scrolling becomes laggy.
- Diff hunks exceed 10,000 lines: Syntax highlighting blocks the event loop.
- Watch mode monitors 100+ files: File system events flood the debounce buffer.
Mitigation strategies:
- Lazy rendering: Only render visible hunks. Scroll events trigger incremental rendering.
- Syntax highlighting off by default: Enable only for small diffs.
- File filtering: Allow users to exclude files by pattern (e.g.,
*.lock,dist/*).
For changesets above 50 files, Hunk recommends splitting the review into multiple sessions or using a web-based review tool.
Failure Modes and Edge Cases
1. Agent Writes Binary Files
Hunk cannot diff binary files. If an agent writes an image or compiled asset, Hunk shows a placeholder:
[Binary file changed: 42KB → 58KB]
Users can open the file externally with a keybinding.
2. Agent Deletes Files Mid-Review
If the agent deletes a file while the user is reviewing it, Hunk:
- Removes the file from the sidebar
- Advances to the next file
- Shows a notification: “File deleted, moved to next”
This prevents the user from reviewing a non-existent file.
3. Terminal Resize During Review
If the terminal resizes below 120 columns, Hunk collapses split view to stack view. Scroll position is preserved, but the user may need to re-orient.
4. Conflicting Watch Events
If two agents write to the same file simultaneously, watch mode reloads twice. The second reload overwrites the first. This is acceptable because the user is reviewing the final state, not intermediate writes.
Code Example: Parsing Inline Annotations
Here’s how Hunk extracts inline AI annotations from diff comments:
interface Annotation {
file: string;
line: number;
text: string;
}
function parseInlineAnnotations(diff: string): Annotation[] {
const annotations: Annotation[] = [];
const lines = diff.split('\n');
let currentFile = '';
let lineNumber = 0;
for (const line of lines) {
// Track current file from diff header
if (line.startsWith('diff --git')) {
currentFile = line.split(' ')[2].replace('b/', '');
lineNumber = 0;
}
// Track line numbers from hunk headers
if (line.startsWith('@@')) {
const match = line.match(/\+(\d+)/);
lineNumber = match ? parseInt(match[1], 10) : 0;
}
// Extract AI annotations from comments
if (line.startsWith('+') && line.includes('// AI:')) {
const text = line.split('// AI:')[1].trim();
annotations.push({ file: currentFile, line: lineNumber, text });
}
if (line.startsWith('+')) lineNumber++;
}
return annotations;
}
This parser walks the unified diff format, tracks file and line context, and extracts comments prefixed with // AI:. It handles multi-line annotations by continuing until the next non-comment line.
Technical Verdict
Use Hunk when:
- You review agent-generated changesets with 5-50 files
- You need inline AI annotations visible during review
- You want watch mode for live agent iteration
- You work in a terminal-first workflow and want Git difftool integration
Avoid Hunk when:
- Your changesets exceed 50 files (performance degrades)
- You need web-based review with team collaboration features
- You review binary files or large assets (Hunk cannot diff them)
- You prefer IDE-integrated diff tools with richer syntax highlighting
Hunk fills the gap between agent output and human review. It is not a replacement for GitHub PRs or GitLab MRs, but it is faster and more focused for solo developers reviewing agent code locally. The watch mode and inline annotations are the key differentiators. If your workflow involves agents writing code while you review, Hunk is worth testing.