Repository navigation
With AI coding agents
When an AI coding agent changes code with you, the useful question is what it did to the system. system-diff answers it after every turn, in one line, in a live picture, and through MCP tools the agent can call. You mark what you have understood, and from then on you see only what is new.
pipx install system-diff
pipx inject system-diff mcp # the MCP server's one dependency
system-diff setup claude # for every project; --scope project (shared) or --scope local (you, this repo)setup claude prints each change it makes:
- a Stop hook in Claude Code's settings (
~/.claude/settings.json; with--scope project,.claude/settings.json; with--scope local,.claude/settings.local.json). It runssystem-diff hookafter each turn; - a skill (
~/.claude/skills/system-diff/SKILL.md, or.claude/skills/in the repository) that tells the agent when to show the system diff and how to explain it; - the MCP server, registered with
claude mcp addin the same scope.
Your own hooks and settings are kept. Running it twice changes nothing, and system-diff setup claude --undo removes
exactly what it added.
- You and the agent change code.
- After the turn, the hook shows one line: System diff since checkpoint: Adds 1 endpoint (DELETE /api/orders/{id}); changes 1 table (public.orders). When nothing structural changed, it says nothing.
-
system-diff watchserves http://127.0.0.1:8765/, which redraws as files change. Open it beside the editor (in VS Code: Simple Browser: Show). - Ask the agent to explain. It calls
system_diffand answers from the exact plan. - Press Mark as seen (or run
system-diff checkpoint, or ask the agent to callcheckpoint). The next diff starts from there.
The hook answers Claude Code with {"systemMessage": "…"}, which Claude Code's hooks documentation describes as a
message shown to the user; plain output of a Stop hook only reaches the debug log. To check that it runs, type /hooks
in Claude Code, or start it with claude --debug. The hook always exits 0 and has a 30-second timeout, so it can
never hold up the end of a turn.
- The working tree is read as a snapshot: a commit made with a temporary index, so untracked files count and ignored ones do not. Your index, HEAD and branches do not change.
- The checkpoint is such a snapshot, kept under
refs/system-diff/checkpoint. It is local to your clone and never pushed. Before your first checkpoint, the diff starts from HEAD.
| Tool | What it returns |
|---|---|
system_diff(base="checkpoint", head=".") |
the headline, the exact plan with each line's impact, the number of changes, and the picture's path (under .git/system-diff/) |
system_map(ref=".") |
the parts by column, the connections, counts of entry points and tables, the outside systems, and the picture's path |
draw(spec, name) |
a map, stages or sequence picture from a typed spec (the schema shows every field), or what is wrong with the spec |
checkpoint(ref="") |
marks the working tree (or ref) as seen; the skill tells the agent to call it only when you say so |
Any MCP client can run the server: the command is system-diff mcp (stdio).
- The live page listens on 127.0.0.1 only. "Mark as seen" needs the page's own token, so another web page open in the same browser cannot press it.
- The hook and the tools read the repository; they write only under
.git/system-diff/andrefs/system-diff/. - The optional LLM summary (
diff --narrate) sends the headline, the plan and the commit messages, never the code.