@erclx/canon 5.38.0 → 5.39.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 (149) hide show
  1. package/README.md +1 -1
  2. package/claude/.claude-plugin/plugin.json +1 -1
  3. package/claude/skills/api-design/SKILL.md +12 -9
  4. package/claude/skills/auto-ship/SKILL.md +43 -23
  5. package/claude/skills/backlog-triage/SKILL.md +62 -53
  6. package/claude/skills/backlog-triage/references/apply.md +69 -0
  7. package/claude/skills/build-in-slices/SKILL.md +8 -4
  8. package/claude/skills/canon-cli/SKILL.md +5 -1
  9. package/claude/skills/canon-feedback/SKILL.md +18 -8
  10. package/claude/skills/canon-feedback-triage/SKILL.md +10 -3
  11. package/claude/skills/canvas-board/SKILL.md +36 -17
  12. package/claude/skills/ci-workflow/SKILL.md +5 -4
  13. package/claude/skills/code-craft/SKILL.md +10 -6
  14. package/claude/skills/codebase-layout/SKILL.md +3 -5
  15. package/claude/skills/context-fold/REQUIREMENT.md +4 -4
  16. package/claude/skills/context-fold/SKILL.md +42 -23
  17. package/claude/skills/context-fold/references/context-refresh.md +4 -3
  18. package/claude/skills/context-fold/references/context.md +79 -64
  19. package/claude/skills/create-rule/SKILL.md +7 -3
  20. package/claude/skills/create-skill/SKILL.md +27 -7
  21. package/claude/skills/create-skill/references/skill-reference.md +41 -17
  22. package/claude/skills/decision-escalate/SKILL.md +8 -5
  23. package/claude/skills/deploy-app/SKILL.md +1 -1
  24. package/claude/skills/deprecation-migration/SKILL.md +12 -4
  25. package/claude/skills/design-taste/SKILL.md +17 -11
  26. package/claude/skills/docs-sync/REQUIREMENT.md +1 -0
  27. package/claude/skills/docs-sync/SKILL.md +17 -6
  28. package/claude/skills/docs-sync/references/docs.md +54 -21
  29. package/claude/skills/docs-sync/references/readme.md +32 -8
  30. package/claude/skills/document-health/SKILL.md +3 -4
  31. package/claude/skills/draft-and-pick/SKILL.md +73 -47
  32. package/claude/skills/draft-doc/SKILL.md +9 -4
  33. package/claude/skills/draft-doc/references/context.md +4 -4
  34. package/claude/skills/draft-doc/references/docs.md +1 -0
  35. package/claude/skills/draft-doc/references/wiki.md +3 -2
  36. package/claude/skills/draft-figure/SKILL.md +9 -7
  37. package/claude/skills/draft-identity/SKILL.md +24 -52
  38. package/claude/skills/draft-identity/references/card-route.md +46 -0
  39. package/claude/skills/draft-ready/SKILL.md +19 -7
  40. package/claude/skills/draft-screencast/SKILL.md +6 -112
  41. package/claude/skills/draft-screencast/references/beats-template.md +119 -0
  42. package/claude/skills/draft-slides/SKILL.md +7 -4
  43. package/claude/skills/git-branch/SKILL.md +3 -3
  44. package/claude/skills/git-commit/SKILL.md +5 -3
  45. package/claude/skills/git-followup/SKILL.md +16 -9
  46. package/claude/skills/git-issue/SKILL.md +6 -5
  47. package/claude/skills/git-pr/SKILL.md +56 -44
  48. package/claude/skills/git-ship/SKILL.md +43 -34
  49. package/claude/skills/git-ship/references/ci-watch.md +31 -0
  50. package/claude/skills/git-split/SKILL.md +28 -100
  51. package/claude/skills/git-split/references/independent.md +40 -0
  52. package/claude/skills/git-split/references/stacked.md +73 -0
  53. package/claude/skills/git-stage/SKILL.md +9 -7
  54. package/claude/skills/git-worktree/SKILL.md +27 -49
  55. package/claude/skills/git-worktree/references/cleanup.md +55 -0
  56. package/claude/skills/markdown-craft/SKILL.md +2 -2
  57. package/claude/skills/markdown-craft/references/markdown.md +82 -53
  58. package/claude/skills/plan-feature/SKILL.md +52 -46
  59. package/claude/skills/plan-feature/references/batches.md +46 -0
  60. package/claude/skills/plan-groundwork/SKILL.md +60 -74
  61. package/claude/skills/plan-groundwork/references/output.md +48 -0
  62. package/claude/skills/plan-intake/SKILL.md +28 -21
  63. package/claude/skills/plan-intake-answer/SKILL.md +14 -13
  64. package/claude/skills/read-frames/SKILL.md +2 -0
  65. package/claude/skills/record-screencast/SKILL.md +31 -11
  66. package/claude/skills/review-address/SKILL.md +76 -158
  67. package/claude/skills/review-address/references/rebase-only.md +34 -0
  68. package/claude/skills/review-craft/SKILL.md +27 -11
  69. package/claude/skills/review-pr/SKILL.md +91 -40
  70. package/claude/skills/review-ui/SKILL.md +62 -37
  71. package/claude/skills/review-ui/references/hosted-preview.md +30 -0
  72. package/claude/skills/role-orchestrator/SKILL.md +105 -74
  73. package/claude/skills/role-orchestrator/references/orchestrator-filing.md +26 -0
  74. package/claude/skills/role-planner/SKILL.md +66 -64
  75. package/claude/skills/role-reviewer/SKILL.md +57 -46
  76. package/claude/skills/role-worker/SKILL.md +68 -63
  77. package/claude/skills/search-craft/SKILL.md +7 -5
  78. package/claude/skills/session-compact/SKILL.md +16 -11
  79. package/claude/skills/session-map/SKILL.md +31 -10
  80. package/claude/skills/session-relay/SKILL.md +32 -65
  81. package/claude/skills/session-resume/SKILL.md +18 -13
  82. package/claude/skills/session-worktree/SKILL.md +70 -42
  83. package/claude/skills/systematic-debugging/SKILL.md +6 -1
  84. package/claude/skills/target-check/SKILL.md +13 -6
  85. package/claude/skills/target-setup/SKILL.md +39 -27
  86. package/claude/skills/task-board/SKILL.md +68 -60
  87. package/claude/skills/task-board/references/create-report.md +36 -0
  88. package/claude/skills/task-complete/SKILL.md +20 -18
  89. package/claude/skills/teach-workspace/SKILL.md +61 -33
  90. package/claude/skills/test-craft/SKILL.md +2 -1
  91. package/claude/skills/test-first/SKILL.md +15 -9
  92. package/claude/skills/ui-checklist/SKILL.md +18 -16
  93. package/claude/skills/ux-audit/SKILL.md +9 -10
  94. package/claude/skills/ux-measure/SKILL.md +22 -18
  95. package/claude/skills/video-craft/SKILL.md +15 -7
  96. package/claude/skills/write-human/SKILL.md +9 -1
  97. package/claude/skills/youtube-transcripts/SKILL.md +2 -1
  98. package/docs/agents/context-audit-checks.md +19 -1
  99. package/docs/agents/context-audit.md +2 -2
  100. package/docs/agents/driver.md +1 -1
  101. package/docs/agents/hooks.md +21 -1
  102. package/docs/agents/index.md +10 -14
  103. package/docs/agents/indexes.md +25 -29
  104. package/docs/agents/install-and-sync.md +124 -235
  105. package/docs/agents/markdown-audit-density.md +39 -0
  106. package/docs/agents/markdown-audit-weight.md +9 -7
  107. package/docs/agents/markdown-audit.md +18 -14
  108. package/docs/agents/migrate.md +41 -16
  109. package/docs/agents/output-shape.md +60 -45
  110. package/docs/agents/overview.md +36 -12
  111. package/docs/agents/routing.md +1 -1
  112. package/docs/agents/rule-citations.md +1 -1
  113. package/docs/agents/skills-reach.md +1 -1
  114. package/docs/agents/targets.md +25 -77
  115. package/docs/target/migrations.md +1 -1
  116. package/docs/target/projects.md +2 -2
  117. package/docs/workflow/ai-workflow.md +2 -2
  118. package/docs/workflow/parallel-features.md +2 -2
  119. package/docs/workflow/skill-map.md +1 -1
  120. package/docs/workflow/visual-design-workflow.md +1 -1
  121. package/package.json +1 -1
  122. package/src/commands/claude.ts +1 -1
  123. package/src/commands/context.ts +106 -7
  124. package/src/commands/hooks.ts +63 -0
  125. package/src/commands/markdown.ts +169 -32
  126. package/src/context/audit.ts +256 -5
  127. package/src/context/classify/prompts.ts +1 -1
  128. package/src/context/gate.ts +23 -7
  129. package/src/context/shape-gated.ts +28 -0
  130. package/src/design/document.ts +1 -1
  131. package/src/design/tokens.ts +1 -1
  132. package/src/gate/measures.ts +15 -190
  133. package/src/gate/stages.ts +7 -23
  134. package/src/hooks/reply-links.ts +110 -0
  135. package/src/markdown/density.ts +258 -0
  136. package/src/markdown/gate.ts +57 -18
  137. package/src/markdown/reference-shape.ts +103 -0
  138. package/src/markdown/scope.ts +174 -0
  139. package/src/markdown/structure.ts +9 -59
  140. package/src/shipped/references.ts +1 -1
  141. package/tooling/claude/seeds/.claude/hooks/reply-links.sh +72 -0
  142. package/tooling/claude/seeds/.claude/hooks/standards-audit.sh +22 -1
  143. package/tooling/claude/seeds/.claude/settings.json +4 -0
  144. package/docs/agents/commands.md +0 -154
  145. package/docs/agents/docs.md +0 -27
  146. package/docs/agents/drift-surfaces.md +0 -201
  147. package/docs/agents/gov-detect.md +0 -47
  148. package/docs/agents/scripting.md +0 -142
  149. package/src/markdown/growth.ts +0 -43
@@ -15,44 +15,58 @@ The candidates live on the local design canvas, the surface `canon:canvas-board`
15
15
 
16
16
  - If the request names one answer and asks for it to be built, stop: `❌ This names one answer, so there is nothing to pick between. Use /canon:plan-feature.`
17
17
  - If the decision has no visible form, stop: `❌ Nothing to look at. Drafting candidates needs a decision a render can show.`
18
- - Draft no candidate for a decision the operator has not asked to make. A run offering options everywhere spends their attention rather than saving it.
18
+ - Draft no candidate for a decision the operator has not asked to make, since options everywhere spend their attention rather than saving it
19
19
 
20
20
  ## Step 1: name the decision and the arms
21
21
 
22
22
  1. State the decision in one sentence, naming what changes between arms and what stays fixed.
23
- 2. Emit the design read in the run's own output, in the form `design-taste` fixes. The layer comes from that skill's ordered catalog rather than from a word invented here, and the arms differ at it rather than somewhere cheaper to change. A run emitting no read has not decided what it is drafting, and a missing line is visible where an unstated layer is not.
24
- 3. Derive a kebab slug from that sentence. The first round's canvas page takes `<slug>` as its name, and Step 5 names each later round `<slug>-2`, `<slug>-3`, and so on. Inside a live `plan-groundwork` track, the run's renders land in the track's own `evidence/<slug>/renders/`, since a candidate render is evidence the track's decision file cites rather than spike input. Everywhere else they land in session scratch.
23
+ 2. Emit the design read in the run's output, in the form `design-taste` fixes, taking the layer from its ordered catalog. The arms differ at that layer, and a missing read is visible.
24
+ 3. Derive a kebab slug from that sentence. The first round's page is `<slug>`, and Step 5 names later rounds `<slug>-2`, `<slug>-3`, and so on.
25
25
  4. Write one arm per candidate, each carrying an id, a label, and what the arm costs. An arm with no stated cost is not an option.
26
26
  5. Make the current state arm `0`, so the baseline is a candidate rather than an absence. A decision with nothing shipped yet says so and starts at arm `1`.
27
27
  6. Stop at three to five arms. Two is a comparison the operator can hold in prose, and past five the pick stops being a look and becomes a sort.
28
28
 
29
+ Inside a live `plan-groundwork` track, renders land in the track's own `evidence/<slug>/renders/`, since a candidate render is evidence its decision file cites. Everywhere else they land in session scratch.
30
+
29
31
  ## Step 2: draft the arms as frames on one canvas page
30
32
 
31
- Every arm of a round sits as one frame on one canvas page, side by side. The comparison the operator judges is that page, never a set of separate images handed over to compare from memory.
33
+ Every arm of a round sits as one frame on one canvas page, side by side. The operator judges that page, never a set of separate images compared from memory.
32
34
 
33
- 1. Start the canvas the way `canon:canvas-board` Step 1 states, unless this run already has: read `canon canvas list --json`, start `canon canvas serve --json` in the background unless the operator named an address that already answers, and fetch the `url` the record carries to check the shell's body holds a `<script` tag. Note whether this run started the server, since Step 6 stops only a server this run started. A refused serve or a blank shell stops the run, reported with its `reason`. A run with no canvas cannot draft, and no file stands in for one.
34
- 2. Add the round's page with `canon canvas page add <page> --json` and record its name on the run's own list of pages it added. A name `canvas list` already shows belongs to somebody else, so take the next free suffix rather than writing into it.
35
- 3. Add each arm as a frame with `canon canvas frame add <page> arm-<id> --width <px> --height <px> --json`. Name every frame `arm-<id>`, since Step 6's archive keeps those names and its readers key on them. Set the width the arm is judged at. A frame renders at its own layout width on the canvas and in a capture alike, so a decision about layout reads off the frame itself and needs no device toolbar.
35
+ 1. Start the canvas the way `canon:canvas-board` Step 1 states, unless this run already has. Note whether this run started the server, since Step 6 stops only a server this run started.
36
+ 2. Add the round's page with `canon canvas page add <page> --json` and record it on the run's list of pages. A name `canvas list` already shows is somebody else's, so take the next free suffix.
37
+ 3. Add each arm with `canon canvas frame add <page> arm-<id> --width <px> --height <px> --json`. Step 6's archive keys on the `arm-<id>` names.
36
38
  4. Write each arm's whole document to the `path` the add verb reported. From a linked worktree, take the heredoc route `canon:canvas-board` Step 3 gives for a main-root write.
37
39
  5. Lay the frames out in one row, in arm order, with `canon canvas frame move <page> arm-<id> --x <px> --y <px> --json`.
38
40
 
41
+ The `canvas-board` start reads `canon canvas list --json`, serves with `canon canvas serve --json` in the background unless the operator named an address that answers, and checks the shell's body holds a `<script` tag. A refused serve or a blank shell stops the run with its `reason`, and no file stands in for a canvas.
42
+
43
+ Set each frame's width to the one the arm is judged at. A frame renders at its own layout width on the canvas and in a capture alike, so a layout decision needs no device toolbar.
44
+
39
45
  ### What every frame carries
40
46
 
41
- - Label each arm inside its frame with its id and its cost. The composite capture draws no captions, so the label is how the render carries what the question will ask about.
42
- - Theme every arm off the `data-theme` attribute the canvas sets on each frame's root, so the canvas theme toggle sets the whole set at once. A set spanning both themes cannot be compared, since the operator has to hold one arm in memory while reading the next.
43
- - Give no arm a script that stores a theme and reapplies it on load. That script overwrites the toggle, shows one frame in the other theme, and passes a fresh browser profile because the stored value is not there yet.
47
+ Each frame carries its own label and follows the canvas theme, so the set reads as one comparison.
48
+
49
+ - Label each arm inside its frame with its id and its cost, since the composite capture draws no captions
50
+ - Theme every arm off the `data-theme` attribute the canvas sets on each frame's root, so the theme toggle sets the whole set at once. A set spanning both themes cannot be compared.
51
+ - Give no arm a script that stores a theme and reapplies it on load. It overwrites the toggle, and a fresh browser profile hides the fault.
44
52
 
45
- #### Default path and live app
53
+ ### Default path and live app
46
54
 
47
- - Take the live-app branch instead when the surface under decision is a running app: lift the rendered markup and link a copy of the built stylesheet rather than inlining, per `${CLAUDE_SKILL_DIR}/references/live-arms.md`.
48
- - On the default path, inline every style, script, and asset the frame needs. A frame resolves nothing outside its own page folder, so one reaching for a build step or a network font renders without it and the arms differ by something nobody chose.
49
- - On the default path, name a real font first in the stack, one the machine has or the frame embeds, such as the project's own family from its design tokens. A generic keyword such as `system-ui` or `sans-serif` is refused, since it resolves to a different font on each machine. The capture refuses a frame that would rewrap against a substitute rather than shipping a false comparison, so a frame naming no font at all is refused on whatever the default resolves to.
55
+ A running app under decision takes the live-app branch, and every other decision takes the default path.
56
+
57
+ - Live app: lift the rendered markup and link a copy of the built stylesheet rather than inlining, per `${CLAUDE_SKILL_DIR}/references/live-arms.md`
58
+ - Default path: inline every style, script, and asset. A frame resolves nothing outside its own page folder, so a build step or network font silently drops out.
59
+ - Default path: name a real font first in the stack, one the machine has or the frame embeds, such as the project's own family. A generic keyword such as `system-ui` resolves differently per machine.
60
+
61
+ The capture refuses a frame that would rewrap against a substitute font rather than ship a false comparison. A frame naming no font is refused on whatever the default resolves to.
50
62
 
51
63
  ### What varies
52
64
 
53
- - Vary one property across the arms. A page whose arms differ in three ways answers no question, since the pick cannot say which difference decided it.
54
- - Grey-box the arms when the declared layer sits below typography, per `design-taste`. A set judged at composition that carries a finished palette is not grey-boxed, and the higher layers are what the operator will look at instead of the question. Say the set is grey-boxed when handing it over.
55
- - Vary the property the decision is about, which the rule above is satisfiable without. Holding composition fixed and varying color obeys it exactly and produces five skins of one design, because a set differing in the layer a reader notices least answers nothing. A palette is chosen to serve a composition, so it cannot be picked ahead of one.
65
+ Vary one property across the arms, since a pick cannot say which of three differences decided it.
66
+
67
+ - Vary the property the decision is about. Holding composition fixed and varying color produces five skins of one design, and a palette cannot be picked ahead of the composition it serves.
68
+ - Grey-box the arms when the declared layer sits below typography, per `design-taste`, and say the set is grey-boxed when handing it over
69
+ - Do not grey-box a set judged at composition that carries a finished palette, since the operator looks at the higher layers instead of the question
56
70
 
57
71
  ## Step 3: render and hand off
58
72
 
@@ -62,63 +76,73 @@ Render the page and look at what came back before handing anything over:
62
76
  canon canvas capture <page> --composite --json
63
77
  ```
64
78
 
65
- - Point `--out` at `evidence/<slug>/renders/<page>.png` inside a live track, and leave it at its session-scratch default everywhere else. A pick taken from an image the track does not hold is a judgment nobody but this session can check, and the archive in Step 6 covers the picked round alone.
66
- - Read the PNG's `path` off the record. The composite shows every frame in its default theme, so look at the other theme on the live canvas where the arms carry two.
67
- - `canon canvas capture` needs a browser binary the toolkit does not install. When it refuses for that reason, report the refusal and name `bunx playwright install chromium` as the repair, stop the canvas server if this run started it, then stop rather than describing an arm nobody has seen.
68
- - A capture refusing on a font names the family it read off the frame's text. Take the repair `canon:canvas-board` Step 6 gives and capture again.
79
+ - Point `--out` at `evidence/<slug>/renders/<page>.png` inside a live track, and leave the scratch default elsewhere. Step 6 archives the picked round alone.
80
+ - Read the PNG's `path` off the record. The composite shows each frame in its default theme, so check the other theme on the live canvas.
81
+ - A capture refusing on a font names the family it read. Take the repair `canon:canvas-board` Step 6 gives and capture again.
82
+
83
+ When `canon canvas capture` refuses for a missing browser binary, report it and name `bunx playwright install chromium` as the repair. Stop the canvas server if this run started it, then stop rather than describe an arm nobody has seen.
69
84
 
70
85
  ### Handing over
71
86
 
72
- - Hand over the address rather than a description. Emit the canvas link first on its own line, naming the page, then the PNG path on its own line. A still answers how a thing looks and answers none of a hover response, a scroll-linked position, or a pace, which the live frame does.
73
- - Never report a visual result you have not looked at. A claim about appearance with no render behind it is a guess.
74
- - Look to judge rather than to confirm. Reading the image back to check it rendered satisfies the rule above and still hands over weak work, so name the weakest thing on the page in a sentence. Where that sentence would embarrass the work, fix it and hand over the second version. Say the remaining weakness out loud either way, so the operator is not hunting for what you already know.
87
+ Hand over the address rather than a description. Emit the canvas link first on its own line, naming the page, then the PNG path on its own line.
88
+
89
+ - A still answers how a thing looks and none of a hover, a scroll-linked position, or a pace, which the live frame does
90
+ - Never report a visual result you have not looked at, since a claim about appearance with no render behind it is a guess
91
+ - Look to judge rather than to confirm. Name the weakest thing on the page in a sentence, fix it where that sentence would embarrass the work, and say what remains.
75
92
 
76
93
  ## Step 4: take the pick
77
94
 
78
95
  Put the choice to the operator through the structured question surface, since a call the operator's preference decides always routes through it rather than through prose.
79
96
 
80
- - Emit the link in the response text ahead of the question call, and name it again in the question's own text, since some surfaces render the question card alone. A question that goes out with no address is one the operator cannot answer by looking.
81
- - One option per arm, labeled with the arm's id and carrying its cost as the description.
82
- - Rank the recommendation first and mark it `(Recommended)`.
83
- - Author the real arms only. The surface appends its own escapes for a free-text answer and for reopening the question, so writing either as an option ships a duplicate the tool rejects.
97
+ - Emit the link ahead of the question call and again in the question's text, since some surfaces render the card alone
98
+ - One option per arm, labeled with the arm's id and carrying its cost as the description
99
+ - Rank the recommendation first and mark it `(Recommended)`
100
+ - Author the real arms only. The surface appends its own free-text and reopen escapes, and a duplicate is rejected.
84
101
 
85
102
  ### Taking the answer
86
103
 
87
- - Take no pick on the operator's behalf when two arms are both defensible and the difference is taste. That call is theirs, and a silent one is the failure this skill exists to prevent.
88
- - Read `canon canvas selection --json` when the answer points at the canvas rather than naming an arm, such as "the selected one". Resolve it against the record's `page` as well as its `frame`, since every round names its arms `arm-<id>` from the same ids. A selected frame on the current round's page is the pick. One on an earlier round's page picks that round's arm, which is a revert, so name the round back to the operator before acting on it. A fresh element inside a picked frame is a correction Step 5 carries by its `index`.
89
- - Treat `selection: null`, a frame on a page this run did not add, or an element carrying `stale: true` as no answer, and ask again rather than guessing.
104
+ Take no pick on the operator's behalf when two arms are both defensible and the difference is taste. That call is theirs, and a silent one is the failure this skill exists to prevent.
105
+
106
+ Read `canon canvas selection --json` when the answer points at the canvas, such as "the selected one". Resolve it against the record's `page` as well as its `frame`, since every round reuses the `arm-<id>` names.
107
+
108
+ | Selection | Reading |
109
+ | ---------------------------------------------------------------- | ---------------------------------------------- |
110
+ | A frame on the current round's page | The pick |
111
+ | A frame on an earlier round's page | A revert, so name the round back before acting |
112
+ | A fresh element inside a picked frame | A correction Step 5 carries by its `index` |
113
+ | `selection: null`, a page this run did not add, or `stale: true` | No answer, so ask again rather than guess |
90
114
 
91
115
  ## Step 5: loop on the pick
92
116
 
93
- 1. Add each iteration as its own page, recorded on the run's list, rather than narrowing the previous page in place. A page overwritten is one a later pass cannot open, and the losing round is what stops a correction re-proposing something already rejected. The canvas page list reaches every round from one address.
117
+ 1. Add each iteration as its own page, recorded on the run's list. An overwritten page cannot be reopened, and the losing round stops a correction re-proposing a rejected arm.
94
118
  2. Write fresh arms off the pick and return to Step 2 where the correction opens a new question. Revise the one arm's frame where it does not.
95
119
  3. Re-render, hand off again, and take the next answer.
96
- 4. Repeat until the operator says it is right. The loop stops on their word and on nothing else, so a run stopping because the arms stopped differing has stopped early.
120
+ 4. Repeat until the operator says it is right. A run stopping because the arms stopped differing has stopped early.
97
121
  5. Hold the real surface untouched across every iteration. Nothing outside the run's own canvas pages changes until the pick is final.
98
122
 
99
123
  ## Step 6: close
100
124
 
101
125
  1. Apply the winning arm to the real surface, in one change.
102
- 2. Close out whatever document stated the decision as open, in the same change, naming the arm that won and the ones that stayed defensible. A pick that changes a surface and records nothing about why leaves the next reader to re-derive it from a diff. Skip this where nothing stated the decision.
103
- 3. Capture the frames of the round the pick came from into the archive with `canon canvas capture <page> --out <archive-dir> --json`. That page is the final round's unless Step 4 resolved a revert to an earlier round, and archiving any other page would let item 5 delete the winning arm with nothing kept. Each frame lands as `arm-<id>.png`, which keeps every arm of that round past the pick, the losing ones included, as a durable revert record.
104
- 4. Resolve `<archive-dir>` as `.canon/picks/<slug>/` against the main worktree root, since shared session scratch resolves there rather than against a linked worktree this run happens to be building in.
105
- 5. Delete every page folder on the run's list from under the `content` folder `canon canvas list --json` reports, now that every arm sits at the durable path. Touch no page the run did not add, whatever its name. A variant left on the canvas is a second design nobody maintains.
126
+ 2. Close out any document stating the decision as open, in the same change, naming the winner and the arms that stayed defensible. Skip this where nothing stated the decision.
127
+ 3. Capture the picked round's frames with `canon canvas capture <page> --out <archive-dir> --json`. Each lands as `arm-<id>.png`, keeping the losing arms as a revert record.
128
+ 4. Resolve `<archive-dir>` as `.canon/picks/<slug>/` against the main worktree root, since shared session scratch resolves there rather than in a linked worktree.
129
+ 5. Delete every page folder on the run's list from under the `content` folder `canon canvas list --json` reports. Touch no page the run did not add, whatever its name.
106
130
  6. Stop the canvas server if this run started it, and leave one the operator started running.
107
- 7. Leave the renders in place inside a live track's `evidence/<slug>/renders/`, since `plan-groundwork`'s write scope treats evidence as durable rather than as scratch a session may delete.
108
- 8. Report each page still standing when its delete is refused, naming the path for the operator to remove, rather than closing on a report the tree contradicts. The pick is applied either way, so the run has done its work and the page is what outlives it.
109
- 9. Report every surface that changed, each on its own line, name the arm that won by its id and its cost, and report the archive path.
131
+ 7. Leave the renders in a live track's `evidence/<slug>/renders/`, since `plan-groundwork` treats evidence as durable.
132
+ 8. Report each page whose delete is refused, naming the path for the operator to remove. The pick is applied either way.
133
+ 9. Report every surface that changed, each on its own line, name the winning arm by its id and its cost, and report the archive path.
110
134
 
111
- ## Reading a measurement
135
+ The picked round is the final one unless Step 4 resolved a revert. Archiving any other page lets item 5 delete the winning arm with nothing kept, and a variant left on the canvas is a second design nobody maintains.
112
136
 
113
- A capture proves appearance and a measurement proves a relationship, so reach for the second whenever the claim is about a number, such as a contrast ratio, a column width, or a tap target. `canon drive` runs the probes and ships the failure modes each one carries.
137
+ ## Reading a measurement
114
138
 
115
- Three rules no probe reaches:
139
+ A capture proves appearance and a measurement proves a relationship, so reach for the second whenever the claim is a number, such as a contrast ratio, a column width, or a tap target. `canon drive` runs the probes and ships the failure modes each one carries.
116
140
 
117
- - Composite alpha before reading a color. A `color-mix` toward transparent resolves to channels plus an alpha, and reading those channels as opaque reports a color nobody sees.
118
- - Sample inside the shape. A patch taken at the corner of a bounding box misses a round control and reads the page behind it, which is how a ground repair measured as no change at all.
119
- - Ask whether a reader would see the thing, not only whether it has the right shape. A panel reported a healthy 1517 by 639 for as long as it sat 1868px above the viewport, and every check that read its size passed.
141
+ - Composite alpha before reading a color. A `color-mix` toward transparent resolves to channels plus an alpha, and reading them as opaque reports a color nobody sees.
142
+ - Sample inside the shape. A patch at a bounding box corner misses a round control and reads the page behind it.
143
+ - Ask whether a reader would see the thing. A panel sized a healthy 1517 by 639 passed every size check while sitting 1868px above the viewport.
120
144
 
121
- `canon drive` reports findings and never gates, by its own help text. Read its record as evidence handed to the operator rather than as a filter over the arms, since a run dropping an arm on a probe reading has made a claim the probe catalog has not earned.
145
+ `canon drive` reports findings and never gates. Read its record as evidence for the operator rather than as a filter over the arms, since the probe catalog has not earned the right to drop one.
122
146
 
123
147
  ## What this delegates
124
148
 
@@ -130,6 +154,8 @@ Cite these rather than restating them. A step reimplemented here rots against th
130
154
 
131
155
  ### Git and review
132
156
 
157
+ Commits, review, and the canvas mechanics each have an owner.
158
+
133
159
  - `git-stage`, `git-pr`, and `git-followup` carry the commits and the pull request
134
160
  - `review-pr` and `review-address` run the review pass
135
161
  - `canon:canvas-board` carries the canvas start-and-check sequence, the main-root write route for a frame, and the selection and capture refusals
@@ -21,8 +21,10 @@ Each kind has one standard and one reference. Load the reference for the resolve
21
21
  | readme | a `README.md`, at the root or in a folder | `${CLAUDE_SKILL_DIR}/../docs-sync/references/readme.md` | `${CLAUDE_SKILL_DIR}/references/readme.md` |
22
22
 
23
23
  - Read the kind off the destination the request names: a path, a folder, or the document's own name, such as "a context entry" or "a wiki page".
24
- - Ask which kind when the request names no destination, offering the candidates the subject fits with the likeliest first. Never default to `docs/` without saying so, since a subject documented in the wrong surface is invisible to the session that looks for it in the right one.
25
- - If no subject is given for any kind but readme, stop: `❌ No subject given. Name what this document should cover.` A README covers the project or the folder it sits in, so its subject is the target path.
24
+ - Ask which kind when the request names no destination, offering the candidates the subject fits with the likeliest first
25
+ - Never default to `docs/` without saying so, since a subject documented in the wrong surface is invisible to the session that looks for it in the right one
26
+ - If no subject is given for any kind but readme, stop: `❌ No subject given. Name what this document should cover.`
27
+ - A README covers the project or the folder it sits in, so its subject is the target path
26
28
 
27
29
  ## Read
28
30
 
@@ -50,12 +52,13 @@ Settle the path and check the catalog for a collision the way the reference stat
50
52
  ## Confirm
51
53
 
52
54
  - Show the kind, the resolved path, whatever else the reference names for the preview, and the full drafted content before writing.
53
- - Confirm with the user. Wait for that answer rather than treating the tool permission dialog as the gate, since the kind, the placement, and every detection the reference runs are judgment calls with no diff to preview them against.
55
+ - Confirm with the user, and wait for that answer rather than treating the tool permission dialog as the gate
56
+ - The kind, the placement, and every detection the reference runs are judgment calls with no diff to preview them against, which is why the dialog cannot stand in
54
57
 
55
58
  ## Write
56
59
 
57
60
  - Write the file at the confirmed path, creating the folder when it is absent unless the reference narrows that.
58
- - Run `canon markdown audit <path>`.
61
+ - Run `canon markdown audit <path>` and fix every ban, density, and reference shape finding until a re-run reports none. The whole file is this run's draft, so every finding is its own.
59
62
  - Run `canon indexes regen <folder>` on the folder the reference names, so its `index.md` picks up the new document. Skip it where the reference says the kind keeps no catalog.
60
63
 
61
64
  ## Response format
@@ -73,6 +76,8 @@ Settle the path and check the catalog for a collision the way the reference stat
73
76
 
74
77
  ### After confirmation
75
78
 
79
+ One line once the file is written and its audit reports nothing.
80
+
76
81
  ```plaintext
77
82
  ✅ Drafted: <path>
78
83
  ```
@@ -18,13 +18,13 @@ A project the surface move has not reached keeps its context folder under `.clau
18
18
  ## Placement
19
19
 
20
20
  - Read `<context-root>/index.md` and check every title and description it lists against the domain. Stop on a match: `❌ <path> already covers this domain under a different name. Use context-fold to refresh it instead.`
21
- - Default a brand-new entry to a flat file, `<context-root>/<slug>.md`. A domain starts as one page's worth of narrative, and the standard splits it into a folder only once it holds three or more sub-areas, which a fresh domain never does on day one.
21
+ - Default a brand-new entry to a flat file, `<context-root>/<slug>.md`. A domain starts as one page's worth of narrative, and the standard splits it into a folder only once the entry passes the 300-line ceiling, which a fresh domain never does on day one.
22
22
 
23
23
  ## Draft
24
24
 
25
- - Read the domain's own folders and files well enough to answer the standard's three questions: where things live, why they are that way, and how to add one more of what the domain holds.
26
- - Draft `title` and `description` frontmatter, then `## Overview`, `## Layout` (folder ownership lines only, never a file-by-file list), and `## Decisions` or `## Gotchas` wherever the domain's history supplies a non-obvious choice or a workaround worth preserving.
27
- - Keep the standard's closed set and order: `Overview`, `Layout`, `Decisions`, `Gotchas`. A topic of the domain's own is an H3 under one of them, per `context.md` in the `context-fold` skill's references.
25
+ - Read the domain's own folders and files well enough to answer the standard's three questions, being what the domain owns, what each folder does now, and which trap a session would hit.
26
+ - Draft `title` and `description` frontmatter, then `## Overview`, `## Layout` with one H3 per working folder and `### Other folders` for the rest, and `## Gotchas` only for a trap true today.
27
+ - Keep the standard's closed set and order of `Overview`, `Layout`, and `Gotchas`, per `context.md` in the `context-fold` skill's references. Write no decision and no history.
28
28
 
29
29
  ## Write
30
30
 
@@ -21,6 +21,7 @@ description: The guard, placement, draft additions, and regen folder for a brand
21
21
  ## Draft
22
22
 
23
23
  - Draft `title`, `description`, and `category` where one applies, then the page body.
24
+ - Draft a page documenting one command in the docs standard's reference shape, with `kind: reference` in its frontmatter, so `canon markdown audit` checks its sections.
24
25
  - Test the page against the standard's four questions: what the surface is, what to run or write, what it refuses, and where to go for the adjacent surface.
25
26
  - Take a diagram only through the Mermaid fence the docs standard permits. Never build a hand-drawn diagram-and-capture loop here.
26
27
 
@@ -28,7 +28,8 @@ A page failing either is non-conforming even when it satisfies every shape rule
28
28
  ## Placement
29
29
 
30
30
  - Write a page here only when its subject is owned outside this repository. Route anything about how this repository works to `docs/`, `canon/context/`, or a skill body instead.
31
- - File the page in the `claude` subfolder of the `wiki` folder. A subject Anthropic does not own, whether a third-party tool or a vendor-neutral concept, is out of scope for this folder split. Route it to `docs/` or a skill body instead of adding a second wiki folder for it.
31
+ - File the page in the `claude` subfolder of the `wiki` folder
32
+ - Route a subject Anthropic does not own, whether a third-party tool or a vendor-neutral concept, to `docs/` or a skill body rather than adding a second wiki folder for it
32
33
 
33
34
  ## Frontmatter
34
35
 
@@ -50,7 +51,7 @@ A page failing either is non-conforming even when it satisfies every shape rule
50
51
  ## Shape
51
52
 
52
53
  - Keep a page thin: the `Source:` sentence, an orientation paragraph, and lesson sections. The source owns the reference detail and a paraphrase of it falls behind within days.
53
- - Apply the lesson test per section: keep a fact about the subject only when the source page does not state it. Such a fact is a gotcha this project hit, a constraint it relies on, or how it uses the feature.
54
+ - Apply the lesson test per section, keeping a fact only when the source page does not state it. Such a fact is a gotcha this project hit, a constraint it relies on, or how it uses the feature.
54
55
  - Read the current source before keeping or cutting a section. A fact kept from memory is the drift this shape exists to prevent.
55
56
  - Send a session that wants reference detail to the source and fetch it live. The page answers orientation and lessons only.
56
57
  - Leave a page with no lessons as the source link and the orientation paragraph. A catalog routes a reader by page, so the stub stays.
@@ -30,7 +30,7 @@ Apply the standard's bar: a relationship, a boundary, a path, or a before-and-af
30
30
 
31
31
  Take the first that matches, and state which path was picked and why in one sentence:
32
32
 
33
- 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.
33
+ 1. **A teach lesson**, a page in a learning workspace's `lessons/` folder: the hand-drawn path, any shape. The renderer cannot load the lesson's hand font, so Mermaid labels measure narrow and clip.
34
34
  2. **An architecture view**, meaning the request names system context, components, request flow, data pipeline, or deployment: the architecture set, then the Mermaid path.
35
35
  3. **Graph-shaped**, meaning the relationship, boundary, or path is already what a flowchart or sequence diagram expresses: the Mermaid path.
36
36
  4. **Anything else**, a spatial or physical arrangement no flowchart reduces to: the hand-drawn path.
@@ -41,7 +41,7 @@ The standard states this as a render-first policy rather than a ban on any tool-
41
41
 
42
42
  Read the reference for the path Step 3 picked and follow it:
43
43
 
44
- - Architecture set: read `${CLAUDE_SKILL_DIR}/references/architecture-set.md` to shape the view, then `${CLAUDE_SKILL_DIR}/references/mermaid-path.md` to draw and render it. The architecture branch always renders and reads back. An unrendered fence is not a figure.
44
+ - Architecture set: shape the view per `${CLAUDE_SKILL_DIR}/references/architecture-set.md`, then draw, render, and read back per `${CLAUDE_SKILL_DIR}/references/mermaid-path.md`
45
45
  - Mermaid path: read `${CLAUDE_SKILL_DIR}/references/mermaid-path.md`.
46
46
  - Hand-drawn path: read `${CLAUDE_SKILL_DIR}/references/hand-drawn.md`.
47
47
 
@@ -50,17 +50,17 @@ Read the reference for the path Step 3 picked and follow it:
50
50
  - 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.
51
51
  - On the Mermaid path, run the read-back `mermaid-path.md` states before confirming.
52
52
  - 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.
53
- - 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.
53
+ - On a rendered page, an HTML file a browser loads, the check that counts is the figure in the page, which Step 6 captures on either path. A markdown destination's whole check is the checks above.
54
54
 
55
55
  ## Step 6: confirm and write
56
56
 
57
- 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.
58
-
59
- Write the figure into the destination document at the location the user named.
57
+ 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, then write the figure where the user named.
60
58
 
61
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.
62
60
 
63
- 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.
61
+ ### Cleaning up
62
+
63
+ Renders and captures under `.canon/tmp/figures/` are verification artifacts. Delete the scratch PNGs, the stamps beside them, and the JSON config once the checks confirm, since only the SVG ships, and keep the `.mmd` source a later refresh redraws from.
64
64
 
65
65
  ## Output
66
66
 
@@ -75,6 +75,8 @@ Renders and captures under `.canon/tmp/figures/` are verification artifacts, and
75
75
 
76
76
  ### After confirmation
77
77
 
78
+ Report the write in this shape.
79
+
78
80
  ```plaintext
79
81
  ✅ Drafted figure in <path>
80
82
  Render path: <mermaid | architecture | freehand>
@@ -18,12 +18,12 @@ One identity rendered twice: the same mark sized down to an icon sequence and co
18
18
 
19
19
  Read these in parallel, skipping any that do not exist:
20
20
 
21
- - `canon/DESIGN.md`: the `## Overview` paragraph and the role intents under `## Colors` and `## Typography`, read under their earlier names `## Personality` and `## Color` in an older record
21
+ - `canon/DESIGN.md`: the `## Overview` paragraph and the role intents under `## Colors` and `## Typography`, read as `## Personality` and `## Color` in an older record
22
22
  - The stylesheet `canon/DESIGN.md`'s lead names: the color and type values behind those roles
23
23
  - `canon/REQUIREMENTS.md`: the `## Personality` paragraph, when `canon/DESIGN.md` carries none
24
24
  - `CLAUDE.md`: the project's stated voice, when neither file above carries a personality signal
25
25
 
26
- No signal from any of these is not a stop. Draft against a neutral default, and mark each guessed color and type value with a `/* ? verify */` comment beside its declaration in the `.mark` and `.card` markup this run writes, since the design document carries no value to tag.
26
+ No signal from any of these is not a stop. Draft against a neutral default, and mark each guessed color and type value with a `/* ? verify */` comment beside its declaration in the `.mark` and `.card` markup, since the design document carries no value to tag.
27
27
 
28
28
  ## Step 2: detect the icon size sequence
29
29
 
@@ -35,13 +35,11 @@ Fall back to the stated default when nothing is detected, since no `tooling/` st
35
35
  - `180x180`
36
36
  - `192x192`, `512x512`
37
37
 
38
- This default set is raster-only. Step 6 already writes the vector source at `favicon.svg` regardless of which branch decided the sequence, so a project willing to reference an SVG favicon directly is covered either way.
39
-
40
- Announce which of the two decided the sequence.
38
+ This default set is raster-only, and Step 6 writes the vector source at `favicon.svg` on either branch. Announce which of the two decided the sequence.
41
39
 
42
40
  ## Step 3: detect the write folder
43
41
 
44
- A root-only check finds a project's assets only where the project keeps them at the root. A repository holding its site in a subfolder keeps them a level down, and a Next project keeps its favicon under the App Router convention with no `public/` at all, so both fall through to the root fallback while the announcement reads as a detected folder. Walk one level down and know that convention rather than falling through.
42
+ A root-only check misses a site kept in a subfolder, and a Next project keeps its favicon under the App Router with no `public/` at all. Both would fall through to the root while the announcement reads as detected, so walk one level down and know that convention.
45
43
 
46
44
  Read both, from the project root:
47
45
 
@@ -53,18 +51,20 @@ find . -maxdepth 4 \( -name node_modules -o -name .git \) -prune -o -type d -pat
53
51
  Take the first tier that answers:
54
52
 
55
53
  1. A root `public/` or `static/`.
56
- 2. A `public/` or `static/` one level down, such as `web/public/`. Where the first read returns more than one, take the shallowest, and the one whose parent holds the project's own framework config where two sit at the same depth.
57
- 3. A `src/app/` folder, at the root or one level down, which is the Next App Router convention and where that framework's own favicon and card files sit. Take the folder itself, not a `public/` beside it.
54
+ 2. A `public/` or `static/` one level down, such as `web/public/`. Of several, take the shallowest, then the one whose parent holds the project's framework config.
55
+ 3. A `src/app/` folder, at the root or one level down, which is the Next App Router convention. Take the folder itself, not a `public/` beside it.
58
56
  4. A stack-declared asset folder, where the project's own config names one.
59
57
  5. The project root, which is the fallback rather than a detection.
60
58
 
61
- Announce which tier decided, naming the tier rather than the path alone. On tier 5 say the detection found nothing and the root is a fallback, since a folder reported without that word reads as a folder the project declared. Announce it either way so the operator can move the files where the project's own convention differs.
59
+ Announce which tier decided, naming the tier rather than the path alone, so the operator can move the files where the project's convention differs. On tier 5 say the detection found nothing and the root is a fallback.
62
60
 
63
61
  ## Step 4: name the decision and the arms
64
62
 
65
- Follow `${CLAUDE_SKILL_DIR}/../draft-and-pick/SKILL.md` Step 1, with the decision fixed rather than derived: "the project's logo mark and its composition into the social card." Vary the mark's shape or style across arms, keeping the card's type and layout fixed, per that skill's one-property rule. Draft each arm already inside the full 1200x630 card frame, mark and type together, and add its canvas frame at `--width 1200 --height 630`, so the pick settles the shape and the composition in one choice. Arm 0 is the current mark when the folder from Step 3 already holds a logo file (`favicon.svg`, `favicon.ico`, `logo.svg`, or similar). Arms start at 1 otherwise.
63
+ Follow `${CLAUDE_SKILL_DIR}/../draft-and-pick/SKILL.md` Step 1, with the decision fixed rather than derived: "the project's logo mark and its composition into the social card." Vary the mark's shape or style across arms, keeping the card's type and layout fixed, per that skill's one-property rule.
66
64
 
67
- Structure every arm as a `.mark` element, the inline SVG alone, nested inside a `.card` element, the full composition, so Step 6 can address either without re-deriving them.
65
+ - Draft each arm inside the full 1200x630 card frame, mark and type together, and add its canvas frame at `--width 1200 --height 630`, so one pick settles shape and composition
66
+ - Arm 0 is the current mark when the Step 3 folder already holds a logo file (`favicon.svg`, `favicon.ico`, `logo.svg`, or similar). Arms start at 1 otherwise.
67
+ - Structure every arm as a `.mark` element, the inline SVG alone, nested inside a `.card` element, the full composition, so Step 6 can address either
68
68
 
69
69
  ## Step 5: draft, render, pick, and loop
70
70
 
@@ -77,56 +77,28 @@ The final icon and card renders below are not arms, so they stay off the canvas.
77
77
  This step and Step 7 replace `draft-and-pick`'s own Step 6 items 1 and 2, since the pick here produces several final files rather than one applied surface. Its archive capture, its page delete, and its server stop still run, after Step 7.
78
78
 
79
79
  1. Extract the picked arm's `.mark` markup as the final vector source. Write it to `<write-folder>/favicon.svg`.
80
- 2. Under `<dest>/render/`, write one `icon-<w>x<h>.html` page per Step 2 size, carrying the picked `.mark` markup. Give every page's captured element the shared class `.render`, so one capture call renders the whole batch regardless of the size spread. `canon capture` opens every page at a fixed 2x device scale factor and screenshots the element at that scale, so declare each `.render` element at half its target dimension, `<w>/2` by `<h>/2`, to land the captured PNG on the literal target size rather than double it. Declare no font on them, since each holds the mark alone and `canon capture` skips the font check on an element with no text. A generic family such as `system-ui` would be refused if text ever sat inside one.
81
- 3. Render the batch:
80
+ 2. Under `<dest>/render/`, write one `icon-<w>x<h>.html` page per Step 2 size, carrying the picked `.mark` markup in an element with the shared class `.render`.
81
+ 3. Declare each `.render` element at `<w>/2` by `<h>/2`, since `canon capture` screenshots at a fixed 2x scale and the PNG then lands on the target size.
82
+ 4. Declare no font on them. Each holds the mark alone, and `canon capture` skips the font check on an element with no text, where `system-ui` would be refused.
83
+ 5. Render the batch:
82
84
 
83
85
  ```bash
84
86
  canon capture <dest>/render --selector .render --out <write-folder>
85
87
  ```
86
88
 
87
- 4. Report each written file's path and the dimensions `canon capture` printed for it, confirming each equals its Step 2 target rather than half of it.
89
+ 6. Report each written file's path and the dimensions `canon capture` printed, confirming each equals its Step 2 target rather than half of it.
88
90
 
89
- The card leaves this batch and takes Step 7 instead. An icon is the mark alone at a fixed size and a scratch page renders it faithfully, where the card is a composition of the mark with the project's own type and color and a scratch page can only carry typed copies of both.
91
+ The card leaves this batch and takes Step 7 instead. An icon is the mark alone and a scratch page renders it faithfully, where the card composes the mark with the project's own type and color, which a scratch page can only copy.
90
92
 
91
93
  ## Step 7: write the card as a route and capture it through the server
92
94
 
93
- A card captured from a page this run deletes leaves the project a PNG and nothing that produced it, so renaming the project means another pass through the pick loop with an operator in it to move one string. Write the composition into a route the project keeps, and capture that route through a running server so it reads the project's real stylesheet, tokens and fonts.
95
+ A card captured from a page this run deletes leaves a PNG and nothing that produced it, so renaming the project means another pick loop to move one string. Write the composition into a route the project keeps, and capture it through a running server so it reads the real stylesheet, tokens, and fonts.
94
96
 
95
- This is Astro-shaped in v1, because Astro is the one web stack whose config gives a route a structural build exclusion. A project already holding the card route scaffold takes the route path, and everything else falls to the page path below. Say which one decided, since the two leave the project different things.
97
+ This is Astro-shaped for now, because Astro is the one web stack whose config gives a route a structural build exclusion. A project already holding the card route scaffold takes the route path, and everything else takes the page path. Say which one decided, since the two leave the project different things.
96
98
 
97
99
  ### The route path
98
100
 
99
- 1. Check that the project already holds the scaffold, being a `card.config.mjs` with a `card-src/pages/og-card.astro` beside it. Take the page path below where either is missing, and leave the install to the operator:
100
-
101
- ```plaintext
102
- No card route installed, so the card shipped as a PNG this run.
103
- `canon tooling sync astro . --write` installs the route, and it replaces every other
104
- golden config in the astro stack, so run it when you mean to sync the stack.
105
- ```
106
-
107
- Never run that sync to obtain the route. It copies the whole stack over the project's own framework, lint, typescript, and test configs, which is a cost nobody asking for a logo agreed to. Hand-writing the scaffold instead is the other wrong answer, since a copy written here drifts from the one the stack maintains.
108
-
109
- The scaffold is a second framework config pointing `srcDir` at a folder beside `src/`, the route inside that folder importing the project's global stylesheet and carrying a fixed `<meta>` marker, and a shell check failing a build that carries the marker. Of the route's three consumers, the published build is the only one a check reaches. Read the shape with `canon tooling reference astro`.
110
-
111
- 2. Write the picked arm's `.card` markup into the route's `.card` element, leaving the marker, the stylesheet import and the surrounding document alone. Keep the element at 600x315, half of the 1200x630 target, since the capture's 2x scale factor is fixed and a 1200x630 element captures at 2400x1260.
112
-
113
- 3. Start the card server in the background and read the port off its own output:
114
-
115
- ```bash
116
- bun run card:dev
117
- ```
118
-
119
- It serves under a strict port, so it refuses rather than walking to the next free one. Set `WORKTREE_PORT_OFFSET` by hand and start it again where something already holds that port.
120
-
121
- 4. Capture the route to the write folder, naming the destination PNG rather than a directory, which is what a URL source takes for `--out`:
122
-
123
- ```bash
124
- canon capture http://localhost:<port>/og-card --selector .card --out <write-folder>/og-image.png
125
- ```
126
-
127
- 5. Stop the server. Report the dimensions `canon capture` printed, confirming 1200x630.
128
-
129
- A refusal naming a font here is the mechanism working rather than a failure to route around. It says the route asked for a family the machine cannot resolve, which is the same rewrap a published card would have shipped silently.
101
+ Read `${CLAUDE_SKILL_DIR}/references/card-route.md` on reaching this path, for the scaffold check, the message to give when it is missing, and the write, serve, and capture sequence. A project with no scaffold skips it.
130
102
 
131
103
  ### The page path
132
104
 
@@ -136,13 +108,13 @@ Where the project holds no route to write into, write `og-image.html` into `<des
136
108
  canon capture <dest>/render/og-image.html --selector .render --out <write-folder>
137
109
  ```
138
110
 
139
- It takes its own call rather than riding Step 6's batch, since Step 6 runs before this step chooses a path and the batch is already captured by the time the choice is made. Say that the card shipped as a PNG with no source, and that the project gains one when it grows a route to hold the composition.
111
+ It takes its own call because Step 6's batch is already captured by the time this step picks a path. Say that the card shipped as a PNG with no source, and that the project gains one when it grows a route to hold the composition.
140
112
 
141
113
  ### Closing the scratch folder and the canvas
142
114
 
143
- Delete `<dest>` once both captures land, then close the canvas through `draft-and-pick` Step 6 items 3 to 8, which archive every arm and delete the pages the run added. The route is not a leftover variant that close forbids: a variant is one of several candidates none of which was chosen, and the route holds the arm the operator picked.
115
+ Delete `<dest>` once both captures land, then close the canvas through `draft-and-pick` Step 6 items 3 to 8, which archive every arm and delete the pages the run added. The route is not a leftover variant, since it holds the arm the operator picked.
144
116
 
145
- A project whose card was generated before this route existed keeps its PNG. Say so rather than regenerating it, since re-running the pick loop spends an operator's attention on a file nobody complained about, and the next real edit to the card picks up the route.
117
+ A project whose card was generated before this route existed keeps its PNG. Say so rather than regenerating it, since the pick loop spends attention on a file nobody complained about, and the next real edit picks up the route.
146
118
 
147
119
  ## Response format
148
120
 
@@ -162,5 +134,5 @@ Cite these rather than restating them.
162
134
 
163
135
  - `draft-and-pick` owns Steps 1 through 5 of the render-and-pick loop, cited above
164
136
  - `canon:canvas-board` carries a picked direction into `canon/DESIGN.md`. This skill only reads it.
165
- - `canon capture` owns the render mechanics, its font refusal, its fixed 2x scale factor, and its reported dimensions. It already reads an `http(s)://` source, where `--out` names the destination PNG rather than a directory, so the route capture needs nothing added to it.
137
+ - `canon capture` owns the render mechanics, its font refusal, its fixed 2x scale, and its reported dimensions. It reads an `http(s)://` source, where `--out` names the PNG.
166
138
  - The `astro` tooling stack owns the card route's scaffold, its second config, and the exclusion check, read with `canon tooling reference astro`. This skill writes into the route and never reshapes it.
@@ -0,0 +1,46 @@
1
+ ---
2
+ title: Card route path
3
+ description: How draft-identity writes the picked card composition into a project's existing Astro card route and captures it through the card server
4
+ ---
5
+
6
+ # Card route path
7
+
8
+ Applies to Step 7 of `draft-identity` when the project already holds the card route scaffold. A project without it takes the page path in the skill body instead.
9
+
10
+ ## The scaffold
11
+
12
+ The scaffold is a second framework config pointing `srcDir` at a folder beside `src/`, a route inside that folder, and a shell check. Read the shape with `canon tooling reference astro`.
13
+
14
+ - The route imports the project's global stylesheet and carries a fixed `<meta>` marker
15
+ - The shell check fails a build that carries the marker
16
+ - Of the route's three consumers, the published build is the only one a check reaches
17
+
18
+ ### When the scaffold is missing
19
+
20
+ Check for a `card.config.mjs` with a `card-src/pages/og-card.astro` beside it. Where either is missing, take the page path and leave the install to the operator, saying:
21
+
22
+ ```plaintext
23
+ No card route installed, so the card shipped as a PNG this run.
24
+ `canon tooling sync astro . --write` installs the route, and it replaces every other
25
+ golden config in the astro stack, so run it when you mean to sync the stack.
26
+ ```
27
+
28
+ Never run that sync to obtain the route, since it copies the whole stack over the project's own framework, lint, typescript, and test configs. Never hand-write the scaffold either, since a copy written here drifts from the one the stack maintains.
29
+
30
+ ## Writing and capturing the route
31
+
32
+ 1. Write the picked arm's `.card` markup into the route's `.card` element, leaving the marker, the stylesheet import, and the surrounding document alone.
33
+ 2. Keep the element at 600x315, half the 1200x630 target, since the capture's 2x scale factor is fixed and a 1200x630 element captures at 2400x1260.
34
+ 3. Start the card server in the background with `bun run card:dev` and read the port off its own output.
35
+ 4. Capture the route, naming the destination PNG rather than a directory, which is what a URL source takes for `--out`.
36
+ 5. Stop the server. Report the dimensions `canon capture` printed, confirming 1200x630.
37
+
38
+ ```bash
39
+ canon capture http://localhost:<port>/og-card --selector .card --out <write-folder>/og-image.png
40
+ ```
41
+
42
+ ### Port and font refusals
43
+
44
+ The card server runs under a strict port, so it refuses rather than walking to the next free one. Where something already holds that port, set `WORKTREE_PORT_OFFSET` by hand and start it again.
45
+
46
+ A capture refusing on a font is the mechanism working rather than a failure to route around. The route asked for a family the machine cannot resolve, which is the rewrap a published card would have shipped silently.