diffle
Keyboard-first git diff reviewer with LSP and GitHub comments
TLDR
SYNOPSIS
diffle [options] [revs...]diffle working [options]diffle show [rev] [options]diffle pr [number|url] [options]diffle range-diff ranges... [options]diffle config subcommand [args]diffle lspdiffle completion --shell bash|zsh|fish
DESCRIPTION
diffle reviews a git diff in a local browser UI. It starts an HTTP server (default 127.0.0.1:4966, or the next free port), opens a tab, and lets you comment on lines, blocks, or whole files with keyboard shortcuts. Closing the last auto-opened tab stops the server and prints the open comments on stdout as a prompt for an agent. Ctrl+C always stops it.The npm package is @moritzwilksch/diffle (command diffle). The published version is 0.2.4. The npm package needs Node.js 24 or newer. A standalone binary install needs no Node: `curl -fsSL https://diffle.app/install.sh | sh` writes to `~/.local/bin`. pixi global install diffle and nix run github:moritzwilksch/diffle are the same CLI.Without revisions, diffle compares HEAD..worktree, like a bare `git diff`. A lone revision compares from the merge base (`diffle main` is `main...HEAD`). `worktree` names the uncommitted tree on either side of a revspec. pr needs a GitHub token. A PR from another repository opens in a temporary clone.Comments live under \<git-dir\>/diffle/ and never touch the worktree. They follow their text as the code changes and go stale once it leaves the diff. Generated files start collapsed when `.gitattributes` marks them `linguist-generated`. The pull-request icon adds open threads to a pending GitHub review; diffle never submits it.Language servers start for languages in the diff when a matching program is on PATH. Symbol navigation needs the new side of the comparison to be the checkout. Language servers run through a shell inside the repository and can read anything the user can.
PARAMETERS
-C path
Run as if started in path (any directory inside a git worktree)-p, --port port
Port to listen on. Default 4966, or the next free one. 0 picks a random port-H, --host host
Address to bind. Default 127.0.0.1. Use 0.0.0.0 to expose on the network--allowed-origin origin
Trusted public HTTP(S) origin behind a reverse proxy, without a path (for example `https://proxy.example`)--no-open
Do not open a browser--keep-alive
Keep the server running after all browser tabs close--no-watch
Do not watch the worktree or refs for changes--auto-viewed glob
Mark matching files viewed for this session (repeatable)-U, --context n
Context lines around changes for this session (0–10000). Default from config, 5--lsp language=command
Language-server command for one language for this run (repeatable). Default: the diff's languages, resolved on PATH--no-lsp
Do not start any language server--timing
Print startup phase timings to stderr--dev
Serve the client through Vite (development). Also on when DIFFLE_DEV=1-v, --version
Print the version and exit-h, --help
Print usagerevs...
Git-diff style revisions: `<rev>`, `<a>..<b>`, `<a>...<b>`, or `<a> <b>`. Without them, HEAD..worktree
CONFIGURATION
$XDG_CONFIG_HOME/diffle/config.json
User config (default `~/.config/diffle/config.json`). Machine-wide, not per repository. Mode 0600. The same settings appear in the UI dialog. diffle config reads and writes this fileautoViewed
Picomatch globs for files that start viewed and collapsed. Empty by defaultcontextLines
Unchanged lines shown around each change (`git -U`). Default 5followRefs
on, auto, or off. Default autolspCommands
Per-language shell commands that start a stdio language server. An empty value turns that language off. Unknown language keys are ignored\<git-dir\>/diffle/
Per-repository comment store. Does not modify the worktree
COMMANDS
working
Same as `HEAD..worktree`: uncommitted changes, staged and untracked included. Hidden shorthand; listed in help as a revspec shortcutshow [rev]
One commit against its first parent, as `git show` shows it (`<rev>^!`). Default HEADpr [number|url]
A GitHub pull request as GitHub shows it: merge-base(base, head) vs head. Without an argument, the pull request for this branchrange-diff ranges...
How one series of commits became another, as `git range-diff` shows it: `<a>..<b> <c>..<d>`, `<base> <b> <d>`, or `<b>...<d>`config show
Print the config file path and contents (default subcommand of config)config add-auto-viewed glob...
Add picomatch patterns for files that start viewed and collapsed (for example `*.lock`)config remove-auto-viewed glob...
Remove auto-viewed patternsconfig set-context n
Set context lines around changes (0–10000)config set-follow-refs on|auto|off
When a review between refs recomputes as those refs move. on: reload at once. auto (default): wait for Reload when an endpoint names a branch. off: offer a Reload buttonconfig set-lsp language command
Set the stdio language-server command for one language. An empty command turns that language offconfig unset-lsp language...
Drop language-server overrides so those languages resolve on PATH againlsp
Print the language server each known language would get, and what is missing from PATHcompletion --shell shell
Print a standalone completion script for bash, zsh, or fish. The script does not start Node; rerun after upgrading
ENVIRONMENT
GITHUB_TOKEN / GH_TOKEN
GitHub token for diffle pr and exporting threads. If both are unset, a signed-in gh token is used. Without a token, everything except GitHub still worksGITHUB_API_URL
GitHub API base URL (for example in Actions, or another GitHub instance)XDG_CONFIG_HOME
Config directory. Default `~/.config`DIFFLE_INSTALL_DIR
With `install.sh`, install directory. Default `~/.local/bin`DIFFLE_VERSION
With `install.sh`, pin a tagged release (for example `v0.1.9`)DIFFLE_DEV
When 1, serve the client through Vite, same as --devNO_COLOR
Disable ANSI colors on stderr
CAVEATS
The review UI is a local web app, not a terminal TUI. Status goes to stderr so stdout can carry the comment prompt on shutdown.diffle pr and GitHub export need a token. Export works only when the comparison matches the PR's committed diff: unpushed commits and worktree changes rule it out. Stale threads are skipped. Diffle adds threads to a pending review and never submits it.Language servers run with the user's permissions inside the repository. --no-lsp starts none. Symbol navigation is off when the new side is not the checkout.The npm package requires Node.js 24 or newer. The standalone binary does not. Completions are static: rerun diffle completion after an upgrade. Revisions do not complete.Behind a reverse proxy, strip the path prefix (including WebSocket upgrades at `/diffle/ws`) and pass --allowed-origin. A rejected request returns 403 naming the header that failed.
HISTORY
diffle is an Apache-2.0 project by Moritz Wilksch. First tagged releases appeared in September 2026. Version 0.2.0 (6 October 2026) made ref comparisons reload on request instead of recomputing them automatically. 0.2.4 was released on 7 October 2026. The UI is inspired by difit; diffs are rendered with @pierre/diffs.
SEE ALSO
git-diff(1), git-show(1), git-range-diff(1), git-difftool(1), gh(1), delta(1), difft(1)
