@gitgot/cli
v0.1.0
Published
gitgot — local pre-PR diff review for humans and AI, with an MCP server for Claude Code
Downloads
15
Readme
gitgot
Local pre-PR review for humans and AI. Run gitgot review in a repo, get a GitHub-style diff UI at localhost, and an MCP server so Claude Code can read the diff and leave inline comments alongside yours — all before the branch ever leaves your machine.
npm package: gitgot
gitgot review · feature/tokens ← main
4 files · +17 −4 · 0 open threads
ui http://localhost:5599
mcp http://localhost:5599/mcp
claude mcp add --transport sse gitgot http://localhost:5599/mcpSetup
From npm:
npm install -g @gitgot/cli
gitgot connect # one-time: lets Claude Code use gitgot in every repo
gitgot reviewFrom a checkout:
npm install # also builds (prepare hook)
npm link # optional: puts `gitgot` on your PATHOr without linking, from any repo:
node /path/to/gitgot/dist/cli.js reviewnpm run dev runs gitgot review against this repo itself via tsx (no build step).
Usage
gitgot review # start server, open browser UI
gitgot review --base develop # diff against a different base branch
gitgot review --port 6000 # custom port (walks forward if taken)
gitgot review --no-open # don't open the browser
gitgot status # open threads for this branch, in the terminal
gitgot status --all # include resolved threads
gitgot connect # one-time Claude Code registration (all repos)The review diffs your working tree (staged + unstaged + committed) against merge-base(base, HEAD) — the same changes a PR against base would contain, but including what you haven't committed yet. Untracked files are not included. The base branch defaults to the last one used for this branch, then main, then master.
Multiple repos at once
Each repo gets a stable port derived from its path (5500–5899), so a repo's review URL never changes between runs — bookmark it. Running gitgot review again while a server is already up for the same repo + branch reopens the existing UI instead of spawning a duplicate (and tells you if the running server is an older version). Reviewing two repos simultaneously is just two servers on their two stable ports; the header and tab title show repo · branch so the tabs stay distinguishable. On the MCP side there is nothing to juggle at all — see below.
The UI
- Unified or split view (toggle in the header; unified is the default — it reads better for review-with-comments, split is there when you're comparing rewrites).
- Changed-file list on the left, grouped by directory, with per-file +/− counts and open-thread badges.
- Hover any line, hit
+to start a thread.⌘↵submits,Esccancels. - Threads can be replied to and resolved; resolved threads collapse to one line.
- Comments anchored to lines that have since left the diff show under "Outdated comments".
- The UI live-updates over SSE — when Claude posts a comment via MCP, it appears without a refresh.
Connecting Claude Code
Once, from anywhere:
gitgot connectThis registers gitgot with Claude Code at user scope via a stdio bridge (gitgot mcp). Claude Code launches the bridge inside whichever repo it's working in, and the bridge resolves that repo's diff and .got/ state from its working directory — so one registration covers every repo, two repos can be reviewed at the same time with zero port juggling, and Claude in repo A can never read repo B's review. New Claude sessions pick it up automatically; in a running session, type /mcp and reconnect. (The UI's sidebar footer has a copy button for the command.)
The bridge talks to git and .got/ directly, so Claude can read the diff and comment even when no UI server is running. When one is running, comments Claude posts appear in the browser live — the server watches the review state files for outside writes. The bridge re-resolves the current branch on every call, so it follows you across git checkouts. Base branch resolution matches the CLI (last used → main → master), or pin one at registration time with gitgot mcp --base develop.
Prefer a URL transport? The review server also speaks MCP over SSE (GET /mcp) and streamable HTTP (POST /mcp):
claude mcp add --transport sse gitgot http://localhost:<port>/mcpThen ask Claude to review: it can call get_summary → get_diff → add_comment, and you'll see its comments appear inline as it works. Your replies are visible to it through get_comments.
| Tool | Purpose |
| -------------- | ------------------------------------------------------------------------------------------------ |
| get_summary | Branch, base, merge base, changed files with +/− counts, thread counts |
| get_diff | Full unified diff, or one file's via file |
| get_comments | All threads with file/line/side, resolved state, and the anchored diff line text |
| add_comment | New thread (file + line + optional side) or reply (thread_id); author defaults to ai |
Comment anchors use side: new (default) counts line numbers in the current version of the file, old in the base version — use old to comment on deleted lines.
A smoke test for the MCP surface lives at scripts/mcp-smoke.mjs (npm run smoke with a server running).
State
Everything lives in .got/ at the repo root — plain, pretty-printed JSON you can cat:
.got/
.gitignore # contains "*" — .got ignores itself, your repo stays untouched
reviews/
<branch>/ # slashes in branch names become "__"
meta.json # { branch, base, createdAt, updatedAt }
comments.json # { threads: [{ id, file, line, side, resolved, comments: [...] }] }Reviews are per-branch, so switching branches and running gitgot review again gives you a separate thread set. Nothing ever leaves the machine; the server binds to 127.0.0.1.
Stack rationale
- Hono + @hono/node-server — tiny, typed routing with zero ceremony, and (the deciding factor) clean access to the raw Node
req/res, which the MCP SDK's HTTP transports need. Express would also work; Hono is lighter and faster to read. - @modelcontextprotocol/sdk — the official SDK. Hand-rolling JSON-RPC + SSE framing is a bug farm; the SDK also gave us both transport flavors (legacy SSE and streamable HTTP) on one endpoint for ~30 extra lines, so it works with either
claude mcp add --transport sseor--transport http. - Vanilla JS frontend, no build step — the UI is one diff viewer with comment threads. A framework would add a build pipeline, a dependency tree, and version churn to a tool whose whole job is to be cloned and run. ~600 lines of plain DOM code is well within the budget where vanilla stays maintainable, and the server just serves three static files.
- Diff parsing in-house (
src/diff.ts) —git diffoutput is a stable, documented format; parsing it is ~120 lines and means line-number/side semantics are exactly what the UI and MCP tools need, rather than adapting a third-party AST. - JSON files over SQLite — state is a handful of KB per branch, single-writer, and the spec's real constraint is inspectability.
cat .got/reviews/feature__x/comments.jsonbeats a SQLite shell for that; writes are atomic (tmp + rename). SQLite earns its place when there's concurrency or query needs — neither exists here. - TypeScript with
tscbuild +tsxfor dev — matches the existing stack; no bundler needed for a CLI.
