@diffohq/diffo 0.7.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/README.md +79 -204
  2. package/dist/cli.mjs +462 -4
  3. package/dist/client/assets/{abnfDiagram-O67JEVCF-1LPV7Bta.js → abnfDiagram-O67JEVCF-Dh4is2Nj.js} +1 -1
  4. package/dist/client/assets/{arc-B6fobjtY.js → arc-CMN0Gb1g.js} +1 -1
  5. package/dist/client/assets/architecture-7GRP2DOG-DaIFNiR2.js +1 -0
  6. package/dist/client/assets/{architectureDiagram-NJMV4G6O-CTN0gguk.js → architectureDiagram-NJMV4G6O-DxVGDSE1.js} +1 -1
  7. package/dist/client/assets/{blockDiagram-BEXU5L5S-DTR5PHKV.js → blockDiagram-BEXU5L5S-T1F9hSwZ.js} +1 -1
  8. package/dist/client/assets/{c4Diagram-YGBWAQC7-NGxq4JmF.js → c4Diagram-YGBWAQC7-DC6zwYuX.js} +1 -1
  9. package/dist/client/assets/channel-Ci5ZF5xD.js +1 -0
  10. package/dist/client/assets/{chunk-3FUC2YCW-DA-Lgw5Q.js → chunk-3FUC2YCW-D0PAoCRl.js} +2 -2
  11. package/dist/client/assets/{chunk-5DYCD2WN-DcE0aMs7.js → chunk-5DYCD2WN-NqHzOtt0.js} +1 -1
  12. package/dist/client/assets/{chunk-742MDFTN-CyTGvDWd.js → chunk-742MDFTN-B9Y5HHB7.js} +1 -1
  13. package/dist/client/assets/{chunk-7INBJB4K-Dd4mQ9Jx.js → chunk-7INBJB4K-CBOWlj91.js} +1 -1
  14. package/dist/client/assets/{chunk-7M6MHVWA-CTU7JU3x.js → chunk-7M6MHVWA-D2dZ_rQI.js} +1 -1
  15. package/dist/client/assets/{chunk-7PRAP22T-BF_GNhON.js → chunk-7PRAP22T-7dilu8x-.js} +1 -1
  16. package/dist/client/assets/{chunk-GTNCS2PH-Bu7kc4uW.js → chunk-GTNCS2PH-at0ENjhB.js} +1 -1
  17. package/dist/client/assets/{chunk-GWA4HPMP-DOeikbS_.js → chunk-GWA4HPMP-C06n_37U.js} +1 -1
  18. package/dist/client/assets/{chunk-MBY4JIJT-BMMqnoVS.js → chunk-MBY4JIJT-DuowBunG.js} +1 -1
  19. package/dist/client/assets/{chunk-NETBCI7D-YxbfsgLs.js → chunk-NETBCI7D-ClNA7QFH.js} +1 -1
  20. package/dist/client/assets/{chunk-O7XYJQB3-B5lrUf5i.js → chunk-O7XYJQB3-BjcjInBL.js} +1 -1
  21. package/dist/client/assets/{chunk-UA2S7LBM-BDaXVsL8.js → chunk-UA2S7LBM-B-PAn1hd.js} +1 -1
  22. package/dist/client/assets/{chunk-WEXAMYUT-DxlWoHYQ.js → chunk-WEXAMYUT-Br84uK4B.js} +1 -1
  23. package/dist/client/assets/{chunk-XXDRQBXY-Cp47KzsC.js → chunk-XXDRQBXY-BbBZykgX.js} +1 -1
  24. package/dist/client/assets/{chunk-Z7XXMR3K-CESnPXew.js → chunk-Z7XXMR3K-CQ-grwfe.js} +1 -1
  25. package/dist/client/assets/{chunk-ZIGJFQKS-CNWS7Wkq.js → chunk-ZIGJFQKS-CLwfE-hs.js} +1 -1
  26. package/dist/client/assets/{classDiagram-v2-NBCMYWYE-BceAVX_T.js → classDiagram-v2-NBCMYWYE-DD-bcOHO.js} +1 -1
  27. package/dist/client/assets/{core-Br-4vljZ.js → core-BADyutHL.js} +1 -1
  28. package/dist/client/assets/{cose-bilkent-JH36ORCC-D__9SuyS.js → cose-bilkent-JH36ORCC-fuMg3J_l.js} +1 -1
  29. package/dist/client/assets/{cynefin-OW5HDTMX-DgTdpSz6.js → cynefin-OW5HDTMX-DwFXJ_x8.js} +1 -1
  30. package/dist/client/assets/{cynefinDiagram-VND7K2PF-CWEqRTNF.js → cynefinDiagram-VND7K2PF-cGL_k8gj.js} +1 -1
  31. package/dist/client/assets/{dagre-6A5THRUB-B3HGDOgj.js → dagre-6A5THRUB-BetgCBn9.js} +1 -1
  32. package/dist/client/assets/{diagram-22UHCM2B-Ce04XJcX.js → diagram-22UHCM2B-C7qT2Ix2.js} +1 -1
  33. package/dist/client/assets/{diagram-3UASUU5V-Bp5Chgzw.js → diagram-3UASUU5V-DGUO9DWV.js} +1 -1
  34. package/dist/client/assets/{diagram-ATOU4E4O-BmKaDuB5.js → diagram-ATOU4E4O-f520gjx5.js} +1 -1
  35. package/dist/client/assets/{diagram-CDSNMT55-DrSDVwyB.js → diagram-CDSNMT55-Dhrm4GzB.js} +1 -1
  36. package/dist/client/assets/{diagram-MLGK6HIB-8AyH2eMG.js → diagram-MLGK6HIB-Di0aRiuU.js} +1 -1
  37. package/dist/client/assets/{diagram-MPIPVDR6-C9AcuOld.js → diagram-MPIPVDR6-BHhVZUxI.js} +1 -1
  38. package/dist/client/assets/{dist-CVtr89jj.js → dist-CbdYocyN.js} +1 -1
  39. package/dist/client/assets/{dist-Cdc7REqJ.js → dist-Cezvykkn.js} +1 -1
  40. package/dist/client/assets/{ebnfDiagram-ZINNZB2B-DX6ekwEH.js → ebnfDiagram-ZINNZB2B-CQA0eib_.js} +1 -1
  41. package/dist/client/assets/{elk-276RUBZZ-Cm9uWHa7.js → elk-276RUBZZ-CZKKVSu0.js} +1 -1
  42. package/dist/client/assets/{engine-oniguruma-DbGd6VkA.js → engine-oniguruma-B68c_YAs.js} +1 -1
  43. package/dist/client/assets/{erDiagram-OPXOYQCR-CaUHiYv4.js → erDiagram-OPXOYQCR-DcNnfq_S.js} +1 -1
  44. package/dist/client/assets/eventmodeling-NTZA5JFV-C61pKQjq.js +1 -0
  45. package/dist/client/assets/flowDiagram-KWPJA3E3-BolWtw3C.js +1 -0
  46. package/dist/client/assets/{ganttDiagram-FUAMR5RP-DL6UN0sq.js → ganttDiagram-FUAMR5RP-Dteh33ci.js} +1 -1
  47. package/dist/client/assets/{gitGraph-4MIJSDKK-CsKV1QJN.js → gitGraph-4MIJSDKK-DMTE1jTV.js} +1 -1
  48. package/dist/client/assets/{gitGraphDiagram-X574FWY7-D8Snpa_F.js → gitGraphDiagram-X574FWY7-EV_0IPok.js} +1 -1
  49. package/dist/client/assets/index-B__poZ2b.js +93 -0
  50. package/dist/client/assets/{index-CE0LasmM.css → index-CL4K6Y07.css} +1 -1
  51. package/dist/client/assets/{info-A6RAGUB7-BxOCsCG2.js → info-A6RAGUB7-WkHzxEDS.js} +1 -1
  52. package/dist/client/assets/{infoDiagram-VRGFBTTK-CfW5lEnk.js → infoDiagram-VRGFBTTK-BcH5U5G2.js} +1 -1
  53. package/dist/client/assets/{ishikawaDiagram-OU5B5YK6-B4gbggT_.js → ishikawaDiagram-OU5B5YK6-Z8vZnj1l.js} +1 -1
  54. package/dist/client/assets/{journeyDiagram-ZHPQQLJL-IWmYxrcn.js → journeyDiagram-ZHPQQLJL-Cn-m-UYg.js} +1 -1
  55. package/dist/client/assets/{kanban-definition-PNTS6WVX-CbaKE2PB.js → kanban-definition-PNTS6WVX-DLOrUOML.js} +1 -1
  56. package/dist/client/assets/{line-BtA026Ya.js → line-DhKwT3E3.js} +1 -1
  57. package/dist/client/assets/{linear-B5Crnel0.js → linear-DvwuMCFu.js} +1 -1
  58. package/dist/client/assets/{mermaid-parser.core-BPmT-0j3.js → mermaid-parser.core-CwcOI9nG.js} +3 -3
  59. package/dist/client/assets/{mermaid.core-BTblV3B-.js → mermaid.core-BabKb2iQ.js} +4 -4
  60. package/dist/client/assets/{mindmap-definition-NLK3R4M7-CIB2jRud.js → mindmap-definition-NLK3R4M7-D7wpNtz6.js} +1 -1
  61. package/dist/client/assets/{packet-AYTQ26CC-BWwlCBfL.js → packet-AYTQ26CC-BJablqte.js} +1 -1
  62. package/dist/client/assets/{pegDiagram-GJSIUBJH-DhOZCJeC.js → pegDiagram-GJSIUBJH-EAlXAkUz.js} +1 -1
  63. package/dist/client/assets/{pie-WAS4IAKB-BYPEomkb.js → pie-WAS4IAKB-BAAbtIiO.js} +1 -1
  64. package/dist/client/assets/{pieDiagram-5QR66LMP-BPMuMrQa.js → pieDiagram-5QR66LMP-b1pYP4ES.js} +1 -1
  65. package/dist/client/assets/{quadrantDiagram-O4NWA36T-CNiAZ4Fx.js → quadrantDiagram-O4NWA36T-B_LJNNdE.js} +1 -1
  66. package/dist/client/assets/{radar-RG4KPBEZ-D4cJCxoB.js → radar-RG4KPBEZ-BKldNRRC.js} +1 -1
  67. package/dist/client/assets/{railroad-74A4TZTK-GypTiD9-.js → railroad-74A4TZTK-LvULpHpQ.js} +1 -1
  68. package/dist/client/assets/railroad-abnf-HS5TGJTU-CORGw4Le.js +1 -0
  69. package/dist/client/assets/railroad-ebnf-LZEXJU2U-BXCX4hkl.js +1 -0
  70. package/dist/client/assets/railroad-peg-WCYAUIDC-C6BQUpjn.js +1 -0
  71. package/dist/client/assets/{railroadDiagram-XR7U4H2S-C9onf3MB.js → railroadDiagram-XR7U4H2S-kp6LeaeM.js} +1 -1
  72. package/dist/client/assets/{requirementDiagram-PLB6GJNP-BAtMHH1O.js → requirementDiagram-PLB6GJNP-Br-OgP6b.js} +1 -1
  73. package/dist/client/assets/{sankeyDiagram-IPEJSGJF-ByIBebPb.js → sankeyDiagram-IPEJSGJF-DSIbAxcK.js} +1 -1
  74. package/dist/client/assets/{sequenceDiagram-PO4LG4MO-CZWeGbVd.js → sequenceDiagram-PO4LG4MO-uVv8u8VI.js} +1 -1
  75. package/dist/client/assets/sizeCapture-INFHLROL-3uHXrFqA.js +1 -0
  76. package/dist/client/assets/{src-3ZsKiqdK.js → src-Bmfs-TFn.js} +1 -1
  77. package/dist/client/assets/{stateDiagram-v2-GCMORJYK-BLS3Ppqp.js → stateDiagram-v2-GCMORJYK-Crql1z4d.js} +1 -1
  78. package/dist/client/assets/{swimlanes-2SLR337P-VfJv1Azt.js → swimlanes-2SLR337P-CnpU7AM-.js} +1 -1
  79. package/dist/client/assets/swimlanesDiagram-TC7HE7FX-Crca2YKi.js +8 -0
  80. package/dist/client/assets/{timeline-definition-EJHVYXUP-CFsTCeFJ.js → timeline-definition-EJHVYXUP-CqzGi-Sd.js} +1 -1
  81. package/dist/client/assets/{treeView-Q6P3EWNA-BcU2cd9W.js → treeView-Q6P3EWNA-N_EzEUvg.js} +1 -1
  82. package/dist/client/assets/{treemap-WGGIJYW6-BKWQgOsJ.js → treemap-WGGIJYW6-BYeVgP-v.js} +1 -1
  83. package/dist/client/assets/{usecaseDiagram-POWQR4AR-CaDVH5UF.js → usecaseDiagram-POWQR4AR-Dyeq2Zcy.js} +1 -1
  84. package/dist/client/assets/{vennDiagram-UO4OBE2U-BD60NU6D.js → vennDiagram-UO4OBE2U-CuCjJaOo.js} +1 -1
  85. package/dist/client/assets/{wardley-WFR3VGLG-CGRKLXxQ.js → wardley-WFR3VGLG-AV0-dO_Z.js} +1 -1
  86. package/dist/client/assets/{wardleyDiagram-VNRHLVJA-BNSajOpz.js → wardleyDiagram-VNRHLVJA-f0dVm2LA.js} +1 -1
  87. package/dist/client/assets/{xychartDiagram-PMCCYNJV-Bw7XhF-N.js → xychartDiagram-PMCCYNJV-BNjSW7P1.js} +1 -1
  88. package/dist/client/index.html +2 -2
  89. package/package.json +4 -2
  90. package/plugin.json +3 -3
  91. package/dist/client/assets/architecture-7GRP2DOG-WcOrmKkC.js +0 -1
  92. package/dist/client/assets/channel-DhaDDyGS.js +0 -1
  93. package/dist/client/assets/eventmodeling-NTZA5JFV-n7NgJYAj.js +0 -1
  94. package/dist/client/assets/flowDiagram-KWPJA3E3-B-DNn9sz.js +0 -1
  95. package/dist/client/assets/index-CEiheKtN.js +0 -91
  96. package/dist/client/assets/railroad-abnf-HS5TGJTU-CJCTFtWl.js +0 -1
  97. package/dist/client/assets/railroad-ebnf-LZEXJU2U-DEndv2ed.js +0 -1
  98. package/dist/client/assets/railroad-peg-WCYAUIDC-BJQI82cq.js +0 -1
  99. package/dist/client/assets/sizeCapture-INFHLROL-B0uUizjq.js +0 -1
  100. package/dist/client/assets/swimlanesDiagram-TC7HE7FX-CsAstSgi.js +0 -8
package/README.md CHANGED
@@ -11,23 +11,26 @@
11
11
 
12
12
  ### The human way to review agent-written code.
13
13
 
14
- A live review on your machine, wired to the agent that wrote the code, so your comments
15
- come back as fixes.
14
+ Ask your agent for a review. You get the change in **layers**, in the order it should be
15
+ read, and **the agent on the other end of every comment**: it answers on the line and fixes
16
+ while you read. Hand it a pull request instead, and it reads beside you and sends your
17
+ review to GitHub.
16
18
 
17
- [Quick start](#quick-start) · [Why Diffo](#why-diffo) · [Docs](#docs) · [Status](#status) · [Contributing](#contributing)
19
+ [Quick start](#quick-start) · [The conversation](#talk-to-the-agent-on-the-line) · [Layers](#read-it-in-layers) · [Pull requests](#review-a-pull-request) · [Docs](#docs) · [Contributing](#contributing)
18
20
 
19
21
  [![CI](https://img.shields.io/github/actions/workflow/status/DiffoHQ/diffo/ci.yml?branch=main&label=CI)](https://github.com/DiffoHQ/diffo/actions/workflows/ci.yml)
20
22
  [![npm](https://img.shields.io/npm/v/%40diffohq%2Fdiffo?label=npm&color=cb3837)](https://www.npmjs.com/package/@diffohq/diffo)
21
23
  [![License](https://img.shields.io/badge/license-Apache--2.0-blue)](LICENSE)
22
24
  [![Node](https://img.shields.io/badge/node-%E2%89%A5%2024-brightgreen)](#quick-start)
23
25
  [![Docs](https://img.shields.io/badge/docs-diffo-8b5cf6)](https://diffohq.github.io/diffo/)
24
- [![Tests](https://img.shields.io/badge/tests-1143-brightgreen)](#contributing)
26
+ [![Tests](https://img.shields.io/badge/tests-1327-brightgreen)](#contributing)
25
27
 
26
28
  </div>
27
29
 
28
30
  <!-- Every clip here is a real recording: a real Claude Code session, a real server, and a
29
- real changeset under review. The hero reviews a small demo app, so the diff reads at a
30
- glance; the clips further down and in the tutorial review this repo's own changesets. -->
31
+ real changeset under review. The hero and the pull request clip review a small demo
32
+ app, so the diff reads at a glance; the layers clip, and the tutorial, review this
33
+ repo's own changesets. -->
31
34
 
32
35
  <!-- Light-theme only. The clip opens once the session has finished writing the change:
33
36
  waiting on the agent is fast-forwarded — the badge in the session's corner says so
@@ -40,47 +43,30 @@ come back as fixes.
40
43
 
41
44
  ## Quick start
42
45
 
43
- Requires **Node >= 24** and **git**.
44
-
45
- **Have your agent set it up.** Paste this into Claude Code, Cursor, Codex, or whichever
46
- agent you already use:
46
+ Requires **Node >= 24** and **git**. Paste this into Claude Code, Cursor, Codex, or
47
+ whichever agent you already use:
47
48
 
48
49
  ```text
49
50
  Run `npx skills add DiffoHQ/diffo --skill diffo -g` and open the diffo review
50
51
  ```
51
52
 
52
- **Or install the skill yourself:**
53
-
54
- ```bash
55
- npx skills add DiffoHQ/diffo --skill diffo -g
56
- ```
57
-
58
- Either way, that's the whole install. Then, in any session, say:
59
-
60
- > **"let's review that"**, or just **`/diffo`**
61
-
62
- The agent opens a live review of its own work and hands you the URL. Your comments arrive
63
- in its context, its replies land inline in your threads, and its fixes update the diff
64
- while you read. That is the clip above, with no URL to ask for.
65
-
66
- <details>
67
- <summary><b>Running from a clone instead</b></summary>
68
-
69
- <br>
53
+ That's the whole install. From then on, one command in any session:
70
54
 
71
- You can also run the CLI straight out of a checkout, which is what contributors do:
72
-
73
- ```bash
74
- git clone https://github.com/DiffoHQ/diffo.git && cd diffo
75
- pnpm install && pnpm build
76
- node dist/cli.mjs setup # or `node dist/cli.mjs` from any repo to review it
77
- ```
55
+ | Run | And the agent reviews |
56
+ | --- | --- |
57
+ | `/diffo` | what it just wrote, before anything is committed |
58
+ | `/diffo main` | everything since you branched off `main` |
59
+ | `/diffo <PR link>` | a GitHub pull request, checked out in a worktree of its own; your review goes back to GitHub when you finish |
78
60
 
79
- </details>
61
+ Every time, the agent opens the review and hands you the URL. It all runs on your
62
+ machine, and nothing needs to be committed or pushed first. A pull request needs the
63
+ [GitHub CLI](https://cli.github.com) signed in. Otherwise the only thing that leaves your
64
+ machine is two small anonymous usage events per review, [listed in full](https://diffohq.github.io/diffo/telemetry)
65
+ and off with `diffo telemetry off`.
80
66
 
81
67
  New here? [**Your first review, end to end**](https://diffohq.github.io/diffo/tutorial) takes about five minutes.
82
68
 
83
- ## Why Diffo
69
+ ## Talk to the agent on the line
84
70
 
85
71
  **We write code with an LLM. We review it alone.**
86
72
 
@@ -89,115 +75,59 @@ the thing is right. Reviewing never did. The code lands, the conversation ends,
89
75
  read four hundred lines by yourself, in a viewer built for a world where whoever wrote it
90
76
  had already moved on.
91
77
 
92
- Diffo keeps the conversation open through the review. Ask what a hunk does and the agent
93
- that wrote it answers in the thread. Ask why, and it explains, with a diagram when the
94
- shape needs one. Ask for a change and it makes it, and the diff updates while you read.
95
- The judgement stays yours. You just stop reading alone.
96
-
97
- <picture>
98
- <source media="(prefers-color-scheme: dark)" srcset="docs/assets/hero-dark.gif">
99
- <img alt="Two windows side by side. The reviewer asks for a change on a line of src/cli.ts; the real Claude Code session on the left makes the edit, and the diff on the right updates while they watch." src="docs/assets/hero.gif" width="100%">
100
- </picture>
101
-
102
- <p align="center"><sub>Ask for a change and the agent makes it. The diff updates under you, and the file count falls as those files stop differing.</sub></p>
103
-
104
- ## What you get
105
-
106
- <table>
107
- <tr>
108
- <td width="50%">
109
-
110
- **A thread is a decision**
111
-
112
- Each comment is one small call: change this, explain that, leave it alone. Drop it on a
113
- line or drag down the gutter for a range of them. Mark it a Change or a Question and the
114
- agent is told which. The review is the sum of those decisions, not a verdict at the end.
115
-
116
- </td>
117
- <td width="50%">
118
-
119
- **Reading, not scrolling**
120
-
121
- Syntax-highlighted unified and split diffs, word-level marks, keyboard-first movement,
122
- context expansion, images side by side, lockfiles collapsed. The conventions are GitHub's,
123
- deliberately: a reviewer shouldn't have to learn a new diff.
124
-
125
- </td>
126
- </tr>
127
- <tr>
128
- <td width="50%">
129
-
130
- **Live while you iterate**
131
-
132
- Fixes land in the diff you are already reading. A hunk you had marked read says *changed
133
- since you read it* once it's edited, so the second pass stays honest.
134
-
135
- </td>
136
- <td width="50%">
137
-
138
- **Local**
139
-
140
- One process on your machine, bound to loopback. No account, no telemetry, no cloud, and
141
- nothing to configure.
142
-
143
- </td>
144
- </tr>
145
- <tr>
146
- <td width="50%">
147
-
148
- **It explains itself**
78
+ Diffo keeps the conversation open through the review. The judgement stays yours. You just
79
+ stop reading alone.
149
80
 
150
- On a change that's multi-file, structural, or just subtle, the agent opens the review with
151
- one orienting comment: a sentence on what the change does, plus a small
152
- [mermaid](https://mermaid.js.org) diagram when the shape is easier to see than to read. It
153
- orients, and it never pre-reviews: no verdicts, nothing is "fine". That judgement is the
154
- part it doesn't get to make.
155
-
156
- </td>
157
- <td width="50%">
158
-
159
- **Read it in the right order**
81
+ - **Ask on any line.** The agent that wrote the code answers in the thread, with a
82
+ diagram when the shape needs one. Mark a thread a **Question** and it explains; mark it
83
+ a **Change** and it edits, so a question never turns into an unrequested refactor.
84
+ - **Fixes land in the diff you're reading.** The diff updates under your cursor, and a
85
+ hunk you had already read says *changed since you read it*, so the second pass stays
86
+ honest.
87
+ - **A map, not a verdict.** On a multi-file or subtle change the agent opens the review
88
+ with one orienting comment on what the change does. It never pre-reviews: no verdicts,
89
+ nothing is "fine". That judgement is the part it doesn't get to make.
90
+ ## Read it in layers
160
91
 
161
92
  A diff arrives alphabetically, which is almost never the order to read it in. Ask, and the
162
93
  agent posts **layers**: the change as ordered steps, each with a title, a summary, and its
163
- files. You read one layer at a time; `]` steps to the next. Anything the agent touches after
164
- posting gathers in a *Since your review* layer, so nothing hides outside the plan.
165
-
166
- </td>
167
- </tr>
168
- </table>
94
+ files. You read one layer at a time, in the order the agent would explain it; `]` steps to
95
+ the next. Anything the agent touches after posting gathers in a *Since your review* layer,
96
+ so nothing hides outside the plan.
169
97
 
170
98
  <picture>
171
99
  <source media="(prefers-color-scheme: dark)" srcset="docs/assets/layers-dark.gif">
172
100
  <img alt="A 23-file change, every file folded. The header chip reads agent · suggests layers; the reviewer clicks it, eight layers land, and picking the first shows its summary card. ] steps to layers 2 and 3, where the reviewer asks on a line and the agent answers in the thread." src="docs/assets/layers.gif" width="100%">
173
101
  </picture>
174
102
 
175
- <p align="center"><sub>Layers, in one take: the agent offers an outline, the reviewer asks, and a 23-file change arrives as eight steps to read in order. Three layers in, a question on a line comes back answered in the thread. A real server and a real <code>diffo poll</code> on the other end; only the agent's thinking time is cut.</sub></p>
103
+ <p align="center"><sub>Layers, in one take: the agent offers an outline, the reviewer asks, and a 23-file change arrives as eight steps to read in order. Three layers in, a question on a line comes back answered in the thread. Only the agent's thinking time is cut.</sub></p>
176
104
 
177
- ## Where it fits
105
+ ## Review a pull request
178
106
 
179
- Diffo doesn't replace pull request review, and it isn't trying to. A pull request is how you
180
- hand finished work to someone else. Diffo is the step before that: the loop where you and the
181
- agent turn a first draft into something worth another person's time.
107
+ When a pull request lands on *your* desk, give your agent the link. It checks the PR out
108
+ in a worktree of its own, so your checkout is never touched, and opens it as the same
109
+ review: the description and the GitHub threads come with it, and the agent reads beside
110
+ you as a copilot for code it did not write. Every comment has two tabs. **Comment on PR**
111
+ goes to the author, as one review when you finish. **Ask agent** stays on your machine:
112
+ the agent can run the tests and answer with evidence, and it never posts to GitHub.
182
113
 
183
- | | **Diffo** | Pull request review | AI reviewer bot |
184
- | --- | --- | --- | --- |
185
- | When | **before the PR exists** | after you push | after you push |
186
- | What it's for | **getting the code right** | getting it approved | catching the obvious |
187
- | Who you work with | **the agent that wrote it** | your teammates | nobody |
188
- | Where the code is | **uncommitted, on your disk** | pushed to a branch | pushed to a branch |
189
- | What comes out | **code worth pushing** | an approval and a record | a list of comments |
114
+ <!-- Light-theme only, like the hero. The pull request is a real one on a demo repo
115
+ (DiffoHQ/todo-demo#1), and the review at the end is the one this take submitted. -->
116
+ <img alt="One take of a pull request review. On GitHub, a pull request adds recurring todos to a todo app; in Claude Code the reviewer types /diffo with its link, and the review opens beside the session, the PR's title, author and checks in the header. The agent lays the change out in layers. On the streak check the reviewer asks the agent whether anything done on its due day now counts as late, and the answer comes back in the thread; they leave a comment for GitHub on the same line, submit the review with Request changes, and the review appears on the pull request." src="docs/assets/pr-review.gif" width="100%">
190
117
 
191
- So they stack rather than compete: iterate here until the diff reads clean, then open the
192
- pull request you actually want reviewed. Your judgement is the scarce resource, and this is
193
- the stage where spending it changes the outcome.
118
+ <p align="center"><sub>A pull request, end to end: hand over the link, read it in layers, ask your agent on a line, leave a comment for the author, and submit to GitHub. A real Claude Code session and a real pull request; the only edit is that waiting on the agent runs fast.</sub></p>
194
119
 
195
- And when a pull request lands on *your* desk, Diffo reads that too: `/diffo <PR link>`
196
- opens it in a worktree of its own, imports its conversation, puts your agent beside you as
197
- a copilot for code it did not write, and submits your review to GitHub when you finish.
198
- [Reviewing a pull request](https://diffohq.github.io/diffo/guide/pr-review) has the loop.
120
+ ## Where it fits
199
121
 
200
- ---
122
+ Diffo isn't an AI reviewer. It doesn't grade your diff or leave generated nitpicks: you
123
+ read, and the agent is there to answer, explain, and fix.
124
+
125
+ | | **Diffo** | AI reviewer bot | Plain pull request review |
126
+ | --- | --- | --- | --- |
127
+ | Who reads the code | **you** | a model | you |
128
+ | Who answers your questions | **the agent, in the thread, now** | nobody | the author, when they get to it |
129
+ | When | **while the agent writes, or when the PR lands** | after you push | after you push |
130
+ | What comes out | **fixes in the diff, or a review on GitHub** | a list of comments | a review on GitHub |
201
131
 
202
132
  ## How it works
203
133
 
@@ -206,17 +136,12 @@ a copilot for code it did not write, and submits your review to GitHub when you
206
136
  <img alt="Diffo's architecture: your agent writes the code and opens the review; a local Diffo server watches the changeset and serves it to your browser; your comments and Finish review return to the agent through diffo poll, and its answers and fixes land back in the review live." src="assets/how-it-works-light.svg" width="100%">
207
137
  </picture>
208
138
 
209
- The left half is a diff viewer. The right half is what Diffo is for: your comment doesn't
210
- land in a queue for later, it lands in **the conversation that wrote the code**, while that
211
- conversation still remembers why. Nothing needs to be committed, pushed, or opened as a PR
212
- first, so agent output is reviewable the moment it hits the disk, which is the moment it's
213
- cheapest to change.
214
-
215
- | You want to review | Command |
216
- | --- | --- |
217
- | Uncommitted work in progress (the default) | `diffo` |
218
- | Everything since you branched off `main` | `diffo --base main` |
219
- | A pull request | *not supported yet* |
139
+ One process on your machine, bound to loopback: no account, no cloud, and no model API.
140
+ The one thing it reports is [anonymous usage data](https://diffohq.github.io/diffo/telemetry),
141
+ two events per review, never code or paths, off with one command. Diffo spawns no agents
142
+ of its own; the one you're already talking to stays attached through the `diffo` CLI, so
143
+ your comments land in the session that holds the context. The viewer itself is a real diff viewer, unified and split, keyboard-first, with
144
+ GitHub's conventions. The CLI, the flags, and everything under the hood are in the docs.
220
145
 
221
146
  ## Docs
222
147
 
@@ -224,81 +149,31 @@ cheapest to change.
224
149
  | --- | --- |
225
150
  | [**Your first review**](https://diffohq.github.io/diffo/tutorial) | The whole loop end to end, about five minutes |
226
151
  | [**Getting started**](https://diffohq.github.io/diffo/guide/getting-started) | Install, and where each agent gets wired |
227
- | [**The review loop**](https://diffohq.github.io/diffo/guide/the-loop) | Reading, layers, commenting, and what the agent receives |
152
+ | [**The review loop**](https://diffohq.github.io/diffo/guide/the-loop) | Reading, commenting, and what the agent receives |
153
+ | [**Layers**](https://diffohq.github.io/diffo/guide/layers) | The agent's reading plan: ordered steps, one at a time |
154
+ | [**Reviewing a pull request**](https://diffohq.github.io/diffo/guide/pr-review) | A GitHub PR in a worktree, your agent beside you, your review back on GitHub |
228
155
  | [**How it works**](https://diffohq.github.io/diffo/guide/how-it-works) | The components and the server lifecycle |
229
156
  | [**The agent side**](https://diffohq.github.io/diffo/agents) | The agent protocol: every command, every payload |
230
157
  | [**Architecture**](https://diffohq.github.io/diffo/architecture) | Diff pipeline, delivery queue, SQLite state |
231
158
  | [**CLI**](https://diffohq.github.io/diffo/reference/cli) and [**Keyboard shortcuts**](https://diffohq.github.io/diffo/reference/keyboard-shortcuts) | Reference |
232
159
  | [**FAQ**](https://diffohq.github.io/diffo/faq) | The short answers |
233
160
 
234
- ## Under the hood
235
-
236
- TypeScript on Node >= 24: a [Hono](https://hono.dev) server over loopback serving a React 19
237
- UI, live updates over server-sent events from one recursive filesystem watch, and state in a
238
- single SQLite file at `~/.diffo/diffo.db` through the runtime's built-in `node:sqlite`, so
239
- there is no database to install. **No network calls of its own**: a pull request review
240
- talks to GitHub only through your `gh`. 1,307 tests across 70 files.
241
-
242
- Reviews are scoped per repo **and branch**, and the server is loopback-only, rejecting
243
- non-loopback `Host` and `Origin` headers so a web page can't reach into your repo through
244
- it. The full walkthrough is in [**Architecture**](https://diffohq.github.io/diffo/architecture).
245
-
246
- <details>
247
- <summary><b>Why read marks survive a live diff</b></summary>
248
-
249
- <br>
250
-
251
- Every hunk carries a **content-addressed id**: a hash of its path and changed lines, and
252
- deliberately not its line numbers. That one decision is what makes the live review honest.
253
-
254
- - Read marks survive a refresh, because an untouched hunk keeps its id.
255
- - An edited hunk mints a new id, loses its mark, and says **changed since you read it**. You
256
- can't accidentally sign off on code you never saw.
257
- - The ids from your last Finish are a complete record of what existed then, so "what moved
258
- since I last looked" is a set subtraction, needing no timestamps.
259
-
260
- </details>
261
-
262
- ---
263
-
264
161
  ## Open core
265
162
 
266
163
  Everything in this repository is the core, and the core stays Apache-2.0: local review, the
267
- agent loop, the CLI, the Agent Skill. It works offline, for one reviewer, forever, for free.
268
-
269
- A hosted team tier is planned: shared changesets, review history across a team, SSO. None of
270
- it exists yet, and none of it will take an existing core feature behind a paywall. The line
271
- we commit to: **anything that runs on your machine for one reviewer is core.**
272
-
273
- ## Status
274
-
275
- Diffo is pre-1.0: the loop below works end to end (this repo is reviewed with it
276
- daily) and the edges are still moving. What works today:
277
-
278
- - [x] [Live review of any changeset](https://diffohq.github.io/diffo/guide/how-it-works): the working tree, or anything since `--base`.
279
- - [x] [The comment loop](https://diffohq.github.io/diffo/guide/the-loop): threads that reach the session that wrote the code.
280
- - [x] [Layers](https://diffohq.github.io/diffo/guide/the-loop#read-it-in-layers): the agent's reading plan, one ordered step at a time.
281
- - [x] [One setup, every agent](https://diffohq.github.io/diffo/guide/getting-started): Claude Code, Codex, Cursor, VS Code, Copilot CLI, Gemini CLI, Amp, Goose, OpenCode.
282
- - [x] [Reading tools](https://diffohq.github.io/diffo/reference/keyboard-shortcuts): unified and split diffs, word-level marks, coverage tracking.
283
- - [x] [Pull request review](https://diffohq.github.io/diffo/guide/pr-review): `diffo <PR URL>` reviews a GitHub PR in a worktree of its own, with the conversation imported and your review submitted from Diffo.
164
+ agent loop, pull request review, the CLI, the Agent Skill. It works offline, for one
165
+ reviewer, forever, for free. A hosted team tier is planned, and none of it will take an
166
+ existing core feature behind a paywall: **anything that runs on your machine for one
167
+ reviewer is core.**
284
168
 
285
169
  ## Contributing
286
170
 
287
- Five gates, all of which CI runs, or `pnpm check` for all five:
288
-
289
- ```bash
290
- pnpm typecheck && pnpm test && pnpm build && pnpm lint && pnpm docs:build
291
- ```
292
-
293
- Local development is `pnpm dev` (server and client together). One hard rule:
294
- **`skills/diffo/SKILL.md` is generated.** Edit [`src/skill.ts`](src/skill.ts) and run
295
- `pnpm build:skill`; a test fails if the committed file drifts. That rewrites the repo
296
- file, not the skill your own agent runs; `pnpm dev:skill --global` installs a separate
297
- `/diffo-dev` that drives your checkout, alongside the shipped `/diffo`.
298
-
299
- Details in [CONTRIBUTING.md](CONTRIBUTING.md), plus a [Code of Conduct](CODE_OF_CONDUCT.md)
300
- and the [CHANGELOG](CHANGELOG.md). First-time contributors sign a [CLA](CLA.md): a bot asks
301
- on your first pull request, and signing is one reply.
171
+ Diffo is pre-1.0: this repo is reviewed with it daily, and the edges are still moving.
172
+ `pnpm check` runs the five gates CI runs. One hard rule: **`skills/diffo/SKILL.md` is
173
+ generated** from [`src/skill.ts`](src/skill.ts); edit the source and run `pnpm build:skill`.
174
+ [CONTRIBUTING.md](CONTRIBUTING.md) has the rest, with a [Code of Conduct](CODE_OF_CONDUCT.md),
175
+ the [CHANGELOG](CHANGELOG.md), and the [CLA](CLA.md) a bot asks first-time contributors to
176
+ sign, in one reply.
302
177
 
303
178
  Found a security problem? Please don't open a public issue. The
304
179
  [Security Policy](SECURITY.md) says where to send it and what's in scope.