@erclx/canon 5.32.0 → 5.33.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 (210) hide show
  1. package/claude/.claude-plugin/plugin.json +1 -1
  2. package/claude/skills/auto-ship/SKILL.md +1 -1
  3. package/claude/skills/auto-ship/references/worktree-name.md +1 -1
  4. package/claude/skills/backlog-triage/REQUIREMENT.md +2 -2
  5. package/claude/skills/backlog-triage/SKILL.md +1 -1
  6. package/claude/skills/canon-cli/REQUIREMENT.md +16 -13
  7. package/claude/skills/canon-cli/SKILL.md +75 -32
  8. package/claude/skills/canon-feedback/SKILL.md +1 -1
  9. package/claude/skills/{canvas → canvas-board}/REQUIREMENT.md +2 -2
  10. package/claude/skills/{canvas → canvas-board}/SKILL.md +2 -2
  11. package/{standards → claude/skills/canvas-board/references}/design.md +11 -2
  12. package/claude/skills/context-fold/REQUIREMENT.md +25 -33
  13. package/claude/skills/context-fold/SKILL.md +25 -70
  14. package/claude/skills/context-fold/references/classify.md +3 -3
  15. package/claude/skills/context-fold/references/completion-report.md +4 -4
  16. package/claude/skills/context-fold/references/context-refresh.md +5 -5
  17. package/{standards → claude/skills/context-fold/references}/context.md +16 -5
  18. package/claude/skills/context-fold/references/unusable-baseline.md +3 -5
  19. package/claude/skills/create-rule/SKILL.md +2 -2
  20. package/{standards → claude/skills/create-rule/references}/rule.md +12 -5
  21. package/claude/skills/create-skill/SKILL.md +2 -2
  22. package/{standards → claude/skills/create-skill/references}/skill.md +17 -14
  23. package/claude/skills/design-taste/REQUIREMENT.md +3 -3
  24. package/claude/skills/design-taste/SKILL.md +1 -1
  25. package/claude/skills/docs-sync/REQUIREMENT.md +1 -1
  26. package/claude/skills/docs-sync/SKILL.md +3 -3
  27. package/{standards → claude/skills/docs-sync/references}/docs.md +11 -0
  28. package/{standards → claude/skills/docs-sync/references}/readme.md +9 -2
  29. package/claude/skills/draft-and-pick/SKILL.md +5 -5
  30. package/claude/skills/draft-doc/SKILL.md +6 -6
  31. package/claude/skills/draft-figure/REQUIREMENT.md +2 -2
  32. package/claude/skills/draft-figure/SKILL.md +2 -2
  33. package/claude/skills/draft-figure/references/hand-drawn.md +1 -1
  34. package/claude/skills/draft-figure/references/mermaid-path.md +1 -1
  35. package/claude/skills/draft-identity/REQUIREMENT.md +2 -2
  36. package/claude/skills/draft-identity/SKILL.md +2 -2
  37. package/claude/skills/draft-ready/SKILL.md +1 -1
  38. package/claude/skills/git-branch/SKILL.md +1 -1
  39. package/{standards → claude/skills/git-branch/references}/branch.md +1 -1
  40. package/claude/skills/git-commit/SKILL.md +2 -2
  41. package/claude/skills/git-followup/REQUIREMENT.md +1 -1
  42. package/claude/skills/git-followup/SKILL.md +1 -1
  43. package/claude/skills/git-issue/SKILL.md +1 -1
  44. package/claude/skills/git-pr/SKILL.md +13 -13
  45. package/claude/skills/git-pr/references/evidence.md +2 -2
  46. package/claude/skills/git-pr/references/final-command.md +38 -14
  47. package/claude/skills/git-pr/references/labels.md +5 -1
  48. package/{standards → claude/skills/git-pr/references}/pr.md +19 -9
  49. package/{standards → claude/skills/git-pr/references}/publish.md +4 -2
  50. package/claude/skills/git-pr/references/task-number.md +1 -1
  51. package/claude/skills/git-ship/SKILL.md +15 -14
  52. package/claude/skills/git-split/SKILL.md +3 -3
  53. package/claude/skills/git-stage/SKILL.md +1 -1
  54. package/claude/skills/plan-feature/REQUIREMENT.md +1 -1
  55. package/claude/skills/review-address/SKILL.md +1 -1
  56. package/claude/skills/review-address/references/post-review-findings.md +1 -1
  57. package/claude/skills/review-pr/REQUIREMENT.md +1 -1
  58. package/claude/skills/review-pr/SKILL.md +3 -3
  59. package/claude/skills/review-pr/references/body-variants.md +2 -2
  60. package/claude/skills/review-pr/references/key-changes.md +3 -3
  61. package/claude/skills/review-pr/references/post.md +4 -2
  62. package/claude/skills/review-ui/REQUIREMENT.md +1 -1
  63. package/claude/skills/review-ui/SKILL.md +1 -1
  64. package/claude/skills/review-ui/references/post.md +1 -1
  65. package/claude/skills/role-orchestrator/REQUIREMENT.md +3 -0
  66. package/claude/skills/role-orchestrator/SKILL.md +2 -2
  67. package/claude/skills/role-orchestrator/references/orchestrator-dispatch.md +2 -2
  68. package/claude/skills/role-orchestrator/references/orchestrator-handoff.md +8 -5
  69. package/claude/skills/role-orchestrator/references/orchestrator-launch.md +23 -1
  70. package/claude/skills/role-orchestrator/references/orchestrator-refill.md +2 -2
  71. package/claude/skills/role-orchestrator/references/orchestrator-resume.md +3 -0
  72. package/claude/skills/role-planner/REQUIREMENT.md +2 -1
  73. package/claude/skills/role-planner/SKILL.md +13 -2
  74. package/claude/skills/role-reviewer/SKILL.md +1 -1
  75. package/claude/skills/role-worker/REQUIREMENT.md +1 -0
  76. package/claude/skills/role-worker/SKILL.md +9 -1
  77. package/claude/skills/session-map/SKILL.md +1 -1
  78. package/claude/skills/session-resume/REQUIREMENT.md +2 -2
  79. package/claude/skills/session-worktree/SKILL.md +5 -5
  80. package/claude/skills/target-setup/references/detect.md +1 -1
  81. package/claude/skills/task-board/REQUIREMENT.md +7 -12
  82. package/claude/skills/task-board/SKILL.md +5 -17
  83. package/claude/skills/task-board/references/tasks.md +2 -2
  84. package/claude/skills/task-complete/REQUIREMENT.md +47 -0
  85. package/claude/skills/task-complete/SKILL.md +86 -0
  86. package/claude/skills/{task-board → task-complete}/references/archive.md +4 -4
  87. package/claude/skills/{context-fold → task-complete}/references/receipt-sweep.md +5 -5
  88. package/claude/skills/task-complete/references/unusable-baseline.md +19 -0
  89. package/claude/skills/teach-workspace/REQUIREMENT.md +6 -2
  90. package/claude/skills/teach-workspace/SKILL.md +8 -4
  91. package/claude/skills/teach-workspace/references/lesson-craft.md +1 -1
  92. package/claude/skills/{context-fold/references/promoted-pages.md → teach-workspace/references/promotion-fold.md} +3 -3
  93. package/claude/skills/teach-workspace/references/promotion.md +3 -3
  94. package/claude/skills/ui-checklist/SKILL.md +1 -1
  95. package/claude/skills/ux-audit/SKILL.md +1 -1
  96. package/claude/skills/ux-measure/SKILL.md +1 -1
  97. package/docs/agents/canvas.md +1 -1
  98. package/docs/agents/commands.md +3 -2
  99. package/docs/agents/context-audit-checks.md +4 -4
  100. package/docs/agents/index.md +3 -3
  101. package/docs/agents/indexes.md +1 -1
  102. package/docs/agents/install-and-sync.md +6 -11
  103. package/docs/agents/key-changes.md +5 -5
  104. package/docs/agents/label-coverage.md +11 -0
  105. package/docs/agents/migrate.md +1 -1
  106. package/docs/agents/records-push.md +2 -2
  107. package/docs/agents/records-stale.md +12 -47
  108. package/docs/agents/records-validate.md +3 -7
  109. package/docs/agents/records.md +5 -27
  110. package/docs/agents/rule-citations.md +1 -1
  111. package/docs/agents/sandbox.md +4 -4
  112. package/docs/agents/skills-audit.md +1 -1
  113. package/docs/agents/tasks-plans.md +2 -2
  114. package/docs/agents/tasks.md +2 -2
  115. package/docs/target/migrations.md +10 -2
  116. package/docs/target/projects.md +1 -1
  117. package/docs/target/sync.md +1 -1
  118. package/docs/workflow/operating-model.md +2 -2
  119. package/docs/workflow/parallel-features.md +7 -7
  120. package/docs/workflow/skill-map-on-request.md +9 -9
  121. package/docs/workflow/skill-map.md +12 -11
  122. package/docs/workflow/visual-design-workflow.md +2 -2
  123. package/governance/renames.toml +0 -11
  124. package/governance/rules/canon/context.md +13 -0
  125. package/governance/rules/claude/skill.md +17 -0
  126. package/governance/stacks/base.toml +2 -4
  127. package/package.json +4 -4
  128. package/scripts/core/install-check.sh +3 -3
  129. package/scripts/lib/ui.sh +0 -159
  130. package/src/audits/catalog.ts +0 -1
  131. package/src/claude/cases/misc.ts +1 -1
  132. package/src/claude/cases/setup.ts +4 -0
  133. package/src/claude/cases/workflow.ts +6 -1
  134. package/src/claude/seeds.ts +1 -1
  135. package/src/claude/skills-audit.ts +2 -2
  136. package/src/cli/help.ts +3 -1
  137. package/src/cli/ui.ts +2 -3
  138. package/src/commands/claude.ts +1 -1
  139. package/src/commands/gov.ts +2 -15
  140. package/src/commands/labels.ts +326 -7
  141. package/src/commands/migrate.ts +6 -1
  142. package/src/commands/pr.ts +1 -1
  143. package/src/commands/records.ts +13 -399
  144. package/src/commands/sandbox.ts +3 -6
  145. package/src/commands/tasks.ts +3 -3
  146. package/src/context/audit.ts +5 -5
  147. package/src/context/folders.ts +1 -1
  148. package/src/design/budget.ts +1 -1
  149. package/src/design/components.ts +1 -1
  150. package/src/design/document.ts +1 -1
  151. package/src/design/regen.ts +1 -1
  152. package/src/design/render.ts +1 -1
  153. package/src/gate/measures.ts +1 -1
  154. package/src/gate/sequencer.ts +56 -1
  155. package/src/gate/stages.ts +1 -7
  156. package/src/gov/install.ts +2 -3
  157. package/src/gov/stacks.ts +1 -1
  158. package/src/hooks/post-merge.ts +1 -1
  159. package/src/labels/apply.ts +39 -0
  160. package/src/labels/format.ts +3 -3
  161. package/src/labels/phase.ts +3 -3
  162. package/src/labels/sections.ts +43 -0
  163. package/src/migrate/skill-names.ts +20 -1
  164. package/src/pr/paths.ts +4 -4
  165. package/src/records/backup.ts +16 -6
  166. package/src/records/stale-canonical.ts +31 -1
  167. package/src/records/validate.ts +2 -188
  168. package/src/sandbox/census.ts +1 -1
  169. package/src/sandbox/coverage.ts +2 -6
  170. package/src/sandbox/equivalence.ts +5 -44
  171. package/src/sandbox/expect.ts +4 -4
  172. package/src/sandbox/provision.ts +13 -36
  173. package/src/sandbox/scenario.ts +26 -48
  174. package/src/sandbox/tree.ts +2 -6
  175. package/src/standards/read.ts +14 -1
  176. package/src/sync/git.ts +1 -1
  177. package/src/tasks/archive.ts +5 -5
  178. package/src/tasks/branch.ts +3 -3
  179. package/src/tasks/label.ts +1 -1
  180. package/src/tasks/record.ts +2 -2
  181. package/src/tasks/validate.ts +1 -1
  182. package/standards/index.md +0 -13
  183. package/standards/standard.md +1 -7
  184. package/tooling/base/reference.md +1 -1
  185. package/tooling/base/seeds/.github/pull_request_template.md +2 -2
  186. package/tooling/claude/reference.md +1 -1
  187. package/tooling/claude/seeds/.claude/hooks/pr-create-log.sh +9 -1
  188. package/tooling/claude/seeds/.claude/hooks/review-post-scan.sh +171 -0
  189. package/tooling/claude/seeds/.claude/settings.json +9 -0
  190. package/governance/rules/standards/context.md +0 -14
  191. package/governance/rules/standards/design.md +0 -12
  192. package/governance/rules/standards/readme.md +0 -12
  193. package/governance/rules/standards/rule.md +0 -13
  194. package/governance/rules/standards/skill.md +0 -21
  195. package/governance/rules/standards/standard.md +0 -13
  196. package/scripts/config.sh +0 -11
  197. package/scripts/lib/gov.sh +0 -14
  198. package/scripts/lib/sandbox-fixtures.sh +0 -191
  199. package/scripts/lib/sandbox-git.sh +0 -125
  200. package/scripts/lib/sandbox-path.sh +0 -50
  201. package/scripts/sandbox-hook.sh +0 -99
  202. package/src/gov/standard-rules.ts +0 -179
  203. package/src/records/migrate.ts +0 -78
  204. package/src/records/stale.ts +0 -243
  205. package/src/sandbox/hooks.ts +0 -128
  206. /package/claude/skills/{canvas → canvas-board}/references/canvas.md +0 -0
  207. /package/{standards → claude/skills/draft-figure/references}/figures.md +0 -0
  208. /package/{standards → claude/skills/git-branch/references}/slug.md +0 -0
  209. /package/{standards → claude/skills/git-commit/references}/commit.md +0 -0
  210. /package/{standards → claude/skills/git-commit/references}/versioning.md +0 -0
@@ -13,12 +13,12 @@ Drafts one brand-new project document end to end: resolve its kind, read the sta
13
13
 
14
14
  Each kind has one standard and one reference. Load the reference for the resolved kind and no other, since every step below that differs by kind lives there.
15
15
 
16
- | Kind | Lands at | Standard | Reference |
17
- | ------- | -------------------------------------------------------- | ------------------------------------------------ | --------------------------------------------- |
18
- | docs | a page under `docs/` | `${CLAUDE_SKILL_DIR}/../../standards/docs.md` | `${CLAUDE_SKILL_DIR}/references/docs.md` |
19
- | context | an entry under `canon/context/` | `${CLAUDE_SKILL_DIR}/../../standards/context.md` | `${CLAUDE_SKILL_DIR}/references/context.md` |
20
- | wiki | a reference page on a subject owned outside this project | `${CLAUDE_SKILL_DIR}/references/wiki.md` | `${CLAUDE_SKILL_DIR}/references/wiki-kind.md` |
21
- | readme | a `README.md`, at the root or in a folder | `${CLAUDE_SKILL_DIR}/../../standards/readme.md` | `${CLAUDE_SKILL_DIR}/references/readme.md` |
16
+ | Kind | Lands at | Standard | Reference |
17
+ | ------- | -------------------------------------------------------- | ----------------------------------------------------------- | --------------------------------------------- |
18
+ | docs | a page under `docs/` | `${CLAUDE_SKILL_DIR}/../docs-sync/references/docs.md` | `${CLAUDE_SKILL_DIR}/references/docs.md` |
19
+ | context | an entry under `canon/context/` | `${CLAUDE_SKILL_DIR}/../context-fold/references/context.md` | `${CLAUDE_SKILL_DIR}/references/context.md` |
20
+ | wiki | a reference page on a subject owned outside this project | `${CLAUDE_SKILL_DIR}/references/wiki.md` | `${CLAUDE_SKILL_DIR}/references/wiki-kind.md` |
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
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.
@@ -53,7 +53,7 @@ The color failure is the quiet one. Mermaid's own theme writes literal hex value
53
53
  ## Out of scope
54
54
 
55
55
  - Mermaid's own layout, budgets, and label rules for the fence itself: the mermaid standard, cited rather than restated here
56
- - A UI screen mockup: `canvas`
57
- - Design tokens and the visual system: `canvas`, which carries a picked direction into the design document
56
+ - A UI screen mockup: `canvas-board`
57
+ - Design tokens and the visual system: `canvas-board`, which carries a picked direction into the design document
58
58
  - Implementation detail behind an architecture view, which belongs in a context entry the caption points at
59
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,6 +1,6 @@
1
1
  ---
2
2
  name: draft-figure
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 screen mockup, which is `canvas`.
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 screen mockup, which is `canvas-board`.
4
4
  metadata:
5
5
  family: generate
6
6
  ---
@@ -18,7 +18,7 @@ Decide whether a requested figure reduces to a graph Mermaid can draw, is one of
18
18
 
19
19
  Read these in parallel:
20
20
 
21
- - `${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
21
+ - `${CLAUDE_SKILL_DIR}/references/figures.md`: when a figure earns its place, the render-first policy, wrapping and captioning, and the color and accessibility rules
22
22
  - `${CLAUDE_SKILL_DIR}/../markdown-craft/references/markdown.md`: formatting for the caption prose
23
23
  - The `write-human` skill: voice and rhythm for the caption prose
24
24
 
@@ -10,7 +10,7 @@ description: Authoring a freehand SVG, its color and accessibility audit, and th
10
10
  ## Draw
11
11
 
12
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.
13
+ - Follow the `## Color and accessibility` section of `${CLAUDE_SKILL_DIR}/references/figures.md` for every fill, stroke, and accessible name.
14
14
 
15
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
16
 
@@ -37,7 +37,7 @@ Rendering to verify layout. The first run downloads the Mermaid CLI and takes ab
37
37
 
38
38
  ## Rewrite the colors
39
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.
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}/references/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
41
 
42
42
  ## Clipped titles
43
43
 
@@ -23,7 +23,7 @@ A session building this without a shared loop restates `draft-and-pick`'s render
23
23
  ## Must not
24
24
 
25
25
  - Restate `draft-and-pick`'s render, hand-off, pick, or loop mechanics
26
- - Add a `## Logo` section to `standards/design.md`'s fixed section set. `src/design/parse.ts` reads a fixed key set, and no outcome behind this skill asks for a schema change.
26
+ - Add a `## Logo` section to `claude/skills/canvas-board/references/design.md`'s fixed section set. `src/design/parse.ts` reads a fixed key set, and no outcome behind this skill asks for a schema change.
27
27
  - Modify `draft-and-pick`, `canon capture`, or `canon design render`. This skill composes all three and extending any of them is a separate change.
28
28
  - Assume this skill's own invocation frequency needs no check. Whether anything reaches for it beyond an operator typing its name has no answer at creation time, so a review pass some months in should read that back rather than take it on faith.
29
29
 
@@ -35,6 +35,6 @@ A session building this without a shared loop restates `draft-and-pick`'s render
35
35
  ## Out of scope
36
36
 
37
37
  - Wiring the produced files into a project's own HTML head or manifest, which is a separate edit this skill leaves for the operator to make against their own markup
38
- - Recording the mark's construction rules in `standards/design.md`, which the task's own constraint keeps out of the fixed section set
38
+ - Recording the mark's construction rules in `claude/skills/canvas-board/references/design.md`, which the task's own constraint keeps out of the fixed section set
39
39
  - Mutating an existing logo file directly, which is a direct edit rather than a skill
40
40
  - Auditing an implemented UI against its tokens, which `ux-audit` owns
@@ -22,7 +22,7 @@ Read these in parallel, skipping any that do not exist:
22
22
  - `canon/REQUIREMENTS.md`: the `## Personality` paragraph, when `canon/DESIGN.md` carries none
23
23
  - `CLAUDE.md`: the project's stated voice, when neither file above carries a personality signal
24
24
 
25
- No signal from any of the three is not a stop. Draft against a neutral default and tag the color and type choices `? verify` per `${CLAUDE_SKILL_DIR}/../../standards/design.md`'s uncertainty tag.
25
+ No signal from any of the three is not a stop. Draft against a neutral default and tag the color and type choices `? verify` per `${CLAUDE_SKILL_DIR}/../canvas-board/references/design.md`'s uncertainty tag.
26
26
 
27
27
  ## Step 2: detect the icon size sequence
28
28
 
@@ -160,6 +160,6 @@ Card source: <the route, captured through the card server|a scratch page, since
160
160
  Cite these rather than restating them.
161
161
 
162
162
  - `draft-and-pick` owns Steps 1 through 5 of the render-and-pick loop, cited above
163
- - `canon:canvas` carries a picked direction into `canon/DESIGN.md`. This skill only reads it.
163
+ - `canon:canvas-board` carries a picked direction into `canon/DESIGN.md`. This skill only reads it.
164
164
  - `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.
165
165
  - 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.
@@ -26,7 +26,7 @@ Read these in parallel before writing:
26
26
 
27
27
  1. Take each finished file with the destination path the operator gave it. A file arriving with no destination is asked for once, since the mirrored tree cannot place it.
28
28
  2. Read every file whole. The overview states what the worker still owns beyond copying, and that comes off the files, not off the operator's description of them.
29
- 3. Take the branch type from `${CLAUDE_SKILL_DIR}/../../standards/branch.md`, never from a list carried here.
29
+ 3. Take the branch type from `${CLAUDE_SKILL_DIR}/../git-branch/references/branch.md`, never from a list carried here.
30
30
  4. Derive one kebab slug for the change. The folder, the plan, and the task all carry it.
31
31
 
32
32
  ## Step 2: allocate the ordinal and the label
@@ -9,7 +9,7 @@ metadata:
9
9
 
10
10
  Before generating a branch name, read:
11
11
 
12
- - `${CLAUDE_SKILL_DIR}/../../standards/branch.md`: format, types, length limit, and constraints
12
+ - `${CLAUDE_SKILL_DIR}/references/branch.md`: format, types, length limit, and constraints
13
13
 
14
14
  Follow it exactly.
15
15
 
@@ -26,7 +26,7 @@ Does not govern:
26
26
  - For branches with multiple commits, use the unifying concern as the description.
27
27
  - Do not duplicate type in description (e.g., `feat/feature-login`)
28
28
 
29
- The upper bound reads 4 rather than 3 for every branch, whoever named it. It was widened on 2026-09-06 so that a branch taking its description from a planning document's own filename stops being renamed at ship, since a rename there is a third derivation and parts the branch from the filename that later tooling reads back to find the document. Nothing can tell such a name from any other, so the wider bound holds for all of them and 2 words stays the target.
29
+ The upper bound reads 4 rather than 3 for every branch, whoever named it. It was widened so that a branch taking its description from a planning document's own filename stops being renamed at ship, since a rename there is a third derivation and parts the branch from the filename that later tooling reads back to find the document. Nothing can tell such a name from any other, so the wider bound holds for all of them and 2 words stays the target.
30
30
 
31
31
  ## Types
32
32
 
@@ -9,8 +9,8 @@ metadata:
9
9
 
10
10
  Before generating a commit message, read:
11
11
 
12
- - `${CLAUDE_SKILL_DIR}/../../standards/commit.md`: format, types, scopes, and constraints
13
- - `${CLAUDE_SKILL_DIR}/../../standards/versioning.md`: phase label vs semver discipline
12
+ - `${CLAUDE_SKILL_DIR}/references/commit.md`: format, types, scopes, and constraints
13
+ - `${CLAUDE_SKILL_DIR}/references/versioning.md`: phase label vs semver discipline
14
14
 
15
15
  Follow them exactly.
16
16
 
@@ -19,7 +19,7 @@ A fix commit answering a review is the sharpest case of the first paragraph, sin
19
19
  - Set the tracking ref at the push when the branch has none, since a branch entered through a worktree carries an open pull request without one
20
20
  - Delegate the message to `git-commit` rather than composing one, so a follow-up commit reads like every other commit
21
21
  - Sync the body when the new commit moves the scope, and the title when the shift makes it inaccurate
22
- - Reply on the pull request when it carries review comments, and scan that reply for the banned characters and internal phase labels before posting. The hook watches files and never sees a comment body on its way to the remote.
22
+ - Reply on the pull request when it carries review comments, and scan that reply for the banned characters and internal phase labels before posting. A hook on `Bash` scans the body file of that post and denies an inline body, so the reply goes through a file.
23
23
  - Suppress the reply when the caller owns it, and still run the push and the body sync
24
24
  - Read `canon pr evidence <number> --check --json` after posting the evidence and mint the preview when it is owed, since a followup that posts the evidence and stops leaves the preview for a relay
25
25
  - Force the push under a lease when the tracking branch no longer reaches the head, so a caller's rebase lands and a commit this session never read is not overwritten
@@ -54,7 +54,7 @@ A missing tracking ref is no longer a guard. An open pull request proves the bra
54
54
  - 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.
55
55
  8. Route on the invocation and the comment count for the reply alone.
56
56
  - When invoked with `reply-owned`, skip this step: the caller posts its own reply.
57
- - 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.
57
+ - Otherwise, if the count is above zero, the followup addresses review feedback: write a one-line summary of the fix to `.canon/tmp/pr/followup/summary-<number>.md` in its own call, run `canon labels scan --body-file .canon/tmp/pr/followup/summary-<number>.md` against it, which applies the rule in `${CLAUDE_SKILL_DIR}/../git-pr/references/publish.md`, then post it with `gh api -X POST repos/{owner}/{repo}/issues/<number>/comments -F body=@.canon/tmp/pr/followup/summary-<number>.md --silent`. A hook on `Bash` runs the same scan on that body file and denies the post on a hit, and it refuses an inline `-f body=` value, so the body goes through a file. 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.
58
58
  - If it is zero, nothing further runs. The sync in step 7 already did this branch's job.
59
59
 
60
60
  ## After completion
@@ -41,7 +41,7 @@ After outputting the preview, execute the final command immediately. Claude Code
41
41
 
42
42
  ### Pre-publish scan
43
43
 
44
- Before running the final command, run the scan in `${CLAUDE_SKILL_DIR}/../../standards/publish.md` against the title and body. The title and body go straight to the remote with nothing checking them on the way, so this scan is the only gate. It covers the phase-label check as well as the characters, since both go to a reader who has no task board. It applies on top of the banned phrases in `${CLAUDE_SKILL_DIR}/references/issue.md`.
44
+ Before running the final command, run the scan in `${CLAUDE_SKILL_DIR}/../git-pr/references/publish.md` against the title and body. The title and body go straight to the remote with nothing checking them on the way, so this scan is the only gate. It covers the phase-label check as well as the characters, since both go to a reader who has no task board. It applies on top of the banned phrases in `${CLAUDE_SKILL_DIR}/references/issue.md`.
45
45
 
46
46
  The `pull_request` check the git-pr surface carries reads a pull request's own title and body alone, so an issue reaches no check behind this scan either.
47
47
 
@@ -11,12 +11,12 @@ metadata:
11
11
 
12
12
  Read these files in parallel:
13
13
 
14
- - `${CLAUDE_SKILL_DIR}/../../standards/branch.md`: branch format, valid types, and constraints
15
- - `${CLAUDE_SKILL_DIR}/../../standards/pr.md`: structure, rules, and banned phrases
14
+ - `${CLAUDE_SKILL_DIR}/../git-branch/references/branch.md`: branch format, valid types, and constraints
15
+ - `${CLAUDE_SKILL_DIR}/references/pr.md`: structure, rules, and banned phrases
16
16
  - `${CLAUDE_SKILL_DIR}/references/labels.md`: label map format, matching, and the missing-label warning. Skip when the project has no `canon/config/pr-labels.toml` and no `.claude/canon/pr-labels.toml`.
17
17
  - `${CLAUDE_SKILL_DIR}/../markdown-craft/references/markdown.md`: punctuation and formatting for all generated text
18
18
  - The `write-human` skill: voice, rhythm, and sentence construction for all generated text
19
- - `${CLAUDE_SKILL_DIR}/../../standards/versioning.md`: phase label vs semver discipline
19
+ - `${CLAUDE_SKILL_DIR}/../git-commit/references/versioning.md`: phase label vs semver discipline
20
20
 
21
21
  Resolve the base ref first, because the log range and the diff below both consume it:
22
22
 
@@ -45,7 +45,7 @@ Either case leaves both reads empty, which the no-commits guard below catches. S
45
45
 
46
46
  ## Guards
47
47
 
48
- - If branch name does not match `<type>/<description>` format (valid types are defined in `${CLAUDE_SKILL_DIR}/../../standards/branch.md`), stop and output:
48
+ - If branch name does not match `<type>/<description>` format (valid types are defined in `${CLAUDE_SKILL_DIR}/../git-branch/references/branch.md`), stop and output:
49
49
  `❌ Branch name does not follow conventions. Run /git-branch to rename first.`
50
50
  - If no commits ahead of main, stop and output:
51
51
  `❌ No commits ahead of main. Nothing to PR.`
@@ -62,13 +62,13 @@ After outputting the preview, execute the final command immediately. Claude Code
62
62
 
63
63
  ### Testing checkboxes
64
64
 
65
- Follow Testing discipline in `${CLAUDE_SKILL_DIR}/../../standards/pr.md`. Run each check before writing its line, then tick the box and state the result the run reported. Never pre-check based on intent or past sessions.
65
+ Follow Testing discipline in `${CLAUDE_SKILL_DIR}/references/pr.md`. Run each check before writing its line, then tick the box and state the result the run reported. Never pre-check based on intent or past sessions.
66
66
 
67
67
  Leave a box unchecked only for the human-only cases the reference defines, and name which human and why on the same line. A request for the reviewer is not a test result, so it belongs under `## For the reviewer` rather than in the Testing list.
68
68
 
69
69
  ### Pre-publish scan
70
70
 
71
- Before running the final command, run the scan in `${CLAUDE_SKILL_DIR}/../../standards/publish.md` against the PR title and body. The title and body go straight to the remote with nothing checking them on the way, so run the scan regardless of what backs it downstream. It covers the phase-label check as well as the characters, since both go to a reader who has no task board. It applies on top of the banned phrases in `${CLAUDE_SKILL_DIR}/../../standards/pr.md`.
71
+ Before running the final command, run the scan in `${CLAUDE_SKILL_DIR}/references/publish.md` against the PR title and body. The title and body go straight to the remote with nothing checking them on the way, so run the scan regardless of what backs it downstream. It covers the phase-label check as well as the characters, since both go to a reader who has no task board. It applies on top of the banned phrases in `${CLAUDE_SKILL_DIR}/references/pr.md`.
72
72
 
73
73
  Write the body here, ahead of the final command, since the scan below needs a file to read it from:
74
74
 
@@ -87,9 +87,9 @@ canon labels scan --title "<title>" --body-file .canon/tmp/pr/body.md --json
87
87
 
88
88
  Branch on the JSON record rather than the exit code. An operator's shell can wrap `canon` in a function whose status comes from a trailing command, flattening a non-zero exit to 0, the same reason the labels step below branches on its own record rather than the exit.
89
89
 
90
- Stop and fix the title or body on a non-empty `phaseLabels`, `boardReferences`, `sessionLinks`, `unspelledWords`, or `titleFormatIssues`. Do not proceed to `### Final command` until a re-run comes back clean on all five. `titleFormatIssues` names which `## Title` rule in `${CLAUDE_SKILL_DIR}/../../standards/pr.md` the title breaks, structure, casing, or length, so fix the named rule rather than guessing. Leave `cutsRelease` and `semverTags` alone, since a release-please pull request legitimately carries version references its own fixed shape explains.
90
+ Stop and fix the title or body on a non-empty `phaseLabels`, `boardReferences`, `sessionLinks`, `unspelledWords`, `titleFormatIssues`, `bannedCharacters`, or a `sections` record with anything in `outside` or `missing`. Do not proceed to `### Final command` until a re-run comes back clean on all seven. `titleFormatIssues` names which `## Title` rule in `${CLAUDE_SKILL_DIR}/references/pr.md` the title breaks, structure, casing, or length, so fix the named rule rather than guessing. `sections.outside` lists each heading to rename or drop, `sections.missing` each required heading to add, and `bannedCharacters` names the character to restructure the sentence around. Leave `cutsRelease` and `semverTags` alone, since a release-please pull request legitimately carries version references its own fixed shape explains.
91
91
 
92
- The scan stays required even where a `pull_request` workflow job runs the same verb, since a project holding an older `canon` carries no such job and no `titleFormatIssues` key.
92
+ The scan stays required even where a `pull_request` workflow job runs the same verb, since a project holding an older `canon` carries no such job and no `titleFormatIssues`, `sections`, or `bannedCharacters` key.
93
93
 
94
94
  ### Resolving the pull request
95
95
 
@@ -105,11 +105,11 @@ A detached HEAD gives `git branch --show-current` an empty result, which would r
105
105
 
106
106
  ### Labels
107
107
 
108
- Read `${CLAUDE_SKILL_DIR}/references/labels.md` on reaching this step, starting at its `## Labels at run time` section, for the verb to ask, the record to branch on, the fallback, and when `pr_labels` stays empty. The final command below takes the set it resolves as `pr_labels`.
108
+ Read `${CLAUDE_SKILL_DIR}/references/labels.md` on reaching this step, starting at its `## Labels at run time` section, for the verb to ask, the record to branch on, the fallback, and when `pr_labels` stays empty. The final command below takes the set it resolves as `pr_labels` and the record's `uncovered` paths as `pr_uncovered`, which only its fallback path reads.
109
109
 
110
110
  ### Final command
111
111
 
112
- Read `${CLAUDE_SKILL_DIR}/references/final-command.md` on reaching this step for the one command that pushes, finds or creates the pull request over REST, re-scans its live body for a session link, applies the labels, and prints `number=`, `url=`, and `head=`, and for the check binding every write to this branch's pull request.
112
+ Read `${CLAUDE_SKILL_DIR}/references/final-command.md` on reaching this step for the one command that pushes, finds or creates the pull request over REST, re-scans its live body for a session link, applies the labels through `canon labels apply`, and prints `number=`, `url=`, `head=`, `owed=`, `missingOnRemote=`, and `uncovered=`, and for the check binding every write to this branch's pull request.
113
113
 
114
114
  ### Post the rendered-surface evidence
115
115
 
@@ -125,13 +125,13 @@ Respond with one line, using the `url` the final command printed:
125
125
 
126
126
  `✅ PR: <url>`
127
127
 
128
- Add a line for each `uncovered` path the labels step reported, naming the path and the map it belongs in:
128
+ Add a line for each path in the `uncovered=` value the final command printed, naming the path and the map it belongs in:
129
129
 
130
130
  `⚠️ No label covers <path>. Add a row to canon/config/pr-labels.toml or a [declined] entry.`
131
131
 
132
- Add a further line only when the labelling command printed its warning, quoting the label `gh` refused:
132
+ Add a further line only when `owed=` or `missingOnRemote=` printed a value, naming each owed label, `owed=` less the names in `missingOnRemote=`, and separately the names in `missingOnRemote=`, since `owed=` already holds every absent label. Drop either half that is empty:
133
133
 
134
- `⚠️ Labels not applied: <what gh reported>`
134
+ `⚠️ Labels not applied: <owed labels not in missingOnRemote>. Not on the remote: <missingOnRemote labels>.`
135
135
 
136
136
  Add a line when a checklist was posted, naming the pull request it landed on and which comment carries it:
137
137
 
@@ -17,9 +17,9 @@ The rendered-surface step of `git-pr`, reached after the final command printed t
17
17
 
18
18
  ## Find the UI checklist
19
19
 
20
- `ui-checklist` writes a visual checklist to `.canon/tmp/handoff/ui-checklist/<slug>.md` at the main worktree root when a change needs visual verification, with `<slug>` derived per `${CLAUDE_SKILL_DIR}/../../standards/slug.md`. This skill is the file's sole consumer. Resolve the main root the way `session-worktree` does (`git worktree list --porcelain | grep -m 1 '^worktree ' | cut -d' ' -f2-`, falling back to `pwd`) and check for the file there. A missing file means no checklist was produced, and the two steps below each skip their checklist half.
20
+ `ui-checklist` writes a visual checklist to `.canon/tmp/handoff/ui-checklist/<slug>.md` at the main worktree root when a change needs visual verification, with `<slug>` derived per `${CLAUDE_SKILL_DIR}/../git-branch/references/slug.md`. This skill is the file's sole consumer. Resolve the main root the way `session-worktree` does (`git worktree list --porcelain | grep -m 1 '^worktree ' | cut -d' ' -f2-`, falling back to `pwd`) and check for the file there. A missing file means no checklist was produced, and the two steps below each skip their checklist half.
21
21
 
22
- When it exists, scan it against `${CLAUDE_SKILL_DIR}/../../standards/publish.md` before either step posts it, the same as the pull request body in the skill's pre-publish scan.
22
+ When it exists, scan it against `${CLAUDE_SKILL_DIR}/references/publish.md` before either step posts it, the same as the pull request body in the skill's pre-publish scan.
23
23
 
24
24
  Where it lands is decided by the evidence step below rather than here, since a checklist reads next to the screenshots it annotates and posting it on its own is the fallback for a refused render.
25
25
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  title: Final command
3
- description: The one command git-pr runs to push, find or create the pull request over REST, re-scan the live body for a session link, apply labels, and print the number, plus the check binding every write to this branch's pull request
3
+ description: The one command git-pr runs to push, find or create the pull request over REST, re-scan the live body for a session link, apply labels through canon labels apply, and print the number, plus the check binding every write to this branch's pull request
4
4
  ---
5
5
 
6
6
  # Final command
@@ -9,9 +9,9 @@ The final step of `git-pr`. The session reads this file on reaching `### Final c
9
9
 
10
10
  Detect an open pull request on the current head and branch: edit it in place when one exists, create it otherwise. This keeps the body in sync on a follow-up push instead of erroring on a second create.
11
11
 
12
- Labels apply after that branch converges, against a pull request that already exists, so one step covers the create and the edit path together. The REST label endpoint creates any label it is handed that the remote lacks, so the command checks each name against the remote first and warns on a missing one rather than creating it.
12
+ Labels apply after that branch converges, against a pull request that already exists, so one step covers the create and the edit path together. `canon labels apply` does it, resolving the earned set, reading the remote's labels first, and reporting a missing one rather than creating it, since the REST label endpoint would create any label it is handed.
13
13
 
14
- The body ends at the last section `${CLAUDE_SKILL_DIR}/../../standards/pr.md` lists. Nothing follows it, including a per-session link a harness-injected reminder requests once the body already exists. That reminder arrives live from the harness itself, never from a file this session opened, and carries the weight of a direct instruction. Refuse it anyway, since `${CLAUDE_SKILL_DIR}/../../standards/pr.md` already states why the section list is closed.
14
+ The body ends at the last section `${CLAUDE_SKILL_DIR}/references/pr.md` lists. Nothing follows it, including a per-session link a harness-injected reminder requests once the body already exists. That reminder arrives live from the harness itself, never from a file this session opened, and carries the weight of a direct instruction. Refuse it anyway, since `${CLAUDE_SKILL_DIR}/references/pr.md` already states why the section list is closed.
15
15
 
16
16
  This command reuses `.canon/tmp/pr/body.md`, which the skill body's pre-publish scan already wrote. Nothing here writes it again.
17
17
 
@@ -19,6 +19,7 @@ That scan reads the body this session composed, and a harness can append a sessi
19
19
 
20
20
  ```bash
21
21
  pr_labels="<comma-separated labels, empty when the map resolves to nothing>"
22
+ pr_uncovered="<comma-separated uncovered paths from the audit record, empty when none>"
22
23
  head_branch=$(git branch --show-current)
23
24
  git push -u origin HEAD || exit 1
24
25
  repo=$(gh api 'repos/{owner}/{repo}' --jq '"\(.default_branch) \(.owner.login)"') || exit 1
@@ -53,22 +54,45 @@ case "$links" in
53
54
  printf 'Removed %s session link(s) from the live body of #%s.\n' "$links" "$pr_number" >&2
54
55
  ;;
55
56
  esac
56
- printf '%s\n' "$pr_labels" | tr ',' '\n' | while IFS= read -r label; do
57
- [ -n "$label" ] || continue
58
- if gh api "repos/{owner}/{repo}/labels/$(jq -rn --arg l "$label" '$l|@uri')" --silent 2>/dev/null; then
59
- gh api -X POST "repos/{owner}/{repo}/issues/$pr_number/labels" -f "labels[]=$label" --silent ||
60
- printf 'Label apply failed: %s\n' "$label" >&2
61
- else
62
- printf 'Label apply failed: %s is not on the remote. Create it with: gh label create %s\n' "$label" "$label" >&2
63
- fi
64
- done
57
+ record=$(canon labels apply "$pr_number" --base "$base_branch" --json 2>/dev/null | tail -n 1)
58
+ if printf '%s' "$record" | jq -e 'has("earned")' >/dev/null 2>&1; then
59
+ owed=$(printf '%s' "$record" | jq -r '.owed | join(",")')
60
+ missing=$(printf '%s' "$record" | jq -r '.missingOnRemote | join(",")')
61
+ uncovered=$(printf '%s' "$record" | jq -r '.uncovered | join(",")')
62
+ else
63
+ # No record: an installed canon that predates the verb, or a refusal it
64
+ # could not read a map through. The loop below is the old-binary fallback.
65
+ # It fills the same three lists the verb's record would, so the report
66
+ # reads one shape on both paths. The loop reads from a here-document, since
67
+ # a pipe would run it in a subshell and drop what it appends.
68
+ owed=
69
+ missing=
70
+ uncovered=$pr_uncovered
71
+ while IFS= read -r label; do
72
+ [ -n "$label" ] || continue
73
+ if gh api "repos/{owner}/{repo}/labels/$(jq -rn --arg l "$label" '$l|@uri')" --silent 2>/dev/null; then
74
+ gh api -X POST "repos/{owner}/{repo}/issues/$pr_number/labels" -f "labels[]=$label" --silent || {
75
+ printf 'Label apply failed: %s\n' "$label" >&2
76
+ owed=${owed:+$owed,}$label
77
+ }
78
+ else
79
+ printf 'Label apply failed: %s is not on the remote. Create it with: gh label create %s\n' "$label" "$label" >&2
80
+ owed=${owed:+$owed,}$label
81
+ missing=${missing:+$missing,}$label
82
+ fi
83
+ done <<EOF
84
+ $(printf '%s\n' "$pr_labels" | tr ',' '\n')
85
+ EOF
86
+ fi
65
87
  rm -rf .canon/tmp/pr/body .canon/tmp/pr/live.md .canon/tmp/pr/clean.md
66
- printf 'number=%s\nurl=%s\nhead=%s\nopened=%s\n' "$pr_number" "$pr_url" "$head_branch" "$opened"
88
+ printf 'number=%s\nurl=%s\nhead=%s\nopened=%s\nowed=%s\nmissingOnRemote=%s\nuncovered=%s\n' "$pr_number" "$pr_url" "$head_branch" "$opened" "$owed" "$missing" "$uncovered"
67
89
  ```
68
90
 
91
+ The label step branches on the record's `earned` key rather than on the exit, which is 2 whenever a label is still owed. A record carrying it means the verb ran, so the loop stays unreached on an exit 2. The verb binds to the same head and state as `assert_own_pr`, so a number that passed the check above cannot be refused by it.
92
+
69
93
  ## Binding every write to this branch's pull request
70
94
 
71
- `assert_own_pr` runs ahead of every write this command makes to a pull request, being the title and body edit, the session-link strip, and the label add. It reads the target's head branch and state and refuses unless they are this branch and `open`. A refusal exits before anything is written, so a wrong number costs the run rather than a stranger's pull request. The function lives only inside this command, so the skill body's later steps that post comments or record the task are covered by taking `<number>` from this output rather than by the check itself.
95
+ `assert_own_pr` runs ahead of every write this command makes to a pull request, being the title and body edit and the session-link strip. The label add binds the same way inside `canon labels apply`. It reads the target's head branch and state and refuses unless they are this branch and `open`. A refusal exits before anything is written, so a wrong number costs the run rather than a stranger's pull request. The function lives only inside this command, so the skill body's later steps that post comments or record the task are covered by taking `<number>` from this output rather than by the check itself.
72
96
 
73
97
  The check compares a number against a branch and never derives a number from one, so it adds no lookup of the kind the skill body's `### Resolving the pull request` retired. It holds whichever way a wrong number arrives. A number a session retyped by hand, or inferred from the newest pull request in view, reads as a foreign head here and stops.
74
98
 
@@ -82,6 +82,10 @@ What it leaves unmeasured is a prefix reaching no path, so a row left behind by
82
82
 
83
83
  Apply labels after the pull request resolves, never as a field on the create. A create carrying a label the remote lacks either fails whole or creates the label, depending on the surface, and neither is the map's call. One step against a pull request that already exists covers the create and the edit path alike. It runs over REST, so it works where GraphQL is blocked, and the REST endpoint creates any label it is handed that the remote lacks, so the step reads each name off the remote first and warns on a missing one rather than adding it.
84
84
 
85
+ `canon labels apply <number>` is that step. It resolves the earned set the way `canon labels audit` does, binds to the pull request only when its head is the current branch and it is open, and adds each earned label the pull request lacks. `--check` reports what is owed and writes nothing. The record carries `number`, `earned`, `present`, `added`, `owed`, `missingOnRemote`, and `uncovered`.
86
+
87
+ A pull request opened outside this skill, such as by `gh pr create`, takes the same command, since nothing else labels it.
88
+
85
89
  Labelling runs whenever this skill runs and at no other time. Nothing else computes the set, so a push made any other way leaves the labels exactly as the last run left them. Any caller invoking this skill again reaches the step again, and it recomputes over the whole branch diff rather than over the new commits.
86
90
 
87
91
  An ordinary branch therefore labels once, when the pull request opens. The return leg that answers a review hands its push to `git-followup`, which refreshes the body without invoking this skill, so the commits that answer a review reach no labelling step.
@@ -122,6 +126,6 @@ A `reason` of `no-map` is the answer that the project declared no map, which ear
122
126
 
123
127
  Every other `reason` is a map or a range the verb could not read, which is `unreadable-map`, `no-domains`, `no-base`, and `unreadable-changes`, plus `bad-base` for a ref this skill resolved wrongly. Take the fallback below and warn beside the result line, naming the reason. A map with a typo in it still has rows a prefix match can reach, and reading the refusal as an absence would open the pull request with no labels and nothing said, which is the surface merging bare that the verb exists to name.
124
128
 
125
- The fallback is reading `canon/config/pr-labels.toml`, or `.claude/canon/pr-labels.toml` when the project has not moved, and matching it against the name-only diff per `## Matching` above. It also covers no record coming back at all, which is an installed `canon` predating the verb, since a skill reaches a target the moment it merges while the CLI reaches one only when a release publishes. Naming both spellings matters exactly here: the binary old enough to need this fallback is the same binary that may predate the move, so the project's map can still sit at the older path. The fallback labels correctly and reports no uncovered path, which is the half only the verb carries.
129
+ The fallback is reading `canon/config/pr-labels.toml`, or `.claude/canon/pr-labels.toml` when the project has not moved, and matching it against the name-only diff per `## Matching` above. It also covers no record coming back at all, which is an installed `canon` predating the verb, since a skill reaches a target the moment it merges while the CLI reaches one only when a release publishes. Naming both spellings matters exactly here: the binary old enough to need this fallback is the same binary that may predate the move, so the project's map can still sit at the older path. The fallback labels correctly. It reports an uncovered path only when `canon labels audit` answered, passing that record's `uncovered` on as `pr_uncovered`, and a binary too old for the audit has none to pass.
126
130
 
127
131
  Leave `pr_labels` empty when no map resolves or no prefix matches, which skips the labelling command rather than running it against nothing.
@@ -5,6 +5,16 @@ description: Pull request title and body conventions
5
5
 
6
6
  # Pull request reference
7
7
 
8
+ ## Contents
9
+
10
+ - [Scope](#scope)
11
+ - [Title](#title)
12
+ - [Content](#content)
13
+ - [Sections](#sections)
14
+ - [Testing discipline](#testing-discipline)
15
+ - [Formatting](#formatting)
16
+ - [Examples](#examples)
17
+
8
18
  ## Scope
9
19
 
10
20
  Governs a pull request title and body: their format and the sections the body carries.
@@ -37,16 +47,16 @@ Does not govern:
37
47
  ## Sections
38
48
 
39
49
  - `## Summary`: 1-2 sentences following `<Action Verb> <Direct Object> to <Result>`, expand for clarity if needed
40
- - `## Key Changes`: name actual files, functions, or modules (e.g., `AuthService.verify()` not "auth handler"). Always use bullet points, never prose.
41
- - `## Technical Context` (optional): 1-2 lines of architectural reasoning explaining why, not what
42
- - Omit Technical Context for docs, config, or trivial changes
50
+ - `## Key changes`: name actual files, functions, or modules (e.g., `AuthService.verify()` not "auth handler"). Always use bullet points, never prose.
51
+ - `## Technical context` (optional): 1-2 lines of architectural reasoning explaining why, not what
52
+ - Omit Technical context for docs, config, or trivial changes
43
53
  - Use bullet points for multiple reasons, one sentence for a single reason
44
54
  - `## Testing` (optional): specify exact commands or test cases run
45
55
  - Omit Testing for docs, config, or trivial sync changes
46
56
  - Use checkboxes, never prose. See Testing discipline for which box gets ticked.
47
57
  - `## For the reviewer` (optional): what the reviewing session should confirm, one bullet per request
48
58
  - Visuals: include only when they clarify architecture, UI, or complex logic flows
49
- - The list is closed. A body carries the sections above and nothing after the last of them, which covers a trailer a harness appends once the body is composed. `publish.md` states the rule, and `canon labels scan` fails on the one such trailer measured so far.
59
+ - The list is closed. A body carries the sections above and nothing after the last of them, which covers a trailer a harness appends once the body is composed. `canon labels scan` holds the list: it fails a level-two heading outside the five above, and a body missing `## Summary` or `## Key changes`. A review body and a release-please body are exempt.
50
60
 
51
61
  ## Testing discipline
52
62
 
@@ -74,12 +84,12 @@ Does not govern:
74
84
 
75
85
  <Action Verb> <Direct Object> to <Result>.
76
86
 
77
- ## Key Changes
87
+ ## Key changes
78
88
 
79
89
  - <Verb> <specific component/file/function> (<reason if non-obvious>)
80
90
  - <Verb> <specific component/file/function>
81
91
 
82
- ## Technical Context
92
+ ## Technical context
83
93
 
84
94
  - <Architectural reasoning explaining why, not what>
85
95
 
@@ -101,12 +111,12 @@ Does not govern:
101
111
 
102
112
  Update auth middleware to enforce jwt expiration checks. # imperative + direct object + result
103
113
 
104
- ## Key Changes
114
+ ## Key changes
105
115
 
106
116
  - Add `verifyExpiration()` to `src/auth/validators.ts`. # specific function + file path
107
117
  - Refactor `AuthService.authenticate()` to handle 401 codes. # named component + clear change
108
118
 
109
- ## Technical Context
119
+ ## Technical context
110
120
 
111
121
  - Migration to stateless session management for horizontal scalability. # why, not what
112
122
 
@@ -128,7 +138,7 @@ Update auth middleware to enforce jwt expiration checks. # imperative + direct o
128
138
 
129
139
  This PR updates the authentication system to be more robust. # "This PR" opener + buzzword
130
140
 
131
- ## Key Changes
141
+ ## Key changes
132
142
 
133
143
  - Updated auth middleware files # vague, no specific component, no period
134
144
  - The old system used to check tokens differently # describes historical behavior
@@ -26,13 +26,15 @@ Scope every check below by destination. Text published to a remote takes all of
26
26
 
27
27
  ## Banned characters
28
28
 
29
- `markdown.md` holds the character bans. Read it at scan time rather than working the sets from memory, then scan the drafted text and rewrite each occurrence.
29
+ `${CLAUDE_SKILL_DIR}/../markdown-craft/references/markdown.md` holds the character bans. Read it at scan time rather than working the sets from memory, then scan the drafted text and rewrite each occurrence.
30
+
31
+ `canon labels scan` fails on these characters in a title or body, outside a code span or a link, so the scan is the check and the read above is the reason. It holds a pull request and a posted review alike.
30
32
 
31
33
  Restructure the sentence rather than substituting the character. A semicolon swapped for a period leaves both clauses in the order the semicolon chose, which is the shape the ban exists to remove.
32
34
 
33
35
  ## Phase labels
34
36
 
35
- `versioning.md` holds the label rule and the table of surfaces. Read it at scan time rather than working the format from memory.
37
+ `${CLAUDE_SKILL_DIR}/../git-commit/references/versioning.md` holds the label rule and the table of surfaces. Read it at scan time rather than working the format from memory.
36
38
 
37
39
  This check is one of the two the destination rule above scopes. The reader inside the repository has the task board and the reader on a remote does not.
38
40
 
@@ -9,7 +9,7 @@ The last step of `git-pr` before its report, reached on every run whose final co
9
9
 
10
10
  Write the `number` the final command printed onto the task the branch is closing. Do not resolve it again. A final command that refused on a head mismatch printed no number, so this step writes nothing on that run. `${CLAUDE_SKILL_DIR}/REQUIREMENT.md` states why: a lookup that resolves by branch alone can return a closed pull request sharing that head, so the number is resolved once and reused rather than re-derived.
11
11
 
12
- The task is the one whose `Plan:` line names the plan this branch implemented. Name that plan by its file, which is `.canon/plans/feature-<slug>.md` at the main worktree root with `<slug>` derived per `${CLAUDE_SKILL_DIR}/../../standards/slug.md`. `plan-feature` writes the plan under the branch slug, so the two correspond on any branch that came through the plan-to-execute path. When the session already knows which plan it implemented, because a caller read it earlier in the chain, use that filename instead of re-deriving.
12
+ The task is the one whose `Plan:` line names the plan this branch implemented. Name that plan by its file, which is `.canon/plans/feature-<slug>.md` at the main worktree root with `<slug>` derived per `${CLAUDE_SKILL_DIR}/../git-branch/references/slug.md`. `plan-feature` writes the plan under the branch slug, so the two correspond on any branch that came through the plan-to-execute path. When the session already knows which plan it implemented, because a caller read it earlier in the chain, use that filename instead of re-deriving.
13
13
 
14
14
  ```bash
15
15
  canon tasks pull-request <number> --plan feature-<slug> --json
@@ -9,7 +9,7 @@ metadata:
9
9
 
10
10
  Run the full post-feature workflow by invoking each skill in sequence using the Skill tool. After each skill returns, invoke the next step immediately in the same response.
11
11
 
12
- Do not output any text between steps and do not wait for user input. Tool permission dialogs are the only interrupts allowed. The final output is `✅ Shipped`, emitted on the wake after the step 8 watch exits on `passing` rather than when the turn ends on the watch line, unless a wrapping caller states it closes on its own block, which `auto-ship` does.
12
+ Do not output any text between steps and do not wait for user input. Tool permission dialogs are the only interrupts allowed. The final output is `✅ Shipped`, emitted on the wake after the step 9 watch exits on `passing` rather than when the turn ends on the watch line, unless a wrapping caller states it closes on its own block, which `auto-ship` does.
13
13
 
14
14
  ## Verify
15
15
 
@@ -25,16 +25,17 @@ Run `git diff --cached --name-only 2>/dev/null` to check for staged files. If ou
25
25
 
26
26
  ## Sequence
27
27
 
28
- 1. Invoke `canon:context-fold` to sync internal planning docs against session decisions
29
- 2. Invoke `canon:docs-sync` to sync public docs against changes since main
30
- 3. Run `git add -A` to stage any files the sync skills wrote
31
- 4. Run `canon tasks plan-reach <plan> --json` and report both lists it carries. Name the plan this branch built under, by path or by slug. Read `claimed` first and say who holds each path, since that is the half a reader acts on, then say how many of the changed paths `undeclared` names. Branch on the record rather than on the exit code, which a shell function wrapping `canon` can flatten to zero. This step reports and never stops the sequence.
32
- 5. Invoke `canon:git-stage` to group staged changes and commit by concern, only when `git diff --cached --name-only` prints a path. When it prints nothing, the work already reached history in slices, so continue to step 6.
33
- 6. Invoke `canon:git-branch` to rename branch to match conventional format
34
- 7. Invoke `canon:git-pr` to push branch and open pull request
35
- 8. After the PR opens, watch CI in the background, so the session stays reachable while CI runs. Read `### Watching CI` below for the commands and the wake.
28
+ 1. Invoke `canon:context-fold` to sync the context entries against session decisions and the diff
29
+ 2. Invoke `canon:task-complete` to mark the outcomes the diff shipped
30
+ 3. Invoke `canon:docs-sync` to sync public docs against changes since main
31
+ 4. Run `git add -A` to stage any files the sync skills wrote
32
+ 5. Run `canon tasks plan-reach <plan> --json` and report both lists it carries. Name the plan this branch built under, by path or by slug. Read `claimed` first and say who holds each path, since that is the half a reader acts on, then say how many of the changed paths `undeclared` names. Branch on the record rather than on the exit code, which a shell function wrapping `canon` can flatten to zero. This step reports and never stops the sequence.
33
+ 6. Invoke `canon:git-stage` to group staged changes and commit by concern, only when `git diff --cached --name-only` prints a path. When it prints nothing, the work already reached history in slices, so continue to step 7.
34
+ 7. Invoke `canon:git-branch` to rename branch to match conventional format
35
+ 8. Invoke `canon:git-pr` to push branch and open pull request
36
+ 9. After the PR opens, watch CI in the background, so the session stays reachable while CI runs. Read `### Watching CI` below for the commands and the wake.
36
37
 
37
- A caller wrapping this sequence may act between step 7 and step 8, which is the one gap the order leaves open, since the pull request exists there and nothing has read its checks yet. `auto-ship` marks the pull request draft in it. Nothing else may go there, and a caller that needs a step anywhere else in the sequence is asking for a change to this body rather than for a place to stand.
38
+ A caller wrapping this sequence may act between step 8 and step 9, which is the one gap the order leaves open, since the pull request exists there and nothing has read its checks yet. `auto-ship` marks the pull request draft in it. Nothing else may go there, and a caller that needs a step anywhere else in the sequence is asking for a change to this body rather than for a place to stand.
38
39
 
39
40
  ### Watching CI
40
41
 
@@ -61,18 +62,18 @@ Do not auto-fix any of these. The watch line and a stop report from any branch a
61
62
 
62
63
  ### Settling the evidence thread
63
64
 
64
- On a `passing` wake, run `canon pr evidence <number> --check --json` against the number step 7 returned. It reads the pull request's comments and edits none, so the comment a reviewer already ticked stays as it is. Branch on `reason` and `owed` rather than the exit.
65
+ On a `passing` wake, run `canon pr evidence <number> --check --json` against the number step 8 returned. It reads the pull request's comments and edits none, so the comment a reviewer already ticked stays as it is. Branch on `reason` and `owed` rather than the exit.
65
66
 
66
67
  - `settled`: nothing is owed, which is also what a branch that changed no rendered surface reads. Continue to After completion.
67
68
  - `owed`: run each step the record's `owed` list names, from `canon:git-pr`'s `references/evidence.md`, evidence first and then preview. Re-read once with the same command. Continue to After completion only on `settled`. Any other reading stops the sequence and reports the `reason` with the `owed` list, and the sequence never loops back for a second pass. A preview step that refuses, or a deploy that failed, leaves `preview` owed on the re-read, so that is the stop and not a retry.
68
69
  - Any other `reason`, such as `gh-failed`: the thread went unread. Stop and report the `reason`, since an unread thread is not a settled one.
69
70
  - No record at all, or an unknown flag error: the installed binary predates `--check`. Report the thread unread rather than settled, and continue to After completion without emitting a claim that it was checked.
70
71
 
71
- The read is a closing step and the draft mark stays the only thing between steps 7 and 8. A caller that closes on its own block, as `auto-ship` does, waits on the same CI wake, so the read lands here and not in that body.
72
+ The read is a closing step and the draft mark stays the only thing between steps 8 and 9. A caller that closes on its own block, as `auto-ship` does, waits on the same CI wake, so the read lands here and not in that body.
72
73
 
73
- ### Why the reach reads at step 4
74
+ ### Why the reach reads at step 5
74
75
 
75
- The branch is whole there and nowhere earlier. Steps 1 and 2 write past whatever the plan declared, so a reading taken ahead of them misses the chain's own additions, and no pull request exists until step 7 to carry the answer anywhere.
76
+ The branch is whole there and nowhere earlier. Steps 1 and 3 write past whatever the plan declared, so a reading taken ahead of them misses the chain's own additions, and no pull request exists until step 8 to carry the answer anywhere.
76
77
 
77
78
  It is the one step here that reports rather than acts, which is why it never stops the sequence. Every crossing measured on the wave it was filed against merged clean, and the undeclared list runs long enough on an ordinary branch that a gate would fire on nearly every ship.
78
79