diff-tour
Walk through a diff the way a senior engineer reads it.
English | 日本語
A tour of a branch that adds coupons: what the change is for, how the usage limit is enforced, a question to think about, and the answer: applying a coupon twice to one order uses it up twice.
Note
diff-tour is an early release. The tour format and the screens may still change.
Quick start
You need git and one of Claude Code, Codex CLI or Gemini CLI, signed in.
curl -fsSL https://raw.githubusercontent.com/init-co-jp/diff-tour/main/install.sh | sh cd your-repo tour
Then it goes like this:
- Setup (first time only): choose the display language and the LLM that writes the tour. Both have a recommended choice selected, so press Enter twice.
- Pick a change: the changes you can tour are listed, with your current branch selected. Press Enter.
- Writing: the LLM writes the tour. This takes 2 to 5 minutes.
- The tour: → goes forward, ← goes back, q quits.
If tour is not found, add the line the install script printed to your shell profile.
Other ways to install are in Install, and an example repository to try is in First run.
What it is
AI can write code that works. It does not teach you why the code is written that way, or what a reviewer would worry about.
tour turns a git change into a guided tour you step through with two keys, → and ←. The tour shows what a senior engineer looks at when they read the change:
- How they read it. What the change is for, where to spend time, and which files to jump to next, including files that did not change.
- What they ask. Does it keep the promises the old code kept? What happens when something fails, or runs twice? Can it be rolled out and rolled back safely? Who can call it, and with what input? What happens at 100 times the data? Is the next change easier or harder? Would the tests fail if the code broke?
- How they judge. Which findings must be fixed and which are only suggestions or nits, what looks risky but is fine and why, what is done well, and whether the change makes the codebase better overall.
- Where they stop and say "wait". These come as questions, so you can predict the answer before you see it.
This view comes from what experienced engineers have written down about reading and reviewing code, collected in internal/generate/lessons (in Japanese). The LLM reads it before every tour.
The tour is written by an LLM you already use: Claude Code, Codex CLI or Gemini CLI. tour is read-only. It never changes your files or your repository.
How it works
your repository cache directory (deleted after writing)
─────────────── ──────────────────────────────────────
git archive <base> ──────────────────▶ base/ files before the change
git archive <head> ──────────────────▶ head/ files after the change
git diff ──────────────────▶ change.diff
git log ──────────────────▶ commits.txt
(built into tour) ──────────────────▶ lessons/ what senior engineers have learned
│
▼
Claude Code / Codex / Gemini, started in that directory
with read-only permissions. It reads, then writes the
tour as JSON.
│
▼
tour checks every file and line the JSON points to. If something is wrong,
it asks the LLM to fix only that (up to 2 times). The tour is saved.
│
▼
tour shows the tour. The code on screen is read from git at the right commit,
never copied from the LLM's reply.
- Export.
tourreads your repository withgit archive,git diffandgit log, and writes the files into a new directory in your cache. Only files that git tracks are exported. When you tour uncommitted changes, untracked files that are not ignored are exported too. Files in.gitignore, such as.env, are never exported. - Write.
tourstarts the LLM's command-line tool in that directory with a fixed prompt and read-only permissions (see below). This takes 2 to 5 minutes, and the screen shows which files the LLM is reading. - Check. The tour is JSON that points to files and line numbers.
tourchecks that each one exists, and sends mistakes back to the LLM to fix, at most twice. - Show. Code, diffs and schemas on screen come from git, so the code you see is always the real code at that commit. Code that is not in the repository, such as a naive version or a possible fix, is always labeled Example.
The export directory is deleted once the tour is written. The finished tour is saved in your cache, so opening it again is instant.
What the LLM can and cannot do
Sending your code to an LLM is a real decision, so here is exactly what happens.
Sent to the LLM you chose:
- the files of your repository at the two commits being compared, the diff, and the commit messages. Only tracked files, plus untracked files that are not ignored when you tour uncommitted changes
- the prompt in
internal/generate/prompts - when you press ?: your question and the whole tour, with the same files
They go to the provider of that tool (Anthropic, OpenAI or Google), under the terms of your account with them. tour itself makes no network requests, has no server, and collects no telemetry.
Not possible for the LLM:
- reading files outside the export directory, including your real working tree,
.gitand your home directory - reading files ignored by
.gitignore, because they are never exported - writing, editing or deleting any file
- running commands that change anything, or reaching the network
- using MCP servers, plugins, extensions or web search
This is enforced by the flags tour passes to each tool, not only by the prompt.
Claude Code: tools limited to Read, Grep and Glob
claude -p --restricted --strict-mcp-config --tools Read,Grep,Glob
--permission-mode dontAsk --permission-prompts none --no-session-persistence
--restrictedremoves the command and web tools, and keeps file tools inside the working directory--strict-mcp-configloads no MCP servers--tools Read,Grep,Globleaves only the three read-only tools--permission-mode dontAskrefuses anything that would need permission, without asking--no-session-persistencesaves no session
Source: internal/generate/claude.go
Codex CLI: a sandbox that can only read the export directory
Codex reads files by running commands such as cat and rg, so the protection is the sandbox those commands run in. tour defines its own permission profile on the command line. Commands may read the export directory and system paths such as /usr and /etc. Nothing is writable, and the network is off.
--ignore-user-configand--ignore-rulesskip your~/.codexsettings and rules, so your MCP servers and plugins are not loaded-c approval_policy="never"makes blocked actions fail instead of asking-c web_search="disabled"and--disablefor apps, plugins, multi_agent, browser_use and others remove web search, connectors, sub-agents and browser tools--ephemeraland-c history.persistence="none"save no session or history
Tested on Linux, where Codex uses bubblewrap. On macOS, Codex uses its Seatbelt sandbox instead, which is not tested yet.
Source: internal/generate/codex.go
Gemini CLI: an admin policy that allows only four read tools
--admin-policypoints to a temporary file that allowsread_file,glob,grep_searchandlist_directoryonly inside the export directory, and denies every other tool. Admin policies take priority over your own policies.- Temporary settings in the export directory register only those four tools, and turn off MCP discovery, sub-agents, hooks, checkpoints and telemetry.
--extensions noneloads no extensions.--allowed-mcp-server-namesis set to a name no server has, so no MCP server starts.
Gemini CLI always saves the session to ~/.gemini/tmp, and deletes it after 30 days by default. This cannot be turned off from the command line.
Source: internal/generate/gemini.go
The LLM still reads your code, so text in the code can try to steer what it writes (prompt injection). With these permissions it cannot act on that. Still, a tour is an explanation, not a guarantee: check what it says against the code it shows.
Install
macOS and Linux
curl -fsSL https://raw.githubusercontent.com/init-co-jp/diff-tour/main/install.sh | shThis downloads the latest release for your OS and CPU, checks it against checksums.txt, and puts tour in ~/.local/bin. If that directory is not on your PATH, it prints the line to add. To choose the place or the version:
curl -fsSL https://raw.githubusercontent.com/init-co-jp/diff-tour/main/install.sh | TOUR_INSTALL_DIR=/usr/local/bin TOUR_VERSION=v0.1.0 shWith Go 1.27 or later (any OS)
go install github.com/init-co-jp/diff-tour/cmd/tour@latest
This puts tour in $(go env GOPATH)/bin, usually ~/go/bin.
Windows (PowerShell; not tested on Windows yet)
$tag = (Invoke-RestMethod https://api.github.com/repos/init-co-jp/diff-tour/releases/latest).tag_name $zip = "diff-tour_$($tag.TrimStart('v'))_windows_amd64.zip" $dir = "$env:LOCALAPPDATA\Programs\tour" Invoke-WebRequest "https://github.com/init-co-jp/diff-tour/releases/download/$tag/$zip" -OutFile "$env:TEMP\$zip" Expand-Archive "$env:TEMP\$zip" -DestinationPath $dir -Force [Environment]::SetEnvironmentVariable("Path", [Environment]::GetEnvironmentVariable("Path", "User") + ";$dir", "User")
Open a new terminal afterwards. On ARM, use windows_arm64.
Check the install with tour --version.
First run
You need git and one of these, installed and signed in:
| LLM | Check | Sign in |
|---|---|---|
| Claude Code | claude --version |
run claude once |
| Codex CLI | codex --version |
codex login |
| Gemini CLI | gemini --version |
run gemini once |
Gemini CLI support is experimental. Its read-only setup was tested against the real Gemini CLI, but a full tour has not yet been written with a real Gemini model. If it fails, please open an issue.
Then, in a repository:
cd your-repo
tourThe first time, tour asks for the language (detected from your terminal) and the LLM. Then it lists the changes you can tour. Your current branch is already selected, so press Enter.
To try it without your own code, use the example repository from the GIF:
git clone https://github.com/init-co-jp/diff-tour-example
cd diff-tour-example
git checkout feature/coupons
tourChoosing what to tour
| Command | Tours |
|---|---|
tour |
a branch you pick from a list, compared with the default branch. If you have uncommitted changes, the current branch with them comes first |
tour <branch> |
that branch, e.g. feature/x, or origin/feature/x to review someone else's branch |
tour <commit> |
that single commit |
tour <base>..<head> |
that range |
tour <file>.json |
a saved tour file, e.g. tours/example-coupons.en.json |
tour setup |
choose the language and the LLM again |
Keys
| Key | Action |
|---|---|
| → Space Enter | Next step |
| ← Backspace | Previous step |
| ? | Ask about this step: pick a suggested question or type your own. The answer becomes the next step |
| o | Open the code of this step in your editor |
| ↑ ↓ | Scroll, when a step does not fit on the screen |
| q | Quit |
What a step can show
- code and diffs, read from git at the right commit, with syntax highlighting
- code that is not in the repository, such as a naive version or a possible fix, labeled Example
- flow and timeline diagrams
- database schemas before and after the change, computed by applying the migrations to an in-memory SQLite database (SQLite migrations only for now)
- tables of example data
- questions to think about before the answer appears on the next step
- answers to your own questions about a step, saved with the tour (when you play a tour file, they last only until you quit)
Every explanation is labeled with how it is known:
| Label | Meaning |
|---|---|
| Verified | backed by code, tests or commit messages in this repository |
| From the code | inferred from how the code is structured |
| Senior view | general design judgment, not checked against this repository |
Configuration
| Linux | macOS | Windows | |
|---|---|---|---|
| Settings | ~/.config/tour/config.json |
~/Library/Application Support/tour/config.json |
%AppData%\tour\config.json |
| Saved tours | ~/.cache/tour/tours/ |
~/Library/Caches/tour/tours/ |
%LocalAppData%\tour\tours\ |
On Linux, XDG_CONFIG_HOME and XDG_CACHE_HOME are respected. The cache is safe to delete. Tours are written again when needed.
Editor. o uses $VISUAL or $EDITOR, and knows how to jump to a line in vim, Neovim, Emacs, nano, VS Code, Cursor, Zed, Helix, Sublime Text and others. For any other editor, set a template:
export TOUR_EDITOR='code -g {file}:{line}'
If the file on disk differs from the commit being toured, tour opens a read-only copy from the cache instead, so you see the code the tour talks about.
Language. English and Japanese. tour setup changes it, and tour --lang ja changes it for one run.
FAQ
How much does a tour cost? It runs on your own Claude Code, Codex or Gemini plan. With Claude Code, one tour of a change of about 250 lines used the equivalent of $1.00 to $1.50 at API prices. Opening a saved tour again costs nothing.
Why does it take minutes? Before writing, the LLM reads the files around the change, not only the diff. That reading is what lets the tour explain code that did not change.
Can I share a tour?
Yes. A tour is a JSON file in the cache directory, and anyone with the same repository can open it with tour <file>.json.
When is tour not the right tool?
For a one-line fix, reading the diff is faster. tour is for changes where the "why" is not obvious from the diff: new features, refactors, and code written by AI that you are now expected to own.
Development
go test ./...
go run ./cmd/tour tours/example-coupons.en.json --repo path/to/diff-tour-example --dump --cols 140 --rows 44 --plain--dump prints every step at a fixed screen size, which is handy for checking layouts without a terminal. demo/ records the GIFs, and experiments/generate has the notes from tuning the prompts.
