@diffohq/diffo
v0.3.0
Published
Local, live code review for the AI age — read what the agent wrote and send feedback straight back
Readme
Diffo
The human way to review agent-written code.
A live review on your machine, wired to the agent that wrote the code, so your comments come back as fixes.
Quick start · Why Diffo · Docs · Status · Contributing
Quick start
Requires Node >= 24 and git.
Have your agent set it up. Paste this into Claude Code, Cursor, Codex, or whichever agent you already use:
Run `npx skills add DiffoHQ/diffo --skill diffo -g` and open the diffo reviewOr install the skill yourself:
npx skills add DiffoHQ/diffo --skill diffo -gEither way, that's the whole install. Then, in any session, say:
"let's review that", or just
/diffo
The agent opens a live review of its own work and hands you the URL. Your comments arrive in its context, its replies land inline in your threads, and its fixes update the diff while you read. That is the clip above, with no URL to ask for.
You can also run the CLI straight out of a checkout, which is what contributors do:
git clone https://github.com/DiffoHQ/diffo.git && cd diffo
pnpm install && pnpm build
node dist/cli.mjs setup # or `node dist/cli.mjs` from any repo to review itNew here? Your first review, end to end takes about five minutes.
Why Diffo
We write code with an LLM. We review it alone.
Writing became a conversation: you and the model in the same window, trading context until the thing is right. Reviewing never did. The code lands, the conversation ends, and you go read four hundred lines by yourself, in a viewer built for a world where whoever wrote it had already moved on.
Diffo keeps the conversation open through the review. Ask what a hunk does and the agent that wrote it answers in the thread. Ask why, and it explains, with a diagram when the shape needs one. Ask for a change and it makes it, and the diff updates while you read. The judgement stays yours. You just stop reading alone.
What you get
A thread is a decision
Each comment is one small call: change this, explain that, leave it alone. Drop it on a line or drag down the gutter for a range of them. Mark it a Change or a Question and the agent is told which. The review is the sum of those decisions, not a verdict at the end.
Reading, not scrolling
Syntax-highlighted unified and split diffs, word-level marks, keyboard-first movement, context expansion, images side by side, lockfiles collapsed. The conventions are GitHub's, deliberately: a reviewer shouldn't have to learn a new diff.
Live while you iterate
Fixes land in the diff you are already reading. A hunk you had marked read says changed since you read it once it's edited, so the second pass stays honest.
Local
One process on your machine, bound to loopback. No account, no telemetry, no cloud, and nothing to configure.
It explains itself
On a change that's multi-file, structural, or just subtle, the agent opens the review with one orienting comment: a sentence on what the change does, plus a small mermaid diagram when the shape is easier to see than to read. It orients, and it never pre-reviews: no verdicts, nothing is "fine". That judgement is the part it doesn't get to make.
Where it fits
Diffo doesn't replace pull request review, and it isn't trying to. A pull request is how you hand finished work to someone else. Diffo is the step before that: the loop where you and the agent turn a first draft into something worth another person's time.
| | Diffo | Pull request review | AI reviewer bot | | --- | --- | --- | --- | | When | before the PR exists | after you push | after you push | | What it's for | getting the code right | getting it approved | catching the obvious | | Who you work with | the agent that wrote it | your teammates | nobody | | Where the code is | uncommitted, on your disk | pushed to a branch | pushed to a branch | | What comes out | code worth pushing | an approval and a record | a list of comments |
So they stack rather than compete: iterate here until the diff reads clean, then open the pull request you actually want reviewed. Your judgement is the scarce resource, and this is the stage where spending it changes the outcome.
How it works
The left half is a diff viewer. The right half is what Diffo is for: your comment doesn't land in a queue for later, it lands in the conversation that wrote the code, while that conversation still remembers why. Nothing needs to be committed, pushed, or opened as a PR first, so agent output is reviewable the moment it hits the disk, which is the moment it's cheapest to change.
| You want to review | Command |
| --- | --- |
| Uncommitted work in progress (the default) | diffo |
| Everything since you branched off main | diffo --base main |
| A pull request | not supported yet |
Docs
| | | | --- | --- | | Your first review | The whole loop end to end, about five minutes | | Getting started | Install, and where each agent gets wired | | The review loop | Reading, commenting, and what the agent receives | | How it works | The components and the server lifecycle | | The agent side | The agent protocol: every command, every payload | | Architecture | Diff pipeline, delivery queue, SQLite state | | CLI and Keyboard shortcuts | Reference | | FAQ | The short answers |
Under the hood
TypeScript on Node >= 24: a Hono server over loopback serving a React 19
UI, live updates over server-sent events from one recursive filesystem watch, and state in a
single SQLite file at ~/.diffo/diffo.db through the runtime's built-in node:sqlite, so
there is no database to install. Zero network calls. 1,000 tests across 57 files.
Reviews are scoped per repo and branch, and the server is loopback-only, rejecting
non-loopback Host and Origin headers so a web page can't reach into your repo through
it. The full walkthrough is in Architecture.
Every hunk carries a content-addressed id: a hash of its path and changed lines, and deliberately not its line numbers. That one decision is what makes the live review honest.
- Read marks survive a refresh, because an untouched hunk keeps its id.
- An edited hunk mints a new id, loses its mark, and says changed since you read it. You can't accidentally sign off on code you never saw.
- The ids from your last Finish are a complete record of what existed then, so "what moved since I last looked" is a set subtraction, needing no timestamps.
Open core
Everything in this repository is the core, and the core stays Apache-2.0: local review, the agent loop, the CLI, the Agent Skill. It works offline, for one reviewer, forever, for free.
A hosted team tier is planned: shared changesets, review history across a team, SSO. None of it exists yet, and none of it will take an existing core feature behind a paywall. The line we commit to: anything that runs on your machine for one reviewer is core.
Status
Diffo is pre-1.0: the loop below works end to end — this repo is reviewed with it daily — and the edges are still moving. What works today:
- [x] Live review of any changeset: the working tree, or anything since
--base. - [x] The comment loop: threads that reach the session that wrote the code.
- [x] One setup, every agent: Claude Code, Codex, Cursor, VS Code, Copilot CLI, Gemini CLI, Amp, Goose, OpenCode.
- [x] Reading tools: unified and split diffs, word-level marks, coverage tracking.
Contributing
Five gates, all of which CI runs, or pnpm check for all five:
pnpm typecheck && pnpm test && pnpm build && pnpm lint && pnpm docs:buildLocal development is pnpm dev (server and client together). One hard rule:
skills/diffo/SKILL.md is generated. Edit src/skill.ts and run
pnpm build:skill; a test fails if the committed file drifts. That rewrites the repo
file, not the skill your own agent runs — pnpm dev:skill --global installs a separate
/diffo-dev that drives your checkout, alongside the shipped /diffo.
Details in CONTRIBUTING.md, plus a Code of Conduct and the CHANGELOG. First-time contributors sign a CLA: a bot asks on your first pull request, and signing is one reply.
Found a security problem? Please don't open a public issue. The Security Policy says where to send it and what's in scope.
License & trademark
Diffo is open source under the Apache License 2.0, the whole of it, today. A Diffo Enterprise License exists but currently covers no files at all; it is written down so the open-core boundary is settled before it is needed, and it carries the commitment that nothing Apache-2.0 in a released version moves out of it later.
The Diffo name and logo are trademarks of Diffo: the license covers the code, not the name. Forks are welcome; ship them under your own name.
