@coldtea/pr-lens-agent-skill 0.2.0 → 0.4.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.
package/SKILL.md CHANGED
@@ -11,11 +11,13 @@ The diff or code is represented as one JSON document (lanes, nodes, edges, order
11
11
 
12
12
  ## Operating manual
13
13
 
14
+ Decide where the diagram lands before you write it: a canvas, or an SVG and a pull request comment. Only a canvas draws `payload`, the sample request and response on a flow step. A late decision costs another pass through steps 2 and 3.
15
+
14
16
  1. **Read the diff.** When asked to represent a code change: `git diff --find-renames <base>...<head>`. The base is the merge base, not the tip of the base branch.
15
17
 
16
18
  If not expressing a code diff, read the code to be visually represented
17
19
 
18
- 2. **Write the document** to `.pr-lens/graph.json`, following `references/graph-document.md`. `references/example.graph.json` is valid reference with three lanes, all four delta states, a hero edge, a seven-step flow, a nested drill-down tree and a six-step walkthrough. Read it before you write your first one. It is quicker than reading the reference.
20
+ 2. **Write the document** to `.pr-lens/graph.json`, following `references/graph-document.md`. `references/example.graph.json` is valid reference with three lanes, all four delta states, a hero edge, a seven-step flow, a nested drill-down tree and a six-step walkthrough. Read it before you write your first one. It is quicker than reading the reference. If it is going to a canvas, give every flow step (`messages`) that moves data a `payload` as you write it. "Sample traffic on a flow step" below says what goes in one. Only a flow step carries one. Flows need the `data-flow` lens, so an architecture view draws none.
19
21
 
20
22
  3. **Validate, and fix**
21
23
 
@@ -28,20 +30,24 @@ The diff or code is represented as one JSON document (lanes, nodes, edges, order
28
30
  4. **Render.**
29
31
 
30
32
  ```bash
31
- npx @coldtea/pr-lens-cli@latest render .pr-lens/graph.json --theme dark
33
+ npx @coldtea/pr-lens-cli@latest render .pr-lens/graph.json --theme light
32
34
  ```
33
35
 
34
- Render dark as the default theme unless explicitly requested. The SVGs, the manifest and `drawn.graph.json` land in `.pr-lens/`, which the CLI adds to the repository's .gitignore. Do not commit any of it. These files are rebuilt from the diff whenever anyone wants them again. Each SVG is named after its view, the theme and a content hash; `manifest.json` lists them by lens and view, so read the names from there or from the directory.
36
+ Render light by default unless the user requests another theme. The SVGs, the manifest and `drawn.graph.json` land in a directory of their own under `.pr-lens/`, named after the document's title. The render prints that path, so read it from there. The CLI adds `.pr-lens/` to the repository's .gitignore. Do not commit any of it. These files are rebuilt from the diff whenever anyone wants them again. Each SVG is named after its view, the theme and a content hash; `manifest.json` lists them by lens and view, so read the names from there or from the directory.
35
37
 
36
38
  If the user asked for a diagram, an explanation or a picture of the architecture and nothing more, put it on a canvas and hand back the link:
37
39
 
38
40
  ```bash
39
- npx @coldtea/pr-lens-cli@latest canvas push
41
+ npx @coldtea/pr-lens-cli@latest canvas push .pr-lens/<drawing>/drawn.graph.json
40
42
  ```
41
43
 
42
- This pushes `.pr-lens/drawn.graph.json` and prints three links. Give the user the view link, `https://prlens.dev/c/{id}`: that is the diagram, full screen, every view on one page, and it opens without a login. The edit link, the one ending in `#w=…`, lets its holder push over the canvas, so leave it out of the reply unless they ask, and never paste it anywhere public. The embed link serves the top view as an SVG for a README.
44
+ Pass the path the render printed. A bare `canvas push` finds the drawing when the checkout holds only one; with more than one it lists them and asks which, so always pass the path.
45
+
46
+ It prints three links. Give the user the view link, `https://prlens.dev/c/{id}`: that is the diagram, full screen, every view on one page, and it opens without a login. The edit link, the one ending in `#w=…`, lets its holder push over the canvas, so leave it out of the reply unless they ask, and never paste it anywhere public. The embed link serves the top view as an SVG for a README.
47
+
48
+ Pushing the same document again updates the same canvas, so a follow-up such as "rename that node" or "add the queue" is: edit the document, validate, render, push. While the title stays the same, it renders to the same directory and pushes to the same canvas, so the link does not change. If the push fails, say so and tell them where the SVGs are and which one is the top view.
43
49
 
44
- Pushing the same file again updates the same canvas, so a follow-up such as "rename that node" or "add the queue" is: edit the document, validate, render, push. The link stays the same. If the push fails, say so and tell them where the SVGs are and which one is the top view.
50
+ A different diagram only needs a different title. It renders into its own directory and pushes to its own canvas, and the first one stays as it was. `canvas list` shows them all.
45
51
 
46
52
  5. **Attach, when there is a pull request to attach to.** That means the user asked you to open a PR, asked for a diagram on one that exists, or you are opening a PR as part of changes made. Otherwise skip this step.
47
53
 
@@ -50,12 +56,12 @@ The diff or code is represented as one JSON document (lanes, nodes, edges, order
50
56
  ```markdown
51
57
  Moves bulk sending off the per-recipient trigger and onto a batch endpoint.
52
58
 
53
- ![Architecture after this change: the queue route, the new bulk sender and the retired per-recipient path](.pr-lens/overview-dark-4f9bd6c1.svg)
59
+ ![Architecture after this change: the queue route, the new bulk sender and the retired per-recipient path](.pr-lens/overview-light-4f9bd6c1.svg)
54
60
  ```
55
61
 
56
62
  ```bash
57
63
  gh pr create --title "Batch broadcast sends" --body-file .pr-lens/body.md \
58
- --attach .pr-lens/overview-dark-4f9bd6c1.svg
64
+ --attach .pr-lens/overview-light-4f9bd6c1.svg
59
65
  ```
60
66
 
61
67
  On a pull request that already exists, `gh pr edit <number>` with the same two flags puts the diagram in the description, and `gh pr comment <number>` puts it in a comment. Repeat `--attach` for each diagram the body references.
@@ -71,12 +77,12 @@ The diff or code is represented as one JSON document (lanes, nodes, edges, order
71
77
 
72
78
  ```bash
73
79
  npx @coldtea/pr-lens-cli@latest comment \
74
- --graph .pr-lens/drawn.graph.json \
75
- --manifest .pr-lens/manifest.json \
80
+ --graph .pr-lens/<drawing>/drawn.graph.json \
81
+ --manifest .pr-lens/<drawing>/manifest.json \
76
82
  --asset-base-url https://raw.githubusercontent.com/<owner>/<repo>/<branch>/<dir>
77
83
  ```
78
84
 
79
- `--graph` takes `drawn.graph.json`, not the document you wrote, because corrections change what the diagrams show and the CLI refuses a document its manifest does not describe. `--asset-base-url` is where you published the SVGs; leave it out and the markdown points at local paths no reader can fetch. The markdown goes to stdout, with each diagram as a `<picture>` pair; posting it is your business.
85
+ `--graph` takes the drawing's own `drawn.graph.json`, not the document you wrote, because corrections change what the diagrams show and the CLI refuses a document its manifest does not describe. `--asset-base-url` is where you published the SVGs; leave it out and the markdown points at local paths no reader can fetch. The markdown goes to stdout, with each diagram as a `<picture>` pair; posting it is your business.
80
86
 
81
87
  If you would rather not author the document yourself, `npx @coldtea/pr-lens-cli@latest analyze --base <ref>` does steps 1 and 2 by asking a provider — Gemini, OpenAI, or any endpoint speaking `/chat/completions` — with a key of your own. That is the only path here that needs one.
82
88
 
@@ -161,6 +167,69 @@ The validator checks:
161
167
 
162
168
  The field arrived with contract 0.1.1. A CLI older than 0.4.0 does not know it and rejects the whole document as an invented field, so validate with a current one.
163
169
 
170
+ ## Sample traffic on a flow step
171
+
172
+ A flow step can carry a `payload`: what travels on it. Only the canvas draws it, in the rail that opens when a reader clicks a step. Nothing in an SVG or a pull request comment changes. Write it when the document is going to a canvas (step 4, `canvas push`) and leave it out otherwise. Six payloads on the reference document add half its length again, so this is not a field to fill by default.
173
+
174
+ On a canvas document, add it to a step that moves data: a request body, a job record, a query, a result. Leave it off a step that only signals, such as a trigger with nothing attached.
175
+
176
+ ```json
177
+ {
178
+ "id": "batch-post",
179
+ "from": "send-broadcast-bulk",
180
+ "to": "postmark",
181
+ "label": "POST /email/batch",
182
+ "kind": "sync",
183
+ "delta": "added",
184
+ "repeat": 4,
185
+ "payload": {
186
+ "request": {
187
+ "type": "EmailBatch[500]",
188
+ "shape": "Email[] // max 500\nEmail = { From: string; To: string; Subject: string; HtmlBody: string; MessageStream: \"broadcast\"; Metadata: { campaignId: string; batchId: string } }",
189
+ "sample": [
190
+ {
191
+ "From": "news@example.com",
192
+ "To": "ada@example.com",
193
+ "Subject": "The batching issue, fixed",
194
+ "HtmlBody": "<!doctype html><html><body>…",
195
+ "MessageStream": "broadcast",
196
+ "Metadata": { "campaignId": "cmp_0001", "batchId": "b_0001" }
197
+ }
198
+ ],
199
+ "before": [
200
+ {
201
+ "From": "news@example.com",
202
+ "To": "ada@example.com",
203
+ "Subject": "The batching issue, fixed",
204
+ "HtmlBody": "<!doctype html><html><body>…",
205
+ "Metadata": { "campaignId": "cmp_0001" }
206
+ }
207
+ ],
208
+ "source": { "path": "tests/fixtures/postmark-batch.json" }
209
+ },
210
+ "response": {
211
+ "type": "BatchResult[500]",
212
+ "shape": "SendResult[] // one per Email, same order",
213
+ "sample": [{ "ErrorCode": 0, "Message": "OK", "To": "ada@example.com", "MessageID": "b7fa5c1e-…" }]
214
+ }
215
+ }
216
+ }
217
+ ```
218
+
219
+ A payload has a `request` side, a `response` side, or both. Each side has:
220
+
221
+ - `type`: the name a reader of the code would recognise. Put the count in it when the step carries a collection: `EmailBatch[500]`, not `EmailBatch`. Write `{ "type": "void" }` for a side that carries nothing, such as the answer to a fire and forget call.
222
+ - `shape`: the type signature as text, taken from the code's own types. Up to 2048 bytes.
223
+ - `sample`: one exemplar instance after the change, written inline as JSON. It is a JSON value, not a JSON string: `"sample": [{ "To": "ada@example.com" }]`, never `"sample": "[{\"To\": ...}]"`. A string here is rejected. Every key once, one element in any array, long strings cut with an ellipsis. At most 8 levels deep and 4096 bytes once serialised. The parser refuses a sample over either cap rather than trimming it.
224
+ - `before`: the same exemplar as it was before the change, when it differs. Same rules as `sample`, and it needs a `sample` to differ from.
225
+ - `source`: the fixture or type the shape and sample came from, as a file reference. It becomes the permalink.
226
+
227
+ Use placeholder values: `ada@example.com`, `cmp_0001`. Never copy a value from a fixture that could belong to a real person or unlock something, even in test data.
228
+
229
+ Do not write `changedPaths`. The paths that differ between `before` and `sample` are worked out when the document is stored. A list you write is discarded.
230
+
231
+ The field arrived with contract 0.2.0. A CLI built before it rejects the whole document as an invented field, so validate with a current one.
232
+
164
233
  ## What the validator will catch
165
234
 
166
235
  Read `references/graph-document.md` before writing. The four failures that account for nearly everything:
@@ -172,14 +241,14 @@ Read `references/graph-document.md` before writing. The four failures that accou
172
241
  | `DUPLICATE_ID` | two nodes, edges or views sharing an id |
173
242
  | `UNSUPPORTED_SCHEMA_VERSION` | `schemaVersion` is not the contract version installed |
174
243
 
175
- Six rules cannot be expressed in JSON Schema and are checked only by the parser, so structured output alone does not make a document valid: referential integrity, a line range that ends before it starts, a `self` message whose endpoints disagree, a patch whose two commits are the same, more views than a render manifest could describe, and a walkthrough step focusing flow steps the diagram on its stage does not draw. Always validate.
244
+ Seven rules cannot be expressed in JSON Schema and are checked only by the parser, so structured output alone does not make a document valid: referential integrity, a line range that ends before it starts, a `self` message whose endpoints disagree, a patch whose two commits are the same, more views than a render manifest could describe, a walkthrough step focusing flow steps the diagram on its stage does not draw, and sample traffic past its depth or byte caps. Always validate.
176
245
 
177
246
  ## Fixing a map instead of writing one
178
247
 
179
248
  When someone says the diagram is wrong (a node is misnamed, a folder should not be on it, something sits in the wrong lane), do not edit the generated document. It is regenerated on every run. Write the correction into `.github/pr-lens.yml`, which is an overlay applied over fresh inference every time:
180
249
 
181
250
  ```yaml
182
- schemaVersion: 0.1.1
251
+ schemaVersion: 0.2.0
183
252
  map:
184
253
  rename:
185
254
  - match: functions/src/broadcast/sendBroadcastBulk.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coldtea/pr-lens-agent-skill",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "The PR Lens skill for coding agents: author a graph document from a diff, validate it, render it, and correct a repository's map.",
5
5
  "license": "MIT",
6
6
  "author": "Coldtea AI",
@@ -34,8 +34,8 @@
34
34
  "typescript": "7.0.2",
35
35
  "vitest": "4.1.11",
36
36
  "yaml": "^2.8.1",
37
- "@coldtea/pr-lens-renderer": "^0.2.0",
38
- "@coldtea/pr-lens-schema": "^0.2.0"
37
+ "@coldtea/pr-lens-renderer": "^0.2.6",
38
+ "@coldtea/pr-lens-schema": "^0.4.0"
39
39
  },
40
40
  "scripts": {
41
41
  "skill:sync": "tsx scripts/sync.ts",
@@ -3,7 +3,7 @@
3
3
  The generated document is regenerated on every run, so editing it is pointless. Corrections live in `.github/pr-lens.yml`, an overlay applied over fresh inference every time. Inference never writes back into this file, which is why a correction keeps holding as the code moves.
4
4
 
5
5
  ```yaml
6
- schemaVersion: 0.1.1 # required
6
+ schemaVersion: 0.2.0 # required
7
7
  lenses: [architecture, data-flow]
8
8
  branding: true
9
9
  map:
@@ -88,6 +88,8 @@ The hosted App reads `github` settings from the PR's head commit. Other options
88
88
  | Setting | Default | Effect |
89
89
  | --- | --- | --- |
90
90
  | `github.comment.collapsed` | `false` | Start diagrams and details closed. Drawing still runs automatically. |
91
+ | `github.draw` | `auto` | `on-demand` leaves a pull request undrawn, with a short notice, until someone comments `@pr-lens draw`. |
92
+ | `github.comment.notice` | `true` | `false` drops that notice, so an on-demand repository hears nothing until someone asks. |
91
93
 
92
94
  ## Check it
93
95
 
@@ -1,5 +1,5 @@
1
1
  {
2
- "schemaVersion": "0.1.1",
2
+ "schemaVersion": "0.2.0",
3
3
  "kind": "graph",
4
4
  "generatedAt": "2026-08-19T18:24:00.000Z",
5
5
  "title": "Batch broadcast sending through Postmark",
@@ -10,7 +10,7 @@ Every schema here is **strict**: an unknown key is a rejection, not a warning. A
10
10
 
11
11
  ```json
12
12
  {
13
- "schemaVersion": "0.1.1",
13
+ "schemaVersion": "0.2.0",
14
14
  "kind": "graph",
15
15
  "title": "Batch broadcast sending through Postmark",
16
16
  "summary": "One paragraph answering: what does this change do?",
@@ -114,6 +114,39 @@ Up to 16, for the data-flow lens.
114
114
  - `kind` is `sync`, `async`, `return` or `self`. `self` requires `from === to`, and no other kind may have them equal.
115
115
  - Both endpoints must be participants of that flow, not merely nodes of the document.
116
116
  - `repeat` says a step happens more than once per run, e.g. 4 batched requests.
117
+ - `payload`: what travels on the step. Optional. Only a canvas draws it, so leave it out of a document that is not going to one.
118
+
119
+ ### Sample traffic
120
+
121
+ ```json
122
+ {
123
+ "id": "send",
124
+ "from": "send-broadcast-bulk",
125
+ "to": "postmark",
126
+ "label": "POST /email/bulk",
127
+ "kind": "sync",
128
+ "delta": "added",
129
+ "payload": {
130
+ "request": {
131
+ "type": "EmailBatch[500]",
132
+ "shape": "Email[] // max 500\nEmail = { From: string; To: string; Subject: string }",
133
+ "sample": [{ "From": "news@example.com", "To": "ada@example.com", "Subject": "The batching issue, fixed" }],
134
+ "before": [{ "From": "news@example.com", "To": "ada@example.com", "Cc": "ops@example.com", "Subject": "The batching issue, fixed" }],
135
+ "source": { "path": "tests/fixtures/postmark-batch.json" }
136
+ },
137
+ "response": { "type": "void" }
138
+ }
139
+ }
140
+ ```
141
+
142
+ - A payload has `request`, `response` or both. One with neither is rejected.
143
+ - `type` is required on a side: a name a reader of the code would know, with the count in it for a collection (`EmailBatch[500]`). `void` for a side that carries nothing.
144
+ - `shape` is the type signature as text, up to 2048 bytes.
145
+ - `sample` and `before` are JSON values written inline, not JSON strings. A string where a value belongs is rejected. Each is at most 8 levels deep and 4096 bytes once serialised. The parser refuses a value over either cap rather than truncating it.
146
+ - `before` needs a `sample` to differ from.
147
+ - `source` is a file reference, the fixture or type the side was taken from.
148
+ - `changedPaths` is filled in when the document is stored, from `before` and `sample`. Do not write it. Up to 64 paths of the form `Metadata.batchId`, `[0].Cc` or `headers["Content-Type"]`.
149
+ - Use placeholder values in samples: `ada@example.com`, `cmp_0001`. Never one that could belong to a real person or unlock anything.
117
150
 
118
151
  ## Stats
119
152
 
@@ -267,7 +300,7 @@ Repository-relative POSIX paths: no leading `/`, no drive letter, no backslash,
267
300
 
268
301
  ## Length limits
269
302
 
270
- Labels 120 characters, summaries 2000, chip values 32. They are display fields: a label that needs 120 characters is a label the diagram cannot draw.
303
+ Labels 120 characters, summaries 2000, chip values 32. They are display fields: a label that needs 120 characters is a label the diagram cannot draw. On a payload side, `shape` 2048 bytes, `sample` and `before` 4096 bytes each once serialised and 8 levels deep, `changedPaths` 64 entries.
271
304
 
272
305
  ## Then validate
273
306