@erclx/canon 5.23.0 → 5.25.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 (98) hide show
  1. package/claude/.claude-plugin/plugin.json +1 -1
  2. package/claude/skills/backlog-triage/REQUIREMENT.md +2 -2
  3. package/claude/skills/backlog-triage/SKILL.md +19 -6
  4. package/claude/skills/canon-operator/REQUIREMENT.md +1 -0
  5. package/claude/skills/canon-operator/SKILL.md +5 -1
  6. package/claude/skills/canvas/REQUIREMENT.md +49 -0
  7. package/claude/skills/canvas/SKILL.md +106 -0
  8. package/claude/skills/design-extract/REQUIREMENT.md +1 -1
  9. package/claude/skills/draft-doc/REQUIREMENT.md +2 -1
  10. package/claude/skills/draft-doc/references/readme/agent-facing.md +59 -0
  11. package/claude/skills/draft-doc/references/readme/application.md +66 -0
  12. package/claude/skills/draft-doc/references/readme/cli.md +64 -0
  13. package/claude/skills/draft-doc/references/readme/library.md +57 -0
  14. package/claude/skills/draft-doc/references/readme/plugin.md +66 -0
  15. package/claude/skills/draft-doc/references/readme.md +33 -4
  16. package/claude/skills/draft-figure/REQUIREMENT.md +14 -3
  17. package/claude/skills/draft-figure/SKILL.md +24 -51
  18. package/claude/skills/draft-figure/references/architecture-set.md +35 -0
  19. package/claude/skills/draft-figure/references/hand-drawn.md +31 -0
  20. package/claude/skills/draft-figure/references/mermaid.md +55 -0
  21. package/claude/skills/git-followup/SKILL.md +17 -6
  22. package/claude/skills/git-pr/references/evidence.md +4 -2
  23. package/claude/skills/git-split/SKILL.md +1 -1
  24. package/claude/skills/index-lookup/SKILL.md +2 -2
  25. package/claude/skills/review-address/SKILL.md +6 -13
  26. package/claude/skills/review-address/references/rest-reads.md +43 -0
  27. package/claude/skills/review-craft/references/ui.md +7 -1
  28. package/claude/skills/review-pr/REQUIREMENT.md +1 -0
  29. package/claude/skills/review-pr/SKILL.md +9 -3
  30. package/claude/skills/review-pr/references/close-out.md +2 -2
  31. package/claude/skills/review-pr/references/post.md +17 -5
  32. package/claude/skills/review-pr/references/scope.md +10 -8
  33. package/claude/skills/review-ui/SKILL.md +12 -4
  34. package/claude/skills/role-orchestrator/references/orchestrator-cloud-launch.md +30 -1
  35. package/claude/skills/role-orchestrator/references/orchestrator-launch.md +4 -0
  36. package/claude/skills/role-orchestrator/references/orchestrator-poll.md +4 -4
  37. package/claude/skills/role-orchestrator/references/orchestrator-review-dispatch.md +6 -0
  38. package/claude/skills/role-orchestrator/scripts/poll.ts +90 -27
  39. package/claude/skills/role-orchestrator/scripts/repo.ts +3 -5
  40. package/claude/skills/role-orchestrator/scripts/watch.ts +4 -7
  41. package/docs/agents/canvas.md +6 -2
  42. package/docs/agents/commands.md +45 -45
  43. package/docs/agents/context-audit-checks.md +2 -2
  44. package/docs/agents/index.md +0 -1
  45. package/docs/agents/key-changes.md +3 -3
  46. package/docs/agents/pr-evidence.md +11 -2
  47. package/docs/agents/pr-reads.md +5 -4
  48. package/docs/target/projects.md +4 -4
  49. package/docs/workflow/ai-workflow.md +0 -1
  50. package/docs/workflow/skill-map.md +3 -3
  51. package/docs/workflow/visual-design-workflow.md +2 -1
  52. package/governance/renames.toml +0 -4
  53. package/governance/rules/standards/markdown.md +1 -0
  54. package/package.json +1 -2
  55. package/scripts/core/install-check.sh +1 -1
  56. package/src/audits/catalog.ts +2 -2
  57. package/src/canvas/client/inspector/field.tsx +200 -0
  58. package/src/canvas/client/inspector/fields.css +151 -0
  59. package/src/canvas/client/inspector/section.tsx +27 -0
  60. package/src/canvas/client/inspector/values.ts +60 -0
  61. package/src/canvas/client/inspector.tsx +192 -111
  62. package/src/canvas/client/shell.css +0 -94
  63. package/src/canvas/tokens.ts +9 -1
  64. package/src/claude/cases/misc.ts +5 -0
  65. package/src/claude/cases/workflow.ts +1 -1
  66. package/src/claude/seeds.ts +0 -1
  67. package/src/commands/canvas.ts +29 -0
  68. package/src/commands/design.ts +2 -64
  69. package/src/commands/pr.ts +219 -202
  70. package/src/context/audit.ts +7 -6
  71. package/src/design/budget.ts +149 -0
  72. package/src/design/document.ts +22 -10
  73. package/src/design/render.ts +11 -1
  74. package/src/design/tokens.ts +40 -61
  75. package/src/gate/measures.ts +49 -0
  76. package/src/gate/stages.ts +5 -1
  77. package/src/help.ts +2 -2
  78. package/src/migrate/skill-names.ts +7 -1
  79. package/src/pr/evidence.ts +25 -5
  80. package/src/pr/rest.ts +137 -0
  81. package/standards/canvas.md +112 -0
  82. package/standards/context.md +2 -1
  83. package/standards/design.md +13 -3
  84. package/standards/figures.md +0 -1
  85. package/standards/index.md +1 -1
  86. package/standards/markdown.md +1 -0
  87. package/standards/mermaid.md +1 -7
  88. package/tooling/claude/reference.md +0 -5
  89. package/tooling/claude/seeds/.claude/hooks/scratch-guard.sh +1 -1
  90. package/claude/skills/draft-diagram/REQUIREMENT.md +0 -45
  91. package/claude/skills/draft-diagram/SKILL.md +0 -177
  92. package/docs/agents/design-board.md +0 -33
  93. package/governance/rules/standards/diagrams.md +0 -14
  94. package/governance/rules/standards/mermaid.md +0 -15
  95. package/scripts/core/check-gallery-exclusion.sh +0 -50
  96. package/src/design/board.ts +0 -576
  97. package/standards/diagrams.md +0 -132
  98. package/tooling/claude/seeds/.claude/diagrams/index.md +0 -8
@@ -24,16 +24,44 @@ The target path is the placement. A README keeps no catalog, so there is no coll
24
24
 
25
25
  ## Detect
26
26
 
27
- - Read the project's manifest (`package.json`, `pyproject.toml`, `Cargo.toml`, or equivalent) for a `bin` field or CLI entry point, an installable package name, and its declared dependencies.
28
- - Check for a `claude/skills/` or `.claude/skills/` folder, a `plugin.json`, or a marketplace manifest, each naming an agent-facing or marketplace-distributed surface.
29
- - Note every type that applies rather than stopping at the first match, since a project is often several at once and the draft covers each one.
27
+ Read the project's manifest (`package.json`, `pyproject.toml`, `Cargo.toml`, or equivalent) and the tree, then test each type on its own signal. Note every type that matches rather than stopping at the first, since a project is often several at once.
28
+
29
+ - Library: an installable package name, counted only when no application, CLI, or plugin signal matches, since a named package is also what a site, a CLI, or a plugin carries. An agent-facing match leaves it in place, so a library with a `CLAUDE.md` still gets its quickstart.
30
+ - CLI: a `bin` field, a `[project.scripts]` table in `pyproject.toml`, a `[[bin]]` table in `Cargo.toml`, or a CLI entry point.
31
+ - Application: a site framework dependency, a site config file, or an app entry point.
32
+ - Agent-facing: a `.claude/skills/` folder, or a file an agent loads such as `CLAUDE.md`.
33
+ - Plugin: a `plugin.json` or a marketplace manifest.
34
+
35
+ A match on no type falls back to the standard's generic template. Say so in the preview, and never force the nearest type.
36
+
30
37
  - Check for a page. A dependency on a site framework or a site config file in the manifest or the tree marks a project as having one. Read a live URL separately, from a `homepage` field or a deploy config, since a project can have a page and no known URL.
31
38
  - A monorepo can carry a page in one package and a CLI in another, so both signals may fire. Report each rather than picking one.
32
39
  - Look for the mark and the screenshot among images the project already commits: scan the existing README for image references, then the asset and public folders.
33
40
 
41
+ ## Pick
42
+
43
+ Read the template for each detected type from `readme/`, beside this file:
44
+
45
+ - `readme/library.md`
46
+ - `readme/cli.md`
47
+ - `readme/application.md`
48
+ - `readme/agent-facing.md`
49
+ - `readme/plugin.md`
50
+
51
+ Each is a whole page of slots and structure, so fill it from the manifest and the tree rather than from memory. The standard still owns voice and content, and a template carries no rule of its own.
52
+
53
+ A project matching one type drafts from that template. A project matching several combines them:
54
+
55
+ - Keep one H1, one header block, and one description.
56
+ - Order the sections as the standard orders them.
57
+ - Add each extra type's usage or install subsection under the shared `## Installation` or `## Usage` H2, never as a second H2 of the same name.
58
+ - Drop a template section the page already carries rather than repeating it.
59
+
60
+ Between agent-facing and plugin alone, a repository with no plugin manifest takes only the agent-facing template, and a plugin that is not agent-facing in its own repository takes only the plugin template. A CLI or an application that also matches agent-facing keeps its own template beside it.
61
+
34
62
  ## Draft
35
63
 
36
- - Draft the H1, a 2-3 sentence description in plain text, then the required sections, then whichever optional sections and per-type content Detect found. A README takes no frontmatter.
64
+ - Start from the picked or combined template. Draft the H1, a 2-3 sentence description in plain text, then the required sections, then whichever optional sections and per-type content Detect found. A README takes no frontmatter.
37
65
  - Open the page with the standard's header block, filling each slot from what Detect found: mark, title, badges, a one-line claim from the manifest description, the live link, then the product screenshot.
38
66
  - Fill the screenshot slot only with an image the project already commits, referenced with alt text naming what it depicts. This kind cannot capture one. Omit the slot when no such image exists and say so in the preview. Never write a placeholder path or invent a mark.
39
67
  - Omit the link and the screenshot for a project with no page, and the mark for a project with none, without a note in the drafted page. A project with a page and no known URL gets the screenshot slot, and the Confirm step asks for the link.
@@ -48,6 +76,7 @@ Add these lines, then confirm them with the path:
48
76
 
49
77
  - `**Target:** <root | nested>`
50
78
  - `**Detected:** <project types>`
79
+ - `**Templates:** <each template read, or the generic fallback>`
51
80
  - `**Header:** <each slot as filled (source) or skipped (reason)>`
52
81
  - `**Badges:** <candidates and what backs each one, or none>`
53
82
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: draft-figure
3
- description: Why a figure decides between Mermaid and freehand SVG before drawing, and why only the Mermaid path carries a render-verification loop
3
+ description: Why a figure decides between Mermaid, an architecture view, and freehand SVG before drawing, and why the Mermaid path carries a render-verification loop
4
4
  ---
5
5
 
6
6
  # Draft figure requirement
@@ -11,18 +11,24 @@ Without this skill, a session asked for a figure reaches for whichever path it t
11
11
 
12
12
  A teach lesson breaks the Mermaid path outright. The lesson letters its figures in a hand font the renderer cannot load, so the render sizes every label in a narrower fallback face and the lesson clips the text it actually shows. The check then reads the standalone image, rendered in that same fallback, and passes a figure the reader sees clipped. Both happened on one lesson, where every group title clipped mid-word and only a capture taken inside the lesson showed it.
13
13
 
14
+ An architecture view asked for one at a time fails its own way. A session asked to refresh one view redraws every view beside it, so pictures nobody checked change in the same commit and the reviewer cannot tell which one the pass was about. It reaches for C4, state, or class diagrams that render differently in every viewer. A Mermaid source can satisfy every rule in the standard and still render as a picture asserting something false about the system, so a session that judges the source and calls it verified has spent the only signal a reader has on a picture nobody looked at.
15
+
14
16
  The color failure is the quiet one. Mermaid's own theme writes literal hex values, and a figure carrying one stops re-coloring itself the moment the host page switches its palette, which the figure standard's own accessibility bar rules out.
15
17
 
16
18
  ## Must
17
19
 
18
20
  - Apply the standard's earn-its-place bar before drawing anything
19
21
  - Decide between the Mermaid path and the freehand path by whether the subject reduces to a graph, not by which is faster to produce
22
+ - Draw an architecture view from its named source signal, inside `flowchart` and `sequenceDiagram`, and render it through the Mermaid path
23
+ - Draw only the view the request names, leaving every other figure in the destination untouched
20
24
  - Draw a figure bound for a teach lesson freehand whatever its shape, since the lesson's hand font is one the renderer cannot measure
21
25
  - Verify a figure bound for a rendered page by capturing it inside that page, and fall back to the standalone render only where the destination has no page to load
22
26
  - Keep the scoped overflow style as the documented fallback for a clipped group title wherever the Mermaid path still runs
23
27
  - Render the Mermaid path with the hand-drawn look and the figure font stack, never with Mermaid's default look
24
28
  - Rewrite every literal color the renderer wrote into the custom property the host stylesheet defines
25
- - Read the Mermaid render back and judge it against what the figure means to say, the same verification `draft-diagram` runs for the architecture surface
29
+ - Read the Mermaid render back and judge it against what the figure means to say, rather than judging the source
30
+ - Read the node labels by hand, since no hook checks inside a fence
31
+ - Cite only code paths that exist in an architecture view's caption or prose
26
32
  - Wrap either path in a `<figure>` and `<figcaption>` and give it an accessible name
27
33
 
28
34
  ## Must not
@@ -33,16 +39,21 @@ The color failure is the quiet one. Mermaid's own theme writes literal hex value
33
39
  - Report a clean verification when the Mermaid render was skipped or a defect survived
34
40
  - Loop past two correction passes on a surviving defect
35
41
  - Commit a scratch render. Only the SVG that ships in the destination document survives
42
+ - Redraw a figure the request did not name, or report one as drawn when it was left alone
43
+ - Leave an architecture view as an unrendered fence
36
44
 
37
45
  ## Guards
38
46
 
39
47
  - No subject given: stop, since nothing states what the figure has to show
40
48
  - No destination document given: stop, since the figure has nowhere to land
41
49
  - Subject does not clear the earn-its-place bar: stop rather than drawing decoration
50
+ - An architecture view with no planning file and no folder structure to scan: stop, because nothing anchors it
51
+ - Render fails for any reason: continue to the output and name the skipped check. A missing renderer degrades the loop rather than failing it.
42
52
 
43
53
  ## Out of scope
44
54
 
45
- - The toolkit's own `.canon/diagrams/` architecture surface, which shares no code, font, or visual language with this convention: `draft-diagram`
46
55
  - Mermaid's own layout, budgets, and label rules for the fence itself: the mermaid standard, cited rather than restated here
47
56
  - A UI wireframe or screen mockup: `draft-doc`
57
+ - Design tokens and the visual system: `design-extract`
58
+ - Implementation detail behind an architecture view, which belongs in a context entry the caption points at
48
59
  - Which lesson needs a figure and where it sits among the lesson's blocks: `teach-workspace`, which calls this skill to draw one
@@ -1,11 +1,11 @@
1
1
  ---
2
2
  name: draft-figure
3
- description: Drafts one hand-drawn figure for a document, deciding whether the subject is Mermaid-shaped or needs freehand SVG, then draws it. Renders the Mermaid path through Mermaid's own hand-drawn look, reads the render back, and fixes what it exposes. Wraps either path in the figure standard's caption, color, and accessibility rules. Use when asked to "draw a figure", "add a hand-drawn diagram", "draft a figure for this doc", or "draw this relationship as a figure". Do NOT use for the toolkit's own `.canon/diagrams/` architecture surface, which is `draft-diagram`, or for a UI wireframe, which is `draft-doc`.
3
+ description: Drafts one hand-drawn figure for a document, deciding whether the subject is Mermaid-shaped, an architecture view, or needs freehand SVG, then draws it. Renders the Mermaid path through Mermaid's own hand-drawn look, reads the render back, and fixes what it exposes. Wraps every path in the figure standard's caption, color, and accessibility rules. Use when asked to "draw a figure", "add a hand-drawn diagram", "draft a figure for this doc", "draw this relationship as a figure", "draw the architecture", "diagram the system", or "show the components". Do NOT use for a UI wireframe, which is `draft-doc`, or for design tokens, which is `design-extract`.
4
4
  ---
5
5
 
6
6
  # Draft figure
7
7
 
8
- Decide whether a requested figure reduces to a graph Mermaid can draw, or needs freehand SVG, then draw it and verify what a reader will actually see.
8
+ Decide whether a requested figure reduces to a graph Mermaid can draw, is one of the architecture views, or needs freehand SVG, then draw it and verify what a reader will actually see.
9
9
 
10
10
  ## Guards
11
11
 
@@ -17,7 +17,6 @@ Decide whether a requested figure reduces to a graph Mermaid can draw, or needs
17
17
  Read these in parallel:
18
18
 
19
19
  - `${CLAUDE_SKILL_DIR}/../../standards/figures.md`: when a figure earns its place, the render-first policy, wrapping and captioning, and the color and accessibility rules
20
- - `${CLAUDE_SKILL_DIR}/../../standards/mermaid.md`: direction and layout, node and edge budgets, the accessibility fields, and how a render is verified, for the Mermaid path
21
20
  - `${CLAUDE_SKILL_DIR}/../../standards/markdown.md`: formatting for the caption prose
22
21
  - The `write-human` skill: voice and rhythm for the caption prose
23
22
 
@@ -25,74 +24,48 @@ Read these in parallel:
25
24
 
26
25
  Apply the standard's bar: a relationship, a boundary, a path, or a before-and-after that prose or a list cannot carry as well. Stop when it does not: `❌ <subject> reads fine as prose. A figure adds nothing here.`
27
26
 
28
- ## Step 3: decide the render path
27
+ ## Step 3: pick the path
29
28
 
30
- - **A teach lesson**, meaning the destination is a lesson page in a learning workspace's `lessons/` folder: draw it through Step 5 whatever its shape. The lesson letters its figures in a hand font the renderer cannot load, so a Mermaid render measures its labels in a narrower face and the lesson clips them.
31
- - **Graph-shaped**, meaning the relationship, boundary, or path is already what a flowchart or sequence diagram expresses: draw it through Step 4.
32
- - **Not graph-shaped**, meaning the subject is a spatial or physical arrangement no flowchart reduces to: draw it through Step 5.
29
+ Take the first that matches, and state which path was picked and why in one sentence:
33
30
 
34
- Take the first that matches, and state which path was picked and why in one sentence. The standard states this as a render-first policy rather than a ban on any tool-exported drawing, so outside a teach lesson a graph-shaped subject always routes through Mermaid even though that is itself an external renderer.
31
+ 1. **A teach lesson**, meaning the destination is a lesson page in a learning workspace's `lessons/` folder: the hand-drawn path, whatever the subject's shape, an architecture view included. The lesson letters its figures in a hand font the renderer cannot load, so a Mermaid render measures its labels in a narrower face and the lesson clips them.
32
+ 2. **An architecture view**, meaning the request names system context, components, request flow, data pipeline, or deployment: the architecture set, then the Mermaid path.
33
+ 3. **Graph-shaped**, meaning the relationship, boundary, or path is already what a flowchart or sequence diagram expresses: the Mermaid path.
34
+ 4. **Anything else**, a spatial or physical arrangement no flowchart reduces to: the hand-drawn path.
35
35
 
36
- ## Step 4: the Mermaid path
36
+ The standard states this as a render-first policy rather than a ban on any tool-exported drawing, so outside a teach lesson a graph-shaped subject always routes through Mermaid even though that is itself an external renderer.
37
37
 
38
- - Draft the fence against `mermaid.md`: direction, node and edge budgets, `accTitle`/`accDescr`, and quoted labels.
39
- - Render it with the hand-drawn look and the figure font stack, writing scratch files under `.canon/tmp/figures/`:
38
+ ## Step 4: draw
40
39
 
41
- ```bash
42
- mkdir -p .canon/tmp/figures
43
- cat <<'EOF' >.canon/tmp/figures/<slug>.json
44
- {"look": "handDrawn", "themeVariables": {"fontFamily": "Virgil, Excalifont, cursive"}}
45
- EOF
46
- bunx -y @mermaid-js/mermaid-cli -i .canon/tmp/figures/<slug>.mmd -o .canon/tmp/figures/<slug>.svg -c .canon/tmp/figures/<slug>.json
47
- bunx -y @mermaid-js/mermaid-cli -i .canon/tmp/figures/<slug>.mmd -o .canon/tmp/figures/<slug>.png -c .canon/tmp/figures/<slug>.json
48
- ```
49
-
50
- Render both formats in one pass: the SVG is what ships inside the `<figure>`, and the PNG is what Step 6 reads back, since an SVG's markup carries no recoverable spatial meaning the way `draft-diagram` Step 5 already states for the architecture surface.
51
-
52
- Use `bunx` when bun is available, falling back to `npx -y @mermaid-js/mermaid-cli ...` otherwise.
53
-
54
- - Rewrite every stroke, fill, and text color the renderer wrote as a literal hex value into the custom property the host stylesheet defines, per the standard's color rule. Mermaid's own theme has no notion of a custom property, so this is a source edit made to the rendered SVG, not a config option.
55
- - Expect a group title or a long label to clip once the destination shows it in the hand font, since the renderer sized its box in a fallback face.
56
- - When the in-page check shows a clipped title, add a `<style>` inside the SVG, scoped to that SVG's own id, that sets `overflow: visible` on the clipped label's `foreignObject` and centers the label within it, so the wider text spills past both edges evenly. The style hides the mismatch for a title and does nothing for a node label crowding its box, which takes a shorter label instead.
57
- - Check whether the project ran `canon design css --figures`. The figure and figcaption styling ships unconditionally either way, but that flag alone embeds the Virgil and Excalifont font files. Without it, the figure falls back to the browser's own generic `cursive` face rather than the intended hand-drawn font, and Step 7's output names that gap when the flag was not passed.
58
-
59
- ## Step 5: the freehand path
40
+ Read the reference for the path Step 3 picked and follow it:
60
41
 
61
- - Author the SVG by hand: plain shapes and lines authored directly in the markup.
62
- - Follow the standard's `## Color and accessibility` section for every fill, stroke, and accessible name.
42
+ - Architecture set: read `${CLAUDE_SKILL_DIR}/references/architecture-set.md` to shape the view, then `${CLAUDE_SKILL_DIR}/references/mermaid.md` to draw and render it. The architecture branch always renders and reads back. An unrendered fence is not a figure.
43
+ - Mermaid path: read `${CLAUDE_SKILL_DIR}/references/mermaid.md`.
44
+ - Hand-drawn path: read `${CLAUDE_SKILL_DIR}/references/hand-drawn.md`.
63
45
 
64
- There is no external render to verify a freehand drawing against before it is written. The check here is the stroke-and-fill audit above and a read of the markup against what the subject means to show, done once rather than looped. Hand-placed coordinates can drift out of line where a layout engine would not, so a freehand figure bound for a rendered page also takes Step 7's in-page capture.
65
-
66
- ## Step 6: wrap, caption, and verify
46
+ ## Step 5: wrap, caption, and verify
67
47
 
68
48
  - Wrap the drawing in a `<figure>` element with a `<figcaption>` naming what to take from the figure, never what it shows. Let it run wider than the surrounding prose column.
69
- - On the Mermaid path, read the rendered PNG back and judge it against what the figure means to say, the same check `draft-diagram` Steps 5 and 6 run for the architecture surface. Fix the mermaid source and re-render on a defect. Stop after two correction passes. When a defect survives, keep the figure and name the defect in the output rather than reporting a false verification.
70
- - On either path, confirm the figure still reads once every color and font it depends on is stripped to its fallback, per the standard's own working-figure bar.
71
- - When the render fails for any reason, no browser engine, no network, no package manager, continue to Step 7 and name the skipped check. A missing renderer degrades the loop rather than failing it.
72
- - When the destination is a rendered page, an HTML file a browser loads, the check that counts is the figure inside that page, which Step 7 runs once the figure is written. The standalone PNG is measured in the renderer's own fonts and can read clean while the page clips it. A markdown destination has no page to load, so the standalone check above is the whole check there.
49
+ - On the Mermaid path, run the read-back `mermaid.md` states before confirming.
50
+ - On every path, confirm the figure still reads once every color and font it depends on is stripped to its fallback, per the standard's own working-figure bar.
51
+ - When the destination is a rendered page, an HTML file a browser loads, the check that counts is the figure inside that page, which Step 6 captures once the figure is written, on either path. A markdown destination has no page to load, so the checks above are the whole check there.
73
52
 
74
- ## Step 7: confirm and write
53
+ ## Step 6: confirm and write
75
54
 
76
- Show the destination path, the decided render path, and the full `<figure>` markup before writing. Confirm with the user, since the graph-shaped decision and the render verdict are judgment calls with no diff to preview either against.
55
+ Show the destination path, the decided path, and the full `<figure>` markup before writing. Confirm with the user, since the path decision and the render verdict are judgment calls with no diff to preview either against.
77
56
 
78
57
  Write the figure into the destination document at the location the user named.
79
58
 
80
- When the destination is a rendered page, capture the figure inside it and read the capture against what the figure means to say:
81
-
82
- ```bash
83
- canon capture <destination> --selector figure --out .canon/tmp/figures/
84
- ```
85
-
86
- Narrow the selector to this figure, such as by an id on its `<figure>`, when the page carries more than one. Fix a clipped label, a misaligned shape, or an arrow that misses its target in the destination and capture again, within the same two correction passes Step 6 allows. A clipped group title on the Mermaid path takes the scoped overflow style Step 4 states. When the capture fails, keep the figure and name the skipped check in the output, the same way Step 6 treats a failed render.
59
+ When the destination is a rendered page, read the `## Capture in the page` section of `${CLAUDE_SKILL_DIR}/references/hand-drawn.md` and run it, on the Mermaid path as well as the hand-drawn one, within the same two correction passes the read-back allows.
87
60
 
88
- Renders and captures under `.canon/tmp/figures/` are verification artifacts, and the scratch PNGs, the stamps the capture writes beside them, and the JSON config are deleted once the checks confirm, since only the SVG ships.
61
+ Renders and captures under `.canon/tmp/figures/` are verification artifacts, and the scratch PNGs, the stamps the capture writes beside them, and the JSON config are deleted once the checks confirm, since only the SVG ships. Keep the `.mmd` source, which is what a later refresh redraws from.
89
62
 
90
63
  ## Output
91
64
 
92
65
  ### Preview
93
66
 
94
67
  **Destination:** `<path>`
95
- **Render path:** `<mermaid | freehand>`, `<one-sentence reason>`
68
+ **Render path:** `<mermaid | architecture | freehand>`, `<one-sentence reason>`
96
69
 
97
70
  ```html
98
71
  <drafted figure markup></drafted>
@@ -102,7 +75,7 @@ Renders and captures under `.canon/tmp/figures/` are verification artifacts, and
102
75
 
103
76
  ```plaintext
104
77
  ✅ Drafted figure in <path>
105
- Render path: <mermaid | freehand>
78
+ Render path: <mermaid | architecture | freehand>
106
79
  Verified <in page | as a standalone render>. <defect or skipped check, one line, omitted when clean>
107
80
  <Font not embedded: run `canon design css --figures` to ship Virgil and Excalifont. Omitted when the project already ran it.>
108
81
  ```
@@ -0,0 +1,35 @@
1
+ ---
2
+ title: Architecture set
3
+ description: The five architecture views with each one's question, source signal, and diagram type, the code-scan fallback, cited paths, and what moves to canon/context/ instead, read by draft-figure when a request names an architecture view
4
+ ---
5
+
6
+ # Architecture set
7
+
8
+ `draft-figure` reads this file when the request names an architecture view. It shapes the subject, then the figure goes through `${CLAUDE_SKILL_DIR}/references/mermaid.md` like any other graph-shaped figure. The destination stays the one the user named.
9
+
10
+ ## The five views
11
+
12
+ Draw the view the request names. Each answers one question and is drawn from one source signal:
13
+
14
+ | View | Question it answers | Source signal | Diagram type |
15
+ | -------------- | ------------------------------------------------------- | ------------------------------------------------- | ------------------------------------ |
16
+ | System context | Who uses the system, what it talks to, where it ends | `canon/REQUIREMENTS.md` | `flowchart TB` |
17
+ | Components | The layered structure inside the boundary | `canon/ARCHITECTURE.md` | `flowchart TB` with `subgraph` lanes |
18
+ | Request flow | A request lifecycle, an agent loop, or an actor handoff | the entry point and its handlers | `sequenceDiagram` |
19
+ | Data pipeline | Retrieval, ranking, queues, or ETL | the pipeline's modules | `flowchart TB` |
20
+ | Deployment | Hosts, services, and infrastructure config | deploy config, compose files, infrastructure code | `flowchart TB` |
21
+
22
+ System context is the only view that draws the world outside the boundary, and the one a reader outside the team opens first, so assume no knowledge of the repository there.
23
+
24
+ Stay inside `flowchart` and `sequenceDiagram`. C4, state, ER, and class diagrams render inconsistently across viewers.
25
+
26
+ ## Sources
27
+
28
+ - Read `canon/REQUIREMENTS.md`, `canon/ARCHITECTURE.md`, `CLAUDE.md`, and the language manifest (`package.json`, `pyproject.toml`, `Cargo.toml`) when present, plus the top-level folder layout through `ls`. Do not recurse speculatively.
29
+ - When neither planning file exists and no folder structure names a boundary, stop: `❌ No source signal for <view>. Add canon/ARCHITECTURE.md or run inside a project folder.`
30
+ - When the view came from a code scan rather than planning prose, open the caption with `Source: code.` and add `Fidelity is lower than prose-driven figures. Verify against the project's intent.`
31
+
32
+ ## Caption and prose
33
+
34
+ - Name one or two code paths a reader can open, in the caption or the prose beside the figure. Cite only paths that exist and spell each one exactly, since a reader deciding whether the figure still holds starts by opening them.
35
+ - Keep implementation detail out of the figure: function names and call signatures, library versions, config keys and environment variable names, retry counts and timeouts, and workarounds needing more than a sentence. That detail belongs in a `canon/context/` entry, which the caption points at by path when a reader needs the mechanism.
@@ -0,0 +1,31 @@
1
+ ---
2
+ title: Hand-drawn path
3
+ description: Authoring a freehand SVG, its color and accessibility audit, and the in-page capture loop a rendered destination takes, read by draft-figure once a figure is drawn by hand
4
+ ---
5
+
6
+ # Hand-drawn path
7
+
8
+ `draft-figure` reads this file when Step 3 routes a figure to a freehand drawing: a teach lesson whatever its subject, or a subject no flowchart reduces to.
9
+
10
+ ## Draw
11
+
12
+ - Author the SVG by hand: plain shapes and lines authored directly in the markup.
13
+ - Follow the `## Color and accessibility` section of `${CLAUDE_SKILL_DIR}/../../standards/figures.md` for every fill, stroke, and accessible name.
14
+
15
+ There is no external render to verify a freehand drawing against before it is written. The check here is the stroke-and-fill audit above and a read of the markup against what the subject means to show, done once rather than looped. Hand-placed coordinates can drift out of line where a layout engine would not, so a freehand figure bound for a rendered page also takes the in-page capture below.
16
+
17
+ ## Capture in the page
18
+
19
+ When the destination is a rendered page, an HTML file a browser loads, capture the figure inside it once it is written and read the capture against what the figure means to say:
20
+
21
+ ```bash
22
+ canon capture <destination> --selector figure --out .canon/tmp/figures/
23
+ ```
24
+
25
+ - Narrow the selector to this figure, such as by an id on its `<figure>`, when the page carries more than one.
26
+ - Fix a clipped label, a misaligned shape, or an arrow that misses its target in the destination and capture again. Stop after two correction passes.
27
+ - When the capture fails, keep the figure and name the skipped check in the output.
28
+
29
+ A Mermaid figure bound for a rendered page takes this same capture, since its standalone PNG is measured in the renderer's own fonts and can read clean while the page clips it. A clipped group title there takes the scoped overflow style `${CLAUDE_SKILL_DIR}/references/mermaid.md` states.
30
+
31
+ A markdown destination has no page to load, so the read of the markup, or of the standalone render on the Mermaid path, is the whole check there.
@@ -0,0 +1,55 @@
1
+ ---
2
+ title: Mermaid path
3
+ description: The hand-drawn render config, the SVG and PNG pair, the hex rewrite, the scoped overflow fallback, the label check, and the PNG read-back with its two-pass stop, read by draft-figure once a figure routes through Mermaid
4
+ ---
5
+
6
+ # Mermaid path
7
+
8
+ `draft-figure` reads this file when Step 3 routes a figure through Mermaid, whether the subject is graph-shaped or an architecture view the architecture set already shaped.
9
+
10
+ ## Draft the fence
11
+
12
+ - Draft the fence against `${CLAUDE_SKILL_DIR}/../../standards/mermaid.md` for direction, node and edge budgets, `accTitle` and `accDescr`, and quoted labels. Do not work the layout or the budgets from memory.
13
+ - Read every node and subgraph label against the banned characters `${CLAUDE_SKILL_DIR}/../../standards/markdown.md` lists. The audit hook skips every line inside a fence, so a label carrying a banned character passes silently while the same character in the caption is caught. Reading the labels is the only gate they have. A colon works as a replacement inside a label.
14
+
15
+ ## Render
16
+
17
+ Render with the hand-drawn look and the figure font stack, writing scratch files under `.canon/tmp/figures/`:
18
+
19
+ ```bash
20
+ mkdir -p .canon/tmp/figures
21
+ cat <<'EOF' >.canon/tmp/figures/<slug>.json
22
+ {"look": "handDrawn", "themeVariables": {"fontFamily": "Virgil, Excalifont, cursive"}}
23
+ EOF
24
+ bunx -y @mermaid-js/mermaid-cli -i .canon/tmp/figures/<slug>.mmd -o .canon/tmp/figures/<slug>.svg -c .canon/tmp/figures/<slug>.json
25
+ bunx -y @mermaid-js/mermaid-cli -i .canon/tmp/figures/<slug>.mmd -o .canon/tmp/figures/<slug>.png -c .canon/tmp/figures/<slug>.json
26
+ ```
27
+
28
+ Render both formats in one pass. The SVG is what ships inside the `<figure>`, and the PNG is what the read-back below judges, since an SVG's markup carries no recoverable spatial meaning.
29
+
30
+ Use `bunx` when bun is available, falling back to `npx -y @mermaid-js/mermaid-cli ...` otherwise.
31
+
32
+ Before the first render in a project, say what is about to block:
33
+
34
+ ```plaintext
35
+ Rendering to verify layout. The first run downloads the Mermaid CLI and takes about 15 seconds.
36
+ ```
37
+
38
+ ## Rewrite the colors
39
+
40
+ Rewrite every stroke, fill, and text color the renderer wrote as a literal hex value into the custom property the host stylesheet defines, per the color rule in `${CLAUDE_SKILL_DIR}/../../standards/figures.md`. Mermaid's own theme has no notion of a custom property, so this is a source edit made to the rendered SVG, not a config option.
41
+
42
+ ## Clipped titles
43
+
44
+ - Expect a group title or a long label to clip once the destination shows it in the hand font, since the renderer sized its box in a fallback face.
45
+ - When the in-page check shows a clipped title, add a `<style>` inside the SVG, scoped to that SVG's own id, that sets `overflow: visible` on the clipped label's `foreignObject` and centers the label within it, so the wider text spills past both edges evenly. The style hides the mismatch for a title and does nothing for a node label crowding its box, which takes a shorter label instead.
46
+
47
+ ## Fonts
48
+
49
+ Check whether the project ran `canon design css --figures`. The figure and figcaption styling ships unconditionally either way, but that flag alone embeds the Virgil and Excalifont font files. Without it, the figure falls back to the browser's own generic `cursive` face rather than the intended hand-drawn font, and the output names that gap when the flag was not passed.
50
+
51
+ ## Read the render back
52
+
53
+ - Read the rendered PNG and judge it against what the figure means to say, applying the verification properties in the mermaid standard. A source satisfying every rule there can still render as a picture asserting something false, so the image is what gets judged.
54
+ - Fix the Mermaid source and re-render on a defect. Stop after two correction passes. When a defect survives, keep the figure and name the defect in the output rather than reporting a false verification.
55
+ - When the render fails for any reason, no browser engine, no network, no package manager, continue to the confirm step and name the skipped check. A missing renderer degrades the loop rather than failing it.
@@ -14,7 +14,16 @@ its own reply, so skip the comment in step 7. The push and body sync still run.
14
14
 
15
15
  - If `git branch --show-current` returns `main`, stop: `❌ On main. Switch to a PR branch first.`
16
16
  - If `git status --porcelain` is empty, stop: `❌ No changes to ship.`
17
- - If `gh pr view --json state -q '.state' 2>/dev/null` is not `OPEN`, stop: `❌ No open PR for this branch. Use git-ship to open one.`
17
+ - Resolve `<number>` once, here, through `canon pr head --json`, reading the record's `number`. Every later step names this `<number>` rather than resolving it again. A record refusing with `ambiguous-pull` stops: `❌ Two open PRs on this branch. Name the one to update.`
18
+ - When no record comes back, or it carries no `number`, read the open pull requests on the branch over REST instead. The branch is encoded so a `/` in its name reaches the query as `%2F`:
19
+
20
+ ```bash
21
+ gh api "repos/{owner}/{repo}/pulls?head={owner}:$(git branch --show-current | jq -Rr @uri)&state=open" --jq '.[].number'
22
+ ```
23
+
24
+ Nothing printed stops: `❌ No open PR for this branch. Use git-ship to open one.` More than one number takes the `ambiguous-pull` stop above rather than the first, since two open pull requests on one head against different bases leave nothing to say which one this push updates.
25
+
26
+ Every read and write in this skill runs on REST, since the `gh pr` subcommands run on GraphQL and a cloud session's GitHub proxy refuses it. A cloud worker answering a review reaches this skill through `review-address`, so one GraphQL call here breaks that whole leg.
18
27
 
19
28
  A missing tracking ref is no longer a guard. An open pull request proves the branch reached the remote, and a branch created by worktree entry has been measured carrying an open pull request with no tracking ref, where the old guard reported that the branch still needed pushing. That message describes a state the branch is not in, so the run stopped on a diagnosis nobody could act on. Step 4 sets the ref instead.
20
29
 
@@ -29,21 +38,21 @@ A missing tracking ref is no longer a guard. An open pull request proves the bra
29
38
 
30
39
  The lease is what stops the force from overwriting a commit this session never read. Run the ancestry test only where an upstream resolves, since it reads `@{u}`.
31
40
 
32
- 5. Post the evidence comparison, on every invocation including `reply-owned`, since this comment is not the reply step 8 owns. Run `canon pr evidence <number> --json`, resolving `<number>` from `gh pr view --json number`, and read `reason` on the record rather than the exit code.
41
+ 5. Post the evidence comparison, on every invocation including `reply-owned`, since this comment is not the reply step 8 owns. Run `canon pr evidence <number> --json` and read `reason` on the record rather than the exit code.
33
42
  - `no-evidence`: nothing changed under an `evidence/` segment this push. Say nothing and move on.
34
- - `ok`: write `body` to `.canon/tmp/pr/evidence/body-<number>.md` at the main worktree root (resolved the way `session-worktree` does), then post the comment with `gh pr comment <number> --body-file <main-root>/.canon/tmp/pr/evidence/body-<number>.md` when the record carries no `commentId`, or edit the existing one in place with `gh api -X PATCH repos/{owner}/{repo}/issues/comments/<commentId> -F body=@<main-root>/.canon/tmp/pr/evidence/body-<number>.md` when it does. Clean up the tmp file only after the call reports success.
43
+ - `ok`: write `body` to `.canon/tmp/pr/evidence/body-<number>.md` at the main worktree root (resolved the way `session-worktree` does), then post the comment with `gh api -X POST repos/{owner}/{repo}/issues/<number>/comments -F body=@<main-root>/.canon/tmp/pr/evidence/body-<number>.md --silent` when the record carries no `commentId`, or edit the existing one in place with `gh api -X PATCH repos/{owner}/{repo}/issues/comments/<commentId> -F body=@<main-root>/.canon/tmp/pr/evidence/body-<number>.md` when it does. Clean up the tmp file only after the call reports success.
35
44
  - Any other reason is one of the mirrored git refusals (`gh-missing`, `gh-failed`, `no-base`, `unreadable-changes`, `would-empty`). Report it and continue without stopping the chain.
36
45
 
37
46
  After an `ok` post, read what the pull request is still owed with `canon pr evidence <number> --check --json`, branching on `reason` and `owed` rather than the exit. When `owed` lists `preview`, mint it through the preview section of `canon:git-pr`'s `references/evidence.md`, then re-read once. Report anything but `settled` after that re-read and continue, since a refused deploy would otherwise loop. A binary lacking `--check` reports the thread unread rather than settled. A preview already on the comment counts as settled whatever head built it, so a later push does not re-mint one.
38
47
 
39
- 6. Check for existing review comments: `gh api 'repos/{owner}/{repo}/pulls/<number>/comments' --jq 'length'`, resolving `<number>` from `gh pr view --json number`.
48
+ 6. Check for existing review comments: `gh api 'repos/{owner}/{repo}/pulls/<number>/comments' --jq 'length'`.
40
49
  7. Sync the body and title on every invocation, before the routing below decides on the reply.
41
- - Run `gh pr view --json url,title,body` and update the body with `gh pr edit --body` when the new commit changes scope, and the title with `gh pr edit --title` when the scope shifted enough to make it inaccurate.
50
+ - Read the live title and body with `gh api repos/{owner}/{repo}/pulls/<number> --jq '{html_url, title, body}'`. Update the body with `gh api -X PATCH repos/{owner}/{repo}/pulls/<number> -F body=@<file> --silent` when the new commit changes scope, writing the new body to `<file>` first, and the title with `gh api -X PATCH repos/{owner}/{repo}/pulls/<number> -f title="<title>" --silent` when the scope shifted enough to make it inaccurate.
42
51
  - A fix commit answering a review changes what shipped exactly as much as an ordinary followup does, so the sync cannot wait on the invocation or the comment count below.
43
52
  - A body a person edited by hand between rounds gets no special handling: judge it against the tree the same way regardless of who wrote it last, since a hand-edit the fix commit has made stale is the exact drift this sync exists to close.
44
53
  8. Route on the invocation and the comment count for the reply alone.
45
54
  - When invoked with `reply-owned`, skip this step: the caller posts its own reply.
46
- - Otherwise, if the count is above zero, the followup addresses review feedback: post a one-line summary of the fix with `gh pr comment --body`, first running the scan in `${CLAUDE_SKILL_DIR}/../../standards/publish.md` against it, since the hook does not see an inline comment body. The `pull_request` check the git-pr surface carries triggers on a push or an open rather than a plain edit, so neither this comment nor the title and body step 7 synced reaches it.
55
+ - Otherwise, if the count is above zero, the followup addresses review feedback: post a one-line summary of the fix with `gh api -X POST repos/{owner}/{repo}/issues/<number>/comments -f body="<summary>" --silent`, first running the scan in `${CLAUDE_SKILL_DIR}/../../standards/publish.md` against it, since the hook does not see an inline comment body. The `pull_request` check the git-pr surface carries triggers on a push or an open rather than a plain edit, so neither this comment nor the title and body step 7 synced reaches it.
47
56
  - If it is zero, nothing further runs. The sync in step 7 already did this branch's job.
48
57
 
49
58
  ## After completion
@@ -53,3 +62,5 @@ Output one line:
53
62
  ```plaintext
54
63
  ✅ Followup shipped: <pr-url>
55
64
  ```
65
+
66
+ Take `<pr-url>` off the `html_url` step 7 read.
@@ -53,9 +53,11 @@ Read `reason` on the record rather than the exit code.
53
53
  - `ok`: write `body` to `.canon/tmp/pr/evidence/body-<number>.md` at the main worktree root (resolved the way `session-worktree` does), then post or update the comment:
54
54
 
55
55
  ```bash
56
- gh pr comment <number> --body-file <main-root>/.canon/tmp/pr/evidence/body-<number>.md
56
+ gh api -X POST repos/{owner}/{repo}/issues/<number>/comments -F body=@<main-root>/.canon/tmp/pr/evidence/body-<number>.md --silent
57
57
  ```
58
58
 
59
+ Both posts in this file go through the REST issue-comments endpoint, since the `gh pr` subcommands run on GraphQL and a cloud session's GitHub proxy refuses it. `git-followup` mints a preview through this file, so a GraphQL post here would break the cloud review-address leg.
60
+
59
61
  When the record carries a `commentId`, edit that comment in place instead of posting a second one, reading the body field from the tmp file with `@`, which needs the typed-field flag `-F` because the raw-string flag `-f` posts the path itself as the body:
60
62
 
61
63
  ```bash
@@ -71,7 +73,7 @@ Any other `reason` is one of the mirrored git refusals (`gh-missing`, `gh-failed
71
73
  Run this step only as the fallback, when the evidence step above reported one of the git refusals and a checklist file exists, since every other branch with a checklist rendered `ok` and carried it. The comment this posts carries no marker, so a later `canon pr evidence` call reports no `checklist` for it. Post it as its own comment on `<number>`:
72
74
 
73
75
  ```bash
74
- gh pr comment <number> --body-file <main-root>/.canon/tmp/handoff/ui-checklist/<slug>.md
76
+ gh api -X POST repos/{owner}/{repo}/issues/<number>/comments -F body=@<main-root>/.canon/tmp/handoff/ui-checklist/<slug>.md --silent
75
77
  ```
76
78
 
77
79
  Run the cleanup below only once the call that carried the checklist reports success, whichever of the two steps that was. On a failure, stop and leave the file in place: a retry needs the checklist to still be there, and deleting it on a failed post loses the only copy with nothing landed on the pull request.
@@ -153,7 +153,7 @@ When the user signals the previous stacked PR has merged, restack the next one.
153
153
 
154
154
  1. Rebase and push. The own-commit-count comes from the original split table.
155
155
  `git fetch origin main && git checkout <branch> && git rebase --onto origin/main HEAD~<own-commit-count> && git push --force-with-lease`
156
- 2. Verify the PR's base auto-retargeted to main with `gh pr view <num> --json baseRefName`. If not, `gh pr edit <num> --base main`.
156
+ 2. Verify the PR's base auto-retargeted to main with `gh api repos/{owner}/{repo}/pulls/<num> --jq .base.ref`, a REST read a cloud session's GitHub proxy serves where it refuses GraphQL. If not, `gh pr edit <num> --base main`.
157
157
  3. Reply: `✅ <branch> rebased onto main. Ready for squash-merge.`
158
158
 
159
159
  Edge cases:
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: index-lookup
3
- description: Answers a topic search over every tracked index.md catalog in the project by running `canon indexes list --json` and matching the topic against each entry's title, description, and path, then reports the hits or names why there are none. Names the gitignored task, memory, and diagram catalogs and the groundwork and intake record folders as pointers outside its walked corpus, so it never claims a topic is undocumented when the topic only sits there. Use when asked "where is X documented", "is there a page about X", "search the docs for X", "find the index entry for X", or "what covers X". Do NOT use to grep source code, browse a file whose path is already known, or regenerate an index, which is `canon indexes regen`.
3
+ description: Answers a topic search over every tracked index.md catalog in the project by running `canon indexes list --json` and matching the topic against each entry's title, description, and path, then reports the hits or names why there are none. Names the gitignored task and memory catalogs and the groundwork and intake record folders as pointers outside its walked corpus, so it never claims a topic is undocumented when the topic only sits there. Use when asked "where is X documented", "is there a page about X", "search the docs for X", "find the index entry for X", or "what covers X". Do NOT use to grep source code, browse a file whose path is already known, or regenerate an index, which is `canon indexes regen`.
4
4
  ---
5
5
 
6
6
  # Index lookup
@@ -13,7 +13,7 @@ Answers a topic search over the project's tracked `index.md` catalogs, not a tex
13
13
  2. Run `canon indexes list --json` from that root.
14
14
  3. Read `errors` first. A folder failing frontmatter validation drops out of `entries` and lands its message in `errors` instead, per the verb's own per-folder isolation, so report an error alongside the match rather than reading it as a reason to stop.
15
15
  4. Match the topic case-insensitively as a substring against each entry's `title`, `description`, and `path`. Report every match. A lookup with no ranking is honest about what it found, and a single best guess is not.
16
- 5. Check whether the project carries a gitignored indexed folder or a README-based record catalog outside `list`'s walk: `.canon/tasks/`, `.canon/memory/`, `.canon/diagrams/`, `.canon/groundwork/`, `.canon/intake/`. Test each for existence and at least one file inside it before naming it. A folder absent from this project names nothing.
16
+ 5. Check whether the project carries a gitignored indexed folder or a README-based record catalog outside `list`'s walk: `.canon/tasks/`, `.canon/memory/`, `.canon/groundwork/`, `.canon/intake/`. Test each for existence and at least one file inside it before naming it. A folder absent from this project names nothing.
17
17
  6. Report the hits, plus a pointer to any outside-the-walk folder found present, per Output below.
18
18
 
19
19
  ## Rules
@@ -10,19 +10,13 @@ the PR from an independent session. This skill consumes them: fix, reply, push.
10
10
 
11
11
  ## Guards
12
12
 
13
- - If no open PR resolves for the current branch via `gh pr view`, stop: `❌ No open PR. Nothing to address.`
13
+ - Resolve `<number>` and `<tip>` off `canon pr head --json`. An `ambiguous-pull` refusal stops: `❌ Two open PRs on this branch. Name the one to address.` A record with no `number` takes the lookup in `${CLAUDE_SKILL_DIR}/references/rest-reads.md`. Nothing resolving stops: `❌ No open PR. Nothing to address.`
14
14
  - If the PR has no review comments or threads, run step 5's staleness test before deciding. A branch that still merges stops here: `✅ No review findings to address.` One that does not skips steps 1 through 4 and runs step 5 onward, since a branch goes stale from `main` moving and a closed review says nothing about whether it still merges.
15
15
  - Fix findings. Do not merge.
16
16
 
17
17
  ## Step 1: pull the review findings and CI status
18
18
 
19
- Read the review comments and threads on the PR:
20
-
21
- ```bash
22
- gh pr view --json number,reviews,comments
23
- ```
24
-
25
- For inline review comments, read them via `gh api` on the PR's review comments. Collect each finding with its file, location, and body.
19
+ Read the reviews, the thread's comments, and the inline review comments through the three reads in `${CLAUDE_SKILL_DIR}/references/rest-reads.md`. Collect each finding with its file, location, and body.
26
20
 
27
21
  Also read the CI check status so the fixes cover failing checks, not only review comments:
28
22
 
@@ -30,7 +24,7 @@ Also read the CI check status so the fixes cover failing checks, not only review
30
24
  canon pr checks <number> --json
31
25
  ```
32
26
 
33
- Read the verdict off the record's `state` rather than off the exit. Treat `failing` as a finding to resolve alongside the review comments. A `pending` covers a tip whose runs have yet to conclude and a tip carrying no run at all, which the record separates on `matched`, and neither is a green to continue on. A record carrying `conflicted: true` is a third case: the branch conflicts with its base, so no run will start and the wait never ends. Stop and report it, since a rebase is the repair. Fall back to `gh pr checks <number>` when no record comes back at all, which is a target whose CLI predates the verb.
27
+ Read the verdict off the record's `state` rather than off the exit. Treat `failing` as a finding to resolve alongside the review comments. A `pending` covers a tip whose runs have yet to conclude and a tip carrying no run at all, which the record separates on `matched`, and neither is a green to continue on. A record carrying `conflicted: true` is a third case: the branch conflicts with its base, so no run will start and the wait never ends. Stop and report it, since a rebase is the repair. When no record comes back at all, read the check runs on the tip through `${CLAUDE_SKILL_DIR}/references/rest-reads.md`.
34
28
 
35
29
  ## Step 2: address each finding
36
30
 
@@ -160,12 +154,11 @@ canon labels scan --body-file .canon/tmp/pr/reply/reply-<number>.md
160
154
 
161
155
  The hook skips `.canon/tmp/`, so this scan is the only gate on the published
162
156
  reply. Fix any hit the standard names, then post the reply to the PR and
163
- capture the posted comment's id, since Step 7 edits this exact comment rather
157
+ keep the `id` the POST answers with, since Step 7 edits this exact comment rather
164
158
  than trusting whichever one `gh` considers last:
165
159
 
166
160
  ```bash
167
- comment_url=$(gh pr comment <number> --body-file .canon/tmp/pr/reply/reply-<number>.md)
168
- echo "${comment_url##*issuecomment-}" > .canon/tmp/pr/reply/reply-<number>.id
161
+ gh api -X POST 'repos/{owner}/{repo}/issues/<number>/comments' -F body=@.canon/tmp/pr/reply/reply-<number>.md --jq .id > .canon/tmp/pr/reply/reply-<number>.id
169
162
  ```
170
163
 
171
164
  ## Step 7: confirm resolution
@@ -252,5 +245,5 @@ Not everything worth reaching the reviewing session surfaces inside the numbered
252
245
  Open with `## Post-review findings` rather than `## Review response`, since nothing on the thread is being answered. `review-pr` states the full heading set this belongs to and routes it the same as a response: `role-orchestrator`'s poll picks it up and sends the reviewing session back for a pass. Close the body with `🤖 Addressed by Claude Code` on its own line, matching the reply's footer.
253
246
 
254
247
  ```bash
255
- gh pr comment <number> --body-file .canon/tmp/pr/reply/reply-<number>.md
248
+ gh api -X POST 'repos/{owner}/{repo}/issues/<number>/comments' -F body=@.canon/tmp/pr/reply/reply-<number>.md --silent
256
249
  ```
@@ -0,0 +1,43 @@
1
+ ---
2
+ title: REST reads
3
+ description: The reads review-address runs over REST, being the findings on the pull request, plus the pull request lookup and the check runs it falls back to when the installed canon predates pr head or pr checks
4
+ ---
5
+
6
+ # REST reads
7
+
8
+ The guard and Step 1 of `review-address`. The session reads this file on reaching Step 1, and from the guard when `canon pr head --json` hands back no `number`. Every read runs on REST, since the `gh pr` subcommands run on GraphQL and a cloud session's GitHub proxy refuses it. A cloud worker answering a review runs this skill, so one GraphQL call breaks the whole leg.
9
+
10
+ ## The findings
11
+
12
+ Read the reviews, the thread's comments, and the inline review comments:
13
+
14
+ ```bash
15
+ gh api --paginate 'repos/{owner}/{repo}/pulls/<number>/reviews?per_page=100' --jq '.[] | {id, user: .user.login, state, commit_id, submitted_at, body} | @json'
16
+ gh api --paginate 'repos/{owner}/{repo}/issues/<number>/comments?per_page=100' --jq '.[] | {id, user: .user.login, created_at, body} | @json'
17
+ gh api --paginate 'repos/{owner}/{repo}/pulls/<number>/comments?per_page=100' --jq '.[] | {id, user: .user.login, path, line, body} | @json'
18
+ ```
19
+
20
+ Each read prints one JSON line per row, oldest first across every page. A multi-line body stays inside its own row, and the newest review is the last line of the first read rather than the last row of its first page. `--paginate` runs the filter once per page, so never reduce inside it with `last` or `max`.
21
+
22
+ ## The pull request on the branch
23
+
24
+ The guard's fallback, for a target whose CLI predates `canon pr head`. Read the open pull requests on the branch and the head of the one it finds:
25
+
26
+ ```bash
27
+ gh api "repos/{owner}/{repo}/pulls?head={owner}:$(git branch --show-current | jq -Rr @uri)&state=open" --jq '.[].number'
28
+ gh api repos/{owner}/{repo}/pulls/<number> --jq .head.sha
29
+ ```
30
+
31
+ The branch is encoded so a `/` in its name reaches the query as `%2F`. Written bare, it resolves nothing and reads as no open pull request.
32
+
33
+ Nothing printed takes the guard's no-PR stop. More than one number takes its `ambiguous-pull` stop rather than the first, since two open pull requests on one head against different bases leave nothing to say which one the review is on.
34
+
35
+ ## The check runs on the tip
36
+
37
+ Step 1's fallback, for a target whose CLI predates `canon pr checks`:
38
+
39
+ ```bash
40
+ gh api --paginate 'repos/{owner}/{repo}/commits/<tip>/check-runs?per_page=100' --jq '.check_runs[] | {name, status, conclusion} | @json'
41
+ ```
42
+
43
+ A run whose `status` is not `completed` is pending. A tip listing no run at all is pending too rather than green, the same reading `canon pr checks` gives it.