@erclx/canon 5.45.0 → 5.47.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 (158) hide show
  1. package/claude/.claude-plugin/plugin.json +1 -1
  2. package/claude/skills/api-design/REQUIREMENT.md +15 -31
  3. package/claude/skills/auto-ship/REQUIREMENT.md +14 -25
  4. package/claude/skills/backlog-triage/REQUIREMENT.md +12 -23
  5. package/claude/skills/build-in-slices/REQUIREMENT.md +15 -25
  6. package/claude/skills/canon-cli/REQUIREMENT.md +15 -27
  7. package/claude/skills/canon-feedback/REQUIREMENT.md +10 -18
  8. package/claude/skills/canon-feedback-triage/REQUIREMENT.md +10 -15
  9. package/claude/skills/canvas-board/REQUIREMENT.md +14 -28
  10. package/claude/skills/ci-workflow/REQUIREMENT.md +12 -21
  11. package/claude/skills/code-craft/REQUIREMENT.md +14 -28
  12. package/claude/skills/codebase-layout/REQUIREMENT.md +14 -31
  13. package/claude/skills/context-fold/REQUIREMENT.md +15 -39
  14. package/claude/skills/context-fold/references/context.md +3 -3
  15. package/claude/skills/create-rule/REQUIREMENT.md +10 -24
  16. package/claude/skills/create-rule/SKILL.md +3 -0
  17. package/claude/skills/create-skill/REQUIREMENT.md +10 -21
  18. package/claude/skills/decision-escalate/REQUIREMENT.md +12 -24
  19. package/claude/skills/deploy-app/REQUIREMENT.md +12 -22
  20. package/claude/skills/deprecation-migration/REQUIREMENT.md +14 -42
  21. package/claude/skills/design-identity/REQUIREMENT.md +14 -20
  22. package/claude/skills/design-taste/REQUIREMENT.md +16 -57
  23. package/claude/skills/docs-sync/REQUIREMENT.md +14 -23
  24. package/claude/skills/document-health/REQUIREMENT.md +15 -29
  25. package/claude/skills/document-health/SKILL.md +2 -2
  26. package/claude/skills/document-repair/REQUIREMENT.md +32 -0
  27. package/claude/skills/document-repair/SKILL.md +76 -0
  28. package/claude/skills/document-repair/references/batches.md +44 -0
  29. package/claude/skills/draft-and-pick/REQUIREMENT.md +4 -3
  30. package/claude/skills/draft-doc/REQUIREMENT.md +4 -3
  31. package/claude/skills/draft-figure/REQUIREMENT.md +4 -3
  32. package/claude/skills/draft-identity/REQUIREMENT.md +4 -3
  33. package/claude/skills/draft-ready/REQUIREMENT.md +4 -3
  34. package/claude/skills/draft-screencast/REQUIREMENT.md +4 -3
  35. package/claude/skills/draft-slides/REQUIREMENT.md +4 -3
  36. package/claude/skills/draw-figure/REQUIREMENT.md +15 -39
  37. package/claude/skills/git-branch/REQUIREMENT.md +12 -26
  38. package/claude/skills/git-commit/REQUIREMENT.md +11 -15
  39. package/claude/skills/git-followup/REQUIREMENT.md +11 -22
  40. package/claude/skills/git-followup/SKILL.md +1 -0
  41. package/claude/skills/git-issue/REQUIREMENT.md +9 -15
  42. package/claude/skills/git-pr/REQUIREMENT.md +13 -32
  43. package/claude/skills/git-pr/SKILL.md +11 -2
  44. package/claude/skills/git-pr/references/closing-issues.md +47 -0
  45. package/claude/skills/git-pr/references/pr.md +62 -7
  46. package/claude/skills/git-ship/REQUIREMENT.md +13 -26
  47. package/claude/skills/git-split/REQUIREMENT.md +10 -17
  48. package/claude/skills/git-stage/REQUIREMENT.md +12 -18
  49. package/claude/skills/git-worktree/REQUIREMENT.md +15 -19
  50. package/claude/skills/make-deck/REQUIREMENT.md +13 -21
  51. package/claude/skills/markdown-craft/REQUIREMENT.md +9 -3
  52. package/claude/skills/plan-feature/REQUIREMENT.md +15 -24
  53. package/claude/skills/plan-groundwork/REQUIREMENT.md +12 -28
  54. package/claude/skills/plan-groundwork/SKILL.md +5 -2
  55. package/claude/skills/plan-groundwork/references/output.md +47 -1
  56. package/claude/skills/plan-intake/REQUIREMENT.md +11 -26
  57. package/claude/skills/plan-intake/references/intake.md +2 -2
  58. package/claude/skills/plan-intake-answer/REQUIREMENT.md +14 -29
  59. package/claude/skills/plan-intake-answer/SKILL.md +7 -1
  60. package/claude/skills/plan-ready/REQUIREMENT.md +17 -36
  61. package/claude/skills/pr-evidence/REQUIREMENT.md +11 -17
  62. package/claude/skills/read-frames/REQUIREMENT.md +3 -8
  63. package/claude/skills/record-screencast/REQUIREMENT.md +14 -17
  64. package/claude/skills/review-address/REQUIREMENT.md +14 -38
  65. package/claude/skills/review-address/SKILL.md +18 -6
  66. package/claude/skills/review-address/references/post-review-findings.md +4 -1
  67. package/claude/skills/review-address/references/rebase-only.md +14 -2
  68. package/claude/skills/review-craft/REQUIREMENT.md +14 -32
  69. package/claude/skills/review-pr/REQUIREMENT.md +15 -34
  70. package/claude/skills/review-pr/SKILL.md +9 -2
  71. package/claude/skills/review-pr/references/body-variants.md +29 -8
  72. package/claude/skills/review-pr/references/post.md +29 -10
  73. package/claude/skills/review-ui/REQUIREMENT.md +14 -39
  74. package/claude/skills/review-ui/SKILL.md +1 -0
  75. package/claude/skills/review-ui/references/post.md +2 -0
  76. package/claude/skills/review-ui/references/tick.md +3 -0
  77. package/claude/skills/role-orchestrator/REQUIREMENT.md +2 -2
  78. package/claude/skills/role-orchestrator/references/orchestrator-refill.md +5 -0
  79. package/claude/skills/role-orchestrator/references/orchestrator-review-dispatch.md +9 -0
  80. package/claude/skills/role-reviewer/REQUIREMENT.md +15 -65
  81. package/claude/skills/role-reviewer/SKILL.md +8 -1
  82. package/claude/skills/role-worker/REQUIREMENT.md +2 -2
  83. package/claude/skills/role-worker/SKILL.md +3 -0
  84. package/claude/skills/script-screencast/REQUIREMENT.md +10 -16
  85. package/claude/skills/search-craft/REQUIREMENT.md +12 -36
  86. package/claude/skills/search-craft/SKILL.md +1 -1
  87. package/claude/skills/search-craft/references/adopted.md +2 -2
  88. package/claude/skills/session-compact/REQUIREMENT.md +13 -23
  89. package/claude/skills/session-map/REQUIREMENT.md +13 -29
  90. package/claude/skills/session-relay/REQUIREMENT.md +14 -58
  91. package/claude/skills/session-relay/SKILL.md +6 -0
  92. package/claude/skills/session-resume/REQUIREMENT.md +13 -27
  93. package/claude/skills/session-worktree/REQUIREMENT.md +14 -43
  94. package/claude/skills/systematic-debugging/REQUIREMENT.md +13 -34
  95. package/claude/skills/target-check/REQUIREMENT.md +16 -23
  96. package/claude/skills/target-setup/REQUIREMENT.md +11 -34
  97. package/claude/skills/task-board/REQUIREMENT.md +13 -22
  98. package/claude/skills/task-board/SKILL.md +7 -0
  99. package/claude/skills/task-board/references/decline.md +2 -2
  100. package/claude/skills/task-board/references/tasks.md +1 -1
  101. package/claude/skills/task-complete/REQUIREMENT.md +11 -24
  102. package/claude/skills/task-complete/references/archive.md +4 -2
  103. package/claude/skills/teach-workspace/REQUIREMENT.md +14 -45
  104. package/claude/skills/test-craft/REQUIREMENT.md +15 -46
  105. package/claude/skills/test-first/REQUIREMENT.md +14 -20
  106. package/claude/skills/ui-checklist/REQUIREMENT.md +14 -29
  107. package/claude/skills/ui-checklist/SKILL.md +3 -3
  108. package/claude/skills/ux-audit/REQUIREMENT.md +3 -7
  109. package/claude/skills/ux-measure/REQUIREMENT.md +14 -28
  110. package/claude/skills/video-craft/REQUIREMENT.md +14 -27
  111. package/claude/skills/write-doc/REQUIREMENT.md +14 -24
  112. package/claude/skills/write-human/REQUIREMENT.md +15 -27
  113. package/claude/skills/youtube-transcripts/REQUIREMENT.md +9 -15
  114. package/docs/agents/context-audit.md +19 -12
  115. package/docs/agents/markdown-audit.md +15 -10
  116. package/docs/target/projects.md +2 -0
  117. package/docs/workflow/skill-map.md +6 -5
  118. package/docs/workflow/zshrc-aliases.md +3 -0
  119. package/governance/renames.toml +0 -2
  120. package/governance/rules/claude/output.md +5 -1
  121. package/governance/rules/code/routing.md +5 -1
  122. package/governance/stacks/base.toml +0 -1
  123. package/package.json +1 -1
  124. package/scripts/core/bootstrap.sh +1 -0
  125. package/src/claude/cases/workflow.ts +12 -0
  126. package/src/commands/context.ts +57 -3
  127. package/src/commands/labels.ts +149 -4
  128. package/src/commands/markdown.ts +188 -21
  129. package/src/commands/pr.ts +113 -4
  130. package/src/commands/sessions.ts +58 -11
  131. package/src/commands/tasks.ts +182 -0
  132. package/src/commands/worktrees.ts +2 -0
  133. package/src/context/coverage.ts +210 -0
  134. package/src/context/gate.ts +12 -3
  135. package/src/gate/stages.ts +1 -1
  136. package/src/init/steps.ts +45 -0
  137. package/src/intake/items.ts +14 -0
  138. package/src/labels/closing.ts +46 -0
  139. package/src/labels/density.ts +363 -0
  140. package/src/markdown/gated.ts +250 -0
  141. package/src/markdown/scope.ts +115 -2
  142. package/src/migrate/rename.ts +6 -0
  143. package/src/pr/evidence.ts +1 -1
  144. package/src/pr/rest.ts +2 -0
  145. package/src/pr/tick.ts +89 -0
  146. package/src/sessions/claim.ts +7 -0
  147. package/src/sessions/live.ts +79 -6
  148. package/src/sessions/registry.ts +11 -0
  149. package/src/sessions/resolve.ts +85 -7
  150. package/src/tasks/archive.ts +15 -4
  151. package/src/tasks/closes.ts +136 -0
  152. package/src/tasks/record.ts +1 -1
  153. package/src/worktrees/reclaim.ts +16 -1
  154. package/tooling/base/configs/scripts/verify.ts +1 -1
  155. package/tooling/base/seeds/.github/pull_request_template.md +1 -1
  156. package/tooling/claude/seeds/.claude/hooks/board-validate.sh +1 -1
  157. package/tooling/claude/seeds/CLAUDE.md +2 -2
  158. package/governance/rules/canon/task-scope.md +0 -12
@@ -7,17 +7,18 @@ description: Why a pointer answers under the old `draft-slides` name, and the te
7
7
 
8
8
  ## Gap
9
9
 
10
- Without this skill, a person typing the old name after the rename to `make-deck` meets an unknown command with nothing naming where the skill went. A target that has not run `canon migrate skill-names` still holds files telling someone to type it, and a live gitignored record written before the rename still names it, since the sweep reads the tracked listing only.
10
+ Without this skill, a person typing the old name after the rename to `make-deck` meets an unknown command that names no successor. A target that has not run `canon migrate skill-names` still tells people to type it, and so does a live gitignored record, which the sweep never reads.
11
11
 
12
12
  ## Must
13
13
 
14
14
  - Name `make-deck` as the skill to run, so a typed invocation of the old name reaches the new one in one step
15
- - Carry `disable-model-invocation: true`, so routing never matches the old description against a request the new skill owns
15
+ - Carry `disable-model-invocation: true`, so routing never matches the old description against a request `make-deck` owns
16
+ - Retire once `canon migrate skill-names --json` reports zero citations in every target the rollout reaches and no live `.canon/` record names the old name
16
17
 
17
18
  ## Must not
18
19
 
19
20
  - Carry any part of the deck draft, which would give one behavior two bodies that drift apart
20
- - Retire on a release number. Retire it when `canon migrate skill-names --json` reports zero citations in every target the rollout reaches and no live `.canon/` record names the old name, since a release number retires it on a date nothing measured.
21
+ - Retire on a release number, which retires it on a date nothing measured
21
22
 
22
23
  ## Out of scope
23
24
 
@@ -7,53 +7,29 @@ description: Why a figure decides between Mermaid, an architecture view, and fre
7
7
 
8
8
  ## Gap
9
9
 
10
- Without this skill, a session asked for a figure reaches for whichever path it thought of first. A graph-shaped subject gets model-authored SVG coordinates nobody checked against a render, drifting from the hand-drawn look every other figure in the project carries. A subject that is not graph-shaped gets forced through Mermaid's node-and-edge model, producing a diagram that answers a different question than the one asked. Either failure ships a figure a reader cannot trust, and a figure exists only to be trusted at a glance.
10
+ Without this skill, a session asked for a figure takes the first path it thinks of. A graph gets SVG coordinates nobody checked against a render, and a subject that is not a graph gets forced through Mermaid. In a teach lesson the renderer cannot load the hand font, so labels clip, and a check reading the standalone image passes them.
11
11
 
12
- A teach lesson breaks the Mermaid path outright. The lesson letters its figures in a hand font the renderer cannot load, so the render sizes every label in a narrower fallback face and the lesson clips the text it actually shows. The check then reads the standalone image, rendered in that same fallback, and passes a figure the reader sees clipped. Both happened on one lesson, where every group title clipped mid-word and only a capture taken inside the lesson showed it.
13
-
14
- An architecture view asked for one at a time fails its own way. A session asked to refresh one view redraws every view beside it, so pictures nobody checked change in the same commit and the reviewer cannot tell which one the pass was about. It reaches for C4, state, or class diagrams that render differently in every viewer. A Mermaid source can satisfy every rule in the standard and still render as a picture asserting something false about the system, so a session that judges the source and calls it verified has spent the only signal a reader has on a picture nobody looked at.
15
-
16
- The color failure is the quiet one. Mermaid's own theme writes literal hex values, and a figure carrying one stops re-coloring itself the moment the host page switches its palette, which the figure standard's own accessibility bar rules out.
12
+ Asked to refresh one architecture view, it redraws every view beside it. It judges the source and calls the figure verified, though a valid source can render a picture asserting something false. Mermaid's theme writes literal hex values, so the figure stops re-coloring when the page switches palette.
17
13
 
18
14
  ## Must
19
15
 
20
- - Apply the standard's earn-its-place bar before drawing anything
21
- - Decide between the Mermaid path and the freehand path by whether the subject reduces to a graph, not by which is faster to produce
22
- - Draw an architecture view from its named source signal, inside `flowchart` and `sequenceDiagram`, and render it through the Mermaid path
23
- - Draw only the view the request names, leaving every other figure in the destination untouched
24
- - Draw a figure bound for a teach lesson freehand whatever its shape, since the lesson's hand font is one the renderer cannot measure
25
- - Verify a figure bound for a rendered page by capturing it inside that page, and fall back to the standalone render only where the destination has no page to load
26
- - Keep the scoped overflow style as the documented fallback for a clipped group title wherever the Mermaid path still runs
27
- - Render the Mermaid path with the hand-drawn look and the figure font stack, never with Mermaid's default look
28
- - Rewrite every literal color the renderer wrote into the custom property the host stylesheet defines
29
- - Read the Mermaid render back and judge it against what the figure means to say, rather than judging the source
30
- - Read the node labels by hand, since no hook checks inside a fence
31
- - Cite only code paths that exist in an architecture view's caption or prose
32
- - Wrap either path in a `<figure>` and `<figcaption>` and give it an accessible name
16
+ - The figure clears the standard's earn-its-place bar, and its path follows whether the subject reduces to a graph, with a teach lesson drawn freehand whatever its shape
17
+ - An architecture view is drawn from its named source signal in `flowchart` or `sequenceDiagram`, and only the view the request names changes
18
+ - The Mermaid render uses the hand-drawn look and the figure font stack, with every literal color rewritten to the host's custom property
19
+ - The render is read back against what the figure means to say, and a figure bound for a rendered page is verified by a capture inside that page
20
+ - Either path lands in a `<figure>` with a `<figcaption>` and an accessible name, and an architecture view's caption cites only code paths that exist
33
21
 
34
22
  ## Must not
35
23
 
36
- - Force a non-graph-shaped subject through Mermaid, or route a graph-shaped one through freehand SVG coordinates a model authored by hand outside a teach lesson
37
- - Report a figure bound for a rendered page as verified from the standalone render alone
38
- - Ship a literal hex color on either path
39
- - Report a clean verification when the Mermaid render was skipped or a defect survived
24
+ - Draw with no subject or no destination, an architecture view with no planning file or folder structure to anchor it, or decoration for a subject that fails the bar
25
+ - Report a figure verified from the standalone render alone, or report a clean check when the render was skipped or a defect survived
26
+ - Ship a literal hex color, or commit a scratch render
40
27
  - Loop past two correction passes on a surviving defect
41
- - Commit a scratch render. Only the SVG that ships in the destination document survives
42
- - Redraw a figure the request did not name, or report one as drawn when it was left alone
43
- - Leave an architecture view as an unrendered fence
44
-
45
- ## Guards
46
-
47
- - No subject given: stop, since nothing states what the figure has to show
48
- - No destination document given: stop, since the figure has nowhere to land
49
- - Subject does not clear the earn-its-place bar: stop rather than drawing decoration
50
- - An architecture view with no planning file and no folder structure to scan: stop, because nothing anchors it
51
- - Render fails for any reason: continue to the output and name the skipped check. A missing renderer degrades the loop rather than failing it.
28
+ - Redraw a figure the request did not name, or leave an architecture view as an unrendered fence
52
29
 
53
30
  ## Out of scope
54
31
 
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-board`
57
- - Design tokens and the visual system: `canvas-board`, which carries a picked direction into the design document
58
- - Implementation detail behind an architecture view, which belongs in a context entry the caption points at
59
- - Which lesson needs a figure and where it sits among the lesson's blocks: `teach-workspace`, which calls this skill to draw one
32
+ - Mermaid's layout, budgets, and label rules inside the fence, which the mermaid standard owns
33
+ - A UI screen mockup, and design tokens or the visual system, which `canvas-board` owns
34
+ - Which lesson needs a figure and where it sits, which `teach-workspace` owns
35
+ - Implementation detail behind an architecture view, which the context entry the caption points at owns
@@ -7,43 +7,29 @@ description: What branch naming is for, the gaps it closes, and where the family
7
7
 
8
8
  ## Gap
9
9
 
10
- Without this skill, a branch name is invented once per session. The type prefix drifts from what the history already carries, the name runs past the width a pull request list renders, and a rename lands on a branch that already exists on the remote, which detaches every open pull request pointing at it.
10
+ Without this skill, a branch name is invented once per session. The type prefix drifts from the history's convention, the name runs past the width a pull request list renders, and a rename lands on a branch the remote already carries, which detaches every open pull request pointing at it.
11
11
 
12
- A session standing on `main` has no route either. The `git.md` rule sends every git operation through a `git-*` skill, and the only one for branches stopped on `Cannot rename a protected branch`, so the first act of any feature, creating its branch, had no skill to go through.
12
+ A session standing on `main` has no route to its first act either. Every git operation goes through a `git-*` skill, so creating a feature's branch needs one that creates as well as renames, and that agrees with the name a dispatcher already checked.
13
13
 
14
14
  ## Must
15
15
 
16
- - Read the branch format reference before generating, so the type vocabulary and the length limit come from one source
17
- - Create the branch on `main` or `master` and rename it anywhere else, so one skill covers both ends of a branch's start
18
- - Derive the name from the commits ahead of main when a rename carries no description
19
- - Take a created name from `canon tasks plan-branch` when the invocation names a plan, so the skill and the dispatch gate hold one derivation
20
- - Resolve whether the branch exists on the remote before proposing a rename, since the hazard is invisible from local state
21
- - Read the remote itself with `git ls-remote` before creating, since `origin/<name>` sees only the last fetch
22
- - Show the name and its length against the limit before renaming or creating
23
- - Execute immediately after the preview. The tool permission dialog is the confirmation gate.
16
+ - The name follows the branch format reference, and the user sees it with its length before the branch changes
17
+ - One skill creates on `main` or `master` and renames anywhere else
18
+ - A created name for a plan comes from `canon tasks plan-branch`, and a rename with no description derives from the commits ahead of main
19
+ - Remote existence is read before any rename or create, from the remote itself rather than the last fetch
20
+ - A conforming name passes through as a success, so a chained caller continues
24
21
 
25
22
  ## Must not
26
23
 
27
- - Rename `main` or `master`
28
- - Rename when the current name already conforms. The skill is chained, so a conforming name has to pass through rather than churn the branch.
29
- - Rename a branch that exists on the remote. Local rename plus force push is not the same operation and it breaks the pull request.
30
- - Create a branch from anywhere but `main` or `master`, or create one whose name exists locally or on the remote
31
- - Invent a name when the plan verb refuses, since a name the skill calls non-conforming strands the rename at ship
24
+ - Rename `main`, `master`, or a branch that exists on the remote
25
+ - Create from anywhere but `main` or `master`, or onto a name that exists locally or on the remote
26
+ - Invent a name when the plan verb refuses
32
27
  - Fetch or stash while creating
33
28
  - Emit anything after the result line
34
29
 
35
- ## Guards
36
-
37
- - Create with no plan and no name: stop and name both missing inputs
38
- - Create with a name breaking the branch standard: stop and name the cap
39
- - Create with a name existing locally or on the remote: stop and say which
40
- - Rename name already conforms: stop with a success marker, not a failure, since a chained caller continues past it
41
- - Rename with no commits and no description: stop and name both missing inputs
42
- - Rename of a branch existing on the remote: stop and route to the surface that preserves the pull request link
43
-
44
30
  ## Out of scope
45
31
 
46
32
  - The commit message, which `git-commit` owns
47
- - Pushing and opening the pull request, which `git-pr` owns. That skill reads a conforming name as a precondition and refuses without one, so this skill runs first.
33
+ - Pushing and opening the pull request, which `git-pr` owns and which refuses a non-conforming name
48
34
  - Splitting a branch whose commits span concerns, which `git-split` owns
49
- - Entering a worktree, which `session-worktree` owns and which names its own branch
35
+ - Entering a worktree and naming its branch, which `session-worktree` owns
@@ -7,30 +7,26 @@ description: What commit generation is for, the gaps it closes, and where the fa
7
7
 
8
8
  ## Gap
9
9
 
10
- Without this skill, a commit message takes whatever shape the session settled on. The type and scope drift from the convention the history already follows, the subject runs past the length the log renders, and a lockfile diff floods the context the message is derived from so the message describes the lockfile.
10
+ Without this skill, a commit message takes whatever shape the session picks. The type and scope drift from the history's convention, the subject runs past the log's width, and a lockfile diff crowds out the change the message should describe.
11
11
 
12
- A second failure is routing rather than shape. A plain request to commit reaches this skill and its grouping sibling alike, and the sibling's first step is to unstage everything and restage whole files, so a selection staged hunk by hand comes back widened to the files it sat in. The user reviewed one thing and shipped another, and nothing in the run says the set changed.
12
+ A plain request to commit also reaches the grouping sibling, which restages whole files, so a hunk-level selection ships wider than the user reviewed.
13
13
 
14
14
  ## Must
15
15
 
16
- - Read the commit format reference and the versioning standard before generating, so the type, the scope, and the version discipline come from one source
17
- - Derive the message from the staged diff, with lockfiles excluded
18
- - Show the message and its length against the limit before committing, so an over-length subject is visible while it is still cheap to fix
19
- - Execute immediately after the preview. The tool permission dialog is the confirmation gate, and a second prompt trains the user to skim it.
20
- - Claim the single-concern and the hunk-level staged set in the description, and name the sibling for the multi-concern one. A boundary stated only here routes nothing, since the description is the field the choice is made from.
16
+ - The message follows the commit format and versioning references
17
+ - The message describes the staged diff with lockfiles excluded
18
+ - The user sees the message and its length before the commit runs
19
+ - The committed set is exactly the staged set
20
+ - The description claims single-concern and hunk-level staged sets, and names `git-stage` for a mixed one
21
21
 
22
22
  ## Must not
23
23
 
24
- - Stage anything. What is committed has to be what the user chose to stage.
24
+ - Stage or unstage anything
25
25
  - Commit when nothing is staged
26
- - Emit anything after the result line. A commit is a step inside a longer flow and prose here buries the next one.
27
-
28
- ## Guards
29
-
30
- - Nothing staged: stop and name the command that stages
26
+ - Emit anything after the result line
31
27
 
32
28
  ## Out of scope
33
29
 
34
- - Splitting a mixed diff across several commits, which `git-stage` owns. That skill restages whole files, so a hunk-level selection survives here and not there, and both descriptions carry the difference rather than leaving it stated only in these two files.
35
- - Naming the branch, which `git-branch` owns. The family shares its triggers and not its gaps: this one turns on the staged diff, the length limit, and lockfile exclusion, none of which a branch name has.
30
+ - Splitting a mixed diff into several commits, which `git-stage` owns
31
+ - Naming a branch, which `git-branch` owns
36
32
  - Pushing or opening a pull request, which `git-pr` owns
@@ -7,38 +7,27 @@ description: What the follow-up push is for, the gaps it closes, and how it spli
7
7
 
8
8
  ## Gap
9
9
 
10
- Without this skill, an edit made after a pull request is already open ships as a bare push. The body still describes the scope from before the edit, so a reviewer returning to the page reads a description the diff no longer matches. A reviewer who left comments gets no reply, and when a caller has already posted its own reply, a second one lands underneath it.
10
+ Without this skill, an edit made after a pull request opens ships as a bare push. The body still describes the scope from before the edit, and a review fix always changes what shipped, so the description a merge records is false by the time review ends. A reviewer who left comments gets no reply, or a second one under the caller's own.
11
11
 
12
- A caller that rebased the branch before handing over hits a rejected push, since the tracking branch no longer reaches the head. A branch entered through a worktree hits the opposite shape, carrying an open pull request with no tracking ref at all, which read as a branch that had never been pushed.
13
-
14
- A fix commit answering a review is the sharpest case of the first paragraph, since it always changes what shipped. The routing that once picked whether to sync the body keyed off the same branch that decides whether to reply, so reaching `reply-owned` or a nonzero comment count meant the sync never ran at all. The description a merge record carries was true when the pull request opened and false by the time review finished, with nothing between the two that read it back.
12
+ The push itself fails on two branch shapes. A caller that rebased before handing over hits a rejected push, and a branch entered through a worktree carries an open pull request with no tracking ref, which reads as a branch never pushed.
15
13
 
16
14
  ## Must
17
15
 
18
- - Refuse unless the branch has an open pull request, since every later step addresses it
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
- - Delegate the message to `git-commit` rather than composing one, so a follow-up commit reads like every other commit
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. A hook on `Bash` scans the body file of that post and denies an inline body, so the reply goes through a file.
23
- - Suppress the reply when the caller owns it, and still run the push and the body sync
24
- - Post the evidence through `pr-evidence` and read `canon pr evidence <number> --check --json` after it, since a followup that posts the evidence and stops leaves the preview for a relay
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
16
+ - Every follow-up commit syncs the body when it moves the scope, and the title when the shift makes it inaccurate, whether or not a reply runs
17
+ - The message comes from `git-commit`, so a follow-up reads like every other commit
18
+ - A pull request carrying review comments gets one reply, scanned for banned characters and phase labels and posted through a file, and none when the caller owns it
19
+ - The push lands on a branch with no tracking ref, and on a rebased one under a lease that protects a commit this session never read
20
+ - The evidence is posted through `pr-evidence` and read back with `canon pr evidence <number> --check --json`
26
21
 
27
22
  ## Must not
28
23
 
29
- - Run on `main`
30
- - Open a pull request. A missing one is the stop condition, not a step to add.
24
+ - Run on `main`, or with nothing changed
25
+ - Open a pull request. A missing one is the stop.
31
26
  - Post a second reply when the caller has already replied
32
27
  - Emit anything after the result line
33
28
 
34
- ## Guards
35
-
36
- - On `main`: stop and say to switch to a pull request branch
37
- - Nothing changed: stop
38
- - No open pull request: stop and route to the skill that opens one
39
-
40
29
  ## Out of scope
41
30
 
42
31
  - Opening the pull request, which `git-pr` owns and `git-ship` chains
43
- - Deciding what to fix from a review, which `review-address` owns. This skill is that flow's push leg and takes the fixes as already made.
44
- - Grouping a multi-concern diff, which `git-stage` owns. A follow-up is one concern by definition, which is why this skill stages everything into a single commit.
32
+ - Deciding what to fix from a review, which `review-address` owns
33
+ - Grouping a multi-concern diff, which `git-stage` owns
@@ -58,6 +58,7 @@ A missing tracking ref is not a guard, since an open pull request proves the bra
58
58
  - Read the live title and body with `gh api repos/{owner}/{repo}/pulls/<number> --jq '{html_url, title, body}'`. Update the body with `gh api -X PATCH repos/{owner}/{repo}/pulls/<number> -F body=@<file> --silent` when the new commit changes scope, writing the new body to `<file>` first, and the title with `gh api -X PATCH repos/{owner}/{repo}/pulls/<number> -f title="<title>" --silent` when the scope shifted enough to make it inaccurate.
59
59
  - A fix commit answering a review changes what shipped exactly as much as an ordinary followup does, so the sync cannot wait on the invocation or the comment count below.
60
60
  - 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.
61
+ - Carry a `UI pass` line marked `<!-- pr-ui-pass -->` into any rewritten body unchanged, since `canon pr tick` owns it and a dropped marker defeats the reset on a new head.
61
62
  8. Route on the invocation and the comment count for the reply alone.
62
63
  - When invoked with `reply-owned`, skip this step: the caller posts its own reply.
63
64
  - 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.
@@ -7,32 +7,26 @@ description: What issue filing is for, the gaps it closes, and which reporting p
7
7
 
8
8
  ## Gap
9
9
 
10
- Without this skill, an issue takes the shape of whatever the session was saying. It arrives with no label, so triage cannot filter it, and without the sections a triage pass reads, so the reader has to reconstruct the problem from narrative. Prose bans hold on files the hook watches and not on text leaving through `gh`, so a banned character survives into a published artifact that then has to be edited on the remote.
10
+ Without this skill, an issue takes the shape of whatever the session was saying. It arrives with no label, so triage cannot filter it, and without the sections a triage pass reads, so the reader reconstructs the problem from narrative.
11
+
12
+ Prose bans hold on files the hook watches and not on text leaving through `gh`, so a banned character survives into a published issue that then has to be edited on the remote. A missing remote or an unauthenticated `gh` surfaces only after the body is written.
11
13
 
12
14
  ## Must
13
15
 
14
- - Read the issue reference and the prose standard before formatting
15
- - Confirm a remote and an authenticated `gh` before composing, so the failure lands before a body is written rather than after
16
- - Scan the title and body for banned characters and internal phase labels as an explicit step. Reading the standard does not catch them, because the text is generated after the read.
17
- - Map the type to exactly one label, so filing and filtering agree
18
- - Ask once when the type is ambiguous between a bug and a task, since the label follows from it and a wrong label buries the issue
19
- - Pass the body through a file and remove it afterward, so shell quoting cannot mangle it
16
+ - The title and body follow the issue reference and are scanned for banned characters and phase labels before filing
17
+ - Each issue carries exactly one label mapped from its type, asked once when the type is ambiguous between a bug and a task
18
+ - A remote and an authenticated `gh` are confirmed before any body is composed
19
+ - The body passes through a file that is removed afterward
20
20
 
21
21
  ## Must not
22
22
 
23
- - Invent an issue from a thin session. Nothing concrete in context is a stop rather than a prompt to elaborate.
23
+ - Invent an issue from a thin session
24
24
  - File anywhere other than the current origin
25
25
  - Open a pull request
26
26
  - Emit anything after the result line
27
27
 
28
- ## Guards
29
-
30
- - No concrete bug or task in session context: stop and say what to provide
31
- - No remote: stop and name what `gh issue create` needs
32
- - `gh` not authenticated: stop and name the command that authenticates
33
-
34
28
  ## Out of scope
35
29
 
36
- - Reporting a toolkit defect from a target project, which `canon-feedback` owns. That path opens an issue on the toolkit repository rather than the current one.
30
+ - Reporting a toolkit defect from a target project, which `canon-feedback` owns
37
31
  - Triaging issues already filed, which `canon-feedback-triage` owns
38
32
  - Opening a pull request, which `git-pr` owns
@@ -7,47 +7,28 @@ description: What pull request generation is for, the gaps it closes, and what i
7
7
 
8
8
  ## Gap
9
9
 
10
- Without this skill, a pull request body is written from memory of the branch rather than from its diff, so it describes the intent and omits what the work turned into. Testing boxes get ticked from intent, which records what was meant to run instead of what ran, and a reviewer trusts the list. A second push either errors on create or opens a duplicate pull request, and banned characters survive into a body the hook never sees.
10
+ Without this skill, a pull request body is written from memory rather than the diff, so it describes the intent and omits what the work became. Testing boxes get ticked from intent, a second push errors or opens a duplicate, and banned characters survive into a body the hook never sees. The body grows into a wall nothing measures.
11
11
 
12
- Every pull request also lands unlabelled, so a merged list is a wall of titles with no way to filter it by surface. A reader looking for what changed in one domain reads all of them, and the conventional commit type in the title says what kind of change it is rather than where.
13
-
14
- A lookup that resolves by head branch alone carries its own failure. A branch name reused after an earlier pull request merged resolves to the closed one, so the run rewrites a merged pull request's title and body and reports its URL as the one it opened. Both fields are recoverable only through the issue timeline and the edit history, and nothing reports that the write landed on the wrong object.
12
+ Every pull request lands unlabelled, so a merged list cannot be filtered by surface. A head-branch lookup resolves a reused name to the merged pull request and rewrites it. A pull request changing a rendered surface reaches review with no screenshots, and a hand-written `Closes` line closes an issue on a middle slice or misses one the task names.
15
13
 
16
14
  ## Must
17
15
 
18
- - Refuse a branch name that does not conform, since the name lands on the pull request permanently and renaming it afterward breaks the link
19
- - Derive the title and body from the commits and the diff against main, with lockfiles excluded
20
- - Run each check before writing its line, then state the result the run reported
21
- - Leave a box unchecked only for a human-only case, naming which human and why on the same line
22
- - Scan the title and body for banned characters and internal phase labels as an explicit step, on top of reading the prose standard
23
- - Detect an open pull request and edit it in place, so a follow-up push keeps the body in sync instead of failing
24
- - Scope that detection to an open pull request on the current head and the default base, so neither a reused branch name nor a second base resolves the wrong one
25
- - Resolve the pull request once and reuse what that resolution returned, so the number recorded never depends on how a lookup ranks two pull requests sharing a head
26
- - Prove before every write to an existing pull request that its head is the current branch and its state is open, and refuse with nothing written on a mismatch, so a wrong number reaching a write never lands on another branch's pull request
27
- - Print the head branch beside the number, so a caller writing to the pull request later has a value to check the number against
28
- - Label from the paths the branch changed, against a map the project declares, so the label set belongs to the project rather than to the skill
29
- - Apply labels after the pull request exists, so a label the remote does not carry costs a warning rather than the pull request
30
- - Report a refused label, since a warning nothing surfaces leaves the run indistinguishable from one that labelled
31
- - End every pull request it opens or edits by invoking `pr-evidence` with the number it resolved, since a pull request changing a rendered surface otherwise reaches review with no screenshots, checklist, or address
16
+ - The title and body come from the commits and the lockfile-free diff against main, scanned for banned characters, phase labels, and density, and every ticked box records a check this run executed
17
+ - A follow-up run edits the one open pull request on the current head and default base, resolved once, and every write first proves that pull request's head and open state
18
+ - Closing lines come from `canon tasks closes`, one `Closes #NNN` per issue on the task's last slice only, with the scan failing a body that disagrees
19
+ - Labels come from the paths the branch changed against a map the project declares, applied after the pull request exists, with a refused label reported
20
+ - The run closes by invoking `pr-evidence` with the number it resolved, and prints the head branch beside that number
32
21
 
33
22
  ## Must not
34
23
 
35
- - Tick a testing box from intent or from a past session. The box records a run.
36
- - Put a request for the reviewer in the Testing list, since a request is not a result
37
- - Create a second pull request when one is open
38
- - Edit a pull request that is not open, or record its number on a task
39
- - Name a domain of any one project in the skill body or its references
40
- - Create a label the map names and the remote lacks
24
+ - Run on a non-conforming branch name or with no commits ahead of main
25
+ - Tick a testing box from intent, or put a request for the reviewer in the Testing list
26
+ - Create a second pull request, or edit one that is not open
27
+ - Name a domain of any one project in the body or its references, or create a label the remote lacks
41
28
  - Emit anything after the result line
42
29
 
43
- ## Guards
44
-
45
- - Branch name does not conform: stop and route to the skill that renames
46
- - No commits ahead of main: stop
47
- - No label map in the project: label nothing and warn nothing, since an absent map is a decision rather than a gap
48
-
49
30
  ## Out of scope
50
31
 
51
- - Naming the branch, which `git-branch` owns. This skill requires a conforming name and refuses without one rather than fixing it.
32
+ - Naming the branch, which `git-branch` owns
52
33
  - Grouping the diff into commits, which `git-stage` owns
53
- - Pushing a later edit onto an already-open pull request, which `git-followup` owns. The overlap is real and the split is by state: this skill brings a pull request into existence and keeps it accurate, that one carries a fix onto one already under review.
34
+ - Pushing a later edit onto a pull request already under review, which `git-followup` owns
@@ -75,6 +75,10 @@ Follow Testing discipline in `${CLAUDE_SKILL_DIR}/references/pr.md`. Run each ch
75
75
 
76
76
  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.
77
77
 
78
+ ### Name the issues the pull request closes
79
+
80
+ Ask `canon tasks closes` which issues this pull request closes before writing the body, and put one `Closes #NNN` line per issue last in `## Summary`. Read `${CLAUDE_SKILL_DIR}/references/closing-issues.md` on reaching this step for the invocation, the refusals it skips silently, and why an earlier slice of a sliced task carries none.
81
+
78
82
  ### Pre-publish scan
79
83
 
80
84
  Before running the final command, run the scan in `${CLAUDE_SKILL_DIR}/references/publish.md` against the PR title and body, on top of the banned phrases in `${CLAUDE_SKILL_DIR}/references/pr.md`. The title and body go straight to the remote, so run it whatever backs it downstream.
@@ -94,12 +98,14 @@ BODY
94
98
  Then run:
95
99
 
96
100
  ```bash
97
- canon labels scan --title "<title>" --body-file .canon/tmp/pr/body.md --json
101
+ canon labels scan --title "<title>" --body-file .canon/tmp/pr/body.md --closes <numbers|none> --json
98
102
  ```
99
103
 
104
+ Drop `--closes` when the closes step skipped a refusal, since no list was decided to grade against.
105
+
100
106
  ### Reading the scan
101
107
 
102
- Branch on the JSON record rather than the exit code, since a shell function wrapping `canon` can flatten a non-zero exit to 0. Stop and fix the title or body on any key below, and do not proceed to `### Final command` until a re-run comes back clean on all six.
108
+ Branch on the JSON record rather than the exit code, since a shell function wrapping `canon` can flatten a non-zero exit to 0. Stop and fix the title or body on any key below, and do not proceed to `### Final command` until a re-run comes back clean on all nine.
103
109
 
104
110
  | Key | Fix |
105
111
  | ------------------- | ------------------------------------------------------------------------------------ |
@@ -109,6 +115,9 @@ Branch on the JSON record rather than the exit code, since a shell function wrap
109
115
  | `titleFormatIssues` | Fix the `## Title` rule in `pr.md` it names, being structure, casing, or length |
110
116
  | `bannedCharacters` | Restructure the sentence around the named character |
111
117
  | `sections` | Rename or drop each heading in `outside`, and add each required heading in `missing` |
118
+ | `missingClosures` | Add a `Closes #NNN` line for each number listed |
119
+ | `strayClosures` | Delete the closing keyword for each number listed |
120
+ | `density` | Regroup or split the named section per `## Formatting` in `pr.md`, keeping each path |
112
121
 
113
122
  Leave `cutsRelease` and `semverTags` alone, since a release-please pull request legitimately carries version references its own fixed shape explains.
114
123
 
@@ -0,0 +1,47 @@
1
+ ---
2
+ title: Close the task's issues
3
+ description: How git-pr asks canon tasks closes which issues the pull request closes, the Closes line it writes into the body, the refusals it skips silently, and why an earlier slice carries none
4
+ ---
5
+
6
+ # Close the task's issues
7
+
8
+ Reached before the body is written. A task that cites `Issue: #NNN` ships and archives while its issue stays open unless the pull request body carries a closing keyword, and GitHub closes the issue only when that pull request merges into the default branch. `git-pr` always bases on the default branch, so no handling for another base is needed.
9
+
10
+ ## Ask the verb
11
+
12
+ The plan is the one `task-number.md` names, so reuse the filename an earlier step already read.
13
+
14
+ ```bash
15
+ canon tasks closes --plan feature-<slug> --json
16
+ ```
17
+
18
+ The verb reads the current branch itself and counts the names it carried before a rename, so pass nothing else. Branch on the record rather than the exit code.
19
+
20
+ | Record | Route |
21
+ | --------------------------------------------------- | ---------------------------------------------------------------------------------- |
22
+ | `ok: true`, `closing: true` | Write one `Closes #NNN` line per number in `issues`, and pass the list to the scan |
23
+ | `ok: true`, `closing: false` | Write no closing line, and pass `--closes none` to the scan |
24
+ | `ok: false`, `no-board`, `no-match`, or `ambiguous` | Write nothing and run the scan without `--closes` |
25
+ | Any other refusal | Report it rather than swallowing it |
26
+
27
+ The three skipped refusals are the ones `task-number.md` skips, and for the same reason. A guessed task would close the wrong issue.
28
+
29
+ ## The line
30
+
31
+ - Put the lines last in `## Summary`, after its sentences, one per issue
32
+ - Write `Closes #NNN` with no trailing period, since GitHub reads the keyword and the number and a period adds nothing
33
+ - Write one keyword per issue, because GitHub reads a keyword followed by a comma list as closing the first number alone
34
+
35
+ The scan takes the same list, so a missing line or a closing keyword the verb did not name fails the body:
36
+
37
+ ```bash
38
+ canon labels scan --title "<title>" --body-file .canon/tmp/pr/body.md --closes <numbers|none> --json
39
+ ```
40
+
41
+ ## Why an earlier slice carries none
42
+
43
+ The verb applies the condition the merge-time archive applies, being no open outcome and no other branch on the task's `Pending branch:` line. The issue then closes exactly when the task archives. An earlier slice merging with a closing keyword would close the issue while later slices are still to ship.
44
+
45
+ A re-run on an earlier slice's branch reads the same way. The verb looks up the branch's own pull request numbers, and one that is on the task's `Pull request:` line without being last reports `earlier-slice` and no closing line. The lookup runs over REST, and a failed one reports `lookup-failed` and no closing line once the task lists a pull request, since a failure cannot rule an earlier slice out.
46
+
47
+ `git-ship` ticks the outcomes before `git-pr` runs, so the condition holds at body time. A run with outcomes not yet ticked reads as an earlier slice and writes no line. That is the safe side, since the issue stays open, and the record's `reason` names why.