Interactive git diff learning tool with LLM-powered explanations
DiffLearn helps developers understand code changes through an interactive terminal UI with AI-powered explanations. Navigate diffs with keyboard controls, click on changes to ask questions, and get instant AI insights.
- π¨ Interactive Diff Viewer - Red/green syntax highlighting with keyboard navigation
- π¬ Click-to-Ask - Select any change and ask questions about it
- π Unified Dashboard - View local, staged, and history on one screen in the terminal
- π Commit Comparison - Select any two commits in Web or CLI to see and analyze the diff between them
- π Remote Web UI - Beautiful local web interface with comparison support and AI chat
- π Use Your Subscriptions - Works with Gemini CLI, Claude Code, Cursor (no API fees!)
- π€ API Support - Native support for OpenAI, Anthropic, and Google AI APIs
- π MCP Server - Full integration with Cursor, Claude Code, and other MCP clients (stdio and stateless Streamable HTTP, MCP spec
2026-07-28) - π Multi-Repo - Point DiffLearn at any local clone with
--repo/$DIFFLEARN_REPO, or a per-requestrepoargument β nocdrequired - β¨οΈ Keyboard First - Full scrolling and windowing support for large diffs and histories
- CPU Time is fairly lower on the GO version compared to the Typescript version (it is also far less interactive):
- Memory consumption has a huge difference, if I were in a resource constraint machine GO would be my go to:
- Disk usage, I do not know why it is higher as I did the same thing... maybe it just node doing node things?
curl -fsSL https://raw.githubusercontent.com/lertsoft/DiffLearn/master/install.sh | bash# Clone and install
git clone https://github.com/lertsoft/DiffLearn.git
cd DiffLearn
bun install
# Run directly
bun run dev
# Or install globally
bun link# Clone and install
git clone https://github.com/lertsoft/DiffLearn.git
cd DiffLearn
bun run dev
# Launch web UI
bun run web
# Run tests
bun test
# Run lint
bun run lint
# Auto-fix lint
bun run lint:fix# π Launch the Web UI (recommended!)
difflearn web
# Terminal: View local changes interactively
difflearn local
# View staged changes only
difflearn local --staged
# Compare commits
difflearn commit abc123
difflearn commit abc123 --compare def456
# Compare branches
difflearn branch main feature/new-auth
# Quick AI explanations (non-interactive)
difflearn explain
difflearn review
difflearn summary
# Interactive Compare
difflearn local # Use Tab to switch to History, then Enter to select
difflearn web # Click '+' buttons next to commits to compare two SHAsDiffLearn is designed to jump between the many repos you've downloaded from GitHub, GitLab, etc. without changing directories:
# Point any command at a specific repo
difflearn --repo ~/code/some-clone local
difflearn -C ~/code/another-repo history -n 20
difflearn --repo ~/code/some-clone web # serve the web UI for that repo
# Or set a default for the session
export DIFFLEARN_REPO=~/code/some-clone
difflearn explainThe web/API server and MCP server can also serve many repos at once: pass a
?repo=/abs/path query param to REST endpoints, or a repo argument to any MCP tool.
HTTP callers are limited to the default repo and its descendants unless you explicitly
allow more roots with DIFFLEARN_ALLOWED_REPO_ROOTS (colon-separated on macOS/Linux,
semicolon-separated on Windows).
The API/web server and the HTTP MCP server hand out the contents of local repositories, can check out branches, and can spend your LLM credits, so both are locked down to your machine by default:
- Loopback only. They bind
127.0.0.1, not every interface. - Origin validation. Browser requests are only accepted from loopback
origins, so a page you merely visit cannot drive the server β including via
DNS rebinding, where an attacker's hostname resolves to
127.0.0.1but theOriginheader still gives them away. Non-browser clients (curl, MCP clients, the CLI) send noOriginand are unaffected. - Repo allowlisting. HTTP callers can only reach the default repo and its
descendants unless you widen
DIFFLEARN_ALLOWED_REPO_ROOTS.
| Variable | Purpose |
|---|---|
DIFFLEARN_HOST |
Address to bind. Set 0.0.0.0 to expose a server on your network. |
DIFFLEARN_ALLOWED_ORIGINS |
Comma-separated browser origins to allow in addition to loopback. * disables the check. |
DIFFLEARN_ALLOWED_REPO_ROOTS |
Extra directory roots HTTP callers may read repos from. |
Exposing a server beyond loopback means anyone who can reach it can read those
repositories, so pair DIFFLEARN_HOST with an explicit origin allowlist and
your own authentication in front.
The Web Interface (difflearn web) is fully accessible and keyboard-friendly:
| Key | Action |
|---|---|
s/j/β |
Select next commit in list |
w/k/β |
Select previous commit in list |
Enter |
Select currently focused commit / Confirm comparison |
a/β |
Switch to previous view (e.g. History β Staged) |
d/β |
Switch to next view (e.g. Local β Staged) |
/ |
Focus Chat Input |
Esc |
Close panels / Exit comparison mode |
+ (Web) |
Click the '+' button next to commits to select for comparison (max 2) |
| Key | Action |
|---|---|
Tab |
Switch between Local Changes, Staged Changes, and History |
β/β |
Navigate history list or scroll long AI responses |
Enter |
View diff for selected commit or file |
/ / i |
Focus AI Chat input |
Esc |
Exit chat/scrolling mode back to dashboard |
q |
Quit or go back from current view |
c (Chat) |
Clear current chat history |
| Command | Description |
|---|---|
/explain |
Get AI explanation of current changes |
/review |
Get AI code review with suggestions |
/summarize |
Get a quick summary of changes |
/update |
Check for updates |
/export |
Export diff as markdown |
/web |
Open web UI in browser |
/config |
Show LLM configuration status |
The easiest way to configure DiffLearn is with the interactive wizard:
difflearn configThis will:
- Show available providers (CLI-based and API-based)
- Guide you through authentication
- Save configuration securely to
~/.difflearn
Use your existing AI subscriptions without extra API costs:
| Provider | Requirement |
|---|---|
| Gemini CLI | Install gemini-cli |
| Claude Code | Install claude |
| OpenAI Codex | Install codex |
| Cursor | Install Cursor CLI |
Login commands (provider-specific):
# Gemini CLI (interactive login selection)
gemini
# Claude Code (interactive, then type /login)
claude
# OpenAI Codex
codex login
# Cursor CLI
agent login# Check which providers are available
difflearn config --status
# Example: Use Gemini CLI
export DIFFLEARN_LLM_PROVIDER=gemini-cliRun AI locally on your machine with no API costs and full privacy:
| Provider | Default URL | Setup |
|---|---|---|
| Ollama | localhost:11434 |
Install Ollama + ollama pull llama3.2 |
| LM Studio | localhost:1234 |
Install LM Studio + start local server |
The easiest way to configure is with the wizard, which detects your downloaded models:
difflearn config
# Select Ollama or LM Studio, then choose from your available modelsOr set environment variables directly:
# Use Ollama
export DIFFLEARN_LLM_PROVIDER=ollama
export DIFFLEARN_MODEL=llama3.2
# Use LM Studio
export DIFFLEARN_LLM_PROVIDER=lmstudio
# Custom base URL (if not using default port)
export DIFFLEARN_BASE_URL=http://localhost:8080/v1For direct API access (pay-per-use):
# Option 1: OpenAI (default)
export OPENAI_API_KEY=sk-...
# Option 2: Anthropic
export ANTHROPIC_API_KEY=sk-ant-...
export DIFFLEARN_LLM_PROVIDER=anthropic
# Option 3: Google AI
export GOOGLE_AI_API_KEY=...
export DIFFLEARN_LLM_PROVIDER=google
# Optional: Custom model
export DIFFLEARN_MODEL=gpt-4o-miniDiffLearn stores config in ~/.difflearn:
# ~/.difflearn
DIFFLEARN_LLM_PROVIDER=gemini-cli
OPENAI_API_KEY=sk-...Environment variables override the config file.
Note: DiffLearn works without an API key! When no LLM is configured, it outputs formatted prompts you can use with any AI tool.
DiffLearn ships two MCP transports:
- stdio β the widely-supported classic transport, backed by the official
@modelcontextprotocol/sdk. - Stateless Streamable HTTP β implements the
2026-07-28MCP spec: noinitialize/session handshake,MCP-Protocol-Version+Mcp-Method/Mcp-Nameheader routing, an optionalserver/discoverRPC, and cacheable (ttlMs/cacheScope) list results. Any request can land on any instance behind a plain load balancer.
Add to your MCP configuration:
{
"mcpServers": {
"difflearn": {
"command": "bun",
"args": ["run", "/path/to/DiffLearn/src/mcp/server.ts"]
}
}
}# Start the stateless Streamable-HTTP MCP server (default port 3333)
difflearn serve --mcp-http -p 3333
# Discover capabilities (no handshake required)
curl -s http://localhost:3333/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-H 'MCP-Protocol-Version: 2026-07-28' \
-H 'Mcp-Method: server/discover' \
-d '{"jsonrpc":"2.0","id":1,"method":"server/discover"}'
# Call a tool against a specific repo
curl -s http://localhost:3333/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-H 'MCP-Protocol-Version: 2026-07-28' \
-H 'Mcp-Method: tools/call' -H 'Mcp-Name: get_local_diff' \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"get_local_diff","arguments":{"repo":"/abs/path/to/repo","format":"markdown"}}}'Every tool accepts an optional repo argument (absolute path) so one server can serve many repos.
get_local_diff- Get uncommitted changesget_commit_diff- Get diff for a commitget_branch_diff- Compare branchesget_commit_history- List recent commitsexplain_diff- AI explanation of changesreview_diff- AI code reviewask_about_diff- Ask questions about changes
All GET endpoints accept an optional ?repo=/abs/path query param; POST bodies accept a repo field β so one server can serve diffs from many local repos.
# Start API server
difflearn serve --api --port 3000
# Endpoints (append ?repo=/abs/path to target another local repo)
GET /diff/local # Local changes
GET /diff/commit/:sha # Single commit or comparison (using ?compare=sha2)
GET /diff/branch/:b1/:b2 # Branch diff
GET /history # Commit history with windowing support
POST /explain # AI explanation (supports commit/staged/compare)
POST /review # AI code review (supports commit/staged/compare)
POST /ask # Ask questions (supports commit/staged/compare)
POST /summary # Quick summary (supports commit/staged/compare)| Command | Description |
|---|---|
local [--staged] |
View local changes interactively |
commit <sha> [--compare <sha2>] |
View commit diff |
branch <b1> <b2> |
Compare branches |
explain [--staged] |
AI explanation |
review [--staged] |
AI code review |
summary [--staged] |
Quick summary |
export [--format json|markdown] |
Export diff |
history [-n count] |
List commits |
web [-p port] |
Launch the web UI |
config [--status] |
Configure LLM provider |
serve --mcp|--mcp-http|--api |
Start MCP (stdio/HTTP) or REST/Web server |
Global option:
-C, --repo <path>works on every command to target a specific local repository (falls back to$DIFFLEARN_REPO, then the current directory).
src/
βββ cli/
β βββ index.tsx # CLI entry point
β βββ components/
β βββ App.tsx # Main app component
β βββ DiffViewer.tsx # Interactive diff viewer
β βββ ChatPanel.tsx # Q&A chat panel
βββ git/
β βββ extractor.ts # Git operations
β βββ parser.ts # Diff parsing
β βββ formatter.ts # Output formatting
β βββ repo.ts # Multi-repo path resolution + cached extractors
βββ llm/
β βββ client.ts # LLM providers
β βββ prompts.ts # Prompt templates
βββ mcp/
β βββ server.ts # MCP server (stdio, official SDK)
β βββ http.ts # Stateless Streamable-HTTP MCP server (spec 2026-07-28)
βββ api/
βββ server.ts # REST API
MIT
