@diffohq/diffo 0.6.0 → 0.8.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 (102) hide show
  1. package/README.md +80 -200
  2. package/dist/cli.mjs +2678 -310
  3. package/dist/client/assets/{abnfDiagram-O67JEVCF-vILxBZcB.js → abnfDiagram-O67JEVCF-BUIFF3Lv.js} +1 -1
  4. package/dist/client/assets/{arc-KM37zfEu.js → arc-x6Ulf5MI.js} +1 -1
  5. package/dist/client/assets/architecture-7GRP2DOG-Cx2ezWq8.js +1 -0
  6. package/dist/client/assets/{architectureDiagram-NJMV4G6O-CCe24XcA.js → architectureDiagram-NJMV4G6O-D25O1A2B.js} +1 -1
  7. package/dist/client/assets/{blockDiagram-BEXU5L5S-GL2esJ0w.js → blockDiagram-BEXU5L5S-Dy7P3IZw.js} +1 -1
  8. package/dist/client/assets/{c4Diagram-YGBWAQC7-BcRujrvs.js → c4Diagram-YGBWAQC7-BnE5HTw4.js} +1 -1
  9. package/dist/client/assets/channel-IK-3bv-L.js +1 -0
  10. package/dist/client/assets/{chunk-3FUC2YCW-Gj4X9KK9.js → chunk-3FUC2YCW-6C72_i5n.js} +2 -2
  11. package/dist/client/assets/{chunk-5DYCD2WN-DZs-erj_.js → chunk-5DYCD2WN-B0IgEc5I.js} +1 -1
  12. package/dist/client/assets/{chunk-742MDFTN-Db1JJZ9G.js → chunk-742MDFTN-BNLZzbxp.js} +1 -1
  13. package/dist/client/assets/{chunk-7INBJB4K-B_wqJ7Xn.js → chunk-7INBJB4K-K1DkKka3.js} +1 -1
  14. package/dist/client/assets/{chunk-7M6MHVWA-DuALBizw.js → chunk-7M6MHVWA-B-KIWC1T.js} +1 -1
  15. package/dist/client/assets/{chunk-7PRAP22T-D9QvZUm3.js → chunk-7PRAP22T-DR6CzDYx.js} +1 -1
  16. package/dist/client/assets/{chunk-GTNCS2PH-JFHsSpPU.js → chunk-GTNCS2PH-BWkvnYRd.js} +1 -1
  17. package/dist/client/assets/{chunk-GWA4HPMP-CX_60U9Y.js → chunk-GWA4HPMP-l8NLPoZc.js} +1 -1
  18. package/dist/client/assets/{chunk-MBY4JIJT-BVqUStmy.js → chunk-MBY4JIJT-k1mwME9y.js} +1 -1
  19. package/dist/client/assets/{chunk-NETBCI7D-BoSm0O5f.js → chunk-NETBCI7D-DV1F8c_R.js} +1 -1
  20. package/dist/client/assets/{chunk-O7XYJQB3-DG64mbS_.js → chunk-O7XYJQB3-Bb8gIxaB.js} +1 -1
  21. package/dist/client/assets/{chunk-UA2S7LBM-BL039fcM.js → chunk-UA2S7LBM-BL7m6fd_.js} +1 -1
  22. package/dist/client/assets/{chunk-WEXAMYUT-BPFyuzbi.js → chunk-WEXAMYUT-CAnQv1qY.js} +1 -1
  23. package/dist/client/assets/{chunk-XXDRQBXY-BzCs4oPB.js → chunk-XXDRQBXY-DooI1miH.js} +1 -1
  24. package/dist/client/assets/{chunk-Z7XXMR3K-D9UN9ldM.js → chunk-Z7XXMR3K-DPVaCcdM.js} +1 -1
  25. package/dist/client/assets/{chunk-ZIGJFQKS-D47UlTiy.js → chunk-ZIGJFQKS-Bz4IWpFy.js} +1 -1
  26. package/dist/client/assets/{classDiagram-v2-NBCMYWYE-CXeBds6Z.js → classDiagram-v2-NBCMYWYE-Dso7ogb5.js} +1 -1
  27. package/dist/client/assets/{core-De6Bel6T.js → core-Dy-hJrbg.js} +1 -1
  28. package/dist/client/assets/{cose-bilkent-JH36ORCC-C5C9BMn5.js → cose-bilkent-JH36ORCC-Baj8S6bg.js} +1 -1
  29. package/dist/client/assets/{cynefin-OW5HDTMX-TQm3krMs.js → cynefin-OW5HDTMX-BkA1ccYX.js} +1 -1
  30. package/dist/client/assets/{cynefinDiagram-VND7K2PF-D9L1g2S1.js → cynefinDiagram-VND7K2PF-nyK9OZGN.js} +1 -1
  31. package/dist/client/assets/{dagre-6A5THRUB-D9iVd0tg.js → dagre-6A5THRUB-BP_dyQLS.js} +1 -1
  32. package/dist/client/assets/{diagram-22UHCM2B-CD_1yZgj.js → diagram-22UHCM2B-BIt_aIJx.js} +1 -1
  33. package/dist/client/assets/{diagram-3UASUU5V-BLiXkub3.js → diagram-3UASUU5V-UX2eUwyi.js} +1 -1
  34. package/dist/client/assets/{diagram-ATOU4E4O-CnXY0tjf.js → diagram-ATOU4E4O-CEYK5oZO.js} +1 -1
  35. package/dist/client/assets/{diagram-CDSNMT55-BBnDsrf_.js → diagram-CDSNMT55-4uIYrmGp.js} +1 -1
  36. package/dist/client/assets/{diagram-MLGK6HIB-BUiu4OKD.js → diagram-MLGK6HIB-5BGrc92k.js} +1 -1
  37. package/dist/client/assets/{diagram-MPIPVDR6-DiI9FWeO.js → diagram-MPIPVDR6-0BG375Nf.js} +1 -1
  38. package/dist/client/assets/{dist-Co85aeoI.js → dist-hfzhbdYS.js} +1 -1
  39. package/dist/client/assets/{dist-BWYGCgdo.js → dist-uIEEXDIm.js} +1 -1
  40. package/dist/client/assets/{ebnfDiagram-ZINNZB2B-Bg_BLedv.js → ebnfDiagram-ZINNZB2B-CnAveRvy.js} +1 -1
  41. package/dist/client/assets/{elk-276RUBZZ-BO7Zoa7U.js → elk-276RUBZZ-CejJ0q5w.js} +1 -1
  42. package/dist/client/assets/{engine-oniguruma-DCFwTJLE.js → engine-oniguruma-BpOI5GVJ.js} +1 -1
  43. package/dist/client/assets/{erDiagram-OPXOYQCR-DjBak3Ld.js → erDiagram-OPXOYQCR-Lg3_iVkX.js} +1 -1
  44. package/dist/client/assets/eventmodeling-NTZA5JFV-Dh34QIVY.js +1 -0
  45. package/dist/client/assets/flowDiagram-KWPJA3E3-Bcos9jHd.js +1 -0
  46. package/dist/client/assets/{ganttDiagram-FUAMR5RP-CEn0Np5L.js → ganttDiagram-FUAMR5RP-D5nJpDg8.js} +1 -1
  47. package/dist/client/assets/{gitGraph-4MIJSDKK-DVMdaaG2.js → gitGraph-4MIJSDKK-BLNIFBUu.js} +1 -1
  48. package/dist/client/assets/{gitGraphDiagram-X574FWY7-B6ZkiY7u.js → gitGraphDiagram-X574FWY7-YHwgA3VE.js} +1 -1
  49. package/dist/client/assets/index-CE0LasmM.css +1 -0
  50. package/dist/client/assets/index-DYt1d3uP.js +93 -0
  51. package/dist/client/assets/{info-A6RAGUB7-Idt2RahI.js → info-A6RAGUB7-Bfa8ErwC.js} +1 -1
  52. package/dist/client/assets/{infoDiagram-VRGFBTTK-CA8T3csq.js → infoDiagram-VRGFBTTK-Dzp_xQpV.js} +1 -1
  53. package/dist/client/assets/{ishikawaDiagram-OU5B5YK6-DcgLwVJX.js → ishikawaDiagram-OU5B5YK6-Hun-xe-t.js} +1 -1
  54. package/dist/client/assets/{journeyDiagram-ZHPQQLJL-_AVEW5aE.js → journeyDiagram-ZHPQQLJL-CT5fXqj_.js} +1 -1
  55. package/dist/client/assets/{kanban-definition-PNTS6WVX-CZ2gNo-B.js → kanban-definition-PNTS6WVX-kFYcpsMx.js} +1 -1
  56. package/dist/client/assets/{line-CHew3ngr.js → line-Cda_OIfO.js} +1 -1
  57. package/dist/client/assets/{linear-Baz1Hb3u.js → linear-CDQGk4q-.js} +1 -1
  58. package/dist/client/assets/{mermaid-parser.core-D2BrkwRE.js → mermaid-parser.core-CCoRJPAh.js} +3 -3
  59. package/dist/client/assets/{mermaid.core-CCFlYVgY.js → mermaid.core-SnjyC0ZV.js} +4 -4
  60. package/dist/client/assets/{mindmap-definition-NLK3R4M7-BXG9w5sC.js → mindmap-definition-NLK3R4M7-C3oLUr5b.js} +1 -1
  61. package/dist/client/assets/{packet-AYTQ26CC-BOvg32Rh.js → packet-AYTQ26CC-BT6BgV6a.js} +1 -1
  62. package/dist/client/assets/{pegDiagram-GJSIUBJH-COukdq7o.js → pegDiagram-GJSIUBJH-OT5BsfLg.js} +1 -1
  63. package/dist/client/assets/{pie-WAS4IAKB-ChHsdIQV.js → pie-WAS4IAKB-Bou89QXR.js} +1 -1
  64. package/dist/client/assets/{pieDiagram-5QR66LMP-Deng5oun.js → pieDiagram-5QR66LMP-AzEtJfJu.js} +1 -1
  65. package/dist/client/assets/{quadrantDiagram-O4NWA36T-DmEJ83mR.js → quadrantDiagram-O4NWA36T-BUKCkyd7.js} +1 -1
  66. package/dist/client/assets/{radar-RG4KPBEZ-YxcXBiXc.js → radar-RG4KPBEZ-D77V4y6h.js} +1 -1
  67. package/dist/client/assets/{railroad-74A4TZTK-RkYX7A2D.js → railroad-74A4TZTK-CIYb8bnG.js} +1 -1
  68. package/dist/client/assets/railroad-abnf-HS5TGJTU-OVikttJY.js +1 -0
  69. package/dist/client/assets/railroad-ebnf-LZEXJU2U-DPAI1fGw.js +1 -0
  70. package/dist/client/assets/railroad-peg-WCYAUIDC-CcsZpvwt.js +1 -0
  71. package/dist/client/assets/{railroadDiagram-XR7U4H2S-uj5HQbYy.js → railroadDiagram-XR7U4H2S-DhUQyIW9.js} +1 -1
  72. package/dist/client/assets/{requirementDiagram-PLB6GJNP-C_QtkIlI.js → requirementDiagram-PLB6GJNP-5HRstoAa.js} +1 -1
  73. package/dist/client/assets/{sankeyDiagram-IPEJSGJF-BfxM5TKv.js → sankeyDiagram-IPEJSGJF-sNbgZbEH.js} +1 -1
  74. package/dist/client/assets/{sequenceDiagram-PO4LG4MO-DXflg1u_.js → sequenceDiagram-PO4LG4MO-B_vIrQ3k.js} +1 -1
  75. package/dist/client/assets/sizeCapture-INFHLROL-3uHXrFqA.js +1 -0
  76. package/dist/client/assets/{src-YTrwJCk8.js → src-BWz11yEV.js} +1 -1
  77. package/dist/client/assets/{stateDiagram-v2-GCMORJYK-BjDmED1Q.js → stateDiagram-v2-GCMORJYK-BnRt6hQF.js} +1 -1
  78. package/dist/client/assets/{swimlanes-2SLR337P-BAvnQ6KT.js → swimlanes-2SLR337P-CLlJdLDU.js} +1 -1
  79. package/dist/client/assets/swimlanesDiagram-TC7HE7FX-D6iEiuTl.js +8 -0
  80. package/dist/client/assets/{timeline-definition-EJHVYXUP-BYemcgr1.js → timeline-definition-EJHVYXUP-sXwAwUmH.js} +1 -1
  81. package/dist/client/assets/{treeView-Q6P3EWNA-CsuBtqLq.js → treeView-Q6P3EWNA-BmhLEMPr.js} +1 -1
  82. package/dist/client/assets/{treemap-WGGIJYW6-DUk1Z6g4.js → treemap-WGGIJYW6-D_PGkPFQ.js} +1 -1
  83. package/dist/client/assets/{usecaseDiagram-POWQR4AR-j1nHXvyL.js → usecaseDiagram-POWQR4AR-GARihMJS.js} +1 -1
  84. package/dist/client/assets/{vennDiagram-UO4OBE2U-B5eUL-dD.js → vennDiagram-UO4OBE2U-DXSYoTtG.js} +1 -1
  85. package/dist/client/assets/{wardley-WFR3VGLG-1YjpwPJM.js → wardley-WFR3VGLG-Caebv6bl.js} +1 -1
  86. package/dist/client/assets/{wardleyDiagram-VNRHLVJA-C7laBq5A.js → wardleyDiagram-VNRHLVJA-BnFa4EKC.js} +1 -1
  87. package/dist/client/assets/{xychartDiagram-PMCCYNJV-BkYPx-ts.js → xychartDiagram-PMCCYNJV-XS2BbOyB.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/skills/diffo/SKILL.md +7 -4
  92. package/dist/client/assets/architecture-7GRP2DOG-DzlmD0Wj.js +0 -1
  93. package/dist/client/assets/channel-BffjfVqs.js +0 -1
  94. package/dist/client/assets/eventmodeling-NTZA5JFV-BA4dpxhq.js +0 -1
  95. package/dist/client/assets/flowDiagram-KWPJA3E3-BXSGu0Q5.js +0 -1
  96. package/dist/client/assets/index-6w3rS9cw.js +0 -91
  97. package/dist/client/assets/index-D934d4yh.css +0 -1
  98. package/dist/client/assets/railroad-abnf-HS5TGJTU-CYF7Z2Wu.js +0 -1
  99. package/dist/client/assets/railroad-ebnf-LZEXJU2U-CqV11tet.js +0 -1
  100. package/dist/client/assets/railroad-peg-WCYAUIDC-CPusJj6I.js +0 -1
  101. package/dist/client/assets/sizeCapture-INFHLROL-B0uUizjq.js +0 -1
  102. package/dist/client/assets/swimlanesDiagram-TC7HE7FX-CbFPwcec.js +0 -8
package/README.md CHANGED
@@ -11,76 +11,61 @@
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
34
37
  while it runs — and nothing else is cut. -->
35
- <img alt="One take of the whole loop. A Claude Code session has just written natural-language due dates into a todo app; the reviewer types /diffo, and the session opens a live review and hands over its localhost URL, which opens beside the session. The reviewer leaves a question on the weekday line — a bare weekday always lands next week, should it mean today? — and the agent's answer appears in the thread while they watch." src="docs/assets/loop.gif" width="100%">
38
+ <img alt="One take of the whole loop. A Claude Code session has just written natural-language due dates into a todo app; the reviewer types /diffo, and the session opens a live review and hands over its localhost URL, which opens beside the session. The reviewer leaves a question on the weekday line (a bare weekday always lands next week, should it mean today?) and the agent's answer appears in the thread while they watch." src="docs/assets/loop.gif" width="100%">
36
39
 
37
- <p align="center"><sub>The whole loop in one take: type <code>/diffo</code>, read the diff, ask on the line — and the answer comes back in the thread. Left is a real Claude Code session, right is the real review it opened. Nothing here is a mock-up; the only edit is that waiting on the agent runs fast.</sub></p>
40
+ <p align="center"><sub>The whole loop in one take: type <code>/diffo</code>, read the diff, ask on the line, and the answer comes back in the thread. Left is a real Claude Code session, right is the real review it opened. Nothing here is a mock-up; the only edit is that waiting on the agent runs fast.</sub></p>
38
41
 
39
42
  ---
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, and that is the only time Diffo touches
64
+ the network.
80
65
 
81
66
  New here? [**Your first review, end to end**](https://diffohq.github.io/diffo/tutorial) takes about five minutes.
82
67
 
83
- ## Why Diffo
68
+ ## Talk to the agent on the line
84
69
 
85
70
  **We write code with an LLM. We review it alone.**
86
71
 
@@ -89,110 +74,59 @@ the thing is right. Reviewing never did. The code lands, the conversation ends,
89
74
  read four hundred lines by yourself, in a viewer built for a world where whoever wrote it
90
75
  had already moved on.
91
76
 
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**
77
+ Diffo keeps the conversation open through the review. The judgement stays yours. You just
78
+ stop reading alone.
149
79
 
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**
80
+ - **Ask on any line.** The agent that wrote the code answers in the thread, with a
81
+ diagram when the shape needs one. Mark a thread a **Question** and it explains; mark it
82
+ a **Change** and it edits, so a question never turns into an unrequested refactor.
83
+ - **Fixes land in the diff you're reading.** The diff updates under your cursor, and a
84
+ hunk you had already read says *changed since you read it*, so the second pass stays
85
+ honest.
86
+ - **A map, not a verdict.** On a multi-file or subtle change the agent opens the review
87
+ with one orienting comment on what the change does. It never pre-reviews: no verdicts,
88
+ nothing is "fine". That judgement is the part it doesn't get to make.
89
+ ## Read it in layers
160
90
 
161
91
  A diff arrives alphabetically, which is almost never the order to read it in. Ask, and the
162
92
  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>
93
+ files. You read one layer at a time, in the order the agent would explain it; `]` steps to
94
+ the next. Anything the agent touches after posting gathers in a *Since your review* layer,
95
+ so nothing hides outside the plan.
169
96
 
170
97
  <picture>
171
98
  <source media="(prefers-color-scheme: dark)" srcset="docs/assets/layers-dark.gif">
172
99
  <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
100
  </picture>
174
101
 
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>
102
+ <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
103
 
177
- ## Where it fits
104
+ ## Review a pull request
178
105
 
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.
106
+ When a pull request lands on *your* desk, give your agent the link. It checks the PR out
107
+ in a worktree of its own, so your checkout is never touched, and opens it as the same
108
+ review: the description and the GitHub threads come with it, and the agent reads beside
109
+ you as a copilot for code it did not write. Every comment has two tabs. **Comment on PR**
110
+ goes to the author, as one review when you finish. **Ask agent** stays on your machine:
111
+ the agent can run the tests and answer with evidence, and it never posts to GitHub.
182
112
 
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 |
113
+ <!-- Light-theme only, like the hero. The pull request is a real one on a demo repo
114
+ (DiffoHQ/todo-demo#1), and the review at the end is the one this take submitted. -->
115
+ <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
116
 
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.
117
+ <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
118
 
195
- ---
119
+ ## Where it fits
120
+
121
+ Diffo isn't an AI reviewer. It doesn't grade your diff or leave generated nitpicks: you
122
+ read, and the agent is there to answer, explain, and fix.
123
+
124
+ | | **Diffo** | AI reviewer bot | Plain pull request review |
125
+ | --- | --- | --- | --- |
126
+ | Who reads the code | **you** | a model | you |
127
+ | Who answers your questions | **the agent, in the thread, now** | nobody | the author, when they get to it |
128
+ | When | **while the agent writes, or when the PR lands** | after you push | after you push |
129
+ | What comes out | **fixes in the diff, or a review on GitHub** | a list of comments | a review on GitHub |
196
130
 
197
131
  ## How it works
198
132
 
@@ -201,17 +135,11 @@ the stage where spending it changes the outcome.
201
135
  <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%">
202
136
  </picture>
203
137
 
204
- The left half is a diff viewer. The right half is what Diffo is for: your comment doesn't
205
- land in a queue for later, it lands in **the conversation that wrote the code**, while that
206
- conversation still remembers why. Nothing needs to be committed, pushed, or opened as a PR
207
- first, so agent output is reviewable the moment it hits the disk, which is the moment it's
208
- cheapest to change.
209
-
210
- | You want to review | Command |
211
- | --- | --- |
212
- | Uncommitted work in progress (the default) | `diffo` |
213
- | Everything since you branched off `main` | `diffo --base main` |
214
- | A pull request | *not supported yet* |
138
+ One process on your machine, bound to loopback: no account, no cloud, no telemetry, and
139
+ no model API. Diffo spawns no agents of its own; the one you're already talking to stays
140
+ attached through the `diffo` CLI, so your comments land in the session that holds the
141
+ context. The viewer itself is a real diff viewer, unified and split, keyboard-first, with
142
+ GitHub's conventions. The CLI, the flags, and everything under the hood are in the docs.
215
143
 
216
144
  ## Docs
217
145
 
@@ -219,79 +147,31 @@ cheapest to change.
219
147
  | --- | --- |
220
148
  | [**Your first review**](https://diffohq.github.io/diffo/tutorial) | The whole loop end to end, about five minutes |
221
149
  | [**Getting started**](https://diffohq.github.io/diffo/guide/getting-started) | Install, and where each agent gets wired |
222
- | [**The review loop**](https://diffohq.github.io/diffo/guide/the-loop) | Reading, layers, commenting, and what the agent receives |
150
+ | [**The review loop**](https://diffohq.github.io/diffo/guide/the-loop) | Reading, commenting, and what the agent receives |
151
+ | [**Layers**](https://diffohq.github.io/diffo/guide/layers) | The agent's reading plan: ordered steps, one at a time |
152
+ | [**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 |
223
153
  | [**How it works**](https://diffohq.github.io/diffo/guide/how-it-works) | The components and the server lifecycle |
224
154
  | [**The agent side**](https://diffohq.github.io/diffo/agents) | The agent protocol: every command, every payload |
225
155
  | [**Architecture**](https://diffohq.github.io/diffo/architecture) | Diff pipeline, delivery queue, SQLite state |
226
156
  | [**CLI**](https://diffohq.github.io/diffo/reference/cli) and [**Keyboard shortcuts**](https://diffohq.github.io/diffo/reference/keyboard-shortcuts) | Reference |
227
157
  | [**FAQ**](https://diffohq.github.io/diffo/faq) | The short answers |
228
158
 
229
- ## Under the hood
230
-
231
- TypeScript on Node >= 24: a [Hono](https://hono.dev) server over loopback serving a React 19
232
- UI, live updates over server-sent events from one recursive filesystem watch, and state in a
233
- single SQLite file at `~/.diffo/diffo.db` through the runtime's built-in `node:sqlite`, so
234
- there is no database to install. **Zero network calls.** 1,143 tests across 63 files.
235
-
236
- Reviews are scoped per repo **and branch**, and the server is loopback-only, rejecting
237
- non-loopback `Host` and `Origin` headers so a web page can't reach into your repo through
238
- it. The full walkthrough is in [**Architecture**](https://diffohq.github.io/diffo/architecture).
239
-
240
- <details>
241
- <summary><b>Why read marks survive a live diff</b></summary>
242
-
243
- <br>
244
-
245
- Every hunk carries a **content-addressed id**: a hash of its path and changed lines, and
246
- deliberately not its line numbers. That one decision is what makes the live review honest.
247
-
248
- - Read marks survive a refresh, because an untouched hunk keeps its id.
249
- - An edited hunk mints a new id, loses its mark, and says **changed since you read it**. You
250
- can't accidentally sign off on code you never saw.
251
- - The ids from your last Finish are a complete record of what existed then, so "what moved
252
- since I last looked" is a set subtraction, needing no timestamps.
253
-
254
- </details>
255
-
256
- ---
257
-
258
159
  ## Open core
259
160
 
260
161
  Everything in this repository is the core, and the core stays Apache-2.0: local review, the
261
- agent loop, the CLI, the Agent Skill. It works offline, for one reviewer, forever, for free.
262
-
263
- A hosted team tier is planned: shared changesets, review history across a team, SSO. None of
264
- it exists yet, and none of it will take an existing core feature behind a paywall. The line
265
- we commit to: **anything that runs on your machine for one reviewer is core.**
266
-
267
- ## Status
268
-
269
- Diffo is pre-1.0: the loop below works end to end — this repo is reviewed with it
270
- daily — and the edges are still moving. What works today:
271
-
272
- - [x] [Live review of any changeset](https://diffohq.github.io/diffo/guide/how-it-works): the working tree, or anything since `--base`.
273
- - [x] [The comment loop](https://diffohq.github.io/diffo/guide/the-loop): threads that reach the session that wrote the code.
274
- - [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.
275
- - [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.
276
- - [x] [Reading tools](https://diffohq.github.io/diffo/reference/keyboard-shortcuts): unified and split diffs, word-level marks, coverage tracking.
162
+ agent loop, pull request review, the CLI, the Agent Skill. It works offline, for one
163
+ reviewer, forever, for free. A hosted team tier is planned, and none of it will take an
164
+ existing core feature behind a paywall: **anything that runs on your machine for one
165
+ reviewer is core.**
277
166
 
278
167
  ## Contributing
279
168
 
280
- Five gates, all of which CI runs, or `pnpm check` for all five:
281
-
282
- ```bash
283
- pnpm typecheck && pnpm test && pnpm build && pnpm lint && pnpm docs:build
284
- ```
285
-
286
- Local development is `pnpm dev` (server and client together). One hard rule:
287
- **`skills/diffo/SKILL.md` is generated.** Edit [`src/skill.ts`](src/skill.ts) and run
288
- `pnpm build:skill`; a test fails if the committed file drifts. That rewrites the repo
289
- file, not the skill your own agent runs — `pnpm dev:skill --global` installs a separate
290
- `/diffo-dev` that drives your checkout, alongside the shipped `/diffo`.
291
-
292
- Details in [CONTRIBUTING.md](CONTRIBUTING.md), plus a [Code of Conduct](CODE_OF_CONDUCT.md)
293
- and the [CHANGELOG](CHANGELOG.md). First-time contributors sign a [CLA](CLA.md): a bot asks
294
- on your first pull request, and signing is one reply.
169
+ Diffo is pre-1.0: this repo is reviewed with it daily, and the edges are still moving.
170
+ `pnpm check` runs the five gates CI runs. One hard rule: **`skills/diffo/SKILL.md` is
171
+ generated** from [`src/skill.ts`](src/skill.ts); edit the source and run `pnpm build:skill`.
172
+ [CONTRIBUTING.md](CONTRIBUTING.md) has the rest, with a [Code of Conduct](CODE_OF_CONDUCT.md),
173
+ the [CHANGELOG](CHANGELOG.md), and the [CLA](CLA.md) a bot asks first-time contributors to
174
+ sign, in one reply.
295
175
 
296
176
  Found a security problem? Please don't open a public issue. The
297
177
  [Security Policy](SECURITY.md) says where to send it and what's in scope.