@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
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: task-board
3
- description: Why creating and archiving a task file is one skill, the origin invariant enforceable only at creation, and why archiving routes through the command the merge hook calls
3
+ description: Why creating and declining a task file is one skill, the origin invariant enforceable only at creation, and why settling a shipped task belongs elsewhere
4
4
  ---
5
5
 
6
6
  # Task board requirement
@@ -9,8 +9,6 @@ description: Why creating and archiving a task file is one skill, the origin inv
9
9
 
10
10
  Without this skill, a task file gets a filename and frontmatter invented on the spot, so the board sorts wrong and the regenerated index reads fields that are not there. A task arrives with no origin, which is either lost context or work nobody decided to do, and by the time anyone notices there is no way to recover which it was. The phase label gets derived from a version file rather than from what the board already means, and a single-digit phase sorts after a double-digit one because nobody padded it. A label picked off the live board alone repeats one the archive already spent, since the archive holds most of what has ever been allocated and a board-only scan cannot see it.
11
11
 
12
- Archiving fails in two ways that both lose work. Moving the file, editing the ordering file, and regenerating the index as three separate acts drifts from the one command the merge hook calls, so the attended and unattended paths stop agreeing. And an all-`[x]` task gets archived while its pull request is still open, because marking outcomes happens on the branch as the first step of shipping. The board is gitignored, so nothing restores a task archived early.
13
-
14
12
  Placing a row without checking for another writer collides the same way. Two sessions filing work at once can claim one phase label twice or land two rows beside each other unread, since neither reads the board before writing it.
15
13
 
16
14
  ## Must
@@ -20,29 +18,26 @@ Placing a row without checking for another writer collides the same way. Two ses
20
18
  - Require an origin at creation, because that is the only moment the invariant is enforceable
21
19
  - Claim the phase label with `canon tasks next-label --claim` rather than reading or proposing one by hand
22
20
  - Check the roster for a live orchestrator before writing a row, and hand off rather than write when one is found
23
- - Confirm the work reached the default branch before archiving
24
- - Run the archive command and route on the reason it refuses, since each reason has one resolution
21
+ - Run the decline command and route on the reason it refuses, since each reason has one resolution
25
22
  - Report an origin that carries no task, as a list rather than a prompt
26
23
 
27
24
  ## Must not
28
25
 
29
- - Mark an outcome complete or archive a plan
26
+ - Mark an outcome complete, archive a task, or move a plan
30
27
  - Hand-edit the index or the ordering file, or move the task file directly
31
28
  - Write a pull request line at creation, when any number is a guess at someone else's work
32
- - Archive around a refusal
33
- - Split the legacy single-file archive into per-task files nobody wrote
29
+ - Decline around a refusal
34
30
  - Claim a label or write a task file for a session holding the worker role, since that role reports a row upward and the controlling session places it
35
31
  - Fall through to a direct write when no orchestrator is found and this session's own name starts with `worker-` or `planner-`, since those role bodies ban the write with no exception
36
32
 
37
33
  ## Guards
38
34
 
39
35
  - No task board at the main root: stop
40
- - The request fits neither creating nor archiving: stop rather than picking one
41
- - Work not yet on the default branch: stop, because the board has no history to restore from
36
+ - The request fits neither creating nor declining: stop rather than picking one
42
37
  - No origin given and none offered: stop
43
38
 
44
39
  ## Out of scope
45
40
 
46
- - Editing the contents of a task that already exists, which `context-fold` owns along with marking outcomes and sweeping plans
41
+ - Marking a shipped task's outcomes and archiving it, which `task-complete` owns, with the `post-merge` hook running the unattended archive
47
42
  - Deciding what the task should argue. This owns the file's existence and its shape, not its content.
48
- - Relocating a plan, which one skill owns so two do not relocate it differently
43
+ - Relocating a plan, which `canon tasks archive` owns so two movers do not relocate it differently
@@ -1,22 +1,22 @@
1
1
  ---
2
2
  name: task-board
3
- description: Creates a task file in `.canon/tasks/` with the filename, phase label, and frontmatter the standard requires, and archives a shipped one out of the folder. Use when asked to "add a task", "create a task", "queue this", "put this on the board", "archive that task", or "close out a shipped task". Do NOT use to mark an outcome `[x]`. That is `context-fold`.
3
+ description: Creates a task file in `.canon/tasks/` with the filename, phase label, and frontmatter the standard requires, and declines one decided against. Use when asked to "add a task", "create a task", "queue this", "put this on the board", or "decline that task". Do NOT use to mark an outcome `[x]` or to archive a shipped task. That is `task-complete`.
4
4
  metadata:
5
5
  family: decide
6
6
  ---
7
7
 
8
8
  # Task board
9
9
 
10
- Owns the two operations that bring a task file into existence and take it out of the folder. `context-fold` edits the contents of a task that already exists, marking outcomes `[x]`. Do not mark outcomes here, and do not move a plan by hand: the archive carries it.
10
+ Owns the two operations that decide a task: bringing its file into existence, and declining one decided against. `task-complete` settles a task once its work exists, marking outcomes `[x]` and archiving a shipped one. Do not mark outcomes or archive here, and do not move a plan by hand.
11
11
 
12
12
  Read `${CLAUDE_SKILL_DIR}/references/tasks.md` before writing any file. It holds the filename convention, the frontmatter contract, and the file format. Do not work them from memory.
13
13
 
14
14
  ## Guards
15
15
 
16
16
  - Resolve the board at the main worktree root, not `pwd`. Run `git worktree list --porcelain | grep -m 1 '^worktree ' | cut -d' ' -f2-`, falling back to `pwd` outside a git repo. Every read and write below resolves against that root. The board is gitignored scratch shared across worktrees, so a linked worktree writing to its own `pwd` creates a second board nothing else reads.
17
- - A new task file is a main-root write, so it goes out as a heredoc. Archiving already runs through `canon tasks archive`, which resolves the root in-process. Marking an outcome shipped is `context-fold` and runs through `canon tasks outcome`. Resolve that root and route the write the way `session-worktree` states.
17
+ - A new task file is a main-root write, so it goes out as a heredoc. Declining already runs through `canon tasks decline`, which resolves the root in-process. Resolve that root and route the write the way `session-worktree` states.
18
18
  - If `.canon/tasks/` does not exist at that root, stop: `❌ No .canon/tasks/ board. Run canon claude init to set it up.`
19
- - Route on the request rather than on a flag. Creating names work that does not exist yet, archiving names a task file already shipped, and declining names one decided against. If the request fits none of the three, stop: `❌ Ambiguous. Say whether to create a task, archive one, or decline one.`
19
+ - Route on the request rather than on a flag. Creating names work that does not exist yet, and declining names a task file decided against. A request to archive a shipped task or mark its outcomes belongs to `task-complete`, so name it and stop. If the request fits neither, stop: `❌ Ambiguous. Say whether to create a task or decline one.`
20
20
  - Never hand-edit `.canon/tasks/index.md`. A hook regenerates it from sibling frontmatter after a write. Do not run the regen command directly, except after a shell write from a linked worktree: the hook matches `Write|Edit|MultiEdit` and nothing fires on `Bash`, so that one case regenerates explicitly with `canon indexes regen --no-stage --root <main-root> <main-root>/.canon/tasks/index.md`.
21
21
 
22
22
  ## Create
@@ -39,7 +39,7 @@ The guard sits ahead of Step 2 because `--claim` reserves a label on disk, so a
39
39
 
40
40
  Run `canon tasks next-label --claim --json` and take its `label` field. The verb reads the live board and its `archive/` sibling together, so the label it returns accounts for what the board alone no longer shows, and `--claim` reserves it under `.canon/ordinal-locks/` so a second session filing at the same moment gets the next one. Branch on the record's `reason` rather than the exit: `label-contended` means re-run the claim, and a usage error from an unknown `--claim` means the installed binary predates the flag, so report the verb as unavailable rather than falling back to a bare read, which reopens the race.
41
41
 
42
- Do not derive the label from a version file. `${CLAUDE_SKILL_DIR}/../../standards/versioning.md` permits free renumbering, so the verb's two folders are the only surface that knows what a label currently means.
42
+ Do not derive the label from a version file. `${CLAUDE_SKILL_DIR}/../git-commit/references/versioning.md` permits free renumbering, so the verb's two folders are the only surface that knows what a label currently means.
43
43
 
44
44
  ### Step 3: write the file
45
45
 
@@ -90,10 +90,6 @@ Report rather than prompt. A track can be opened long after its task would have
90
90
 
91
91
  Say the origins were read even when nothing comes back, which is the ordinary result. A step going silent on a clean pass is indistinguishable from one that never ran.
92
92
 
93
- ## Archive
94
-
95
- Read `${CLAUDE_SKILL_DIR}/references/archive.md` when the request names a shipped task to archive. It carries the check that the work reached `main`, the `canon tasks archive` call, the route for each refusal, and the prose to clear afterwards. Never move the file, edit `priority.md`, or regenerate the index by hand, since the command owns all three.
96
-
97
93
  ## Decline
98
94
 
99
95
  Read `${CLAUDE_SKILL_DIR}/references/decline.md` when the request names a task decided against. It carries gathering the reason, the `canon tasks decline` call, the route for each refusal, and the prose to clear afterwards. Never move the file, edit `priority.md` or `backlog.md`, or regenerate the index by hand, since the command owns all three.
@@ -124,12 +120,4 @@ Create:
124
120
 
125
121
  Drop either block when it carries no rows. When both are empty, which is the ordinary result, replace them with one line naming what was read: `Read <n> tracks, <n> dumps, and <n> open issues. Nothing unlinked.`
126
122
 
127
- Archive, reporting the paths the command returned:
128
-
129
- ```plaintext
130
- 📦 Archived: .canon/tasks/archive/vXX.Y-<slug>.md
131
-
132
- <ordering and index disposition in one line>
133
- ```
134
-
135
123
  A refusal reports the reason and the resolution the mode's reference routes it to under its Step 3, on one line each.
@@ -54,13 +54,13 @@ One file per task is what keeps the board safe under parallel sessions. Two sess
54
54
 
55
55
  Siblings sit in the folder without being tasks, and each earns its place by being governed somewhere. `index.md`, `priority.md`, and `backlog.md` are governed by `board.md`. Every `session-` file is a pre-compaction handoff governed by `session.md`, and each is optional: a project whose sessions never approach a compaction carries none. Anything filtering the folder to tasks skips all of them, so a name outside the set is a task whatever it holds.
56
56
 
57
- The `task-board` skill creates and archives task files, and the archive carries the task's plan with it. `context-fold` marks outcomes `[x]` in an existing file. Neither does the other's job.
57
+ The `task-board` skill creates and declines task files. The `task-complete` skill marks outcomes `[x]` in an existing file and archives a shipped one, and the archive carries the task's plan with it. Neither does the other's job.
58
58
 
59
59
  ## Filenames
60
60
 
61
61
  `vXX.Y-<slug>.md`, where the version is the phase label zero-padded to two digits and the slug is kebab-case.
62
62
 
63
- Padding is load-bearing. Index entries sort by filename and nothing else, so a bare `v9.0` sorts after `v15.0` and the catalog reads out of board order. `standards/versioning.md` governs the label itself and permits free renumbering, so expect the occasional rename. Nothing points at a task filename, since a `Plan:` line runs from task to plan rather than the reverse. <!-- canon-allow-reference: illustrates the padding rule's own sort collision, not a citation of a real task -->
63
+ Padding is load-bearing. Index entries sort by filename and nothing else, so a bare `v9.0` sorts after `v15.0` and the catalog reads out of board order. `${CLAUDE_SKILL_DIR}/../git-commit/references/versioning.md` governs the label itself and permits free renumbering, so expect the occasional rename. Nothing points at a task filename, since a `Plan:` line runs from task to plan rather than the reverse. <!-- canon-allow-reference: illustrates the padding rule's own sort collision, not a citation of a real task -->
64
64
 
65
65
  ## Frontmatter
66
66
 
@@ -0,0 +1,47 @@
1
+ ---
2
+ name: task-complete
3
+ description: Why marking shipped outcomes and archiving a shipped task sit in one skill, why the diff decides completion alone, and why the ship chain marks but never archives
4
+ ---
5
+
6
+ # Task complete requirement
7
+
8
+ ## Gap
9
+
10
+ Without this skill, the board describes the scope a branch opened with. An outcome the diff shipped stays unchecked, so the board reports finished work as open and the next session re-plans it. When marking rode inside the context fold, it kept a ten-step skill running on every ship for a write that had nothing to do with the context entries, and a session reading the fold's name never learned that it also wrote the board.
11
+
12
+ Archiving fails in two ways that both lose work. Moving the file, editing the ordering file, and regenerating the index as three separate acts drifts from the one command the merge hook calls, so the attended and unattended paths stop agreeing. And an all-`[x]` task gets archived while its pull request is still open, because marking happens on the branch as a ship-chain step. The board is gitignored, so nothing restores a task archived early.
13
+
14
+ Review receipts pile up the same way. A branch report is read once by the session addressing it, and nothing but an operator asking ever collected one whose branch was gone, so the folder grew per shipped branch and never shrank.
15
+
16
+ ## Must
17
+
18
+ - Take completion from the diff, since completion is a fact about the repository rather than about the conversation
19
+ - Match an outcome on the behavior it names, never on a filename or a commit subject
20
+ - Leave an outcome unchecked when the diff is ambiguous. An unmarked shipped outcome costs one manual edit and a wrongly marked one hides work that never happened.
21
+ - Close outcomes through `canon tasks outcome` and branch on the record's `ok` and `reason` rather than the exit
22
+ - Resolve the board at the main worktree root, since a linked worktree reading `pwd` finds no board
23
+ - Sweep a branch review report whose branch no longer exists, and leave the current branch's receipt alone, since its branch is still live
24
+ - Confirm the work reached the default branch before archiving
25
+ - Run the archive command and route on the reason it refuses, since each reason has one resolution
26
+
27
+ ## Must not
28
+
29
+ - Infer a new task from the diff. Only outcomes already on the board get marked.
30
+ - Touch a task file the diff does not relate to
31
+ - Archive from the ship chain. The pull request has not merged there, and the `post-merge` hook archives through the same command once it does.
32
+ - Hand-edit the index or the ordering file, or move a task file or a plan directly
33
+ - Archive around a refusal
34
+ - Split the legacy single-file archive into per-task files nobody wrote
35
+ - Widen what the marking step reads into a write when the baseline is unusable
36
+
37
+ ## Guards
38
+
39
+ - No task board at the main root: Mark reports one skip line and returns, since the ship chain runs it on every project, and Archive stops naming the command that sets one up
40
+ - Work not yet on the default branch when archiving: stop, because the board has no history to restore from
41
+
42
+ ## Out of scope
43
+
44
+ - Creating or declining a task, which `task-board` owns
45
+ - The context entries, which `context-fold` owns
46
+ - The unattended archive at merge, which the `post-merge` hook runs through `canon tasks archive`
47
+ - Regenerating the task index, owned by a hook
@@ -0,0 +1,86 @@
1
+ ---
2
+ name: task-complete
3
+ description: Marks the outcomes a branch's diff shipped `[x]` on the task board, sweeps the review receipts whose branch is gone, and archives a shipped task by hand where the `post-merge` hook could not. Use when asked to "mark what shipped", "tick the outcomes", "close out a shipped task", or "archive that task", or as the ship-chain step after `context-fold`. Do NOT use to create or decline a task, which is `task-board`, or to update the context entries, which is `context-fold`.
4
+ metadata:
5
+ family: ship
6
+ ---
7
+
8
+ # Task complete
9
+
10
+ Owns the two operations that settle a task once its work exists: marking the outcomes the diff shipped, and archiving a task whose work reached `main`. `task-board` brings a task into existence and declines one, and `context-fold` writes the context entries. Do not create a task here, and do not move a plan by hand: the archive carries it.
11
+
12
+ ## Guards
13
+
14
+ - Resolve the board at the main worktree root, not `pwd`. Run `git worktree list --porcelain | grep -m 1 '^worktree ' | cut -d' ' -f2-`, falling back to `pwd` outside a git repo. The board is gitignored scratch shared across worktrees, so a linked worktree reading its own `pwd` finds no board at all.
15
+ - If `.canon/tasks/` does not exist at that root, Mark has nothing to mark: report `⏭️ No .canon/tasks/ board, so no outcomes to mark.` and return, still running Step 4's receipt sweep, since `git-ship` invokes Mark on every ship and a project with no board is not a failed one. Archive stops instead: `❌ No .canon/tasks/ board. Run canon claude init to set it up.`
16
+ - Route on the request rather than on a flag. A request naming a shipped task to archive, or a task file the `post-merge` hook left in place, takes Archive. Every other request takes Mark, which is what the ship chain invokes.
17
+ - Never hand-edit `.canon/tasks/index.md`. A hook regenerates it.
18
+
19
+ ## Mark
20
+
21
+ ### Step 1: resolve the diff baseline
22
+
23
+ Resolve the base ref once:
24
+
25
+ ```bash
26
+ git merge-base HEAD origin/main 2>/dev/null || git merge-base HEAD main 2>/dev/null
27
+ ```
28
+
29
+ Take the union of `git diff --name-only <base> HEAD`, `git diff --name-only HEAD`, and `git ls-files --others --exclude-standard`. Read content with `git diff <base> HEAD` and `git diff HEAD`.
30
+
31
+ Prefer `origin/main` over local `main`. On `main` itself the local ref resolves to HEAD, so every committed change drops out of the set and this step goes blind to the work it is meant to read.
32
+
33
+ The baseline is unusable when no merge base resolves against either ref, or when the base came from local `main` and equals HEAD. On an unusable baseline, read `${CLAUDE_SKILL_DIR}/references/unusable-baseline.md` before Step 2 for what to read instead.
34
+
35
+ ### Step 2: match the diff against the board
36
+
37
+ Read `.canon/tasks/index.md` at the main worktree root, pick the task files whose title or description relates to the changed paths, and read them.
38
+
39
+ Path matching only chooses which files to open. Behavior decides each outcome. For each unchecked outcome, decide whether the diff shipped the behavior that outcome names.
40
+
41
+ Completion is a fact about the repository rather than a fact about the conversation, so the diff decides it and the session does not.
42
+
43
+ Keep the match conservative:
44
+
45
+ - Mark only outcomes already written on the board. Never infer a new task from the diff.
46
+ - Match on the behavior an outcome describes, not on filenames or commit subjects. The path match above only narrowed which task files to open.
47
+ - Leave an outcome `[ ]` when the diff is ambiguous. An unmarked shipped outcome costs one manual edit, while a wrongly marked one hides work that never happened.
48
+ - Do not touch task files the diff does not relate to.
49
+
50
+ ### Step 3: close the matched outcomes
51
+
52
+ Mark each completed outcome `[x]` in the task's own file through `canon tasks outcome <stem> --close <n> --json`, repeating `--close` for each. Positions count every outcome checkbox in file order from 1, which the read above already gives. Do not move or archive the file, even when every outcome now reads `[x]`, since the pull request has not merged and the `post-merge` hook archives the task once it does.
53
+
54
+ The verb resolves the board at the main worktree root in-process, which is the route `session-worktree` states for an edit inside an existing main-root file.
55
+
56
+ Read `ok` and `reason` out of that record rather than the exit. An operator's shell profile may wrap `canon` in a function that runs the binary and then a second command and takes the second status, which flattens every non-zero exit to zero. A refusal arriving as success leaves the outcome unmarked while the chain moves on, so the board reports shipped work as open and the next session re-plans it.
57
+
58
+ ### Step 4: sweep consumed receipts
59
+
60
+ Read `${CLAUDE_SKILL_DIR}/references/receipt-sweep.md` for which review receipts this run sweeps, which it keeps, and the output lines. Skip this step silently when nothing qualifies.
61
+
62
+ ## Archive
63
+
64
+ Read `${CLAUDE_SKILL_DIR}/references/archive.md` when the request names a shipped task to archive. It carries the check that the work reached `main`, the `canon tasks archive` call, the route for each refusal, and the prose to clear afterwards. Never move the file, edit `priority.md`, or regenerate the index by hand, since the command owns all three.
65
+
66
+ ## Output
67
+
68
+ Emit the full relative path from the project root for every file written or moved. A bare filename names a file the reader cannot open.
69
+
70
+ Mark, one line per outcome closed, then the sweep lines Step 4 names:
71
+
72
+ ```plaintext
73
+ ✅ Marked: .canon/tasks/vXX.Y-<slug>.md, outcome <n>
74
+ ```
75
+
76
+ When the diff closed nothing, output `✅ No outcomes shipped on this diff.` and nothing for Step 3. A refusal reports the record's `reason` on one line, naming the task.
77
+
78
+ Archive, reporting the paths the command returned:
79
+
80
+ ```plaintext
81
+ 📦 Archived: .canon/tasks/archive/vXX.Y-<slug>.md
82
+
83
+ <ordering and index disposition in one line>
84
+ ```
85
+
86
+ A refusal reports the reason and the resolution `references/archive.md` routes it to under its Step 3, on one line each.
@@ -1,11 +1,11 @@
1
1
  ---
2
2
  title: Archive a shipped task
3
- description: How task-board confirms a task's work reached main, runs canon tasks archive, routes each refusal, and clears prose naming the archived task
3
+ description: How task-complete confirms a task's work reached main, runs canon tasks archive, routes each refusal, and clears prose naming the archived task
4
4
  ---
5
5
 
6
6
  # Archive a shipped task
7
7
 
8
- The Archive mode of `task-board`. The session reads this file when the request names a task file already shipped.
8
+ The Archive mode of `task-complete`. The session reads this file when the request names a task file already shipped.
9
9
 
10
10
  The `post-merge` git hook archives the task a merge closed, so a request arriving here is usually one the hook could not resolve on its own. Run the steps below against whatever the hook left in place.
11
11
 
@@ -13,7 +13,7 @@ Do not move the file, edit `priority.md`, or regenerate the index by hand. `cano
13
13
 
14
14
  ## Step 1: confirm the work reached main
15
15
 
16
- `context-fold` marks outcomes on the branch as step 1 of the ship chain, so an all-`[x]` task routinely describes a pull request that is still open. The command gates on the outcomes and cannot tell those two apart, which is what puts this check here:
16
+ `task-complete` marks outcomes on the branch as step 2 of the ship chain, so an all-`[x]` task routinely describes a pull request that is still open. The command gates on the outcomes and cannot tell those two apart, which is what puts this check here:
17
17
 
18
18
  ```bash
19
19
  git fetch origin main --quiet && git log origin/main --oneline -20
@@ -39,7 +39,7 @@ On success the record carries `from`, `to`, `priorityRowRemoved`, and `indexRege
39
39
 
40
40
  Each reason has one resolution and none of them is to archive around it:
41
41
 
42
- - `open-outcomes`: the named outcomes are unmarked or genuinely open. Run `context-fold` when the work shipped and nothing marked it. Leave the task on the board when the outcome is real. When the work is being abandoned, cut it by striking the body, `- ~~<outcome>~~ <why>`, whatever the checkbox holds, so the board records what was dropped rather than meeting this refusal a second time.
42
+ - `open-outcomes`: the named outcomes are unmarked or genuinely open. Run `task-complete` when the work shipped and nothing marked it. Leave the task on the board when the outcome is real. When the work is being abandoned, cut it by striking the body, `- ~~<outcome>~~ <why>`, whatever the checkbox holds, so the board records what was dropped rather than meeting this refusal a second time.
43
43
  - `ambiguous`: two tasks name one pull request, which is the misfile `${CLAUDE_SKILL_DIR}/references/tasks.md` rules out. Resolve the citation by hand, since no sweep repairs it.
44
44
  - `earlier-slice`: the number is listed on the task but is not the last, so a later slice is still to merge. Leave the task on the board. Its last slice's merge archives it.
45
45
  - `pending-branch`: a branch named in `detail` ticked an outcome before its own pull request number was recorded. Leave the task live, since that branch's merge archives it once `git-pr` records the number. When the operator decides a named branch was abandoned, archive by stem, which is the one case for it.
@@ -1,17 +1,17 @@
1
1
  ---
2
2
  title: Sweep consumed receipts
3
- description: How context-fold Step 7 sweeps branch review reports whose branch is gone, and what it keeps and reports
3
+ description: How task-complete's marking step sweeps branch review reports whose branch is gone, and what it keeps and reports
4
4
  ---
5
5
 
6
6
  # Sweep consumed receipts
7
7
 
8
- Step 7 of `context-fold`, reached in order on every run.
8
+ Step 4 of `task-complete`'s Mark mode, reached in order on every marking run.
9
9
 
10
- Sweep the review receipts this session consumed. Resolve all paths at the main worktree root, not the current worktree, the way `session-worktree` does.
10
+ Sweep the review receipts a shipped branch left behind. Resolve all paths at the main worktree root, not the current worktree, the way `session-worktree` does.
11
11
 
12
12
  Every delete below is a plain `rm`, one per call, routed the way `session-worktree` states.
13
13
 
14
- Plans are not swept here. A plan is settled by the merge rather than by an outcome this run marked, and `canon tasks archive` moves it with the task the `post-merge` hook archives. Sweeping it from this step read a closure Step 3 had written moments earlier and moved a plan the branch was still building from.
14
+ Plans are not swept here. A plan is settled by the merge rather than by an outcome this run marked, and `canon tasks archive` moves it with the task the `post-merge` hook archives. Sweeping it from this step would read a closure Step 3 wrote moments earlier and move a plan the branch is still building from.
15
15
 
16
16
  ## Reviews
17
17
 
@@ -19,7 +19,7 @@ Leave the current branch's review receipt where it is. No skill writes one now,
19
19
 
20
20
  The body that writes a receipt owns its lifetime. This skill sweeps on behalf of whatever called it and has no way to read whether a file is still in use, where the chain that wrote this one cites it in its own output and knows. What reaps it is the branch sweep below, one branch later, once the branch it names is gone.
21
21
 
22
- Sweep the branch reports this session never opened. List `.canon/review/branch-*.md`, run the slug transform in `${CLAUDE_SKILL_DIR}/../../standards/slug.md` over every name `git branch --format='%(refname:short)'` prints, and delete a report whose slug matches none of them. Take the names from that format rather than from `git branch --list`, which marks the current branch with `* ` and a branch checked out in another worktree with `+ `, so a transform reading the marked lines as written turns a live branch into a slug nothing matches and sweeps a report a sibling worktree is still working from. A branch report is read once, by the session addressing it, and the durable record of what a review found is the comment `review-pr` posts on the pull request, so a report outliving its branch is holding nothing. Skipping this leaves them accumulating for the life of the checkout, since a slug is unique per feature and no later branch ever looks for one.
22
+ Sweep the branch reports this session never opened. List `.canon/review/branch-*.md`, run the slug transform in `${CLAUDE_SKILL_DIR}/../git-branch/references/slug.md` over every name `git branch --format='%(refname:short)'` prints, and delete a report whose slug matches none of them. Take the names from that format rather than from `git branch --list`, which marks the current branch with `* ` and a branch checked out in another worktree with `+ `, so a transform reading the marked lines as written turns a live branch into a slug nothing matches and sweeps a report a sibling worktree is still working from. A branch report is read once, by the session addressing it, and the durable record of what a review found is the comment `review-pr` posts on the pull request, so a report outliving its branch is holding nothing. Skipping this leaves them accumulating for the life of the checkout, since a slug is unique per feature and no later branch ever looks for one.
23
23
 
24
24
  What that removes is a local-only review on a branch deleted before it opened a pull request. The sweep runs anyway rather than keeping every report against the one case, since nothing else ever clears them.
25
25
 
@@ -0,0 +1,19 @@
1
+ ---
2
+ title: An unusable diff baseline
3
+ description: When task-complete's diff baseline is unusable, what the marking step reads to recover the committed half, and why that widened read is safe here
4
+ ---
5
+
6
+ # An unusable diff baseline
7
+
8
+ Step 1 of `task-complete`'s Mark mode. The session reads this file when no merge base resolves or the base came from local `main` and equals HEAD.
9
+
10
+ The baseline is unusable in two cases:
11
+
12
+ - No merge base resolves against either ref.
13
+ - The base came from local `main` and equals HEAD. Nothing is pushed to compare against, so a narrow read reports no changes rather than admitting it cannot see them.
14
+
15
+ An unusable baseline costs only the committed half. `git diff <base> HEAD` is empty by definition once the base equals HEAD, while `git diff HEAD` and `git ls-files --others --exclude-standard` still report uncommitted and untracked work at correct scope.
16
+
17
+ Recover the committed half. Read `git log -p -1`, widening to `git log -p -<n>` when the session spans several commits, and read the candidate task files against the working tree. That yields names and content both, which is what lets Step 2 decide on behavior rather than on filenames. A fresh `git init` on `main` with no remote is the ordinary shape of a scaffolded project, so this path carries the evidence rather than covering an edge case.
18
+
19
+ On a fresh `git init` project the last commit is the scaffold commit, so `git log -p -1` is the whole tree by another route. The marking step tolerates that because it only reads the diff, and it matches conservatively against outcomes already on the board. Widening what a step reads is safe. Never carry the widened set into a step that writes per file.
@@ -21,6 +21,8 @@ The lesson then reaches nobody. It is a page carrying a stylesheet and a script,
21
21
 
22
22
  The durable half then has nowhere to go. A reference page and a glossary carry no learner and are ordinary reference prose, so they belong wherever the project already keeps prose on that subject, and a workspace holding them is a gitignored folder one person reads. A session moving them by hand picks a destination from the reader's activity rather than from who owns the subject, drops a page into a corpus without the source line that corpus requires, and has nothing stopping it from carrying a lesson across.
23
23
 
24
+ A confirmed page then waits in gitignored scratch until something lands it, and the session that produced it is gone by the time a branch exists to carry the write. Left unfolded it reads as promoted while the destination holds nothing.
25
+
24
26
  Two failures land specifically on where the folder sits. A workspace resolved against the current directory forks into a copy per linked worktree, so the learning records split and no session sees the whole history. A body naming only the destination path reports success and loses the write, because the file-editing tools refuse a main-root path from a linked worktree and offer a worktree copy instead.
25
27
 
26
28
  ## Must
@@ -38,12 +40,14 @@ Two failures land specifically on where the folder sits. A workspace resolved ag
38
40
  - Hand the learner a link that opens the workspace in a real browser on every run, reading it back from the verb that served it rather than composing one, since the port a preview lands on is not the port it asked for
39
41
  - Propose a destination for each durable page by who owns its subject, and wait for the operator rather than routing on the session's own reading
40
42
  - Hand each confirmed page off through a named file of its own, so one skill owns the durable writes and no other producer's unread work is discarded with it
43
+ - Land each block of that handoff from a branch, at the destination its heading names, taking the destination as already decided, then delete the file so a later run does not fold it twice
41
44
  - Name what the destination expects that the page does not carry yet, since the workspace runs none of the gates the destination does
42
45
 
43
46
  ## Must not
44
47
 
45
48
  - Teach from recall without saying which claims rest on it
46
- - Write to a destination surface directly, since the skill owning that file makes the edit and two skills writing one file at one step is what the handoff exists against
49
+ - Write to a destination surface outside the fold mode, since the proposal and the landing are two steps a branch boundary separates and two writers at one step is what the handoff exists against
50
+ - Overwrite a file a promotion block routes to. A destination that already holds a page is a merge for a person, and folding over it discards work this skill never read.
47
51
  - Open a second workspace on a subject an existing one already covers
48
52
  - Renumber a workspace folder, a lesson, or a learning record, since the number is cited by files already written
49
53
  - Promote a lesson, at any age and on any request, since it is generated markup carrying a quiz and a learner into a corpus every other page passed a gate to enter
@@ -55,7 +59,7 @@ Two failures land specifically on where the folder sits. A workspace resolved ag
55
59
 
56
60
  ## Out of scope
57
61
 
58
- - Landing a promoted page at its destination, which belongs to the skill that owns durable writes there, and creating a wiki folder a project never chose
62
+ - Creating a wiki folder a project never chose
59
63
  - What the verbs do internally, which is the CLI domain's own contract rather than this skill's, and the records backup that carries the folder off one disk
60
64
  - What a lesson renders as and how a quiz behaves once rendered, which the lesson-craft reference shapes and a rendering layer executes
61
65
  - Deciding when to fire. The skill is user-invoked through `disable-model-invocation`, so opening a workspace is the learner's call rather than a description match.
@@ -1,8 +1,8 @@
1
1
  ---
2
2
  name: teach-workspace
3
- description: Opens and runs a learning workspace on one subject, holding a mission, resources, numbered lessons, reference pages, a glossary, and learning records that survive across sessions, and proposes where a durable page from one belongs once it outgrows the workspace. Use when asked to "teach me X", "open a learning workspace", "I want to learn X", "quiz me on this", "continue the lesson", "resume my workspace on X", or "promote this reference page". Do NOT use to write project documentation, which belongs to the surface owning that document, and do NOT use to answer one question, which is an ordinary reply.
3
+ description: Opens and runs a learning workspace on one subject, holding a mission, resources, numbered lessons, reference pages, a glossary, and learning records that survive across sessions, proposes where a durable page from one belongs once it outgrows the workspace, and lands the confirmed pages from a branch. Use when asked to "teach me X", "open a learning workspace", "I want to learn X", "quiz me on this", "continue the lesson", "resume my workspace on X", "promote this reference page", or "fold the promoted pages in". Do NOT use to write project documentation, which belongs to the surface owning that document, and do NOT use to answer one question, which is an ordinary reply.
4
4
  disable-model-invocation: true
5
- argument-hint: <subject to learn, or the topic of a workspace to resume or promote>
5
+ argument-hint: <subject to learn, the topic of a workspace to resume or promote, or fold>
6
6
  metadata:
7
7
  family: answer
8
8
  ---
@@ -17,7 +17,7 @@ The shape of the workspace is fixed by `${CLAUDE_SKILL_DIR}/references/teach.md`
17
17
 
18
18
  - If the invocation names no subject and no existing workspace matches, stop: `❌ No subject. Invoke with the subject to learn, or the topic of a workspace to resume.`
19
19
  - Never trust recall for what the subject says. Research first, cite what was read, and say what was not.
20
- - Write nothing outside the workspace folder, apart from the one handoff file Step 6 names. A durable page stays in `reference/` and is copied out by the skill that owns the destination, never by this one.
20
+ - Write nothing outside the workspace folder, apart from the one handoff file Step 6 names and the destinations the fold mode lands from that file. A durable page stays in `reference/` until the operator confirms a destination, and only the fold mode copies it out, from a branch.
21
21
  - Do not open a second workspace on a subject one already covers. Resume that one.
22
22
  - Never promote a lesson. It is generated markup carrying a quiz and a learner, and no request makes it promotable.
23
23
  - Never write a favicon link by hand. `canon teach nav` puts the toolkit's icon on every page it generates and inside a lesson's `style` region, so a hand-written one in a lesson's `<head>` gives the page two.
@@ -41,7 +41,7 @@ Every path under the main root is a main-root write, routed the way `session-wor
41
41
 
42
42
  ## Step 1: open or resume
43
43
 
44
- A topic the listing already carries is a resume, and anything else is a new workspace. An invocation asking to promote is neither: read the named workspace through the listing and go to Step 6, which teaches nothing and writes no lesson.
44
+ A topic the listing already carries is a resume, and anything else is a new workspace. An invocation asking to promote is neither: read the named workspace through the listing and go to Step 6, which teaches nothing and writes no lesson. An invocation asking to fold confirmed promotions in is neither as well: go to `## Fold mode`.
45
45
 
46
46
  On a resume, run `canon teach list <topic> --json` for the files behind each count, then read the highest-numbered learning record and `GLOSSARY.md`. Those carry where the learner stopped and what they got wrong. The listing record carries `success`, the mission's success lines, which are the exit criteria this workspace is finished against. Report them with what is already met before teaching anything.
47
47
 
@@ -141,6 +141,10 @@ Run this when the invocation asks for it, or offer it in one line when a mission
141
141
 
142
142
  Read `${CLAUDE_SKILL_DIR}/references/promotion.md` first. It carries what may be promoted, the routing test, both spellings of the wiki folder, the refusal when a project has none, what each destination expects a page to carry, and under `## Proposing and handing off` the proposal block, the handoff file this step writes in place of any destination, and how the operator is told to fold it. Propose and wait, and write nothing to a destination here.
143
143
 
144
+ ## Fold mode
145
+
146
+ Run this only when the invocation asks to fold, and only from a branch in a linked worktree, since every destination is a tracked file that commits with the branch while the handoff sits in gitignored scratch at the main root. Read `${CLAUDE_SKILL_DIR}/references/promotion-fold.md` for how each block lands, the overwrite refusal, the handoff delete, and the output lines, which replace the Output block below.
147
+
144
148
  ## Output
145
149
 
146
150
  ```plaintext
@@ -50,7 +50,7 @@ Every element competes with the material for attention.
50
50
  Decide the figure once per lesson, before writing the body.
51
51
 
52
52
  1. Name the one relationship, boundary, path, or before-and-after the lesson is about. A lesson about none ends here, with `Figure: none, <why it names no structure>` on the reply.
53
- 2. Hold it against the bar in `${CLAUDE_SKILL_DIR}/../../standards/figures.md`, which also carries the drawing rules.
53
+ 2. Hold it against the bar in `${CLAUDE_SKILL_DIR}/../draft-figure/references/figures.md`, which also carries the drawing rules.
54
54
  3. Draw it hand-written through `canon:draft-figure` into a `raw` block before the quiz, never inside it or after its feedback, which breaks the stepper's gating. Report it, never draw it yourself, if the skill does not resolve.
55
55
  4. Or write one line on why prose carries it better, such as a structure an earlier lesson gave.
56
56
 
@@ -1,13 +1,13 @@
1
1
  ---
2
2
  title: Fold promoted pages
3
- description: How context-fold Step 6 lands each page a teach promotion handoff carries, deletes the handoff, and reports what it landed or left unfolded
3
+ description: How teach-workspace's fold mode lands each page a teach promotion handoff carries from a branch, deletes the handoff, and reports what it landed or left unfolded
4
4
  ---
5
5
 
6
6
  # Fold promoted pages
7
7
 
8
- Step 6 of `context-fold`. The session reads this file when a teach promotion handoff exists.
8
+ The fold mode of `teach-workspace`, run from a branch in a worktree. The session reads this file when the invocation asks to fold confirmed promotions in.
9
9
 
10
- Derive `<slug>` per `${CLAUDE_SKILL_DIR}/../../standards/slug.md`, falling back to `latest` on an empty result, and read `.canon/tmp/handoff/teach-promotion/<slug>.md` at the main worktree root. `teach-workspace` writes it, one H2 per destination naming the path, with a source line under the heading and the page body in a fenced block below that. Read the body out of the fence rather than off the heading level, since a reference page carries headings of its own and only the fence separates them from the next destination. Skip this step silently when the file is absent, which is every run where nothing was promoted.
10
+ Derive `<slug>` per `${CLAUDE_SKILL_DIR}/../git-branch/references/slug.md`, falling back to `latest` on an empty result, and read `.canon/tmp/handoff/teach-promotion/<slug>.md` at the main worktree root. `teach-workspace` writes it, one H2 per destination naming the path, with a source line under the heading and the page body in a fenced block below that. Read the body out of the fence rather than off the heading level, since a reference page carries headings of its own and only the fence separates them from the next destination. Stop when the file is absent, reporting `❌ No promotion handoff at .canon/tmp/handoff/teach-promotion/<slug>.md. Run the promotion step from the workspace first.`
11
11
 
12
12
  Each block is a page an operator already confirmed a destination for, so this step lands it rather than judging it again. Write to the destination the heading names, at `pwd` rather than at the main root, since every destination here is a tracked file that commits with the branch:
13
13
 
@@ -77,17 +77,17 @@ Source: .canon/teach/<nn>-<topic>/reference/<slug>.md
77
77
 
78
78
  The body is fenced rather than written bare because a reference page carries headings of its own, and the reader splits this file on its H2 lines. An unfenced body turns every section heading in the page into a destination naming no path. Open the body fence with four backticks so a page carrying a fenced code block of its own still closes where it should, and widen both fences together if it carries a four-backtick fence.
79
79
 
80
- Derive `<slug>` per `${CLAUDE_SKILL_DIR}/../../standards/slug.md`. Fall back to `latest` on an empty result.
80
+ Derive `<slug>` per `${CLAUDE_SKILL_DIR}/../git-branch/references/slug.md`. Fall back to `latest` on an empty result.
81
81
 
82
82
  The handoff is its own file rather than a shared one. The routed-facts file another skill writes is deleted by whichever pass folds it, so a second producer's unread work goes with it, and a sibling path costs the folding skill one more read and removes the interaction.
83
83
 
84
- An append is a whole-file operation, so send it as a heredoc, per the skill's Step 0. Then tell the operator that `/context-fold` folds the file in from a branch. The proposal costs nothing tracked and runs anywhere, while the page it describes is a tracked file, so the fold is a worktree operation and the workspace it came from is not.
84
+ An append is a whole-file operation, so send it as a heredoc, per the skill's Step 0. Then tell the operator that `/teach-workspace fold` folds the file in from a branch. The proposal costs nothing tracked and runs anywhere, while the page it describes is a tracked file, so the fold is a worktree operation and the workspace it came from is not.
85
85
 
86
86
  A promotion pass reports this shape in place of the skill's Output block, one line per page the operator confirmed and one naming the handoff:
87
87
 
88
88
  ```plaintext
89
89
  ➡️ Promoting: .canon/teach/<nn>-<topic>/reference/<slug>.md → <destination path>
90
- → Confirmed pages wait at .canon/tmp/handoff/teach-promotion/<slug>.md. Run /context-fold from a branch to fold them in.
90
+ → Confirmed pages wait at .canon/tmp/handoff/teach-promotion/<slug>.md. Run /teach-workspace fold from a branch to fold them in.
91
91
  ```
92
92
 
93
93
  A pass where the operator confirmed nothing writes no handoff file and reports that alone.
@@ -61,7 +61,7 @@ Omit the heading when every automatable change is covered.
61
61
 
62
62
  ## Persist the checklist
63
63
 
64
- Derive `<slug>` per `${CLAUDE_SKILL_DIR}/../../standards/slug.md`. Fall back to `latest` on an empty result.
64
+ Derive `<slug>` per `${CLAUDE_SKILL_DIR}/../git-branch/references/slug.md`. Fall back to `latest` on an empty result.
65
65
 
66
66
  When a checklist is produced, write it directly to `.canon/tmp/handoff/ui-checklist/<slug>.md` at the main worktree root, not the current worktree. Resolve that root the way `session-worktree` does. Create the directory if it does not exist. Always overwrite. This is a handoff file rather than a deliverable: `git-pr` renders it into the evidence comment once a pull request opens, then removes it, and nothing here talks to `gh` directly.
67
67
 
@@ -61,7 +61,7 @@ If nothing is wrong, use: `✅ No observations.`
61
61
 
62
62
  ### Persist
63
63
 
64
- Derive `<slug>` per `${CLAUDE_SKILL_DIR}/../../standards/slug.md`. Fall back to `latest` on an empty result.
64
+ Derive `<slug>` per `${CLAUDE_SKILL_DIR}/../git-branch/references/slug.md`. Fall back to `latest` on an empty result.
65
65
 
66
66
  Write the full report directly to `.canon/review/ux-audit-<slug>.md` at the main worktree root, not the current worktree. Resolve that root the way `session-worktree` does. Create the directory if it does not exist. Always overwrite.
67
67
 
@@ -108,7 +108,7 @@ Report the reading and stop there. A remedy for a poor verdict is a change with
108
108
 
109
109
  ### Persist
110
110
 
111
- Derive `<slug>` per `${CLAUDE_SKILL_DIR}/../../standards/slug.md`. Fall back to `latest` on an empty result.
111
+ Derive `<slug>` per `${CLAUDE_SKILL_DIR}/../git-branch/references/slug.md`. Fall back to `latest` on an empty result.
112
112
 
113
113
  Write the full reading directly to `.canon/review/ux-measure-<slug>.md` at the main worktree root, not the current worktree. Resolve that root the way `session-worktree` does. Create the directory if it does not exist. Always overwrite.
114
114
 
@@ -5,7 +5,7 @@ description: The canvas server, its content format, and the verbs that list, arr
5
5
 
6
6
  # Canvas
7
7
 
8
- `canon canvas` serves a local canvas of pages and HTML frames and gives an agent the verbs the operator's mouse has. A page is a folder under `.canon/canvas/`, a frame is one HTML file in it, and `layout.json` beside them holds each frame's box. `claude/skills/canvas/references/canvas.md` fixes that content format, and the `canvas` skill carries the procedure a session follows to drive the canvas.
8
+ `canon canvas` serves a local canvas of pages and HTML frames and gives an agent the verbs the operator's mouse has. A page is a folder under `.canon/canvas/`, a frame is one HTML file in it, and `layout.json` beside them holds each frame's box. `claude/skills/canvas-board/references/canvas.md` fixes that content format, and the `canvas-board` skill carries the procedure a session follows to drive the canvas.
9
9
 
10
10
  ## Serve
11
11
 
@@ -108,7 +108,7 @@ Each domain exposes a consistent shape where applicable: `list`, `install`, `syn
108
108
  - `gate`, in `gate.md`: `run`
109
109
  - `secrets`, in `state-scoped-risk.md`: `scan`
110
110
  - `deps`, in `state-scoped-risk.md`: `audit`
111
- - `labels`, in `label-coverage.md`: `audit`, `scan`
111
+ - `labels`, in `label-coverage.md`: `audit`, `apply`, `scan`
112
112
  - `comments`, in `comments.md`: `scan`
113
113
  - `context`, in `context-audit.md`: `audit`, `classify diff`, `classify sweep`, `classifier show`, `classifier set`
114
114
  - `markdown`, in `markdown-audit.md`: `audit`
@@ -129,7 +129,8 @@ Subcommands no other page describes:
129
129
  - `slides render [deck]` takes a deck name or a folder, defaulting to the only deck, and lays out each `.html` file in filename order in Chromium at 1280 by 720 and rebuilds it as editable shapes. Each element drawn as a picture prints one `✗` line on stderr naming the slide, the selector, and the properties that forced it. A link left out, being a `#slide-N` past the deck's end or any target that is neither that nor an absolute URL, prints one too, and the exit stays 0.
130
130
  - A deck folder's `deck.json` and the faces it embeds, its per-slide `<body>` attributes, transitions and entrances, speaker notes, and charts are described in `slides.md`.
131
131
  - `canvas`, with its verbs, content format, and write routes, is described in `canvas.md`.
132
- - `labels scan` fails a pull request or a posted review whose title, body, or review comment carries a phase label, a label a code span quotes, a gitignored record path, a session link, a title word no dictionary holds, or a title breaking `standards/pr.md`'s format, casing, or length rule (`--event`, `--body-file`, `--json`).
132
+ - `labels apply <number>` adds the labels this branch earns to its open pull request, refusing a pull request whose head is not the current branch or that is not open, and never creating a label the remote lacks or removing one a person added (`--check` writes nothing and exits 2 when labels are owed, `--base`, `--json`).
133
+ - `labels scan` fails a pull request or a posted review whose title, body, or review comment carries a phase label, a label a code span quotes, a gitignored record path, a session link, a banned character, a body heading outside the closed section list or a missing `## Summary` or `## Key changes`, a title word no dictionary holds, or a title breaking `claude/skills/git-pr/references/pr.md`'s format, casing, or length rule (`--event`, `--body-file`, `--json`).
133
134
 
134
135
  ## Version skew
135
136