@erclx/canon 5.26.0 → 5.27.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 (242) hide show
  1. package/README.md +2 -2
  2. package/claude/.claude-plugin/plugin.json +1 -1
  3. package/claude/skills/api-design/SKILL.md +2 -0
  4. package/claude/skills/auto-ship/SKILL.md +3 -11
  5. package/claude/skills/auto-ship/references/review-findings.md +20 -0
  6. package/claude/skills/backlog-triage/SKILL.md +2 -0
  7. package/claude/skills/bash-cli-script/SKILL.md +2 -0
  8. package/claude/skills/build-in-slices/SKILL.md +2 -0
  9. package/claude/skills/canon-cli/SKILL.md +2 -0
  10. package/claude/skills/canon-feedback/SKILL.md +2 -0
  11. package/claude/skills/canon-feedback-triage/SKILL.md +2 -0
  12. package/claude/skills/canon-operator/SKILL.md +2 -0
  13. package/claude/skills/canon-rollout/SKILL.md +3 -11
  14. package/claude/skills/canon-rollout/references/failure-recovery.md +20 -0
  15. package/claude/skills/canvas/SKILL.md +13 -0
  16. package/claude/skills/ci-workflow/SKILL.md +2 -0
  17. package/claude/skills/code-craft/SKILL.md +2 -0
  18. package/claude/skills/codebase-layout/SKILL.md +2 -0
  19. package/claude/skills/context-fold/SKILL.md +3 -17
  20. package/claude/skills/context-fold/references/completion-report.md +26 -0
  21. package/claude/skills/create-rule/SKILL.md +2 -0
  22. package/claude/skills/create-skill/SKILL.md +2 -0
  23. package/claude/skills/create-standard/SKILL.md +2 -0
  24. package/claude/skills/decision-escalate/SKILL.md +2 -0
  25. package/claude/skills/deploy-app/SKILL.md +2 -0
  26. package/claude/skills/deprecation-migration/SKILL.md +2 -0
  27. package/claude/skills/design-extract/SKILL.md +2 -0
  28. package/claude/skills/design-taste/SKILL.md +2 -0
  29. package/claude/skills/docs-sync/SKILL.md +2 -0
  30. package/claude/skills/document-health/SKILL.md +2 -0
  31. package/claude/skills/draft-and-pick/SKILL.md +2 -0
  32. package/claude/skills/draft-doc/SKILL.md +2 -0
  33. package/claude/skills/draft-doc/references/wiki.md +1 -1
  34. package/claude/skills/draft-figure/SKILL.md +2 -0
  35. package/claude/skills/draft-identity/SKILL.md +2 -0
  36. package/claude/skills/draft-ready/SKILL.md +2 -0
  37. package/claude/skills/draft-screencast/SKILL.md +2 -0
  38. package/claude/skills/draft-slides/SKILL.md +2 -0
  39. package/claude/skills/git-branch/SKILL.md +2 -0
  40. package/claude/skills/git-commit/SKILL.md +2 -0
  41. package/claude/skills/git-followup/SKILL.md +2 -0
  42. package/claude/skills/git-issue/SKILL.md +2 -0
  43. package/claude/skills/git-pr/SKILL.md +2 -0
  44. package/claude/skills/git-pr/references/evidence.md +6 -6
  45. package/claude/skills/git-ship/SKILL.md +2 -0
  46. package/claude/skills/git-split/SKILL.md +2 -0
  47. package/claude/skills/git-stage/SKILL.md +2 -0
  48. package/claude/skills/git-worktree/SKILL.md +2 -0
  49. package/claude/skills/index-lookup/SKILL.md +2 -0
  50. package/claude/skills/markdown-propose/SKILL.md +2 -0
  51. package/claude/skills/memory-capture/SKILL.md +2 -0
  52. package/claude/skills/memory-review/SKILL.md +2 -0
  53. package/claude/skills/plan-feature/SKILL.md +2 -0
  54. package/claude/skills/plan-groundwork/SKILL.md +2 -0
  55. package/claude/skills/plan-intake/SKILL.md +2 -0
  56. package/claude/skills/plan-intake-answer/SKILL.md +2 -0
  57. package/claude/skills/project-commands/SKILL.md +2 -0
  58. package/claude/skills/read-frames/SKILL.md +2 -0
  59. package/claude/skills/record-screencast/SKILL.md +2 -0
  60. package/claude/skills/repo-metadata/SKILL.md +2 -0
  61. package/claude/skills/restate-plainly/SKILL.md +2 -0
  62. package/claude/skills/review-address/SKILL.md +3 -7
  63. package/claude/skills/review-address/references/post-review-findings.md +16 -0
  64. package/claude/skills/review-branch/SKILL.md +2 -0
  65. package/claude/skills/review-craft/SKILL.md +2 -0
  66. package/claude/skills/review-craft/references/ui.md +2 -2
  67. package/claude/skills/review-pr/SKILL.md +4 -8
  68. package/claude/skills/review-pr/references/body-variants.md +52 -0
  69. package/claude/skills/review-pr/references/key-changes.md +16 -0
  70. package/claude/skills/review-pr/references/post.md +15 -43
  71. package/claude/skills/review-ui/SKILL.md +3 -1
  72. package/claude/skills/role-orchestrator/SKILL.md +5 -14
  73. package/claude/skills/role-orchestrator/references/orchestrator-handback.md +1 -1
  74. package/claude/skills/role-orchestrator/references/orchestrator-inbound.md +23 -0
  75. package/claude/skills/role-orchestrator/references/orchestrator-launch.md +5 -33
  76. package/claude/skills/role-orchestrator/references/orchestrator-poll.md +1 -21
  77. package/claude/skills/role-orchestrator/references/orchestrator-review-dispatch.md +1 -1
  78. package/claude/skills/role-orchestrator/references/orchestrator-reviewer-launch.md +38 -0
  79. package/claude/skills/role-orchestrator/references/orchestrator-watch.md +26 -0
  80. package/claude/skills/role-planner/SKILL.md +2 -0
  81. package/claude/skills/role-reviewer/REQUIREMENT.md +1 -1
  82. package/claude/skills/role-reviewer/SKILL.md +2 -0
  83. package/claude/skills/role-worker/SKILL.md +2 -0
  84. package/claude/skills/search-craft/SKILL.md +2 -0
  85. package/claude/skills/seed-sync/SKILL.md +2 -0
  86. package/claude/skills/session-compact/SKILL.md +2 -0
  87. package/claude/skills/session-map/SKILL.md +2 -0
  88. package/claude/skills/session-relay/SKILL.md +2 -0
  89. package/claude/skills/session-resume/SKILL.md +2 -0
  90. package/claude/skills/session-worktree/SKILL.md +3 -11
  91. package/claude/skills/session-worktree/references/install-command.md +20 -0
  92. package/claude/skills/sketch-design/SKILL.md +2 -0
  93. package/claude/skills/systematic-debugging/SKILL.md +2 -0
  94. package/claude/skills/target-check/SKILL.md +2 -0
  95. package/claude/skills/target-setup/SKILL.md +2 -0
  96. package/claude/skills/task-board/SKILL.md +2 -0
  97. package/claude/skills/teach-workspace/SKILL.md +5 -15
  98. package/claude/skills/teach-workspace/references/lesson-build.md +75 -0
  99. package/claude/skills/teach-workspace/references/lesson-craft.md +13 -69
  100. package/claude/skills/teach-workspace/references/revisit.md +22 -0
  101. package/claude/skills/test-craft/SKILL.md +2 -0
  102. package/claude/skills/test-first/SKILL.md +2 -0
  103. package/claude/skills/ui-checklist/SKILL.md +2 -0
  104. package/claude/skills/ux-audit/SKILL.md +2 -0
  105. package/claude/skills/ux-measure/SKILL.md +2 -0
  106. package/claude/skills/ux-walkthrough/SKILL.md +2 -0
  107. package/claude/skills/video-craft/SKILL.md +2 -0
  108. package/claude/skills/write-human/SKILL.md +2 -0
  109. package/claude/skills/youtube-transcripts/SKILL.md +2 -0
  110. package/docs/agents/canvas.md +23 -7
  111. package/docs/agents/capture.md +5 -5
  112. package/docs/agents/commands.md +2 -2
  113. package/docs/agents/index.md +3 -3
  114. package/docs/agents/install-and-sync.md +7 -0
  115. package/docs/agents/key-changes.md +1 -1
  116. package/docs/agents/pr-evidence.md +38 -15
  117. package/docs/agents/pr-local.md +19 -13
  118. package/docs/agents/pr-preview.md +44 -21
  119. package/docs/agents/sandbox.md +28 -4
  120. package/docs/agents/scripting.md +8 -1
  121. package/docs/agents/skills-audit.md +2 -1
  122. package/docs/workflow/operating-model.md +5 -6
  123. package/docs/workflow/parallel-features.md +22 -1
  124. package/docs/workflow/skill-map.md +3 -1
  125. package/docs/workflow/zshrc-aliases.md +1 -1
  126. package/package.json +1 -1
  127. package/scripts/core/regen-hero.ts +1 -1
  128. package/scripts/lib/sandbox-path.sh +6 -162
  129. package/src/audits/run.ts +1 -1
  130. package/src/canvas/address.ts +12 -3
  131. package/src/canvas/client/inspector/align-grid.tsx +162 -0
  132. package/src/canvas/client/inspector/color-field.tsx +201 -171
  133. package/src/canvas/client/inspector/color-inputs.tsx +139 -0
  134. package/src/canvas/client/inspector/color-picker.tsx +668 -0
  135. package/src/canvas/client/inspector/color-space.ts +240 -0
  136. package/src/canvas/client/inspector/field.tsx +5 -1
  137. package/src/canvas/client/inspector/fields.css +395 -6
  138. package/src/canvas/client/inspector/size-field.tsx +69 -0
  139. package/src/canvas/client/inspector/values.ts +43 -1
  140. package/src/canvas/client/inspector.tsx +190 -4
  141. package/src/canvas/client/selection.tsx +197 -0
  142. package/src/canvas/client/shell.css +104 -12
  143. package/src/canvas/client/state.ts +69 -9
  144. package/src/canvas/client/surface.tsx +147 -22
  145. package/src/canvas/content.ts +50 -1
  146. package/src/canvas/edit.ts +37 -4
  147. package/src/canvas/editing.ts +203 -0
  148. package/src/canvas/global.d.ts +15 -0
  149. package/src/canvas/server.ts +149 -12
  150. package/src/canvas/tokens.ts +59 -17
  151. package/src/census/count.ts +1 -1
  152. package/src/claude/seeds.ts +1 -1
  153. package/src/claude/skills-audit.ts +28 -0
  154. package/src/claude/skills-drift.ts +1 -1
  155. package/src/claude/skills-families.ts +36 -0
  156. package/src/claude/skills-list.ts +76 -15
  157. package/src/commands/audits.ts +2 -2
  158. package/src/commands/canvas.ts +179 -2
  159. package/src/commands/claude.ts +67 -9
  160. package/src/commands/design.ts +142 -2
  161. package/src/commands/gov.ts +1 -1
  162. package/src/commands/hooks.ts +1 -1
  163. package/src/commands/indexes.ts +1 -1
  164. package/src/commands/init.ts +1 -1
  165. package/src/commands/intake.ts +1 -1
  166. package/src/commands/migrate.ts +1 -1
  167. package/src/commands/pr.ts +105 -58
  168. package/src/commands/records.ts +1 -1
  169. package/src/commands/repo.ts +1 -1
  170. package/src/commands/sandbox.ts +54 -2
  171. package/src/commands/sessions.ts +1 -1
  172. package/src/commands/sync.ts +1 -1
  173. package/src/commands/tasks.ts +2 -2
  174. package/src/commands/teach.ts +1 -1
  175. package/src/commands/transcripts.ts +1 -1
  176. package/src/commands/worktrees.ts +1 -1
  177. package/src/comments/scan.ts +1 -1
  178. package/src/comments/trend.ts +1 -1
  179. package/src/context/citations.ts +1 -1
  180. package/src/context/classify/extract.ts +2 -2
  181. package/src/design/project-fonts.ts +392 -0
  182. package/src/feedback/github.ts +1 -1
  183. package/src/gate/measures.ts +47 -9
  184. package/src/gate/sequencer.ts +1 -1
  185. package/src/gate/stages.ts +9 -0
  186. package/src/{git-files.ts → git/files.ts} +2 -2
  187. package/src/{git-ignore.ts → git/ignore.ts} +1 -1
  188. package/src/{worktree.ts → git/worktree.ts} +1 -1
  189. package/src/gov/citations.ts +1 -1
  190. package/src/gov/install.ts +1 -1
  191. package/src/gov/superseded.ts +1 -1
  192. package/src/gov/test-order.ts +2 -2
  193. package/src/help.ts +1 -1
  194. package/src/hooks/post-merge.ts +1 -1
  195. package/src/indexes/walk.ts +1 -1
  196. package/src/labels/audit.ts +1 -1
  197. package/src/markdown/files.ts +1 -1
  198. package/src/migrate/apply.ts +1 -1
  199. package/src/pr/bijection.ts +1 -1
  200. package/src/pr/evidence.ts +96 -43
  201. package/src/pr/local.ts +16 -10
  202. package/src/pr/preview.ts +78 -2
  203. package/src/records/backup.ts +1 -1
  204. package/src/records/stale-canonical.ts +1 -1
  205. package/src/sandbox/headless/dispatch.ts +264 -0
  206. package/src/sandbox/headless/run.ts +653 -0
  207. package/src/sandbox/headless/watch.ts +145 -0
  208. package/src/sandbox/provision.ts +12 -1
  209. package/src/sandbox/tree.ts +4 -8
  210. package/src/secrets/scan.ts +1 -1
  211. package/src/sessions/claim.ts +1 -1
  212. package/src/sessions/resolve.ts +1 -1
  213. package/src/sessions/transfer/bundle.ts +1 -1
  214. package/src/slides/package/fonts.ts +6 -2
  215. package/src/standards/audit.ts +2 -2
  216. package/src/sync/check.ts +2 -2
  217. package/src/sync/engine.ts +2 -2
  218. package/src/sync/git.ts +1 -1
  219. package/src/sync/history.ts +1 -1
  220. package/src/sync/reverse.ts +1 -1
  221. package/src/sync/target.ts +1 -1
  222. package/src/sync/workflow.ts +1 -1
  223. package/src/targets/pulls.ts +2 -2
  224. package/src/targets/sweep.ts +2 -2
  225. package/src/tasks/reach.ts +1 -1
  226. package/src/tasks/trunk.ts +1 -1
  227. package/src/tooling/inject.ts +1 -1
  228. package/src/tooling/subfolder.ts +1 -1
  229. package/src/web/readme-citations.ts +1 -1
  230. package/src/worktrees/bare-flag.ts +1 -1
  231. package/src/worktrees/reclaim.ts +2 -2
  232. package/src/worktrees/remove.ts +1 -1
  233. package/standards/canvas.md +2 -1
  234. package/standards/skill.md +1 -0
  235. package/standards/wiki.md +12 -3
  236. package/tooling/base/configs/.github/workflows/pr-local-preview.yml +2 -2
  237. package/scripts/lib/sandbox-dispatch.sh +0 -190
  238. /package/src/{client-commands.ts → gate/client-commands.ts} +0 -0
  239. /package/src/{git-base.ts → git/base.ts} +0 -0
  240. /package/src/{git-env.ts → git/env.ts} +0 -0
  241. /package/src/{copy.ts → sync/copy.ts} +0 -0
  242. /package/src/{target.ts → targets/validate.ts} +0 -0
@@ -1,9 +1,9 @@
1
1
  ---
2
2
  title: Orchestrator launch runbook
3
- description: The launch every dispatch kind shares, being the build, cloud build, review-address, planning, reviewer, and UI reviewer templates, the session name and controller id each carries, why the command sits at position zero, and what the brief may carry
3
+ description: The launch every dispatch kind shares, being the build, cloud build, review-address, and planning templates, the session name and controller id each carries, why the command sits at position zero, and what the brief may carry
4
4
  ---
5
5
 
6
- Run this once `orchestrator-dispatch.md` has cleared a row, or from its planning, review-address, or reviewer shape below when that runbook's checks do not bind. The model each template names comes from `## Pick the model` in that runbook.
6
+ Run this once `orchestrator-dispatch.md` has cleared a row, or from its planning or review-address shape below when that runbook's checks do not bind. The model each template names comes from `## Pick the model` in that runbook.
7
7
 
8
8
  ## Dispatch
9
9
 
@@ -34,7 +34,7 @@ Put a command whose skill carries `disable-model-invocation: true` at position z
34
34
 
35
35
  Never depend on the `Skill` tool route for a flagged skill. A refusal there tells the session not to replicate the workflow by other means, so a refused worker stops with a clean worktree, which is the correct outcome. The refusal is sticky inside a session, so recovery belongs to whoever writes the next prompt: re-dispatch onto the same branch with the build template above.
36
36
 
37
- The review-address, planning, and reviewer shapes below depend on no expansion at all. None of `role-worker`, `review-address`, `role-planner`, `plan-feature`, `role-reviewer`, or `review-pr` carries the flag, so all three correctly keep their leading word regardless of the delimiter or the position it sits at.
37
+ The review-address and planning shapes below, and the reviewer shapes in `orchestrator-reviewer-launch.md`, depend on no expansion at all. None of `role-worker`, `review-address`, `role-planner`, `plan-feature`, `role-reviewer`, or `review-pr` carries the flag, so all three correctly keep their leading word regardless of the delimiter or the position it sits at.
38
38
 
39
39
  The same rule reaches a human relay. Hand an operator one message carrying one command at position zero, since two chained blocks pasted as separate messages can land as one, where everything after the first command's name reads as that command's argument and the second never fires.
40
40
 
@@ -89,34 +89,6 @@ What a planning dispatch owes instead is the reverse reading, because the plan i
89
89
 
90
90
  One row per dispatch. A session reused across a batch pays the context load once and ages its picture of the tree while it works, which is what puts the in-flight read on the task rather than on the batch, and one that compacts mid-batch loses the reasoning behind its earlier plans with nothing reporting it. Cap a reused session where the saving is worth it and say what the cap was.
91
91
 
92
- ## Dispatch to review a pull request
92
+ ## Dispatch a reviewer
93
93
 
94
- `review-pr` is a single pass rather than a role, so a launch naming it alone reaches no `role-reviewer` and owes no message. Reach the role first on this launch, the way the planning shape reaches `role-planner`. `orchestrator-review-dispatch.md` decides whether a pull request takes this shape at all.
95
-
96
- No branch and no worktree are entered here. The reviewer reads the pull request at the head `review-pr` resolves and writes the comment and its body file alone.
97
-
98
- ```bash
99
- claude --bg --model <model> -n "reviewer-<project>-<number>" "Run /canon:role-reviewer, then /canon:review-pr <number>. Your controller is the session whose sessionId is <dispatcher-id>. Resolve its current name from that id through canon sessions list --json, which carries sessionId per row, at the moment you send, and never resolve an addressee by name prefix. Message it when the pass posts, carrying the heading and the count line, and message it again if you stop on a question."
100
- ```
101
-
102
- `<number>` is the pull request's number, and the brief pins no head, since `review-pr` resolves the head itself and stamps the range it covered in its marker. `<dispatcher-id>`, `<model>`, and `<project>` resolve the same way they do above. Append the cross-branch facts after the controller clause, per `### What the brief may carry`.
103
-
104
- Check `canon sessions list --json` for a live `reviewer-<project>-<number>` before launching, and message that session instead when one holds the pull request.
105
-
106
- ## Dispatch a review to a cloud reviewer
107
-
108
- Read `${CLAUDE_SKILL_DIR}/references/orchestrator-cloud-launch.md` when the operator picked cloud for a code review. Its prompt opens with `/role-reviewer`, carries the cross-branch facts, and makes the posted review the announcement.
109
-
110
- ## Dispatch to drive a pull request's checklist
111
-
112
- `review-ui` is the second pass `role-reviewer` may run, so this shape reaches the role first the way the code reviewer's does. `orchestrator-review-dispatch.md` decides whether a pull request takes it, and it runs beside the code reviewer rather than after it.
113
-
114
- ```bash
115
- claude --bg --model sonnet -n "reviewer-ui-<project>-<number>" "Run /canon:role-reviewer, then /canon:review-ui <number>. Your controller is the session whose sessionId is <dispatcher-id>. Resolve its current name from that id through canon sessions list --json, which carries sessionId per row, at the moment you send, and never resolve an addressee by name prefix. Message it when the pass posts, carrying the heading and the count line, and message it again if you stop on a question."
116
- ```
117
-
118
- The model is fixed at Sonnet rather than taken from `## Pick the model`. A cheaper tier was measured on the same checklist and passed real defects as clean while judging the taste boxes it was told to leave, at a higher cost per run.
119
-
120
- Name an address in the brief only when the evidence record carries no `preview` and no `local` field, as `Drive <url>.` after the controller clause. An address the record already holds is the one the pass reads first, and a second in the brief is a second source for one fact. Name a CLI config path the same way when the operator keeps a GPU recipe for this machine, since the pass renders in software otherwise. Carry nothing else: the UI reviewer reads no diff and no code verdict, so the cross-branch facts the code brief carries stay out of this one.
121
-
122
- `<number>`, `<dispatcher-id>`, and `<project>` resolve the same way they do above. The prefix reads `reviewer-ui-` so a roster read for `reviewer-<project>-<number>` never matches the UI reviewer, and the two passes on one pull request stay two sessions.
94
+ Read `${CLAUDE_SKILL_DIR}/references/orchestrator-reviewer-launch.md` when `orchestrator-review-dispatch.md` sends a pull request to a dispatched reviewer, for the code, cloud, and UI reviewer shapes.
@@ -13,7 +13,7 @@ Start the poll on an open pull request and stop it when the last one merges with
13
13
 
14
14
  A dispatch no longer starts it. The script reads pull requests and a building worker has none, so every interval between the launch and the push is a fixed cost returning nothing, measured as five consecutive runs reporting no movement across roughly fifteen minutes while one worker built. What replaces it is the worker announcing its own pull request the moment it opens one, per the `role-worker` skill that session loads, which covers exactly the transition the poll cannot observe.
15
15
 
16
- The dispatched-worker condition survives as a fallback rather than as a trigger. Start the poll against any dispatch still out after thirty minutes with no announcement, which is past the upper end of the ten to thirty minutes a row here takes. The announcement is newer than the narrowing it justifies, so a silent failure would otherwise leave a finished worker unnoticed the way one already sat idle for eighteen minutes, and the fallback keeps the cover a straight narrowing would have removed. `${CLAUDE_SKILL_DIR}/scripts/watch.ts` covers the same window at a lower cost, since it reads the roster alongside the pull request list and reports a worker that vanished as well as one that finished.
16
+ The dispatched-worker condition survives as a fallback rather than as a trigger. Start the poll against any dispatch still out after thirty minutes with no announcement, which is past the upper end of the ten to thirty minutes a row here takes. The announcement is newer than the narrowing it justifies, so a silent failure would otherwise leave a finished worker unnoticed the way one already sat idle for eighteen minutes, and the fallback keeps the cover a straight narrowing would have removed. `${CLAUDE_SKILL_DIR}/scripts/watch.ts` covers the same window at a lower cost, since it reads the roster alongside the pull request list and reports a worker that vanished as well as one that finished. Read `${CLAUDE_SKILL_DIR}/references/orchestrator-watch.md` before starting it, since it carries the stall alarm and the notification each alarm line owes the operator.
17
17
 
18
18
  A session holding a recurring-prompt scheduler starts the loop itself on that condition and cancels it on the same test, without waiting for the operator. Both halves belong to whoever holds the loop, since a session that can start one can stop one, and a runbook stating only the start leaves the always-on failure unaddressed on the side that causes it.
19
19
 
@@ -80,23 +80,3 @@ The pass now carries its own record instead. `review-pr` writes the commit it re
80
80
  Read `source` on the record before trusting a `SEEN` on a thread whose newest pass is old. `marker` is the read-time record. `fallback` is a pass posted before the mechanism shipped, or a target whose CLI predates the verb, and it carries the defect above unchanged, so a `SEEN` under it is worth one read of the pull's reviews before it is believed. `none` is a thread carrying no pass at all.
81
81
 
82
82
  The other side of that comparison used to lag as well, which made the two errors compound rather than cancel. The pull read's `head.sha` answers from the pull request object and that object trails the branch ref by up to a minute after a push, reporting nothing about the trail, so a pass stamped ahead of the commit it read was compared against a head stamped behind the commit that exists. The head now comes from `canon pr head`, which resolves the tip through `git ls-remote` and reports which commit each source names, and the object's head stays behind it as the fallback for a target whose CLI predates the verb. Both halves of the comparison now answer about a commit somebody named rather than one GitHub stamped, which is what lets a `SEEN` be read as covered.
83
-
84
- ## The watch beside it
85
-
86
- `${CLAUDE_SKILL_DIR}/scripts/watch.ts` is a long-running loop rather than a scheduled prompt, started as `bun <path>`. It reads the open pull request list and the session roster together every sixty seconds and prints one line per new pull request, per worker whose name, branch, or status changed, and per worker that dropped out of the roster. Start it in the background and read what it emits. It writes nothing.
87
-
88
- Coverage is what it buys over the poll. A worker that finishes goes idle and a worker that crashes disappears, so a trigger reading pull requests alone stays silent through the second, and the roster read is the half `poll.ts` cannot make. It ran a full afternoon over four concurrent workers and caught every transition, while the three-minute poll it replaced reported no movement five times in a row.
89
-
90
- It classifies nothing and routes nothing. A line it prints says a pull request opened or a worker moved, and the routing block above is still what decides whether a review follows, so the two compose rather than replace each other.
91
-
92
- Every session in the repository holding a branch other than the base one counts as a worker, whoever launched it. The prototype matched the `orchestrator-` prefix instead, which reads a dispatched worker and misses every hand-launched one. A failed read of either source reports itself on a `watch:` line and leaves the baseline untouched, since reading an empty result as current state would report every worker gone on the pass after.
93
-
94
- ## The stall alarm
95
-
96
- `watch.ts` prints `WORKER-STOPPED <name> <branch> <dwell>s` once a `waiting` row crosses `STALL_THRESHOLD_S`, and `WORKER-UNMEASURABLE <name> <branch>` for one whose record carries neither timestamp the dwell falls back to. Both are prints, not alerts, so the operator learns of one only when a session already reading the loop's output relays it further. The toolkit ships no notification verb, since the surface a stall reaches the operator through is a session tool rather than a command a shell loop can call.
97
-
98
- The two lines carry different confidence and the push has to say so rather than treat them as one signal. `WORKER-STOPPED` fires only once the dwell has already crossed the threshold, so it reports a wait already confirmed long. `WORKER-UNMEASURABLE` has no dwell to threshold on, so it fires on the first pass that meets a `waiting` row carrying neither stamp, whether that row has sat five seconds or fifty minutes.
99
-
100
- On meeting either line, push a notification to the operator through whatever notification surface the client offers, `PushNotification` in this repository's client and one example among the surfaces a different client exposes. Name the worker, the branch, which of the two lines fired, and the dwell where `WORKER-STOPPED` carries one, and send it once per stall the same way `watch.ts` prints it once, rather than repeating it on every interval the row stays stopped.
101
-
102
- The bound stays open. The alarm reaches the operator only through the controller's own read, so a controller mid-turn does not see the line for as long as the turn runs, and a controller that is itself stopped never does. Neither case closes here, since the watch loop and the notification surface both live inside the same session that has to be free to act on either.
@@ -32,7 +32,7 @@ Hand what it finds to each reviewer as facts in the brief, per `### What the bri
32
32
 
33
33
  ## Launching the reviewer
34
34
 
35
- Take the reviewer shape in `orchestrator-launch.md`, or its UI reviewer shape for the UI trigger. Check `canon sessions list --json` for a live `reviewer-<project>-<number>`, or `reviewer-ui-<project>-<number>`, first and message it instead of launching a second, since two reviewers on one pull request post two verdicts. The re-review after a worker's address pass goes back the same way, per `orchestrator-handback.md`.
35
+ Take the reviewer shape in `orchestrator-reviewer-launch.md`, or its UI reviewer shape for the UI trigger. Check `canon sessions list --json` for a live `reviewer-<project>-<number>`, or `reviewer-ui-<project>-<number>`, first and message it instead of launching a second, since two reviewers on one pull request post two verdicts. The re-review after a worker's address pass goes back the same way, per `orchestrator-handback.md`.
36
36
 
37
37
  ## Local or cloud
38
38
 
@@ -0,0 +1,38 @@
1
+ ---
2
+ title: Orchestrator reviewer launch runbook
3
+ description: The launch shapes that start a reviewer rather than a builder, being the code reviewer, the cloud reviewer, and the UI reviewer driving a pull request's checklist
4
+ ---
5
+
6
+ Run this once `orchestrator-review-dispatch.md` has sent a pull request to a dispatched reviewer. The build, review-address, and planning shapes, and the rules every launch shares, stay in `orchestrator-launch.md`.
7
+
8
+ ## Dispatch to review a pull request
9
+
10
+ `review-pr` is a single pass rather than a role, so a launch naming it alone reaches no `role-reviewer` and owes no message. Reach the role first on this launch, the way the planning shape in `orchestrator-launch.md` reaches `role-planner`. `orchestrator-review-dispatch.md` decides whether a pull request takes this shape at all.
11
+
12
+ No branch and no worktree are entered here. The reviewer reads the pull request at the head `review-pr` resolves and writes the comment and its body file alone.
13
+
14
+ ```bash
15
+ claude --bg --model <model> -n "reviewer-<project>-<number>" "Run /canon:role-reviewer, then /canon:review-pr <number>. Your controller is the session whose sessionId is <dispatcher-id>. Resolve its current name from that id through canon sessions list --json, which carries sessionId per row, at the moment you send, and never resolve an addressee by name prefix. Message it when the pass posts, carrying the heading and the count line, and message it again if you stop on a question."
16
+ ```
17
+
18
+ `<number>` is the pull request's number, and the brief pins no head, since `review-pr` resolves the head itself and stamps the range it covered in its marker. `<dispatcher-id>`, `<model>`, and `<project>` resolve the same way they do in `orchestrator-launch.md`. Append the cross-branch facts after the controller clause, per `### What the brief may carry` in that runbook.
19
+
20
+ Check `canon sessions list --json` for a live `reviewer-<project>-<number>` before launching, and message that session instead when one holds the pull request.
21
+
22
+ ## Dispatch a review to a cloud reviewer
23
+
24
+ Read `${CLAUDE_SKILL_DIR}/references/orchestrator-cloud-launch.md` when the operator picked cloud for a code review. Its prompt opens with `/role-reviewer`, carries the cross-branch facts, and makes the posted review the announcement.
25
+
26
+ ## Dispatch to drive a pull request's checklist
27
+
28
+ `review-ui` is the second pass `role-reviewer` may run, so this shape reaches the role first the way the code reviewer's does. `orchestrator-review-dispatch.md` decides whether a pull request takes it, and it runs beside the code reviewer rather than after it.
29
+
30
+ ```bash
31
+ claude --bg --model sonnet -n "reviewer-ui-<project>-<number>" "Run /canon:role-reviewer, then /canon:review-ui <number>. Your controller is the session whose sessionId is <dispatcher-id>. Resolve its current name from that id through canon sessions list --json, which carries sessionId per row, at the moment you send, and never resolve an addressee by name prefix. Message it when the pass posts, carrying the heading and the count line, and message it again if you stop on a question."
32
+ ```
33
+
34
+ The model is fixed at Sonnet rather than taken from `## Pick the model` in `orchestrator-dispatch.md`. A cheaper tier was measured on the same checklist and passed real defects as clean while judging the taste boxes it was told to leave, at a higher cost per run.
35
+
36
+ Name an address in the brief only when the evidence record carries no `preview` and no `local` field, as `Drive <url>.` after the controller clause. An address the record already holds is the one the pass reads first, and a second in the brief is a second source for one fact. Name a CLI config path the same way when the operator keeps a GPU recipe for this machine, since the pass renders in software otherwise. Carry nothing else: the UI reviewer reads no diff and no code verdict, so the cross-branch facts the code brief carries stay out of this one.
37
+
38
+ `<number>`, `<dispatcher-id>`, and `<project>` resolve the same way they do in `orchestrator-launch.md`. The prefix reads `reviewer-ui-` so a roster read for `reviewer-<project>-<number>` never matches the UI reviewer, and the two passes on one pull request stay two sessions.
@@ -0,0 +1,26 @@
1
+ ---
2
+ title: Orchestrator watch runbook
3
+ description: The long-running watch that reads pull requests and the session roster together, and the stall alarm it prints for a worker left waiting
4
+ ---
5
+
6
+ Run the watch beside the poll when the dispatch fallback in `orchestrator-poll.md` is in force, or whenever a worker's exit has to be seen as well as its pull request. The poll classifies and routes, and this loop only reports.
7
+
8
+ ## The watch beside it
9
+
10
+ `${CLAUDE_SKILL_DIR}/scripts/watch.ts` is a long-running loop rather than a scheduled prompt, started as `bun <path>`. It reads the open pull request list and the session roster together every sixty seconds and prints one line per new pull request, per worker whose name, branch, or status changed, and per worker that dropped out of the roster. Start it in the background and read what it emits. It writes nothing.
11
+
12
+ Coverage is what it buys over the poll. A worker that finishes goes idle and a worker that crashes disappears, so a trigger reading pull requests alone stays silent through the second, and the roster read is the half `poll.ts` cannot make. It ran a full afternoon over four concurrent workers and caught every transition, while the three-minute poll it replaced reported no movement five times in a row.
13
+
14
+ It classifies nothing and routes nothing. A line it prints says a pull request opened or a worker moved, and the routing block in `orchestrator-poll.md` is still what decides whether a review follows, so the two compose rather than replace each other.
15
+
16
+ Every session in the repository holding a branch other than the base one counts as a worker, whoever launched it. The prototype matched the `orchestrator-` prefix instead, which reads a dispatched worker and misses every hand-launched one. A failed read of either source reports itself on a `watch:` line and leaves the baseline untouched, since reading an empty result as current state would report every worker gone on the pass after.
17
+
18
+ ## The stall alarm
19
+
20
+ `watch.ts` prints `WORKER-STOPPED <name> <branch> <dwell>s` once a `waiting` row crosses `STALL_THRESHOLD_S`, and `WORKER-UNMEASURABLE <name> <branch>` for one whose record carries neither timestamp the dwell falls back to. Both are prints, not alerts, so the operator learns of one only when a session already reading the loop's output relays it further. The toolkit ships no notification verb, since the surface a stall reaches the operator through is a session tool rather than a command a shell loop can call.
21
+
22
+ The two lines carry different confidence and the push has to say so rather than treat them as one signal. `WORKER-STOPPED` fires only once the dwell has already crossed the threshold, so it reports a wait already confirmed long. `WORKER-UNMEASURABLE` has no dwell to threshold on, so it fires on the first pass that meets a `waiting` row carrying neither stamp, whether that row has sat five seconds or fifty minutes.
23
+
24
+ On meeting either line, push a notification to the operator through whatever notification surface the client offers, `PushNotification` in this repository's client and one example among the surfaces a different client exposes. Name the worker, the branch, which of the two lines fired, and the dwell where `WORKER-STOPPED` carries one, and send it once per stall the same way `watch.ts` prints it once, rather than repeating it on every interval the row stays stopped.
25
+
26
+ The bound stays open. The alarm reaches the operator only through the controller's own read, so a controller mid-turn does not see the line for as long as the turn runs, and a controller that is itself stopped never does. Neither case closes here, since the watch loop and the notification surface both live inside the same session that has to be free to act on either.
@@ -1,6 +1,8 @@
1
1
  ---
2
2
  name: role-planner
3
3
  description: Asserts the planner role for a session writing one plan, groundwork track, or intake pass under one row, holding what it reads before deciding, what may be written and where, how to read what is already in flight, and what it hands back. Use when asked to "be the planner", "you are a planner session", at the start of a dispatched or hand-launched planning, groundwork, or intake run, or when a planning session needs to know what it may not write. Do NOT use to write the record itself, which is `plan-feature`, `plan-groundwork`, or `plan-intake`, to make the cross-feature merge call, or to implement.
4
+ metadata:
5
+ family: parallel
4
6
  ---
5
7
 
6
8
  # Role planner
@@ -57,7 +57,7 @@ a tree the pull request never changed.
57
57
  - Restate a boundary `role-orchestrator`, `role-worker`, or `role-planner` states about itself
58
58
  - Report progress through the channel, which rebuilds on the sender's side the poll the announcement exists to retire
59
59
  - Post outside `review-pr` and `review-ui`, since every reader of the review headings breaks at once when one pass invents its own
60
- - Be a skill nothing invokes but its author typing the name. `orchestrator-launch.md` names it on the reviewer launch the way it names `role-planner` on a planning one, so a stretch where only a typed invocation reaches it is the signal that the role never took.
60
+ - Be a skill nothing invokes but its author typing the name. `orchestrator-reviewer-launch.md` names it on the reviewer launch the way `orchestrator-launch.md` names `role-planner` on a planning one, so a stretch where only a typed invocation reaches it is the signal that the role never took.
61
61
 
62
62
  ## Guards
63
63
 
@@ -1,6 +1,8 @@
1
1
  ---
2
2
  name: role-reviewer
3
3
  description: Asserts the reviewer role for a session dispatched to review one pull request another session built, holding what it may write, what it reads and never reads, the one message it owes on posting, and the acts it refuses. Use when asked to "be the reviewer", "you are a reviewer session", at the start of a dispatched or hand-launched review of one pull request, or when a reviewing session needs to know what it may not write or who it answers to. Do NOT use to run the pass itself, which is `review-pr` for the code and `review-ui` for the running app, to review local changes, which is `review-branch`, or to make the cross-branch call across a wave.
4
+ metadata:
5
+ family: parallel
4
6
  ---
5
7
 
6
8
  # Role reviewer
@@ -1,6 +1,8 @@
1
1
  ---
2
2
  name: role-worker
3
3
  description: Asserts the worker role for a building session, holding the boundary set, the lifetime, and the two channel obligations a session owes whoever dispatched it. Use when asked to "be the worker", "you are a worker session", at the start of a dispatched or hand-launched build, or when a building session needs to know what it may not write. Do NOT use to plan the next feature, to run the independent review pass, or to merge.
4
+ metadata:
5
+ family: parallel
4
6
  ---
5
7
 
6
8
  # Role worker
@@ -1,6 +1,8 @@
1
1
  ---
2
2
  name: search-craft
3
3
  description: Carries the thinking step a session takes before it searches outside the project, naming the field, deriving who that field treats as authoritative, and running a search scoped to those sources beside an open one, plus a dated note on which sites refuse access. Use before any outside search for evidence, papers, documentation, statistics, or opinion, when a procedure loads it at its sourcing step, or when asked "find me the strongest evidence on X", "where should I look for this", "what does the research say", "find papers on", "look up the docs for", or "what are people saying about". Do NOT use to format a citation, which belongs to the surface writing it, to source a Claude Code subject, which is the `claude-code-guide` agent, or to generate an image, which is not search.
4
+ metadata:
5
+ family: build
4
6
  ---
5
7
 
6
8
  # Search craft
@@ -1,6 +1,8 @@
1
1
  ---
2
2
  name: seed-sync
3
3
  description: Audits a project's installed Claude seed docs against the toolkit's current seed source and proposes per-section edits without overwriting customizations. Use when asked to "sync seeds", "update my seeds", "check seed drift", "did the toolkit seeds change", or when reconciling `CLAUDE.md` and `.claude/` preambles after an upstream toolkit update.
4
+ metadata:
5
+ family: upkeep
4
6
  ---
5
7
 
6
8
  # Seed sync
@@ -1,6 +1,8 @@
1
1
  ---
2
2
  name: session-compact
3
3
  description: Captures a session's memory, then writes one handoff note to .canon/compact/ so the session after a compaction picks up where this one stopped. Use before running /compact, when asked to "write a handoff", "prepare for compaction", "save where we got to", or before moving a session to another machine, or when a PreCompact hook blocks and names this skill. Do NOT use for a session holding the orchestrator role, whose board handoff is `session-map`. Do NOT use to record a decision a groundwork track owns, which is `plan-groundwork`.
4
+ metadata:
5
+ family: parallel
4
6
  ---
5
7
 
6
8
  # Session compact
@@ -1,6 +1,8 @@
1
1
  ---
2
2
  name: session-map
3
3
  description: Writes the session map, the board-side handoff at `.canon/tasks/session-<slug>.md`, for an orchestrating session or on a request naming the session map or the task board, running the skill-drift step the write procedure opens with. Use when asked to "write the session map", "write the board handoff", or when a session holding `canon:role-orchestrator` hands off before a compaction. Do NOT use for a plain session about to compact, which is `session-compact` and writes a note outside the board. Do NOT use to route session facts to a context entry or the memory folder, which is `memory-capture` and writes a different artifact, and do NOT use to read a handoff back, which is `session-resume`.
4
+ metadata:
5
+ family: parallel
4
6
  ---
5
7
 
6
8
  # Session map
@@ -1,6 +1,8 @@
1
1
  ---
2
2
  name: session-relay
3
3
  description: Relays a message to another session, turning the sessionId the caller named into an address at the moment of sending and composing a copyable block where no send tool exists. Use when asked to "relay this", "message the controller", "send this over to the session that dispatched me", or "tell the other session", with or without a role, and when a session stuck on a question owes the session that dispatched it a message before it stops to ask. Do NOT use to decide what the message says, and do NOT use to assert what a session may write or is on the hook for, which is `role-worker` or `role-planner`.
4
+ metadata:
5
+ family: parallel
4
6
  ---
5
7
 
6
8
  # Session relay
@@ -1,6 +1,8 @@
1
1
  ---
2
2
  name: session-resume
3
3
  description: Resumes a previous session by reading the handoff it left behind, tracked work, and relevant context. Use when starting a new session, or when asked to "pick up where we left off", "what was I working on", or "resume".
4
+ metadata:
5
+ family: parallel
4
6
  ---
5
7
 
6
8
  # Session resume
@@ -1,6 +1,8 @@
1
1
  ---
2
2
  name: session-worktree
3
3
  description: Enters a Claude Code worktree at `.claude/worktrees/<name>/` with a name derived from the active plan or branch. Use when asked to "enter a worktree", "start a worktree", "work in a worktree", or at the plan-to-execute boundary after `/plan-feature`. Also use when an `Edit` or `Write` to a main-root file such as a plan, a task, or a memory entry was refused for session isolation. Do NOT use to list, clean up, or rotate worktrees (use `git-worktree`).
4
+ metadata:
5
+ family: build
4
6
  ---
5
7
 
6
8
  # Session worktree
@@ -125,17 +127,7 @@ Read the worktree root and evaluate node and python independently against a lite
125
127
 
126
128
  Name the ecosystem in both installed lines rather than leaving `Dependencies are installed.` unqualified. Both checks can fire on one project, so an unqualified line reported the same sentence twice for a dual-root project with both folders present, and a reader could not tell which half each line answered.
127
129
 
128
- Take `<install>` from the lockfile beside the manifest, checked in this order, first match wins:
129
-
130
- | Lockfile | Install command |
131
- | ------------------------- | --------------- |
132
- | `bun.lock` or `bun.lockb` | `bun install` |
133
- | `pnpm-lock.yaml` | `pnpm install` |
134
- | `yarn.lock` | `yarn install` |
135
- | `package-lock.json` | `npm install` |
136
- | none of the above | `bun install` |
137
-
138
- The order matters only when more than one lockfile sits beside the manifest, such as a project mid-migration between package managers. It is fixed rather than derived from anything about the project, so a reader hitting that rare case checks which manager the project actually uses rather than trusting the row the table picked first.
130
+ Take `<install>` from the lockfile beside the manifest. Read `${CLAUDE_SKILL_DIR}/references/install-command.md` when the Node line reports dependencies not installed, for the order the lockfiles are checked in and the command each one names.
139
131
 
140
132
  Emit the closing line only on its own direct test, run ahead of the two checks above rather than reached by falling through them unmatched: `[ ! -f package.json ] && [ ! -f pyproject.toml ] && [ ! -f requirements.txt ]`: `No package manifest, so there is nothing to install.` A dual-root project matches both checks above, and a fallthrough test would route it here by accident.
141
133
 
@@ -0,0 +1,20 @@
1
+ ---
2
+ title: Install command
3
+ description: Which install command session-worktree Step 6 names when a Node worktree has no dependencies, read off the lockfile beside the manifest in a fixed order
4
+ ---
5
+
6
+ # Name the install command
7
+
8
+ Part of Step 6 of `session-worktree`. The session reads this file when the Node check reports dependencies not installed, to fill `<install>` in that line.
9
+
10
+ Take `<install>` from the lockfile beside the manifest, checked in this order, first match wins:
11
+
12
+ | Lockfile | Install command |
13
+ | ------------------------- | --------------- |
14
+ | `bun.lock` or `bun.lockb` | `bun install` |
15
+ | `pnpm-lock.yaml` | `pnpm install` |
16
+ | `yarn.lock` | `yarn install` |
17
+ | `package-lock.json` | `npm install` |
18
+ | none of the above | `bun install` |
19
+
20
+ The order matters only when more than one lockfile sits beside the manifest, such as a project mid-migration between package managers. It is fixed rather than derived from anything about the project, so a reader hitting that rare case checks which manager the project actually uses rather than trusting the row the table picked first.
@@ -1,6 +1,8 @@
1
1
  ---
2
2
  name: sketch-design
3
3
  description: Runs a reference-and-pick loop against operator-supplied images and URLs, then writes the picked reference's traced color, type, and spacing values to a handoff file `design-extract` reads. Use when asked to "sketch a design direction", "compare these reference sites", "pick a look before we build DESIGN.md", "show me a few design directions", or as the first move on `design-extract`'s greenfield path when nothing has been rendered yet. Do NOT use when a value is already anchored to running code or a stylesheet, which is `design-extract`'s source path, or to draft the design system document itself, which stays `design-extract`'s job.
4
+ metadata:
5
+ family: setup
4
6
  ---
5
7
 
6
8
  # Sketch design
@@ -1,6 +1,8 @@
1
1
  ---
2
2
  name: systematic-debugging
3
3
  description: Forces root-cause investigation before any fix when a test fails, a bug surfaces, or unexpected behavior appears. Auto-triggers on "test is failing", "it's broken", "why does X happen", "this isn't working". Do NOT use for trivial typo fixes or when the cause is already agreed on.
4
+ metadata:
5
+ family: build
4
6
  ---
5
7
 
6
8
  # Systematic debugging
@@ -1,6 +1,8 @@
1
1
  ---
2
2
  name: target-check
3
3
  description: Reports what a target project holds against what the toolkit currently ships, one section per domain, reading through `canon` verbs rather than inspecting files. Use when asked to "check this target", "what has this project fallen behind on", "is this project current with the toolkit", "run the target check", or as the first thing a rollout worker runs after entering a target. Do NOT use to repair a finding, which the owning command or skill does, and do NOT use in the toolkit repository itself.
4
+ metadata:
5
+ family: upkeep
4
6
  ---
5
7
 
6
8
  # Target check
@@ -1,6 +1,8 @@
1
1
  ---
2
2
  name: target-setup
3
3
  description: Gets a project onto the toolkit. Detects the stack, resolves per-domain arguments, previews the chain, runs `canon init`, then verifies at a stated depth and bootstraps the `index.md` system. Use when asked to "set up this project", "init this project", "bootstrap the toolkit", "install governance", "install gov rules", "set up indexes", "verify the scaffold", "run the smoke tests", or "one-shot install". Assumes the `canon` CLI is on PATH. Do NOT use on a project that already carries the toolkit, which is `canon-operator`, or to report per-domain drift without repairing it, which is `target-check`.
4
+ metadata:
5
+ family: setup
4
6
  ---
5
7
 
6
8
  # Setup
@@ -1,6 +1,8 @@
1
1
  ---
2
2
  name: task-board
3
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`.
4
+ metadata:
5
+ family: decide
4
6
  ---
5
7
 
6
8
  # Task board
@@ -3,13 +3,15 @@ name: teach-workspace
3
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.
4
4
  disable-model-invocation: true
5
5
  argument-hint: <subject to learn, or the topic of a workspace to resume or promote>
6
+ metadata:
7
+ family: answer
6
8
  ---
7
9
 
8
10
  # Teach workspace
9
11
 
10
12
  Run a learning workspace on one subject across sessions. The workspace holds what the learner has been through, so a session weeks later resumes from the folder rather than from the conversation.
11
13
 
12
- The shape of the workspace is fixed by `${CLAUDE_SKILL_DIR}/../../standards/teach.md`. Read it before writing anything into the folder. The glossary answers to `${CLAUDE_SKILL_DIR}/../../standards/glossary.md` wherever it lands. The pedagogy sits in `${CLAUDE_SKILL_DIR}/references/pedagogy.md`, the lesson craft in `${CLAUDE_SKILL_DIR}/references/lesson-craft.md`, and the promotion routing in `${CLAUDE_SKILL_DIR}/references/promotion.md`.
14
+ The shape of the workspace is fixed by `${CLAUDE_SKILL_DIR}/../../standards/teach.md`. Read it before writing anything into the folder. The glossary answers to `${CLAUDE_SKILL_DIR}/../../standards/glossary.md` wherever it lands. The pedagogy sits in `${CLAUDE_SKILL_DIR}/references/pedagogy.md`, the lesson craft and its build in `${CLAUDE_SKILL_DIR}/references/lesson-craft.md` and `lesson-build.md`, the record's revisit schedule in `revisit.md`, and the promotion routing in `${CLAUDE_SKILL_DIR}/references/promotion.md`.
13
15
 
14
16
  ## Guards
15
17
 
@@ -105,7 +107,7 @@ Write the correct option first, then present the options in the order `order` re
105
107
 
106
108
  ### The quiz, the teach-back block, and the lesson body
107
109
 
108
- Read `${CLAUDE_SKILL_DIR}/references/lesson-craft.md` before writing the lesson. `## Quiz construction` and `## Teach back` there fix the markup `canon teach nav`'s stepper gates on, so a quiz in any other shape shows every question at once and nothing reports it. `## Building the lesson body` carries the four marker pairs, the render, nav, stylesheet, and glossary verbs, and the rule against composing any of them by hand when a verb does not resolve. Keep every quiz answer the same length, so formatting leaks no clue about which one is correct. Decide the figure first, by `## Diagrams` there.
110
+ Read `${CLAUDE_SKILL_DIR}/references/lesson-craft.md` before writing the lesson. `## Quiz construction` and `## Teach back` there fix the markup `canon teach nav`'s stepper gates on, so a quiz in any other shape shows every question at once and nothing reports it. Then read `${CLAUDE_SKILL_DIR}/references/lesson-build.md` for the block list, the four marker pairs, the render, nav, stylesheet, and glossary verbs, and the rule against hand-composing any of them. Keep every quiz answer the same length, so formatting leaks no clue about which one is correct. Decide the figure first, by `## Diagrams` in `lesson-craft.md`.
109
111
 
110
112
  ### Hand over a link, never a path
111
113
 
@@ -129,19 +131,7 @@ Record the wrong answer rather than the count. The next session places the learn
129
131
 
130
132
  Record what the teach-back left out under what the learner got wrong, naming the concept and where the explanation broke. A produced answer and a selected one are both retrieval failures the next session places from, so a second heading would split one input across two sections.
131
133
 
132
- Then write `## Revisit`, one bullet per item, in the shape `${CLAUDE_SKILL_DIR}/../../standards/teach.md` fixes:
133
-
134
- ```markdown
135
- ## Revisit
136
-
137
- - **<what comes back up>**: due <YYYY-MM-DD>, rung <n>
138
- ```
139
-
140
- Take both the date and the rung from the `due` entry Step 1 already read, copying `hit` for an item the learner retrieved unaided and `miss` for one they did not, with the rung stepped the same way. Do not compute a date from the ladder. A session told to widen a gap still picks the number by judgment, which is the reason the verb reports both dates at all.
141
-
142
- An item the records have never scheduled has no `due` entry to copy from. Open it at rung 1, dated the day after this session, which is the ladder's floor and the one number this body states. Every later date for it comes from the verb.
143
-
144
- An entry outside this shape schedules nothing and nothing reports that it was skipped, so write the shape exactly. A later record naming the same item supersedes an earlier entry, so revise a schedule by writing the new bullet rather than editing the record it was set in.
134
+ Then write `## Revisit`. Read `${CLAUDE_SKILL_DIR}/references/revisit.md` before writing it, for the bullet shape, where each date and rung is copied from, and the first schedule for an item no record has set.
145
135
 
146
136
  Then restate the mission's success lines with what is now met, reading them from the `success` the lesson verb already reported rather than from `MISSION.md` by eye. Report each line as met or not met, and name what the learner did that meets it. A mission whose lines are all met is finished, and saying so is what closes a workspace.
147
137
 
@@ -0,0 +1,75 @@
1
+ ---
2
+ title: Lesson build reference
3
+ description: The block list canon teach render takes and the verbs that build the lesson body, being render, nav, stylesheet, and glossary
4
+ ---
5
+
6
+ # Lesson build reference
7
+
8
+ Mechanics rather than judgment. `lesson-craft.md` covers what a lesson should be, and this file covers how its body reaches the page through the verbs.
9
+
10
+ ## The block list
11
+
12
+ `canon teach render` takes a JSON array of blocks and renders it through the same components a lesson body composes. Six types, and every structural body composes from them:
13
+
14
+ - `{"type":"heading","level":1|2,"text":"<text>"}`: an `<h1>` or `<h2>`.
15
+ - `{"type":"paragraph","text":"<text>","lede":true,"cites":[1]}`: a `<p>`, marked `lede` for the dek that opens the lesson. `cites` adds a footnote marker per reference number after the text, and a lede takes none.
16
+ - `{"type":"list","items":["<text>", ...],"ordered":true}`: a `<ul>` or, with `ordered`, an `<ol>`.
17
+ - `{"type":"refs","items":[{"title":"<name>","url":"<https URL>","note":"<text>"}, ...]}`: the lesson's one reference list, numbered from 1 in item order. `url` and `note` are optional, and a `url` must be http or https.
18
+ - `{"type":"code","lang":"ts","text":"<source>"}`: a code sample, highlighted at render time with no script. `lang` is optional and takes a highlight.js name or alias. One the renderer does not register renders as plain escaped code.
19
+ - `{"type":"raw","html":"<markup>"}`: the escape hatch, passed through unescaped.
20
+
21
+ Code never travels through `raw`. A hand-written `<pre><code>` renders with no color, and `nav` never highlights markup already in a lesson body, so a sample written that way stays plain for good. A fenced block in a reference page's markdown is highlighted by `nav` on its own.
22
+
23
+ The quiz and the teach-back block in `lesson-craft.md` are the one case `raw` is always needed for, since their fixed contract is not a components concern. Give them the array's last `raw` entry, followed only by `refs`, rather than reaching for `raw` anywhere the other types could carry the content instead.
24
+
25
+ A claim resting on a source carries a `cites` number, and the source goes in the lesson's one `refs` block rather than into the sentence. Draw every reference from what `canon teach resource --read` recorded, never from a lead, since a lead is a source nobody opened. Render refuses a cite no reference resolves, so number the list before citing into it.
26
+
27
+ ## Building the lesson body
28
+
29
+ Step 4 of `teach-workspace` reads this section before writing a lesson, after the lesson verb has resolved its path and quiz order. Write the chrome as four empty marker pairs rather than composing it by hand: `<!-- canon:teach:style -->`/`<!-- /canon:teach:style -->` inside `<head>`, and `<!-- canon:teach:header -->`, `<!-- canon:teach:footnav -->`, and `<!-- canon:teach:scripts -->` each with its own close marker, in that order in `<body>`.
30
+
31
+ Build the authored `<h1>`, lede, body, and quiz as a JSON array of blocks rather than composing markup by hand, and render it through the verb rather than through a component import:
32
+
33
+ ```bash
34
+ echo '[
35
+ {"type":"heading","level":1,"text":"<title>"},
36
+ {"type":"paragraph","lede":true,"text":"<the dek>"},
37
+ {"type":"paragraph","text":"<a body paragraph>"},
38
+ {"type":"paragraph","text":"<a claim resting on a source>","cites":[1]},
39
+ {"type":"list","ordered":true,"items":["<step one>","<step two>"]},
40
+ {"type":"raw","html":"<the quiz and teach-back block composed per lesson-craft.md>"},
41
+ {"type":"refs","items":[{"title":"<source name>","url":"<https URL>"}]}
42
+ ]' | canon teach render --json
43
+ ```
44
+
45
+ `## The block list` above states each type and where `raw` belongs. Take the call's `html` field and write it between the header's close marker and the footnav's open marker, and nothing else anywhere in the file.
46
+
47
+ Report it rather than proceeding silently when the verb does not resolve, which is an installed CLI predating it, and never compose the lesson body by hand as a fallback. That is the state this section exists to end, and a target holds this skill body before it holds the verb, since a plugin skill reaches a target the moment it merges while the CLI reaches one only when a release publishes.
48
+
49
+ Then run:
50
+
51
+ ```bash
52
+ canon teach nav <topic> --json
53
+ ```
54
+
55
+ It fills every marker pair from what the workspace holds on disk: the embedded stylesheet, the header with its breadcrumb and jump menus, the prev/next footer nav, and the behavior scripts, and it rewrites the workspace's contents page and the teach-root listing in the same run. It refuses a lesson missing one of the four marker pairs by name rather than guessing at the boundary, so a marker dropped while writing the lesson is caught here rather than read back later as a lesson nothing links to. Report it rather than proceeding silently when the verb does not resolve, which is an installed CLI predating it, and never compose the chrome by hand as a fallback.
56
+
57
+ Seed the stylesheet through the verb rather than authoring a palette, on the first lesson in a workspace:
58
+
59
+ ```bash
60
+ canon teach stylesheet <topic> --json
61
+ ```
62
+
63
+ It writes the design tokens as custom properties and the components built on them, from the one source every other rendered surface reads. Add lesson rules under the seed and reach a value through its property rather than restating the hex, which is what let each workspace fork the palette from every other. It refuses to overwrite, so running it again on a workspace that has grown its own rules is safe and reports `written` as false.
64
+
65
+ Report it rather than proceeding silently when the verb does not resolve, which is an installed CLI predating it. Do not fall back to writing a palette by hand.
66
+
67
+ Add every term the lesson defines to `GLOSSARY.md` through the verb, which places the entries alphabetically in the shape the standard fixes:
68
+
69
+ ```bash
70
+ canon teach glossary <topic> --json \
71
+ --term "<term>=<definition, written without using the term>" \
72
+ --first-seen <the lesson or reference page this batch comes from>
73
+ ```
74
+
75
+ `--term` repeats and one call writes the file once, which is what keeps a batch of terms from racing on it. A term already defined is refused, since a definition the subject has moved under is a revision of the entry rather than a second one.