@erclx/canon 5.24.0 → 5.26.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 (185) hide show
  1. package/README.md +2 -1
  2. package/claude/.claude-plugin/plugin.json +1 -1
  3. package/claude/skills/backlog-triage/REQUIREMENT.md +2 -2
  4. package/claude/skills/backlog-triage/SKILL.md +19 -6
  5. package/claude/skills/canvas/REQUIREMENT.md +49 -0
  6. package/claude/skills/canvas/SKILL.md +106 -0
  7. package/claude/skills/context-fold/REQUIREMENT.md +6 -2
  8. package/claude/skills/context-fold/SKILL.md +8 -6
  9. package/claude/skills/context-fold/references/anchor-sweep.md +2 -2
  10. package/claude/skills/design-extract/REQUIREMENT.md +1 -1
  11. package/claude/skills/design-taste/REQUIREMENT.md +1 -1
  12. package/claude/skills/design-taste/SKILL.md +4 -2
  13. package/claude/skills/design-taste/references/adopted.md +40 -0
  14. package/claude/skills/design-taste/references/kinds.md +1 -1
  15. package/claude/skills/design-taste/references/systems.md +1 -7
  16. package/claude/skills/design-taste/references/tells.md +2 -24
  17. package/claude/skills/docs-sync/REQUIREMENT.md +2 -1
  18. package/claude/skills/document-health/REQUIREMENT.md +2 -0
  19. package/claude/skills/document-health/SKILL.md +21 -0
  20. package/claude/skills/document-health/references/axes.md +12 -0
  21. package/claude/skills/draft-and-pick/SKILL.md +1 -1
  22. package/claude/skills/draft-doc/REQUIREMENT.md +1 -1
  23. package/claude/skills/draft-figure/REQUIREMENT.md +14 -3
  24. package/claude/skills/draft-figure/SKILL.md +24 -51
  25. package/claude/skills/draft-figure/references/architecture-set.md +35 -0
  26. package/claude/skills/draft-figure/references/hand-drawn.md +31 -0
  27. package/claude/skills/draft-figure/references/mermaid.md +55 -0
  28. package/claude/skills/draft-identity/SKILL.md +1 -1
  29. package/claude/skills/draft-screencast/SKILL.md +9 -7
  30. package/claude/skills/draft-slides/REQUIREMENT.md +17 -12
  31. package/claude/skills/draft-slides/SKILL.md +31 -20
  32. package/claude/skills/git-followup/SKILL.md +17 -6
  33. package/claude/skills/git-issue/references/issue.md +10 -0
  34. package/claude/skills/git-pr/references/evidence.md +12 -2
  35. package/claude/skills/git-pr/references/labels.md +12 -0
  36. package/claude/skills/git-split/SKILL.md +19 -8
  37. package/claude/skills/index-lookup/SKILL.md +2 -2
  38. package/claude/skills/markdown-propose/references/format.md +9 -0
  39. package/claude/skills/memory-review/references/later-phases.md +7 -0
  40. package/claude/skills/review-address/SKILL.md +6 -13
  41. package/claude/skills/review-address/references/rest-reads.md +43 -0
  42. package/claude/skills/review-craft/references/ui.md +7 -1
  43. package/claude/skills/review-pr/REQUIREMENT.md +1 -0
  44. package/claude/skills/review-pr/SKILL.md +9 -3
  45. package/claude/skills/review-pr/references/close-out.md +2 -2
  46. package/claude/skills/review-pr/references/post.md +17 -5
  47. package/claude/skills/review-pr/references/scope.md +10 -8
  48. package/claude/skills/review-ui/SKILL.md +12 -4
  49. package/claude/skills/review-ui/references/post.md +4 -2
  50. package/claude/skills/role-orchestrator/references/orchestrator-cloud-launch.md +38 -1
  51. package/claude/skills/role-orchestrator/references/orchestrator-dispatch.md +13 -0
  52. package/claude/skills/role-orchestrator/references/orchestrator-launch.md +4 -0
  53. package/claude/skills/role-orchestrator/references/orchestrator-poll.md +4 -4
  54. package/claude/skills/role-orchestrator/references/orchestrator-review-dispatch.md +6 -0
  55. package/claude/skills/role-orchestrator/scripts/poll.ts +90 -27
  56. package/claude/skills/role-orchestrator/scripts/repo.ts +3 -5
  57. package/claude/skills/role-orchestrator/scripts/watch.ts +4 -7
  58. package/claude/skills/search-craft/REQUIREMENT.md +1 -1
  59. package/claude/skills/search-craft/SKILL.md +3 -1
  60. package/claude/skills/search-craft/references/adopted.md +30 -0
  61. package/claude/skills/target-setup/references/detect.md +8 -0
  62. package/claude/skills/target-setup/references/indexes.md +13 -0
  63. package/claude/skills/target-setup/references/verify.md +8 -0
  64. package/claude/skills/test-first/SKILL.md +2 -0
  65. package/claude/skills/test-first/references/adopted.md +36 -0
  66. package/claude/skills/write-human/SKILL.md +1 -1
  67. package/claude/skills/write-human/references/machine-tells.md +13 -0
  68. package/docs/agents/canvas.md +4 -2
  69. package/docs/agents/capture.md +1 -1
  70. package/docs/agents/commands.md +47 -47
  71. package/docs/agents/context-audit-checks.md +2 -2
  72. package/docs/agents/index.md +2 -3
  73. package/docs/agents/key-changes.md +3 -3
  74. package/docs/agents/pr-evidence.md +11 -2
  75. package/docs/agents/pr-reads.md +5 -4
  76. package/docs/agents/records-stale.md +22 -9
  77. package/docs/agents/records.md +1 -1
  78. package/docs/agents/sandbox.md +1 -1
  79. package/docs/agents/skills-audit.md +10 -3
  80. package/docs/agents/slides.md +15 -3
  81. package/docs/target/projects.md +4 -4
  82. package/docs/workflow/ai-workflow.md +1 -2
  83. package/docs/workflow/index.md +1 -0
  84. package/docs/workflow/parallel-features.md +1 -1
  85. package/docs/workflow/skill-map-on-request.md +42 -0
  86. package/docs/workflow/skill-map.md +3 -36
  87. package/docs/workflow/visual-design-workflow.md +1 -0
  88. package/governance/renames.toml +0 -4
  89. package/governance/rules/standards/markdown.md +1 -0
  90. package/package.json +1 -2
  91. package/scripts/core/install-check.sh +1 -1
  92. package/scripts/lib/sandbox-dispatch.sh +1 -1
  93. package/scripts/lib/sandbox-git.sh +1 -9
  94. package/scripts/lib/sandbox-path.sh +1 -1
  95. package/scripts/sandbox-hook.sh +99 -0
  96. package/src/audits/catalog.ts +2 -2
  97. package/src/canvas/capture.ts +1 -9
  98. package/src/canvas/client/inspector/color-field.tsx +368 -0
  99. package/src/canvas/client/inspector/field.tsx +200 -0
  100. package/src/canvas/client/inspector/fields.css +292 -0
  101. package/src/canvas/client/inspector/section.tsx +27 -0
  102. package/src/canvas/client/inspector/values.ts +183 -0
  103. package/src/canvas/client/inspector.tsx +176 -160
  104. package/src/canvas/client/shell.css +0 -101
  105. package/src/capture/render.ts +45 -7
  106. package/src/capture/sources.ts +43 -0
  107. package/src/census/count.ts +1 -1
  108. package/src/claude/cases/misc.ts +5 -0
  109. package/src/claude/cases/workflow.ts +6 -1
  110. package/src/claude/seeds.ts +1 -2
  111. package/src/claude/skills-audit.ts +68 -14
  112. package/src/client-commands.ts +1 -1
  113. package/src/commands/claude.ts +27 -2
  114. package/src/commands/design.ts +2 -64
  115. package/src/commands/feedback.ts +3 -3
  116. package/src/commands/pr.ts +219 -202
  117. package/src/commands/records.ts +88 -6
  118. package/src/commands/sandbox.ts +50 -10
  119. package/src/commands/slides.ts +31 -77
  120. package/src/context/audit.ts +8 -7
  121. package/src/design/tokens.ts +2 -18
  122. package/src/docs/read.ts +1 -1
  123. package/src/{github.ts → feedback/github.ts} +1 -1
  124. package/src/gate/measures.ts +6 -4
  125. package/src/gov/citations.ts +1 -1
  126. package/src/gov/payload.ts +1 -1
  127. package/src/gov/superseded.ts +2 -2
  128. package/src/help.ts +2 -2
  129. package/src/markdown/ceiling.ts +1 -1
  130. package/src/migrate/skill-names.ts +7 -1
  131. package/src/pr/evidence.ts +25 -5
  132. package/src/pr/rest.ts +137 -0
  133. package/src/record-root.ts +1 -0
  134. package/src/records/backup.ts +1 -0
  135. package/src/records/push-guard.ts +1 -1
  136. package/src/records/stale-canonical.ts +146 -0
  137. package/src/records/stale.ts +1 -1
  138. package/src/sandbox/hooks.ts +128 -0
  139. package/src/sandbox/provision.ts +596 -0
  140. package/src/sandbox/tree.ts +103 -4
  141. package/src/secrets/marker.ts +2 -2
  142. package/src/secrets/scan.ts +1 -1
  143. package/src/shipped/references.ts +2 -2
  144. package/src/slides/convert/export.ts +2 -16
  145. package/src/slides/decks.ts +110 -0
  146. package/src/standards/read.ts +1 -1
  147. package/src/sync/seeds-report.ts +1 -1
  148. package/src/tasks/answers.ts +1 -1
  149. package/src/tasks/archive.ts +1 -1
  150. package/src/teach/nav.ts +1 -1
  151. package/src/tooling/inject.ts +1 -1
  152. package/src/web/readme-citations.ts +1 -1
  153. package/standards/architecture.md +1 -0
  154. package/standards/canvas.md +112 -0
  155. package/standards/context.md +2 -1
  156. package/standards/figures.md +0 -1
  157. package/standards/index.md +1 -1
  158. package/standards/markdown.md +1 -0
  159. package/standards/mermaid.md +1 -7
  160. package/standards/requirements.md +2 -0
  161. package/standards/skill-practice.md +2 -1
  162. package/standards/skill.md +1 -0
  163. package/tooling/claude/reference.md +0 -5
  164. package/claude/skills/draft-diagram/REQUIREMENT.md +0 -45
  165. package/claude/skills/draft-diagram/SKILL.md +0 -177
  166. package/docs/agents/design-board.md +0 -33
  167. package/governance/rules/standards/diagrams.md +0 -14
  168. package/governance/rules/standards/mermaid.md +0 -15
  169. package/scripts/core/check-gallery-exclusion.sh +0 -50
  170. package/scripts/manage-sandbox.sh +0 -472
  171. package/src/design/board.ts +0 -576
  172. package/src/slides/layouts.ts +0 -478
  173. package/src/slides/parse.ts +0 -84
  174. package/src/slides/render.ts +0 -110
  175. package/src/slides/styles.ts +0 -96
  176. package/standards/diagrams.md +0 -132
  177. package/tooling/claude/seeds/.claude/diagrams/index.md +0 -8
  178. /package/claude/skills/write-human/references/{source-material.md → adopted.md} +0 -0
  179. /package/src/{commands/feedback-format.ts → feedback/body.ts} +0 -0
  180. /package/src/{github-format.ts → feedback/github-format.ts} +0 -0
  181. /package/src/{frontmatter.ts → markdown/frontmatter.ts} +0 -0
  182. /package/src/{binary.ts → sweep/binary.ts} +0 -0
  183. /package/src/{exempt-marker.ts → sweep/exempt-marker.ts} +0 -0
  184. /package/src/{paths.ts → tasks/paths.ts} +0 -0
  185. /package/src/{seed-marker.ts → tooling/seed-marker.ts} +0 -0
@@ -11,50 +11,50 @@ Full help: `canon <command> --help`. Bare `canon --help` lists every top-level c
11
11
 
12
12
  One row per top-level command, in the order `canon --help` prints them. A domain's subcommands are in `## Domain commands` below.
13
13
 
14
- | Command | Purpose |
15
- | --------------------------- | ------------------------------------------------------------------------------- |
16
- | `canon init [path]` | Bootstrap a project with selected toolkit domains |
17
- | `canon sync [path]` | Sync every installed domain, or report drift and version skew with `--check` |
18
- | `canon upgrade` | Reinstall the CLI globally with the package manager the install path names |
19
- | `canon migrate <verb>` | Move a project off a retired name or layout, reporting the plan until `--write` |
20
- | `canon targets <verb>` | Report the projects this toolkit installed into |
21
- | `canon gov <verb>` | Install and sync governance rules, and audit the tree against them |
22
- | `canon standards <verb>` | List, audit, or print a standard by name |
23
- | `canon tooling <verb>` | Sync, diff, and verify tooling stacks |
24
- | `canon claude <verb>` | Install the Claude workflow and audit both skill corpora |
25
- | `canon wiki <verb>` | Scaffold the wiki pages |
26
- | `canon indexes <verb>` | Regenerate `index.md` files from sibling frontmatter, or flatten them |
27
- | `canon docs [topic]` | Emit toolkit reference docs (`list`, or a topic by name) |
28
- | `canon design <verb>` | Render `canon/DESIGN.md` tokens, build the board, install the base stylesheet |
29
- | `canon slides <verb>` | Render a `.claude/SLIDES.md` deck, or list its layouts |
30
- | `canon capture [source]` | Render HTML or a URL to PNG and prove each declared font resolved |
31
- | `canon serve [dir]` | Serve a directory on loopback and print the link that opens it |
32
- | `canon demo <verb>` | Compile and record a running app |
33
- | `canon inventory [subject]` | Group every route's elements by one computed property, never gating |
34
- | `canon drive <url> <run>` | Walk a page through named interactions and measure each state |
35
- | `canon transcripts <url>` | Fetch a YouTube transcript with metadata frontmatter (needs `yt-dlp`) |
36
- | `canon teach <verb>` | Open and author learning workspaces |
37
- | `canon canvas <verb>` | Serve a local canvas of pages and HTML frames, arrange, edit, and capture them |
38
- | `canon sandbox [cat:cmd]` | Run sandbox scenarios, toolkit-only like the tree it reads |
39
- | `canon tasks <verb>` | Read and write the task board, the plans it cites, and its archive |
40
- | `canon intake <verb>` | Report intake folders and write answers into them |
41
- | `canon records <verb>` | Validate, size, prune, and back up the session records |
42
- | `canon sessions <verb>` | Resolve live sessions to worktree and branch, and move one between machines |
43
- | `canon worktrees <verb>` | Report and remove worktrees whose pull request merged |
44
- | `canon hooks <verb>` | Run the steps a git hook drives |
45
- | `canon autoship <verb>` | Decide whether a changed set needs the review pass |
46
- | `canon pr <verb>` | Read a pull request's diff, head, checks, and review, and post its evidence |
47
- | `canon feedback` | Write toolkit feedback from stdin, or open an issue with `--github` |
48
- | `canon audits <verb>` | Run every audit as one set under one verdict against the recorded baseline |
49
- | `canon gate <verb>` | Run every stage that guards a branch here |
50
- | `canon secrets <verb>` | Report credential-shaped values in the tree the package ships |
51
- | `canon deps <verb>` | Report published advisories against the resolved dependency set |
52
- | `canon labels <verb>` | Read a changed set against the label map, and scan pull request text |
53
- | `canon comments <verb>` | Measure comment density by language and kind, with a trend from git |
54
- | `canon context <verb>` | Report context folder health, and classify changed or stale sections |
55
- | `canon markdown <verb>` | Fail markdown on a banned character or a dead link, and report its structure |
56
- | `canon repo <verb>` | Propose and apply the remote's description, homepage, and topics |
57
- | `canon census [path]` | Report tracked file count, extensions, and a line total skipping binaries |
14
+ | Command | Purpose |
15
+ | --------------------------- | ------------------------------------------------------------------------------------------ |
16
+ | `canon init [path]` | Bootstrap a project with selected toolkit domains |
17
+ | `canon sync [path]` | Sync every installed domain, or report drift and version skew with `--check` |
18
+ | `canon upgrade` | Reinstall the CLI globally with the package manager the install path names |
19
+ | `canon migrate <verb>` | Move a project off a retired name or layout, reporting the plan until `--write` |
20
+ | `canon targets <verb>` | Report the projects this toolkit installed into |
21
+ | `canon gov <verb>` | Install and sync governance rules, and audit the tree against them |
22
+ | `canon standards <verb>` | List, audit, or print a standard by name |
23
+ | `canon tooling <verb>` | Sync, diff, and verify tooling stacks |
24
+ | `canon claude <verb>` | Install the Claude workflow and audit both skill corpora |
25
+ | `canon wiki <verb>` | Scaffold the wiki pages |
26
+ | `canon indexes <verb>` | Regenerate `index.md` files from sibling frontmatter, or flatten them |
27
+ | `canon docs [topic]` | Emit toolkit reference docs (`list`, or a topic by name) |
28
+ | `canon design <verb>` | Render or regenerate `canon/DESIGN.md` tokens, emit their CSS, install the base stylesheet |
29
+ | `canon slides <verb>` | Render a deck folder of HTML slides, or list the decks |
30
+ | `canon capture [source]` | Render HTML or a URL to PNG and prove each declared font resolved |
31
+ | `canon serve [dir]` | Serve a directory on loopback and print the link that opens it |
32
+ | `canon demo <verb>` | Compile and record a running app |
33
+ | `canon inventory [subject]` | Group every route's elements by one computed property, never gating |
34
+ | `canon drive <url> <run>` | Walk a page through named interactions and measure each state |
35
+ | `canon transcripts <url>` | Fetch a YouTube transcript with metadata frontmatter (needs `yt-dlp`) |
36
+ | `canon teach <verb>` | Open and author learning workspaces |
37
+ | `canon canvas <verb>` | Serve a local canvas of pages and HTML frames, arrange, edit, and capture them |
38
+ | `canon sandbox [cat:cmd]` | Run sandbox scenarios, toolkit-only like the tree it reads |
39
+ | `canon tasks <verb>` | Read and write the task board, the plans it cites, and its archive |
40
+ | `canon intake <verb>` | Report intake folders and write answers into them |
41
+ | `canon records <verb>` | Validate, size, prune, and back up the session records |
42
+ | `canon sessions <verb>` | Resolve live sessions to worktree and branch, and move one between machines |
43
+ | `canon worktrees <verb>` | Report and remove worktrees whose pull request merged |
44
+ | `canon hooks <verb>` | Run the steps a git hook drives |
45
+ | `canon autoship <verb>` | Decide whether a changed set needs the review pass |
46
+ | `canon pr <verb>` | Read a pull request's diff, head, checks, and review, and post its evidence |
47
+ | `canon feedback` | Write toolkit feedback from stdin, or open an issue with `--github` |
48
+ | `canon audits <verb>` | Run every audit as one set under one verdict against the recorded baseline |
49
+ | `canon gate <verb>` | Run every stage that guards a branch here |
50
+ | `canon secrets <verb>` | Report credential-shaped values in the tree the package ships |
51
+ | `canon deps <verb>` | Report published advisories against the resolved dependency set |
52
+ | `canon labels <verb>` | Read a changed set against the label map, and scan pull request text |
53
+ | `canon comments <verb>` | Measure comment density by language and kind, with a trend from git |
54
+ | `canon context <verb>` | Report context folder health, and classify changed or stale sections |
55
+ | `canon markdown <verb>` | Fail markdown on a banned character or a dead link, and report its structure |
56
+ | `canon repo <verb>` | Propose and apply the remote's description, homepage, and topics |
57
+ | `canon census [path]` | Report tracked file count, extensions, and a line total skipping binaries |
58
58
 
59
59
  `canon serve` drives no browser, which is what separates it from the four that do. All four ship now that `capture` does, so the line between them is the engine rather than the package. A generated page loses its script to an editor preview and to a `file://` open, so the link is the delivery rather than a convenience, and every generated surface here reaches a reader through one. A teach lesson's stylesheet is embedded rather than linked, so only its script still needs a server. It binds `127.0.0.1` and never a wildcard, because what it is pointed at is routinely a gitignored record tree. It sends `cache-control: no-store`, since a preview exists to be edited and reloaded and a cached stylesheet reads as a fix that did not work.
60
60
 
@@ -91,7 +91,7 @@ Each domain exposes a consistent shape where applicable: `list`, `install`, `syn
91
91
  - `wiki`, in `scripting.md`: `init`
92
92
  - `indexes`, in `indexes.md`: `regen`, `list`
93
93
  - `docs`, in `docs.md`: `list`, `<topic>`
94
- - `design`, in `design-board.md`: `render`, `regen`, `board`, `css`, `install`, `sync`
94
+ - `design`, in `install-and-sync.md` for `install` and `sync`, and described below for the rest: `render`, `regen`, `css`, `install`, `sync`
95
95
  - `slides`, described below: `render`, `list`
96
96
  - `demo`, in `demo.md`: `compile`, `run`, `frames`
97
97
  - `inventory`, described above: `run`
@@ -128,8 +128,8 @@ Subcommands no other page describes:
128
128
  - `claude plugin-update` matches the installed marketplace plugin against `claude/.claude-plugin/plugin.json`'s own name and runs `claude plugin update` on it, reading the version back off `claude plugin list --json`, since the update call reports none of its own (`--json`).
129
129
  - `claude skills rank` scores either skill corpus's descriptions against a case corpus by TF-IDF cosine similarity, reporting rank-one and top-three (`--cases <path>`).
130
130
  - `design regen` rewrites this repository's `canon/DESIGN.md` from `src/design/tokens.ts` and `src/design/base.css` from `src/design/neutral.ts`. `design css` emits the tokens and components as CSS on stdout, with `--no-components` for properties alone, and `design render` declares each vendored face the typography table names under `--embed-fonts`.
131
- - `slides render` renders a `.claude/SLIDES.md` source into a PowerPoint deck and reports any unrecognized layout name on stderr, and `slides list --json` emits the layout catalog.
132
- - `slides render --source <folder>` 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.
131
+ - `slides list --json` emits one row per deck under `.canon/slides/`, carrying `name`, `title`, `slides`, and `path`.
132
+ - `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.
133
133
  - 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`.
134
134
  - `canvas`, with its verbs, content format, and write routes, is described in `canvas.md`.
135
135
  - `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`).
@@ -85,9 +85,9 @@ All three wireframe findings are printed under a bare run. The states-mismatch f
85
85
 
86
86
  The provenance check covers `canon/context/` alone, the reference-form check covers the split folders inside it, the required-section check covers `canon/context/` and `canon/wireframes/`, length and the table finding reach every audited folder, and the wireframe states check covers `canon/wireframes/` alone.
87
87
 
88
- What narrows the provenance check is stated in `standards/context.md`, which opens its scope by handing diagrams and wireframes to `diagrams.md` and `wireframes.md`, and the sibling standards do not restate it. A marker reported in a diagram entry would cite a rule that entry's own standard routes elsewhere. The split is between kinds of rule rather than kinds of folder, and what decides it is which tier states the rule rather than what the check measures.
88
+ What narrows the provenance check is stated in `standards/context.md`, which opens its scope by handing figures to the `draft-figure` skill and wireframes to `wireframes.md`, and the sibling standards do not restate it. A marker reported in a diagram or wireframe entry would cite a rule that entry's own standard routes elsewhere. The split is between kinds of rule rather than kinds of folder, and what decides it is which tier states the rule rather than what the check measures.
89
89
 
90
- Length and the table finding generalize as judgments about how far a reader travels, so both reach wherever the audit is pointed. Required sections narrow for a plainer reason: each list is one standard's own, so it reaches the folder that standard governs. The context and wireframe standards each state a set, and the diagram standard states none.
90
+ Length and the table finding generalize as judgments about how far a reader travels, so both reach wherever the audit is pointed. Required sections narrow for a plainer reason: each list is one standard's own, so it reaches the folder that standard governs. The context and wireframe standards each state a set, and an older install's diagrams folder has no standard to state one.
91
91
 
92
92
  The same test is what moved depth and bullet weight out of this command entirely. A rule stated at the attribute tier reaches every markdown file, and a check reaching every markdown file has no reason to require a folder that resolves.
93
93
 
@@ -20,7 +20,6 @@ CLI catalog and invocation rules for agents, split by command domain. Start with
20
20
  - [Doc classifier](context-classify.md): Classifying canonical-doc content as keep, replace/rewrite, history, or move in diff and sweep mode, the classifier setting pair, the record shape, and the exit codes
21
21
  - [Self-stated counts](counts.md): Reading a sentence that asserts a closed catalog's size, how a match is decided, the plausibility filter that keeps a generic word from matching a subset, and why the sweep reports rather than gates
22
22
  - [Demo](demo.md): Compiling a screencast draft into a runnable plan, driving a served application to a recording and a still, reading numbered frames back out of a recording, the pointer the recording paints, and what each refusal reports
23
- - [Design board](design-board.md): Generating a static index over a project's design surfaces, what each panel reads, and which two stay toolkit-checkout-only
24
23
  - [Docs](docs.md): How canon docs resolves the toolkit's own reference surface from an install root, and how a split domain is named
25
24
  - [Drift surfaces](drift-surfaces.md): The seven sections canon sync --check reports beside the per-domain scan, being seeds, superseded artifacts, unmigrated domains, surfaces at the old root, new rules and skills, and the reverse walk, with the managed-target gate and what counts toward the exit code
26
25
  - [Driver](driver.md): Walking a page through named interactions, the probe catalog and the false finding each one carries, why viewport heights are never defaulted, and what each refusal reports
@@ -42,7 +41,7 @@ CLI catalog and invocation rules for agents, split by command domain. Start with
42
41
  - [The pull request preview deploy](pr-preview.md): How canon pr preview finds a fenced Cloudflare Pages deploy, dispatches it on a pull request's branch, reads the alias the run prints, the refusal reasons it names, and why an unfenced deploy is refused before anything runs
43
42
  - [Head-sensitive pull request reads](pr-reads.md): Resolving a branch tip from the remote rather than from the pull request object, reading what a review pass covered off its own marker rather than off GitHub's submission stamps, why an empty run list is not a pass, the refusal reasons each verb names, and what the remote read costs
44
43
  - [Records push](records-push.md): Backing the record folders to a private remote and restoring them, which folders the payload carries, the one-time setup, the refusal reasons, and the hook that runs the push
45
- - [Records stale](records-stale.md): Reading the memory pen as a review queue, what makes an entry due, how a cited path is read and resolved, the order entries come back in, and the exit codes and refusals
44
+ - [Records stale](records-stale.md): Reading the memory pen as a review queue, what makes an entry due, how a cited path is read and resolved, the order entries come back in, counting the releases since the requirements and architecture records were last reviewed, and the exit codes and refusals
46
45
  - [Records validate](records-validate.md): Validating the session records and the standards corpus, the per-kind checks, which root each kind defaults to, the exit codes, and the refusal reasons
47
46
  - [Records](records.md): The two roots a record folder resolves at, migrating a record a frontmatter change orphaned, claiming the ordinal intake and groundwork share, reading each folder's size and growth, pruning stale scratch, and where validation, the memory review queue, and the private-remote backup are described
48
47
  - [Restated instructions](restated.md): Counting the instructions the always-loaded file and every path-scoped rule share with the seed, the skill bodies, and each other, how a match is decided, the three classes, which surface a later edit starts from, and why the sweep reports rather than gates
@@ -55,7 +54,7 @@ CLI catalog and invocation rules for agents, split by command domain. Start with
55
54
  - [Sessions](sessions.md): Resolving live peer sessions to the worktree and branch each holds, reading which row is the caller, the liveness confidence field, what each session surface can see, and where moving a session to another machine is described
56
55
  - [Skill audit](skills-audit.md): Measuring both skill corpora against the skill standards, the checks it reads, the requirement gate that is the only failing one, and the drift verb that names bodies rewritten since a ref
57
56
  - [Citation reach](skills-reach.md): Reporting the skill bodies that cite a path no target project receives, which corpus the verb reads, the ownership key that decides what counts, the one-word qualifier that marks a citation as decided, and why the verb reports instead of gating
58
- - [Slides](slides.md): What a folder of HTML slides declares for the whole deck in deck.json, the faces it embeds, what each slide declares on its own body, transitions and entrances, the master built from the project's tokens, speaker notes, charts, and what each refusal reports
57
+ - [Slides](slides.md): Where a deck folder lives and what it holds, what it declares for the whole deck in deck.json, the faces it embeds, what each slide declares on its own body, transitions and entrances, the master built from the project's tokens, speaker notes, charts, and what each refusal reports
59
58
  - [Standard success criteria](standards-audit.md): Reading the corpus against the success-criterion gate, the two headings it accepts, why the check scopes to arrival rather than the whole corpus, and the exit codes it sets
60
59
  - [State-scoped risk](state-scoped-risk.md): Reading committed state rather than an arriving change, the shipped-tree corpus the secret scan reads, what it keys on and how a deliberate value is exempted, the advisory check and its network failure mode, and why one gates while the other reports
61
60
  - [Superseded values](superseded.md): Reading where the tree still asserts a value a changed convention no longer produces, why the sweep keys on the value rather than the file, the family stem behind a templated citation, the exemption marker, the blind spots it cannot reach, and why it reports rather than gates
@@ -26,9 +26,9 @@ The positional is the pull request to read, defaulting to the one open on this b
26
26
 
27
27
  `--base` names the far side of that range and never the commit the comparison runs against directly. The reader resolves the merge base between `HEAD` and the ref, so `--base origin/main` measures what the branch wrote rather than what the trunk gained while the branch was open. Passing the trunk as it stands today is therefore safe on a branch of any age, and a ref sharing no history with `HEAD` refuses as `bad-base`.
28
28
 
29
- Without `--body` the body, the file list, and the head commit come back from one `gh pr view` call, because the three have to describe the same commit and reading them apart leaves a window where a push between them compares a body against another head's files.
29
+ Without `--body` the body and the head commit come off the REST pull read and the file list off the paginated files endpoint. Every read runs on REST, since a cloud session's GitHub proxy refuses the GraphQL that `gh pr view` runs on. A push landing between the two reads compares a body against the next head's files, a window the verb accepts for the cloud reach.
30
30
 
31
- That view caps its file list at 100 rows and says nothing about having done so, measured against a pull request carrying 101 files where the view reported 100. A pull request at the cap therefore takes a second read through the paginated endpoint, and a failure there refuses with `gh-truncated` rather than comparing against a set known to be short. A set silently one file short is the worst input this takes, since the missing file is exactly what a correct bullet would then be accused of inventing.
31
+ A failed page refuses as `gh-failed` rather than comparing against a set known to be short. A set silently one file short is the worst input this takes, since the missing file is exactly what a correct bullet would then be accused of inventing. With no number named, the verb reads the one pull request open on the checkout's branch, and refuses as `ambiguous-pull` when two are open against different bases.
32
32
 
33
33
  ## The two directions
34
34
 
@@ -91,7 +91,7 @@ Three refusals separate a clean pass from a read that produced nothing:
91
91
 
92
92
  An empty extraction read as a clean pass is the failure shape this repository has recorded twice, which is why the middle one is its own reason rather than a zero count.
93
93
 
94
- `gh-missing`, `gh-failed`, `gh-truncated`, `unreadable-body`, `unreadable-tree`, `no-base`, `bad-base`, and `unreadable-changes` cover the reads that never reached a comparison.
94
+ `gh-missing`, `gh-failed`, `ambiguous-pull`, `unreadable-body`, `unreadable-tree`, `no-base`, `bad-base`, and `unreadable-changes` cover the reads that never reached a comparison.
95
95
 
96
96
  ## What it was measured against
97
97
 
@@ -138,7 +138,7 @@ call, is what keeps two close-out comments from landing beside each other the
138
138
  way `review-pr` once posted, before that skill's own guard existed. It is
139
139
  also why this verb renders the whole comment body rather than handing each
140
140
  skill a record to format on its own: a fix to the table shape or the
141
- collapsed-details wrapper lands once, not twice.
141
+ details wrapper lands once, not twice.
142
142
 
143
143
  ## The preview line
144
144
 
@@ -232,7 +232,16 @@ render needs, so it never refuses `no-base`. The orchestrator's draft lift is
232
232
  the caller, and lifts only on `settled`, so a refusal holds it the same as
233
233
  `owed` does.
234
234
 
235
- ## What a collapsed comment still leaves to GitHub
235
+ ## When the comment opens
236
+
237
+ The comment opens every state while it carries six images or fewer, counting one
238
+ per row for the head plus one per row that is not new, and closes every state
239
+ past that, so the whole comment is open or closed together. A line under
240
+ `## Evidence` names the compared base and head as short shas, which tells a
241
+ reader whether the images match the latest push. The base is the merge base the
242
+ compare endpoint returns, not trunk's tip.
243
+
244
+ ## What the comment still leaves to GitHub
236
245
 
237
246
  GitHub already draws its own before-and-after comparison on the Files Changed
238
247
  tab for any tracked image that changed. This comment does not make that view
@@ -18,7 +18,7 @@ canon pr review-state 1341 --json
18
18
 
19
19
  ## The pull request object is not the authority for a head
20
20
 
21
- `gh pr view --json headRefOid` reads a field on the pull request object. That object trails the branch ref by up to a minute after a push and carries nothing saying how far behind it is, so a session that keys a read on it is describing whichever commit GitHub last folded into the object.
21
+ The pull request's head sha, `head.sha` on the REST pull read and `headRefOid` in `gh pr view`, is a field on the pull request object. That object trails the branch ref by up to a minute after a push and carries nothing saying how far behind it is, so a session that keys a read on it is describing whichever commit GitHub last folded into the object.
22
22
 
23
23
  Two failures on 2026-09-01 came off that one field. A reviewing session posted a finding calling a pushed commit unpushed. A worker fired a green claim and retracted it on its own thread minutes later. Neither session did anything wrong with the value it was handed. The value was stale and said so nowhere.
24
24
 
@@ -74,7 +74,7 @@ Both empty cases report `pending` instead: a tip carrying no run yet, and a list
74
74
 
75
75
  The verb keeps the newest run per check name rather than rolling every matched run into the state. A workflow that fires twice on one commit used to leave its first, stale run beside the rerun, where a failing one could outvote a passing rerun. Grouping the matched set by name and keeping the highest `id` per group removes that stale run before the rollup runs. `collapsed` on the record counts what the fold discards, so a caller reading it against `matched` sees the dedupe directly, instead of reading a `matched` above the check count as the verb disagreeing with `gh pr checks`.
76
76
 
77
- A conflicted branch produces no `pull_request` check runs rather than a failing one. GitHub builds no merge ref for it, so no `pull_request` workflow starts and a repository running only that trigger leaves the listing empty, which reads as `pending` and never leaves it. A workflow triggered by a push to the branch still runs on the tip, so `matched` rises above zero, `conflicted` stays false, and the wait ends on those runs rather than on the reading. `mergeStateStatus` is the field that separates the two, and the record carries `conflicted: true` and `mergeState` when it reads `DIRTY` with no run belonging to the tip. A `DIRTY` reading beside runs on the tip leaves the state as those runs say, since a conflict arising after they completed does not unsay them. `UNKNOWN` is transient while GitHub computes the merge state, right after a push, so it reads as not conflicted and costs one more poll. A binary predating the field keeps answering `pending`.
77
+ A conflicted branch produces no `pull_request` check runs rather than a failing one. GitHub builds no merge ref for it, so no `pull_request` workflow starts and a repository running only that trigger leaves the listing empty, which reads as `pending` and never leaves it. A workflow triggered by a push to the branch still runs on the tip, so `matched` rises above zero, `conflicted` stays false, and the wait ends on those runs rather than on the reading. The pull request's `mergeable_state` is the field that separates the two. The verb raises it to upper case, matching the GraphQL `mergeStateStatus` it replaced, and the record carries `conflicted: true` and `mergeState` when it reads `DIRTY` with no run belonging to the tip. A `DIRTY` reading beside runs on the tip leaves the state as those runs say, since a conflict arising after they completed does not unsay them. `UNKNOWN` is transient while GitHub computes the merge state, right after a push, so it reads as not conflicted and costs one more poll. A binary predating the field keeps answering `pending`.
78
78
 
79
79
  A listing carrying even one foreign run reports `pending` whatever the matching half says. A set that describes another commit says nothing about this one, so answering off the rows that happen to match would put a verdict on a set already known to be incomplete.
80
80
 
@@ -90,6 +90,7 @@ Each refusal names a different repair:
90
90
  | -------------------- | ------------------------------------------------------------------------------------------ |
91
91
  | `gh-missing` | `gh` is not on the path, so no pull request resolved |
92
92
  | `gh-failed` | `gh` could not answer for this branch, so name a number instead |
93
+ | `ambiguous-pull` | Two open pull requests share the branch against different bases, so name a number |
93
94
  | `no-branch` | The pull request carries no head branch name, so no ref could be read |
94
95
  | `unresolvable-ref` | The remote read failed, which is not the same answer as an absent branch |
95
96
  | `no-remote-branch` | The remote carries no branch by that name, so there is no tip to compare against |
@@ -105,6 +106,6 @@ One remote round trip per call, sampled here at 0.41s, 0.55s, and 0.67s on 2026-
105
106
 
106
107
  One head-sensitive read is left on the object deliberately. `canon targets pulls` reads `statusCheckRollup` for every open pull request across every target, where resolving a tip per row would cost one remote read per pull request across a dozen projects, against a surface that reports a listing rather than gating a push.
107
108
 
108
- The orchestrator poll spends that same read per open pull request and repeats it on a three-minute timer, which makes it the heaviest caller here rather than an exception to the paragraph above. Six open pull requests is around 120 remote reads an hour. It now spends a third read per pull request per tick besides, since `canon pr review-state` makes its own `gh pr view` call beside the payload the poll already fetched. That one is an API round trip rather than a remote ref read, and it buys a coverage test that answers about what a session read. What separates the two cases is what each reading decides rather than what it costs. The poll's head fires the review trigger, so a stale one sends a pass at a commit nobody read or withholds one that is owed. The listing decides nothing, so the same spend buys a fresher column in a report and no correctness at all.
109
+ The orchestrator poll spends that same read per open pull request and repeats it on a three-minute timer, which makes it the heaviest caller here rather than an exception to the paragraph above. Six open pull requests is around 120 remote reads an hour. It reads over REST alone, one reviews read and one issue-comments read per pull request, plus a pull read only when `canon pr head` returns no tip. It spends a further read per pull request per tick besides, since `canon pr review-state` makes its own REST reviews read beside the payload the poll already fetched. That one is an API round trip rather than a remote ref read, and it buys a coverage test that answers about what a session read. What separates the two cases is what each reading decides rather than what it costs. The poll's head fires the review trigger, so a stale one sends a pass at a commit nobody read or withholds one that is owed. The listing decides nothing, so the same spend buys a fresher column in a report and no correctness at all.
109
110
 
110
- `canon pr key-changes` also stays on the object, for a different reason. It reads the body, the file list, and `headRefOid` in one call on purpose, so the three describe one commit. That is a consistency requirement rather than a freshness one, and keying its head elsewhere would break it.
111
+ `canon pr key-changes` also stays on the object, for a different reason. It reads the body and the head off one pull read, so the two describe one commit. That is a consistency requirement rather than a freshness one, and keying its head elsewhere would break it. The file list comes off a second read, since only GraphQL returns it beside the body and a cloud session's proxy refuses GraphQL.
@@ -1,25 +1,26 @@
1
1
  ---
2
2
  title: Records stale
3
- description: Reading the memory pen as a review queue, what makes an entry due, how a cited path is read and resolved, the order entries come back in, and the exit codes and refusals
3
+ description: Reading the memory pen as a review queue, what makes an entry due, how a cited path is read and resolved, the order entries come back in, counting the releases since the requirements and architecture records were last reviewed, and the exit codes and refusals
4
4
  ---
5
5
 
6
6
  # Records stale
7
7
 
8
- `canon records stale memory` reports each memory entry's review state and every backticked path it cites that the project no longer holds. It answers what a review of the pen should read next, so a skill takes the queue from the verb rather than re-deriving it by grep.
8
+ `canon records stale memory` reports each memory entry's review state and every backticked path it cites that the project no longer holds. It answers what a review of the pen should read next, so a skill takes the queue from the verb rather than re-deriving it by grep. `canon records stale canonical` reports when the requirements and architecture records were last reviewed and how many releases have shipped since.
9
9
 
10
10
  ```bash
11
11
  canon records stale memory
12
12
  canon records stale memory --json
13
13
  canon records stale memory --days 60 --json
14
+ canon records stale canonical --json
14
15
  ```
15
16
 
16
- | Option | Behavior |
17
- | --------------- | ------------------------------------------------------------- |
18
- | `--json` | Add a machine-readable record on stdout |
19
- | `--days <n>` | Days after a review before an entry is due again (default 30) |
20
- | `--root <path>` | Project root, defaulting to the main worktree |
17
+ | Option | Behavior |
18
+ | --------------- | --------------------------------------------------------------------------------------------------- |
19
+ | `--json` | Add a machine-readable record on stdout |
20
+ | `--days <n>` | Days after a review before a memory entry is due again (default 30) |
21
+ | `--root <path>` | Project root, defaulting to the main worktree for `memory` and the current worktree for `canonical` |
21
22
 
22
- `memory` is the only kind it reads, since a memory entry is the one record carrying a review date. Any other argument refuses as `unknown-kind`.
23
+ `memory` and `canonical` are the two kinds it reads, since each is a record carrying a review date. Any other argument refuses as `unknown-kind`.
23
24
 
24
25
  It reports and never writes. It moves, archives, and rewrites no entry, matching `validate` and `size`.
25
26
 
@@ -53,10 +54,22 @@ canon records stale memory --json | jq -r '[.entries[] | select(.due)][0:20][] |
53
54
 
54
55
  The record carries `total`, `due`, `days`, the `folder` read relative to the root, and one `entries` row per entry with `name`, `category`, `reviewed`, `due`, and `unresolved`.
55
56
 
57
+ ## Canonical records
58
+
59
+ `canonical` reads `REQUIREMENTS.md` and `ARCHITECTURE.md` at whichever surface root carries each, `canon/` ahead of `.claude/`, and omits one the project does not hold. Both are tracked, so `--root` defaults to the worktree the caller stands in rather than the main one, and a stamp a branch just wrote reads back from that branch.
60
+
61
+ Each doc's review point is an optional `reviewed: YYYY-MM-DD` frontmatter field, set by whoever finishes a review, per `canon standards requirements` and `canon standards architecture`. It is a date rather than a commit, since a commit written on a feature branch never reaches a trunk that squash-merges. The field is read the way the memory field is, so a value that is not a calendar date comes back as `invalidReviewed`.
62
+
63
+ The count is every release tag merged into `HEAD` whose creator date falls after the reviewed day. A release tag ends in a dotted version, bare as `v5.25.0` or behind a component prefix as `canon-v2.1.0`, so an eval, deploy, or snapshot tag on the trunk never inflates it. A lightweight tag's creator date is its commit's date and an annotated tag's is the tagging date, so a project mixing both counts by two clocks.
64
+
65
+ The record carries `tagged`, false when `HEAD` has merged no release tag or the repository has no commit yet, and one `docs` row per doc with `path`, `reviewed`, `releasesSince`, and `latestRelease`. `releasesSince` is null on a doc never reviewed and `0` on one reviewed after every tag. With no tags it is also `0`, which is why `tagged` travels beside it.
66
+
67
+ It gates nothing, and no hook, gate stage, or workflow runs it. `canon:document-health` reads it when asked to review the two records.
68
+
56
69
  ## Exit codes and refusals
57
70
 
58
71
  Exit codes: `0` the reading completed, whatever it found, and `1` refused. A due entry is a queue position rather than a failure, so nothing here gates.
59
72
 
60
- A `reason` field carries which gate fired: `no-folder` when the project holds no memory folder at either record root, `unknown-kind` for any kind but `memory`, and `bad-days` when `--days` is not a positive whole number. An empty pen is not a refusal. It reports an empty list and exits `0`.
73
+ A `reason` field carries which gate fired: `no-folder` when the project holds no memory folder at either record root, `unknown-kind` for any kind but `memory` or `canonical`, `bad-days` when `--days` is not a positive whole number or is passed to `canonical`, and `unreadable-tags` when `canonical` cannot read the tags. An empty pen is not a refusal. It reports an empty list and exits `0`.
61
74
 
62
75
  The pen is shared scratch at the main worktree root, so `--root` defaults there, the same default `validate memory` takes. A pen at the legacy `.claude/memory/` root resolves the way every record verb resolves it, per `records.md`. <!-- canon-keep-record-root -->
@@ -118,7 +118,7 @@ Exit codes: `0` nothing to prune, or `--write` deleted every candidate. `1` refu
118
118
 
119
119
  ## Stale
120
120
 
121
- `canon records stale memory` reports which memory entries are due for review and which cite a path the tree no longer holds, ordered so a review takes the first N as a batch. What makes an entry due, how a cited path resolves, and the refusals are in `records-stale.md`.
121
+ `canon records stale memory` reports which memory entries are due for review and which cite a path the tree no longer holds, ordered so a review takes the first N as a batch. `canon records stale canonical` reports when the requirements and architecture records were last reviewed and how many releases have shipped since. What makes an entry due, how a cited path resolves, how the release count is taken, and the refusals are in `records-stale.md`.
122
122
 
123
123
  ## Push and pull
124
124
 
@@ -9,7 +9,7 @@ description: Scenario routing, the expectation scoring surface, and the coverage
9
9
 
10
10
  ## Scenarios
11
11
 
12
- Scenarios live under `sandbox/`, one folder per category. `sandbox/fixtures/` is the exception, holding file content that scenarios stage rather than scenarios of its own, so both pickers filter it out. That tree sits outside `files` in `package.json`, so an installed `canon` carries the command, reports it as toolkit-only on one line, and exits 1 rather than failing on the missing directory. Route non-interactively with `SANDBOX_SCENARIO`:
12
+ Scenarios live under `sandbox/`, one folder per category. `sandbox/fixtures/` is the exception, holding file content that scenarios stage rather than scenarios of its own, so the picker and the coverage report both filter it out. That tree sits outside `files` in `package.json`, so an installed `canon` carries the command, reports it as toolkit-only on one line, and exits 1 rather than failing on the missing directory. Route non-interactively with `SANDBOX_SCENARIO`:
13
13
 
14
14
  ```bash
15
15
  SANDBOX_SCENARIO=sync canon sandbox infra:tooling
@@ -36,7 +36,8 @@ Each check traces to a line in the standard.
36
36
  - Folder name in kebab-case
37
37
  - Each `REQUIREMENT.md` declaring `Gap` and `Must`, matched at any heading level
38
38
  - No ISO date in `SKILL.md` or any file under `references/`, reported as `datedProvenance` in the JSON record's `findings`
39
- - Each listed practice skill closing with `## Excuses and rebuttals`, `## Red flags`, and `## Before handing over`, and carrying `references/adopted.md`, reported as `practiceShape`
39
+ - Each listed practice skill closing with `## Excuses and rebuttals`, `## Red flags`, and `## Before handing over`, and each skill on the wider ledger list carrying `references/adopted.md`, reported together as `practiceShape`
40
+ - Each file under `references/` running over 100 lines opening with a `## Contents` H2, reported as `referenceContents`
40
41
 
41
42
  A body whose frontmatter does not parse reports as declaring neither field rather than ending the run, so one malformed file cannot hide the corpus behind it. A key present with an empty value reads as absent, since a blank `name` would otherwise report as a name disagreeing with every folder. A folder carrying no requirement is reported once under presence rather than counted again for the sections it therefore lacks.
42
43
 
@@ -44,7 +45,11 @@ The date check reads prose alone. A date inside a fence or a code span is exampl
44
45
 
45
46
  Each finding names the file and the line, such as `claude/skills/<name>/references/<file>.md line 12: <date>`. A date after "measured" or "verified" reports like any other, unlike the context audit, because a skill body states the rule a session follows today rather than a reading of the tree.
46
47
 
47
- The practice check reads only the skills the audit lists, which the JSON record carries as `checkpoints.practiceSkills`. The list names folders under the toolkit's shipped `claude/skills/` corpus alone, so a project's own skill is never read as a practice skill and a same-named folder under `.claude/skills/` produces no finding. Where `claude/skills/` resolves, a listed folder it does not hold reports as a missing skill, so a renamed or misspelled entry cannot pass unread. Each closing section matches only as an exact H2 outside a fence, so an H3 or a heading carrying more words reports as missing.
48
+ The practice check reads only the skills the audit lists, which the JSON record carries as `checkpoints.practiceSkills` for the closing sections and `checkpoints.ledgerSkills` for the ledger. The ledger list holds every practice skill plus the skills that cite outside sources without a practice's closing shape, so a skill on it alone owes the ledger and none of the sections.
49
+
50
+ Both lists name folders under the toolkit's shipped `claude/skills/` corpus alone, so a project's own skill is never read as a practice skill and a same-named folder under `.claude/skills/` produces no finding. Where `claude/skills/` resolves, a listed folder it does not hold reports as a missing skill, so a renamed or misspelled entry cannot pass unread. Each closing section matches only as an exact H2 outside a fence, so an H3 or a heading carrying more words reports as missing.
51
+
52
+ The contents check counts every line of a reference, frontmatter included, the way `wc -l` does, so a file of exactly 100 lines passes and one of 101 needs the list. `## Contents` matches the same way the closing sections do, as an exact H2 outside a fence. `SKILL.md` is never read for it, and the threshold travels in the JSON record as `checkpoints.contentsThreshold`.
48
53
 
49
54
  ## What it leaves alone
50
55
 
@@ -56,7 +61,9 @@ A check with no rule behind it prints an opinion as a defect, which is where the
56
61
 
57
62
  ## Exit codes
58
63
 
59
- Exit codes are `0` for a clean run, `1` for a refusal, and `2` for a skill folder carrying no `REQUIREMENT.md`. Only presence sets a failing code. Name, description, folder, requirement-section, dated-provenance, and practice shape findings print and return `0`, because each is a judgment a reader settles and failing a push on one would make the check something to route around. In the toolkit, two `bun run check` stages read the same report in-process and fail a push on dated provenance and on practice shape, since its own corpus is held at zero on both.
64
+ Exit codes are `0` for a clean run, `1` for a refusal, and `2` for a skill folder carrying no `REQUIREMENT.md`. Only presence sets a failing code. Name, description, folder, requirement-section, dated-provenance, practice shape, and reference contents findings print and return `0`, because each is a judgment a reader settles and failing a push on one would make the check something to route around. In the toolkit, two `bun run check` stages read the same report in-process and fail a push on dated provenance and on practice shape, since its own corpus is held at zero on both.
65
+
66
+ No stage reads reference contents, so a long reference without a list stays a report.
60
67
 
61
68
  ## The requirement gate
62
69
 
@@ -1,16 +1,28 @@
1
1
  ---
2
2
  title: Slides
3
- description: What a folder of HTML slides declares for the whole deck in deck.json, the faces it embeds, what each slide declares on its own body, transitions and entrances, the master built from the project's tokens, speaker notes, charts, and what each refusal reports
3
+ description: Where a deck folder lives and what it holds, what it declares for the whole deck in deck.json, the faces it embeds, what each slide declares on its own body, transitions and entrances, the master built from the project's tokens, speaker notes, charts, and what each refusal reports
4
4
  ---
5
5
 
6
6
  # Slides
7
7
 
8
- `canon slides render --source <folder>` turns a folder of `.html` slides into an editable PowerPoint deck. Each slide describes its own shapes. What belongs to the whole deck, being the bands, the numbers, and the mark, sits in one file beside them, and the master that carries it takes the project's own colors and face.
8
+ `canon slides render <deck>` turns a folder of `.html` slides into an editable PowerPoint deck. Each deck lives in its own folder under `.canon/slides/`, which `canon records push` backs and git ignores, and `canon slides list --json` lists them. Each slide describes its own shapes. What belongs to the whole deck, being the bands, the numbers, and the mark, sits in one file beside them, and the master that carries it takes the project's own colors and face.
9
9
 
10
10
  ```bash
11
- canon slides render --source slides/q3-review
11
+ canon slides list --json
12
+ canon slides render q3-review
12
13
  ```
13
14
 
15
+ ## The deck folder
16
+
17
+ | Path | Holds |
18
+ | -------------------------------- | ---------------------------------------------------- |
19
+ | `.canon/slides/<deck>/*.html` | the slides, rendered in filename order |
20
+ | `.canon/slides/<deck>/deck.json` | what belongs to the whole deck, described below |
21
+ | `.canon/slides/<deck>/assets/` | images the slides reference by a relative path |
22
+ | `.canon/slides/layouts/` | the project's shared layouts, never listed as a deck |
23
+
24
+ A folder holding no `.html` file is not a deck. `render` with no name takes the only deck there is, and refuses with the list when there are several. It also takes a folder path outside `.canon/slides/`.
25
+
14
26
  ## The deck file
15
27
 
16
28
  `deck.json` beside the slides is optional. Without it the deck gets its defaults.
@@ -73,14 +73,14 @@ Scaffold installs tooling and seeds. It does not fill the planning docs or the d
73
73
 
74
74
  1. Fill `canon/REQUIREMENTS.md` and `canon/ARCHITECTURE.md`. The seed provides the files, the scope and decisions are yours to write. Each seed states its own caps, 12 decisions of at most 150 words and 6 risk bullets for the architecture record and 600 words for the requirements, and `canon context audit` gates on them. Edit a number in the record to loosen it.
75
75
  2. For a UI project, invoke `canon:design-extract` to draft `canon/DESIGN.md`. With no UI code yet it takes the greenfield path and proposes tokens from the requirements and a `## Personality` section. Skip for non-UI projects.
76
- 3. Optionally invoke `canon:draft-diagram` to draft entries under `.canon/diagrams/` from the architecture and the requirements. One file per diagram kind, so a later refresh of one kind leaves the others untouched. It renders each diagram it writes to verify the layout, which downloads the Mermaid CLI on first use and takes about 15 seconds.
76
+ 3. Optionally invoke `canon:draft-figure` naming an architecture view, such as system context or components, and the document it belongs in. It draws the view from the architecture and the requirements and renders it to verify the layout, which downloads the Mermaid CLI on first use and takes about 15 seconds.
77
77
  4. Start the feature loop. See [AI workflow](../workflow/ai-workflow.md) for the per-feature sequence.
78
78
 
79
- A machine without a renderer still gets the diagrams and is told which check was skipped.
79
+ A machine without a renderer still gets the figure and is told which check was skipped.
80
80
 
81
- Each diagram entry records the commit and date it was last verified against, and nothing maintains that record for you. The folder is redrawn on demand rather than swept on every ship, so `verified` carries the whole signal: an entry whose date sits far behind your branch is due a read, and no pass will name which one. Run `canon:draft-diagram` again when the code a kind is drawn from moves.
81
+ Nothing watches a figure once it is drawn. Run `canon:draft-figure` again when the code a view is drawn from moves.
82
82
 
83
- `canon/ARCHITECTURE.md` carries the same mechanism on the same ship. `canon:context-fold` anchors a decision it amends to the paths that decision cites, and reports an anchored decision whose cited path the branch touched.
83
+ `canon/ARCHITECTURE.md` is watched where a figure is not. `canon:context-fold` anchors a decision it amends to the paths that decision cites, and reports an anchored decision whose cited path the branch touched.
84
84
 
85
85
  ### Stack decision
86
86
 
@@ -26,7 +26,6 @@ canon/
26
26
  └── rules/ ← path-scoped governance rules, written by canon gov install
27
27
 
28
28
  .canon/
29
- ├── diagrams/ ← one Mermaid entry per diagram kind with a generated index.md, redrawn on demand
30
29
  ├── tasks/ ← one file per task with a generated index.md, local scratch
31
30
  ├── plans/ ← one plan per feature, archived inside itself once it ships
32
31
  ├── memory/ ← durable session facts no context entry owns
@@ -137,7 +136,7 @@ Before the first feature session on a UI-heavy project, pick a design tier. The
137
136
 
138
137
  ## Skills
139
138
 
140
- The [skill map](skill-map.md) gives every skill the plugin ships one row saying when to reach for it, grouped by the moment a project meets it.
139
+ The [skill map](skill-map.md) and its sibling [skill map on request](skill-map-on-request.md) give every skill the plugin ships one row saying when to reach for it. The first groups rows by the moment a project meets them, and the sibling holds the skills that answer a request.
141
140
 
142
141
  ## Feedback routing
143
142
 
@@ -15,6 +15,7 @@ How a person and their agents run a feature, from the design tier through the pa
15
15
 
16
16
  - [Operating model](operating-model.md): Orchestrator, planner, and worker roles for building across parallel sessions
17
17
  - [Parallel features](parallel-features.md): Run independent features in parallel worktrees, with the records and board every session shares
18
+ - [Skill map on request](skill-map-on-request.md): When to reach for the plugin skills that serve a request rather than a moment in a project's life
18
19
  - [Skill map](skill-map.md): When to reach for each plugin skill, grouped by the moment a project meets it
19
20
  - [Visual design workflow](visual-design-workflow.md): Tiered guide for design and wireframe authoring with Claude Code
20
21
  - [Zshrc aliases for Claude Code](zshrc-aliases.md): Shell aliases that shorten common Claude Code invocations
@@ -54,7 +54,7 @@ A plan that ships is archived, never deleted. `canon tasks archive` moves it to
54
54
 
55
55
  A branch review report takes the other route and is swept rather than archived. `review-branch` writes it flat into `.canon/review/` as `branch-<slug>.md`, the session addressing it reads it once, and the durable record of what a review found is the comment `review-pr` posts on the pull request, so `context-fold` deletes any report whose branch is gone. The body that writes a report owns how long it lives, which leaves the shipping branch's own report on disk through the run that cites it and collects it a branch later. What that loses is a local-only review on a branch that never opened a pull request, which is why the report says so where a reader meets it.
56
56
 
57
- `canon:context-fold` decides which task closed by reading the diff rather than the conversation. It resolves a merge base against `origin/main`, unions the committed diff with the working tree and untracked files, then matches unchecked outcomes on the board against what shipped. A task that shipped without ever being discussed still gets marked. Requirements, architecture, and design stay session-sourced, because a diff cannot carry a judgment.
57
+ `canon:context-fold` decides which task closed by reading the diff rather than the conversation. It resolves a merge base against `origin/main`, unions the committed diff with the working tree and untracked files, then matches unchecked outcomes on the board against what shipped. A task that shipped without ever being discussed still gets marked. Architecture and design stay session-sourced, because a diff cannot carry a judgment, and an architecture write further needs a folded plan naming the slot decision. The requirements record is never folded. A direction change gets one report line naming `canon:document-health`, which reviews that record only when asked.
58
58
 
59
59
  ## The task board
60
60
 
@@ -0,0 +1,42 @@
1
+ ---
2
+ title: Skill map on request
3
+ description: When to reach for the plugin skills that serve a request rather than a moment in a project's life
4
+ category: Workflow
5
+ ---
6
+
7
+ # Skill map on request
8
+
9
+ These two groups hold the skills no single moment in a project's life calls for, so they sit apart from the moment-ordered groups in the [skill map](skill-map.md). The two pages together are the corpus the coverage claim is measured against, and a skill takes one row across both.
10
+
11
+ ## Generate an artifact on demand
12
+
13
+ | Skill | When to use |
14
+ | ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
15
+ | `canon:create-rule` | For a project-specific governance rule the toolkit does not ship |
16
+ | `canon:create-skill` | For a new `SKILL.md` |
17
+ | `canon:create-standard` | For a new authoring convention |
18
+ | `canon:draft-doc` | For a brand-new `docs/` page, context entry, wireframe surface, wiki reference page, or `README.md`, drafted against the standard for its kind |
19
+ | `canon:draft-ready` | For finished files a worker should copy, written as a ready folder with its overview, thin plan, and task |
20
+ | `canon:draft-figure` | For a hand-drawn figure or an architecture view inside an existing doc, drafted in Mermaid or freehand SVG |
21
+ | `canon:bash-cli-script` | For a small non-interactive shell wrapper, stopping at 100 lines in favor of TypeScript on Bun |
22
+ | `canon:ci-workflow` | For a GitHub Actions workflow file |
23
+ | `canon:draft-slides` | For a deck, drawn as HTML slides in its own folder and rendered to editable PowerPoint |
24
+ | `canon:draft-screencast` | For a recording script with beats and defaults already seeded |
25
+ | `canon:record-screencast` | For recording a screencast draft, then composing the take into a finished mp4 when the draft asks for a wrap |
26
+ | `canon:draft-identity` | For a project's logo mark and its social card, drafted through `draft-and-pick`'s pick loop |
27
+
28
+ ## Answer a question at any point
29
+
30
+ | Skill | When to use |
31
+ | --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
32
+ | `canon:canon-cli` | Before running an unfamiliar verb, a sync, or an install, to learn which command to run, which reference doc covers it, or what it overwrites, merges, or leaves alone |
33
+ | `canon:index-lookup` | To find where a topic is documented across the tracked `index.md` catalogs |
34
+ | `canon:youtube-transcripts` | When a video transcript is wanted in the repo as context |
35
+ | `canon:read-frames` | To read a recorded demo back frame by frame and report what each one shows, with no verdict on whether the recording looks right |
36
+ | `canon:teach-workspace` | To learn a subject across sessions, in a workspace that holds the progress |
37
+ | `canon:write-human` | Before drafting or revising prose, for voice, rhythm, and density |
38
+ | `canon:restate-plainly` | When an answer or a document has to be read again in plain words |
39
+
40
+ Every row answers a question rather than marking a point in a project's life, so filing one under a phase on the [skill map](skill-map.md) would send a reader to the wrong group.
41
+
42
+ A learning workspace produces two halves and only one of them leaves. A lesson is worked through once and stays in the workspace, and a reference page or a glossary carries no learner, so it belongs wherever the project already keeps prose on that subject. Asking `canon:teach-workspace` to promote sorts each durable page by who owns its subject, sending an Anthropic-owned subject to the wiki, an internal one to the matching context entry, and everything else, subject-neutral material included, to the public docs. It proposes and waits, because a promoted page is public prose that needs a line naming who owns the subject, and it writes nothing to a destination: each page the operator confirms goes to a handoff file that `canon:context-fold` folds in from a branch. A project with no wiki folder gets a refusal naming `canon wiki init` rather than a folder it never asked for.