PhotoStructure's fork of difit, originally by yoshiko-pg.
This fork builds on Yoshiko's diff viewer with a review workflow for coding agents:
- Conversation drawer: discuss the whole review alongside inline code threads, reply in either place, and retain drafts when moving between a discussion and code.
- Live agent feedback: submitted comments reach the agent immediately through JSON events; exact-thread replies appear in the viewer while the review continues.
- Comment progress: see Delivered, Read, Thinking, Replying, Replied, or Noted when the agent reports its activity. This does not wake an idle agent automatically.
- Reversible LGTM: approval stays visible and can be revoked. Conversations and the approval toggle are enabled by default; approval starts off.
- Intent and retained discussions: choose Comment, Change request, or Question in one radio group, resolve and reopen it without losing the history, or explicitly delete it.
- Repository information: expand the Repository info node in the file tree to see the reviewed repository, worktree, server, and launch directory. The browser title identifies the repository and port; the disclosure fits mobile screens.
The question marker and explicit thread deletion incorporate upstream PR #482. Reusable UI and conversation changes are being prepared as focused commits for upstream; scoped packaging, publishing, and default flags belong to this fork.
npx @photostructure/difit .Live agent conversations and the reversible LGTM approval toggle are enabled by default.
Approval starts off; click LGTM to approve or revoke. Use --no-lgtm for a read-only review
and --no-conversation to disable live events. --lgtm and --ship-it are aliases.
The agent must actively watch and answer comments; the viewer does not start an agent.
See the agent conversation protocol.
Install with npm install -g @photostructure/difit to use the difit command.
Node.js 22.14 or newer is required. On other machines, verify the package version
with npx @photostructure/difit --version before beginning a review.
The LGTM image was supplied from this video; its rights remain with the respective rights holders. Upstream code attribution and license are retained below.
difit is a CLI tool that lets you view and review local git diffs with a GitHub-style viewer. In addition to clean visuals, comments can be copied as prompts for AI. The local code review tool for the AI era!
Try it first
npx @photostructure/difit # View the latest commit diff in WebUIInstall and use
npm install -g @photostructure/difit
difit # View the latest commit diff in WebUIEnable use from AI agents
npx skills add photostructure/difit # Add the Skills to your agentInstalled skills include:
difit: ask the user for a review in the difit viewer when the user explicitly opts in to difitdifit-review: review a specific diff or PR and show the findings inside the difit viewer, when the user explicitly asks for difit
difit <target> # View single commit diff
difit <target> [compare-with] # Compare two commits/branchesdifit # HEAD (latest) commit
difit 6f4a9b7 # Specific commit
difit feature # Latest commit on feature branchdifit @ main # Compare with main branch (@ is alias for HEAD)
difit feature main # Compare branches
difit . origin/main # Compare working directory with remote maindifit supports special keywords for common diff scenarios:
difit . # All uncommitted changes (staging area + unstaged)
difit staged # Staging area changes
difit working # Unstaged changes onlydifit --pr https://github.com/owner/repo/pull/123--pr mode fetches patches by running gh pr diff --patch under the hood.
It also imports unresolved inline review threads from the PR so they appear as startup comments in difit.
Authentication is handled by GitHub CLI:
- Login once (recommended):
gh auth login - Token-based auth (CI/non-interactive): set
GH_TOKENorGITHUB_TOKEN
For Enterprise Server PRs, authenticate GitHub CLI against your Enterprise host:
gh auth login --hostname YOUR-ENTERPRISE-SERVER- Or set
GH_HOST=YOUR-ENTERPRISE-SERVERwithGH_TOKEN/GITHUB_TOKEN
You can inject initial review comments when launching difit:
difit --comment '{"type":"thread","filePath":"src/example.ts","position":{"side":"new","line":10},"body":"The background for this change is..."}'--comment is repeatable and accepts either a single JSON object or a JSON array. Supported types:
thread: create a new thread at the specified diff positionreply: add a reply to the latest existing thread at the same diff position
If the same comment already exists, difit skips importing it.
By using a pipe to pass unified diffs via stdin, you can view diffs from any tool with difit.
# View diffs from other tools
diff -u file1.txt file2.txt | difit
# Review saved patches
cat changes.patch | difit
# Compare against merge base
git diff --merge-base main feature | difit
# Review an entire existing file as newly added
git diff -- /dev/null path/to/file | difit
# Explicit stdin mode
git diff --cached | difit -Stdin mode is selected with intent-first rules:
-explicitly enables stdin mode- If positional arguments (
<target>/[compare-with]) or--prare provided, difit treats the command as Git/PR mode and does not auto-read stdin - Auto stdin detection applies only when no explicit mode is selected and stdin is a pipe/file/socket
| Flag | Default | Description |
|---|---|---|
<target> |
HEAD | Commit hash, tag, HEAD~n, branch, or special arguments |
[compare-with] |
- | Optional second commit to compare with (shows diff between the two) |
--merge-base |
false | Resolve the base revision with git merge-base before diffing (Git revision mode only) |
--pr <url> |
- | GitHub PR URL to review (e.g., https://github.com/owner/repo/pull/123) |
--comment <json> |
- | Inject initial comments (repeatable; accepts a JSON object or array) |
--commit-message <text> |
- | Seed the proposed commit message for the initial review |
--why <text> |
- | Seed the rationale for the initial review |
--port |
4966 | Preferred port; falls back to +1 if occupied |
--host |
127.0.0.1 | Host address to bind server to (use 0.0.0.0 for external access) |
--no-open |
false | Don't automatically open browser |
--clean |
false | Clear all existing comments and viewed files on startup |
--lgtm, --ship-it |
true | Show the LGTM toggle to grant or revoke approval while the review stays open |
--conversation |
true | Enable live comment events and exact-thread agent replies |
--include-untracked |
false | Automatically include untracked files in diff (only with . or working) |
--keep-alive |
false | Keep server running after browser disconnects (stop manually with Ctrl+C) |
--background |
false | Keep the server running in the background and output JSON connection info |
--context <lines> |
git default (3) | Limit surrounding context lines per change (0 shows changes only; not available with --pr or stdin) |
difit includes a review comment system that makes it easy to provide feedback to AI coding agents:
- Add Comments: Click the comment button on any diff line or drag to select a range
- Edit Comments: Edit existing comments with the edit button
- Generate Prompts: Comments include a "Copy Prompt" button that formats the context for AI coding agents
- Copy All: Use "Copy All Prompt" to copy all comments in a structured format
- Persistent Storage: Comments are saved in browser localStorage per commit
Open Conversation in the header to see the review's discussions in a side panel. Start a general discussion there when feedback applies to the whole review rather than one line. General threads support replies, editing, and Copy Prompt just like inline threads, and are saved with the selected comparison. Click an inline thread to jump to its code; general threads stay in the panel. Copy All and CLI comment output include both kinds of discussion.
src/components/Button.tsx:L42 # This line is automatically added
Make this variable name more descriptiveFor range selections:
src/components/Button.tsx:L42-L48 # This line is automatically added
This section is unnecessaryYou can install the following Skills to work with difit from AI agents.
npx skills add photostructure/difitInstalled skills include:
difit: ask the user for a review in the difit viewer when the user explicitly opts in to difitdifit-review: review a specific diff or PR and show the findings inside the difit viewer, when the user explicitly asks for difit
After code edits or automated review, the agent can start the difit server with the appropriate skill.
- JavaScript/TypeScript:
.js,.jsx,.ts,.tsx,.svelte - Web Technologies: HTML, CSS, JSON, XML, Markdown
- Shell Scripts:
.sh,.bash,.zsh,.fish - Backend Languages: PHP, SQL, Ruby, Java, Groovy, Scala, Perl, Elixir, Haskell, Clojure
- Systems Languages: C, C++, C#, Rust, Go
- Mobile Languages: Swift, Kotlin, Dart
- Infrastructure as Code: Terraform (HCL), Nix
- Others: Python, Protobuf, YAML, Solidity, Vim script, GDScript
difit automatically identifies and collapses certain files to keep your view clean:
- Deleted files: Removed files are auto-collapsed since they don't require close review
- Generated files: Auto-generated code is collapsed by default. This includes:
- Lock files (
package-lock.json,go.sum,Cargo.lock,Gemfile.lock, etc.) - Minified files (
*.min.js,*.min.css) - Source maps (
*.map) - Generated code:
- Orval (
*.msw.ts,*.zod.ts,*.api.ts) - Dart (
*.g.dart,*.freezed.dart) - C# (
*.g.cs,*.designer.cs) - Protobuf (
*.pb.go,*.pb.cc,*.pb.h)
- Orval (
- Frameworks:
- Ruby on Rails (
db/schema.rb) - Laravel (
_ide_helper.php) - Gradle (
gradle.lockfile) - Python (
uv.lock,pdm.lock)
- Ruby on Rails (
- Generic generated files (
*.generated.cs,*.generated.ts,*.generated.js) - Content-based detection:
- Files containing
@generatedmarker - Files containing
DO NOT EDITheader - Language-specific generated headers (Go, Python, etc.)
- Files containing
- Lock files (
Seed editable review intent with
difit . --commit-message 'fix: preserve review intent' --why 'Explain why the change is needed.'.
Each diff selection keeps its own proposed message and rationale for the server's
lifetime. Saving a change revokes that selection's LGTM approval. Agents can update
the same fields with difit comment summary --port <port> < /tmp/difit-summary.json;
see the proposal protocol.
Use difit <target> <base> --conversation --keep-alive to let an agent
answer submitted comments while you continue reviewing. In another process,
difit comment watch --port <port> streams JSON Lines; comment reply sends
answers to the exact review thread. A bounded comment watch --once wait is
available for tool-driven agents. See the conversation protocol and agent
workflow, including conditional LGTM approval.
The browser's Clipboard API
requires a secure context. Localhost is treated as trustworthy for local development;
a remote HTTP address such as http://10.1.1.24:4966 generally is not. difit tries a
legacy copy fallback, but trusted HTTPS is the reliable setup for remote browsers.
Browser permissions can still prevent copying.
Start the built difit server on the machine containing the repository:
difit . --host localhost --port 4966 --no-open --keep-aliveUse the actual port printed at startup if 4966 is occupied. From a source checkout,
run pnpm build, then use node dist/cli/index.js in place of difit.
Proxy this server, which serves both the UI and /api, at the root of one HTTPS
origin. The development server (pnpm dev, usually port 5173) can embed a localhost
API address for event streams, so it is not the target for these recipes.
The proxy must stream Server-Sent Events (SSE) on /api/watch and /api/heartbeat
without buffering or caching. --keep-alive prevents a dropped browser connection
from ending the review. difit has no built-in login: anyone who can reach the
service can access the review and its enabled actions. Use an authenticated proxy
for private repositories; HTTPS alone does not restrict access.
For ongoing remote reviews, use a named Cloudflare Tunnel
with a hostname such as review.example.com, routed to service type HTTP at
localhost:4966. Configure a Cloudflare Access policy for the intended reviewers
before exposing private code, and open the resulting HTTPS hostname. Keep /api/*
uncached and confirm live updates using the checks below.
For a temporary preview, an installed cloudflared can create a Quick Tunnel:
cloudflared tunnel --url http://localhost:4966Open the HTTPS URL printed by the command. However, Quick Tunnels do not support SSE, which difit uses for live updates. They are unsuitable for the full conversation workflow: a page loading and Copy working do not establish that replies or approval changes will update live. The URL is public unless access restrictions are configured.
With localtunnel, run a second process:
pnpm dlx localtunnel --port 4966 --local-host localhostOpen its printed HTTPS URL. This exposes the review through a third-party service; use non-sensitive diffs for a public preview. Verify streaming replies and updates before relying on a hosted tunnel for a review. Stop the tunnel when finished.
local-ip.sh provides DNS names for IP addresses. For example,
10-1-1-24.local-ip.sh resolves to 10.1.1.24. The reviewing device must be able to
reach that address; this does not create a tunnel or turn difit's HTTP server into
an HTTPS server.
Run a TLS reverse proxy on the repository machine. For example, with Caddy installed,
use this Caddyfile, replacing the address with that machine's LAN IP:
https://10-1-1-24.local-ip.sh:8443 {
tls internal
reverse_proxy localhost:4966
}Run caddy run --config Caddyfile, allow the reviewing device to reach port 8443,
and open https://10-1-1-24.local-ip.sh:8443. Caddy's tls internal uses a local CA;
install and trust its root certificate on each reviewing device before using the
page. Alternatively, configure a certificate trusted by those devices with Caddy's
tls directive.
Caddy streams SSE responses.
local-ip.sh also publishes a wildcard certificate and its private key. Because that key is public, use your own certificate for private code. The hostname alone, or bypassing a certificate warning, is not a substitute for trusted HTTPS.
Open the HTTPS page without a certificate warning, click Copy Prompt, and paste
into a text editor. For conversations, add --conversation when starting difit
and run difit comment watch --port 4966 on the repository machine. Submit a comment
from the remote browser, verify it appears in the local stream, then send a
reply and confirm it appears without refreshing.
Agent commands still connect to localhost on the repository machine; the browser
can use the HTTPS proxy. They do not acquire remote-host support from the URL.
# Install dependencies
pnpm install
# Start development server (with hot reload)
# This runs both Vite dev server and CLI with NODE_ENV=development
pnpm run dev
# Build and start production server
pnpm run start <target>
# Build for production
pnpm run build
# Run tests
pnpm test
# Run typecheck, lint, and format
pnpm run check
pnpm run formatpnpm run dev: Starts both Vite dev server (with hot reload) and CLI server simultaneouslypnpm run start <target>: Builds everything and starts production server (for testing final build)- Development mode: Uses Vite's dev server for hot reload and fast development
- Production mode: Serves built static files (used by npx and production builds)
- CLI: Commander.js for argument parsing with comprehensive validation
- Backend: Express server with simple-git for diff processing
- GitHub Integration: GitHub CLI (
gh pr diff --patch) for PR patch retrieval - Frontend: React 18 + TypeScript + Vite
- Styling: Tailwind CSS v4 with GitHub-like dark theme
- Syntax Highlighting: Prism.js with dynamic language loading
- Testing: Vitest for unit tests with co-located test files
- Quality: oxlint, oxfmt, lefthook pre-commit hooks
- Node.js ≥ 21.0.0
- Git repository with commits to review
- GitHub CLI (
gh) for--prmode
MIT
The optional --ship-it button uses a user-supplied LGTM screenshot from
this video. The image belongs to
its respective rights holders and is not covered by this project's MIT license.

