@erclx/canon 5.37.0 → 5.39.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 (197) hide show
  1. package/README.md +1 -1
  2. package/claude/.claude-plugin/plugin.json +1 -1
  3. package/claude/skills/api-design/SKILL.md +12 -9
  4. package/claude/skills/auto-ship/SKILL.md +43 -23
  5. package/claude/skills/backlog-triage/SKILL.md +62 -53
  6. package/claude/skills/backlog-triage/references/apply.md +69 -0
  7. package/claude/skills/build-in-slices/SKILL.md +8 -4
  8. package/claude/skills/canon-cli/SKILL.md +5 -1
  9. package/claude/skills/canon-feedback/SKILL.md +18 -8
  10. package/claude/skills/canon-feedback-triage/SKILL.md +10 -3
  11. package/claude/skills/canvas-board/SKILL.md +36 -17
  12. package/claude/skills/ci-workflow/SKILL.md +5 -4
  13. package/claude/skills/code-craft/SKILL.md +10 -6
  14. package/claude/skills/codebase-layout/SKILL.md +3 -5
  15. package/claude/skills/context-fold/REQUIREMENT.md +4 -4
  16. package/claude/skills/context-fold/SKILL.md +42 -23
  17. package/claude/skills/context-fold/references/context-refresh.md +4 -3
  18. package/claude/skills/context-fold/references/context.md +79 -64
  19. package/claude/skills/create-rule/SKILL.md +7 -3
  20. package/claude/skills/create-skill/SKILL.md +27 -7
  21. package/claude/skills/create-skill/references/skill-reference.md +41 -17
  22. package/claude/skills/decision-escalate/SKILL.md +8 -5
  23. package/claude/skills/deploy-app/SKILL.md +1 -1
  24. package/claude/skills/deprecation-migration/SKILL.md +12 -4
  25. package/claude/skills/design-taste/SKILL.md +17 -11
  26. package/claude/skills/docs-sync/REQUIREMENT.md +1 -0
  27. package/claude/skills/docs-sync/SKILL.md +17 -6
  28. package/claude/skills/docs-sync/references/docs.md +54 -21
  29. package/claude/skills/docs-sync/references/readme.md +32 -8
  30. package/claude/skills/document-health/SKILL.md +3 -4
  31. package/claude/skills/draft-and-pick/SKILL.md +73 -47
  32. package/claude/skills/draft-doc/SKILL.md +9 -4
  33. package/claude/skills/draft-doc/references/context.md +4 -4
  34. package/claude/skills/draft-doc/references/docs.md +1 -0
  35. package/claude/skills/draft-doc/references/wiki.md +3 -2
  36. package/claude/skills/draft-figure/SKILL.md +9 -7
  37. package/claude/skills/draft-identity/SKILL.md +24 -52
  38. package/claude/skills/draft-identity/references/card-route.md +46 -0
  39. package/claude/skills/draft-ready/SKILL.md +19 -7
  40. package/claude/skills/draft-screencast/SKILL.md +6 -112
  41. package/claude/skills/draft-screencast/references/beats-template.md +119 -0
  42. package/claude/skills/draft-slides/SKILL.md +7 -4
  43. package/claude/skills/git-branch/SKILL.md +3 -3
  44. package/claude/skills/git-commit/SKILL.md +5 -3
  45. package/claude/skills/git-followup/SKILL.md +16 -9
  46. package/claude/skills/git-issue/SKILL.md +6 -5
  47. package/claude/skills/git-issue/references/issue.md +11 -10
  48. package/claude/skills/git-pr/SKILL.md +56 -44
  49. package/claude/skills/git-ship/SKILL.md +43 -34
  50. package/claude/skills/git-ship/references/ci-watch.md +31 -0
  51. package/claude/skills/git-split/SKILL.md +28 -100
  52. package/claude/skills/git-split/references/independent.md +40 -0
  53. package/claude/skills/git-split/references/stacked.md +73 -0
  54. package/claude/skills/git-stage/SKILL.md +9 -7
  55. package/claude/skills/git-worktree/SKILL.md +27 -49
  56. package/claude/skills/git-worktree/references/cleanup.md +55 -0
  57. package/claude/skills/markdown-craft/SKILL.md +2 -2
  58. package/claude/skills/markdown-craft/references/markdown.md +82 -52
  59. package/claude/skills/plan-feature/SKILL.md +52 -46
  60. package/claude/skills/plan-feature/references/batches.md +46 -0
  61. package/claude/skills/plan-groundwork/SKILL.md +60 -74
  62. package/claude/skills/plan-groundwork/references/groundwork.md +53 -24
  63. package/claude/skills/plan-groundwork/references/output.md +48 -0
  64. package/claude/skills/plan-intake/SKILL.md +28 -21
  65. package/claude/skills/plan-intake-answer/SKILL.md +14 -13
  66. package/claude/skills/read-frames/SKILL.md +2 -0
  67. package/claude/skills/record-screencast/SKILL.md +31 -11
  68. package/claude/skills/review-address/SKILL.md +76 -158
  69. package/claude/skills/review-address/references/rebase-only.md +34 -0
  70. package/claude/skills/review-craft/SKILL.md +27 -11
  71. package/claude/skills/review-pr/SKILL.md +91 -40
  72. package/claude/skills/review-pr/references/post.md +1 -1
  73. package/claude/skills/review-ui/SKILL.md +62 -37
  74. package/claude/skills/review-ui/references/hosted-preview.md +30 -0
  75. package/claude/skills/role-orchestrator/SKILL.md +105 -74
  76. package/claude/skills/role-orchestrator/references/orchestrator-filing.md +26 -0
  77. package/claude/skills/role-orchestrator/references/orchestrator-parked.md +1 -1
  78. package/claude/skills/role-planner/SKILL.md +66 -64
  79. package/claude/skills/role-reviewer/SKILL.md +57 -46
  80. package/claude/skills/role-worker/SKILL.md +68 -63
  81. package/claude/skills/search-craft/SKILL.md +7 -5
  82. package/claude/skills/session-compact/SKILL.md +16 -11
  83. package/claude/skills/session-map/SKILL.md +31 -10
  84. package/claude/skills/session-relay/SKILL.md +32 -65
  85. package/claude/skills/session-resume/SKILL.md +18 -13
  86. package/claude/skills/session-worktree/SKILL.md +70 -42
  87. package/claude/skills/systematic-debugging/SKILL.md +6 -1
  88. package/claude/skills/target-check/SKILL.md +13 -6
  89. package/claude/skills/target-setup/SKILL.md +41 -30
  90. package/claude/skills/target-setup/references/verify.md +6 -5
  91. package/claude/skills/task-board/SKILL.md +68 -60
  92. package/claude/skills/task-board/references/create-report.md +36 -0
  93. package/claude/skills/task-board/references/tasks.md +3 -1
  94. package/claude/skills/task-complete/SKILL.md +20 -18
  95. package/claude/skills/teach-workspace/SKILL.md +61 -33
  96. package/claude/skills/test-craft/SKILL.md +2 -1
  97. package/claude/skills/test-first/SKILL.md +15 -9
  98. package/claude/skills/ui-checklist/SKILL.md +18 -16
  99. package/claude/skills/ux-audit/SKILL.md +9 -10
  100. package/claude/skills/ux-measure/SKILL.md +22 -18
  101. package/claude/skills/video-craft/SKILL.md +15 -7
  102. package/claude/skills/write-human/SKILL.md +9 -1
  103. package/claude/skills/youtube-transcripts/SKILL.md +2 -1
  104. package/docs/agents/context-audit-checks.md +19 -1
  105. package/docs/agents/context-audit.md +2 -2
  106. package/docs/agents/driver.md +1 -1
  107. package/docs/agents/hooks.md +21 -1
  108. package/docs/agents/index.md +10 -14
  109. package/docs/agents/indexes.md +25 -29
  110. package/docs/agents/install-and-sync.md +124 -235
  111. package/docs/agents/markdown-audit-density.md +39 -0
  112. package/docs/agents/markdown-audit-weight.md +9 -7
  113. package/docs/agents/markdown-audit.md +18 -14
  114. package/docs/agents/migrate.md +41 -16
  115. package/docs/agents/output-shape.md +60 -45
  116. package/docs/agents/overview.md +36 -12
  117. package/docs/agents/routing.md +1 -1
  118. package/docs/agents/rule-citations.md +1 -1
  119. package/docs/agents/skills-reach.md +1 -1
  120. package/docs/agents/targets.md +25 -77
  121. package/docs/target/migrations.md +1 -1
  122. package/docs/target/projects.md +3 -3
  123. package/docs/target/scenarios.md +1 -1
  124. package/docs/workflow/ai-workflow.md +2 -2
  125. package/docs/workflow/parallel-features.md +2 -2
  126. package/docs/workflow/skill-map.md +1 -1
  127. package/docs/workflow/visual-design-workflow.md +1 -1
  128. package/governance/detect.toml +6 -1
  129. package/package.json +6 -3
  130. package/scripts/core/install-check.sh +1 -1
  131. package/src/commands/claude.ts +1 -2
  132. package/src/commands/context.ts +106 -7
  133. package/src/commands/hooks.ts +63 -0
  134. package/src/commands/markdown.ts +169 -32
  135. package/src/commands/pr.ts +1 -1
  136. package/src/commands/records.ts +0 -1
  137. package/src/context/audit.ts +256 -5
  138. package/src/context/classify/prompts.ts +1 -1
  139. package/src/context/gate.ts +23 -7
  140. package/src/context/shape-gated.ts +28 -0
  141. package/src/design/document.ts +1 -1
  142. package/src/design/tokens.ts +1 -1
  143. package/src/docs/read.ts +15 -21
  144. package/src/gate/measures.ts +15 -190
  145. package/src/gate/stages.ts +21 -23
  146. package/src/hooks/reply-links.ts +110 -0
  147. package/src/markdown/density.ts +258 -0
  148. package/src/markdown/gate.ts +57 -18
  149. package/src/markdown/reference-shape.ts +103 -0
  150. package/src/markdown/scope.ts +174 -0
  151. package/src/markdown/structure.ts +10 -60
  152. package/src/sandbox/equivalence.ts +7 -9
  153. package/src/shipped/references.ts +1 -1
  154. package/src/teach/browser/head.ts +2 -2
  155. package/src/teach/browser/sidebar.ts +3 -3
  156. package/src/teach/browser/theme.ts +2 -2
  157. package/src/tooling/inject.ts +2 -2
  158. package/src/tooling/package.ts +15 -18
  159. package/src/tooling/verify-stack.ts +6 -3
  160. package/tooling/astro/configs/.oxfmtrc.json +8 -0
  161. package/tooling/astro/configs/.prettierrc +13 -0
  162. package/tooling/astro/manifest.toml +13 -0
  163. package/tooling/astro/reference.md +15 -5
  164. package/tooling/base/configs/.oxfmtrc.json +7 -0
  165. package/tooling/base/configs/scripts/verify.ts +1 -1
  166. package/tooling/base/manifest.toml +6 -6
  167. package/tooling/base/reference.md +12 -9
  168. package/tooling/base/seeds/.lintstagedrc +1 -3
  169. package/tooling/base/seeds/canon/context/ci.md +3 -3
  170. package/tooling/base/seeds/canon/context/development.md +2 -2
  171. package/tooling/claude/manifest.toml +5 -1
  172. package/tooling/claude/seeds/.claude/hooks/reply-links.sh +72 -0
  173. package/tooling/claude/seeds/.claude/hooks/standards-audit.sh +22 -1
  174. package/tooling/claude/seeds/.claude/settings.json +4 -0
  175. package/tooling/go/reference.md +2 -2
  176. package/tooling/nextjs/configs/.oxlintrc.json +223 -0
  177. package/tooling/nextjs/manifest.toml +2 -5
  178. package/tooling/nextjs/reference.md +4 -4
  179. package/tooling/php/manifest.toml +6 -1
  180. package/tooling/php/reference.md +2 -2
  181. package/tooling/python/manifest.toml +6 -1
  182. package/tooling/python/reference.md +4 -4
  183. package/tooling/vite-react/manifest.toml +1 -4
  184. package/tooling/vite-react/reference.md +3 -3
  185. package/tooling/web/configs/.oxlintrc.json +213 -0
  186. package/tooling/web/manifest.toml +9 -13
  187. package/tooling/web/reference.md +14 -14
  188. package/docs/agents/commands.md +0 -154
  189. package/docs/agents/docs.md +0 -27
  190. package/docs/agents/drift-surfaces.md +0 -201
  191. package/docs/agents/gov-detect.md +0 -47
  192. package/docs/agents/scripting.md +0 -142
  193. package/src/markdown/growth.ts +0 -43
  194. package/tooling/base/configs/.prettierrc +0 -12
  195. package/tooling/base/seeds/.prettierignore +0 -0
  196. package/tooling/nextjs/configs/eslint.config.js +0 -91
  197. package/tooling/web/configs/eslint.config.js +0 -82
@@ -1,34 +1,59 @@
1
1
  ---
2
2
  title: Migrate
3
- description: What each canon migrate verb moves and rewrites, what it refuses, the markers that keep an old spelling, and the idempotence check a second run gives
3
+ description: What each canon migrate verb moves, the markers that keep an old spelling, and what each one refuses
4
+ kind: reference
4
5
  ---
5
6
 
6
7
  # Migrate
7
8
 
8
- `canon migrate <verb>` moves a project off a retired name or layout. Each verb reports its plan and writes nothing until `--write` is passed, and each takes `--json`. Every verb but `rename` takes `--root`.
9
+ `canon migrate <verb>` moves a project off a retired name or layout. Each verb reports its plan and writes nothing until `--write`, takes `--json`, and, except `rename`, takes `--root`. A second run rewrites nothing, which confirms the exclusions and markers fired.
9
10
 
10
- `migrate rename` moves a project off the retired `aitk` name. It reports until `--write` is passed, and `--scope target` rewrites the toolkit-owned folders alone, reporting every other citation as one the project owns rather than editing prose somebody wrote. A project installing `canon` fresh never needs it.
11
+ | Verb | Moves |
12
+ | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------- |
13
+ | `rename` | The retired `aitk` name. `--scope target` rewrites toolkit-owned folders only. |
14
+ | `skill-names` | Plugin skills off their `claude-` prefix and other retired names, with every citation |
15
+ | `records` | Session records from `.claude/` to `.canon/`, with every tracked citation |
16
+ | `surface-roots` | `context/`, `wireframes/`, `ARCHITECTURE.md`, `REQUIREMENTS.md`, `DESIGN.md`, and the stamp folder from `.claude/` to `canon/`, by `git mv` |
17
+ | `record-tree` | Citations inside `.canon/` folders a session still follows: `diagrams`, `memory`, `plans`, `proposals`, `review`, `tasks`, `teach` |
18
+ | `rule-layout` | A flat installed-rule layout onto the `canon/`-wrapped one |
19
+ | `scratch-evidence` | A folder a durable record cites out of `.tmp/`, with its citations |
20
+ | `record-layout` | Review receipts, memory archives, feedback, renders, picks, and evidence into their current folders |
11
21
 
12
- `migrate skill-names` moves the plugin skills that carried a `claude-` prefix onto their two-word names and rewrites every citation of one. It carries two plain renames as well, where a skill carried no prefix and changed its name because the old one described a job it no longer does, landing on `ui-checklist` and `context-fold`, and one merge, where the five per-kind document drafters land on `draft-doc`. It carries one namespaced-only rename, `canvas` to `canvas-board`, keyed on `canon:canvas` and `skills/canvas` because a bare `canvas` key would rewrite the verb, its source folder, and its record folder. It leaves the pointer answering under the fold skill's old name in place. It shares its engine with `migrate rename` and differs in what it is scanning for: a skill name is a whole name rather than a word stem, so it matches only where the word ends, which is what keeps a longer word that merely opens with a skill name, such as `claude-worktrees`, out of it. It takes no `--scope`, since the skill folders it moves are authored in the toolkit and no target holds a copy of that catalog, which leaves a target's own citations of a renamed skill as the whole of what it rewrites there. The changelog and the eval transcripts are passed over on the argument the other sweep already carries, that each records what shipped or what a session ran under whatever name was current then. <!-- canon-keep-retired -->
22
+ - `skill-names` takes no `--scope` and skips the changelog and eval transcripts
23
+ - `surface-roots` leaves `rules/`, `skills/`, `hooks/`, and `settings.json` where Claude Code reads them
24
+ - `rule-layout` classifies each flat file against the stamp as clean, edited, or unclaimed. Clean and edited files move untouched, and an unclaimed name stays.
25
+ - `record-layout` labels each evidence folder `(pick)` or `(evidence)` in the dry run
13
26
 
14
- `migrate records` moves a project's session records from `.claude/` to `.canon/` and rewrites every tracked file that cites one. It reports until `--write` is passed, and refuses outright when the project does not already ignore `.canon/`, since every folder it relocates is ignored where it stands and landing one under a tracked root commits the memory pen. Take the ignore entry with `canon tooling sync --write` first.
27
+ ## Output
15
28
 
16
- A record folder already present at the destination is a refusal rather than a merge, and a line carrying `canon-keep-record-root`, or the nearest non-blank line below it, keeps the old spelling for prose that dates a decision. The records themselves are never swept: everything under `.canon/` and every `.claude/` record folder is passed over and reported as a count on its own line, which is what keeps the run that follows the ignore collapse touching the same files as one before it. Running it twice rewrites nothing, which is the check that the exclusions, the markers, and that skip all fired.
29
+ - The plan lists every citation in scope by file, line number, and line text
30
+ - `record-tree` reports closed groundwork and intake trails, the scratch folder, and backup history as counts and rewrites none
31
+ - `records` reports skipped record folders as a count on its own line
32
+ - A `record-tree` rewrite has no undo in version control, so read the report before `--write`
17
33
 
18
- `migrate surface-roots` moves the tracked surfaces from `.claude/` to `canon/`: `context/`, `wireframes/`, `ARCHITECTURE.md`, `REQUIREMENTS.md`, `DESIGN.md`, and the install stamp folder, respelled `canon/config/` since a project under `canon/` reserves the bare `canon` name for the CLI's own install. Every path is tracked, so each file moves with `git mv` and its history follows it, and every tracked citation of one is rewritten in the same run. `rules/`, `skills/`, `hooks/`, and `settings.json` stay where Claude Code reads them. It reports until `--write` is passed, and a destination already present under `canon/` refuses the whole plan rather than splitting a surface across both roots.
34
+ Three markers keep an old spelling on a line. Each also covers the nearest non-blank line, below it for `canon-keep-record-root` and above it for `canon-keep-surface-root`.
19
35
 
20
- A line carrying `canon-keep-surface-root`, or the nearest non-blank line above it, keeps the old spelling. A rule's frontmatter `paths:` glob, a citation shaped like a path into another repository, and one inside a dated paragraph are reported by file and line and left alone. Running it twice rewrites nothing, which is the idempotence check. A project that never runs it keeps resolving each surface under `.claude/`, since every reader takes whichever root holds the entry.
36
+ | Marker | Keeps |
37
+ | ------------------------- | ---------------------------------------------- |
38
+ | `canon-keep-record-root` | The old record folder spelling |
39
+ | `canon-keep-surface-root` | The old `.claude/` surface root |
40
+ | `canon-keep-retired` | A retired name, for `rename` and `skill-names` |
21
41
 
22
- `migrate record-tree` is what reaches the records the sweep above passes over, and the two share no scope. That one enumerates through git, so it sees every tracked file and none of the records, which are gitignored by construction. This one walks `.canon/` itself and is scoped to the folders a session still follows a path into: `diagrams`, `memory`, `plans`, `proposals`, `review`, `tasks`, and `teach`, each minus its own `archive/` subtree. A closed groundwork or intake trail, the scratch folder, and the backup history are reported as counts and never rewritten, because a path inside a closed trail sits in a sentence about work that already ended. Run it after the move, since there is no new root to walk before one.
42
+ `surface-roots` also reports and leaves a rule's frontmatter `paths:` glob, a path into another repository, and a citation in a dated paragraph.
23
43
 
24
- Every citation in scope is reported with its file, its line number, and the line text. The record tree is untracked, so a wrong rewrite has no git undo, and that report is what a reader judges before passing `--write`. Marking a line that has to keep the old spelling uses the same `canon-keep-record-root` comment, and a second run rewriting nothing is the idempotence check.
44
+ ## Refusals
25
45
 
26
- `migrate rule-layout` moves a target still on the flat installed-rule layout onto the `canon/`-wrapped one. It classifies each flat file against the target's own recorded stamp: an unchanged hash is clean, a changed one is edited, and a name neither the stamp nor the current rule catalog can vouch for is unclaimed and left in place. Clean and edited files both relocate with their content untouched, since moving a rule is a different decision from re-syncing it. The one renumbered rule reads its destination from a table rather than from its own current name, so it never lands as a second copy under the retired number.
46
+ | Verb | Refuses when |
47
+ | ------------------ | ----------------------------------------------------------------------------------- |
48
+ | `records` | The project does not ignore `.canon/`. Run `canon tooling sync --write` first. |
49
+ | `records` | A record folder already exists at the destination |
50
+ | `surface-roots` | Any destination already exists under `canon/`, refusing the whole plan |
51
+ | `scratch-evidence` | A destination is occupied |
52
+ | `record-layout` | A destination already exists, each move refused on its own |
53
+ | `rule-layout` | A destination holds different bytes. Neither file is touched and other moves apply. |
27
54
 
28
- `migrate scratch-evidence` moves a folder out of `.tmp/` for good rather than repointing a citation in place. A promoted folder is one a durable record, live or archived, cites as its evidence, and no source file under `claude/`, `scripts/`, `src/`, or `governance/` names by path, which is what a script still writing into it fails. It walks every `canon records push` folder rather than the live ones alone, since most of what it repoints sits in `tasks/archive/`, `plans/archive/`, and `groundwork/`. A destination already occupied is a refusal, and a second run rewriting nothing is the same idempotence check `migrate record-tree` uses.
55
+ A `rule-layout` destination holding the same bytes marks a duplicate, which `--write` deletes.
29
56
 
30
- A destination that already holds the same bytes marks the flat file a duplicate, which `--write` deletes rather than moves. One holding different bytes is a real collision: neither file is touched, it is reported by name, and every other planned move still applies independently. Run this before `canon gov install` or `canon gov sync` against a target still on the flat layout, since neither bootstrap verb detects or clears it on its own.
57
+ ## See also
31
58
 
32
- `migrate record-layout` folds two record folders under the memory pen: review receipts move from `.canon/review/memory/` to `.canon/memory/review/`, and retired entries move from `.canon/tmp/memory-archive/` to `.canon/memory/archive/`, backed for the first time since `memory/` is a folder `canon records push` carries and `tmp/` is not. Each move is refused independently when its destination already exists, and the citation repoint sweeps every folder `canon records push` carries, archives included, since an archived receipt still cites the row it retired. The same `canon-keep-record-root` marker and second-run idempotence check apply. A receipt sitting at the flat `review/` root, from before `.canon/review/memory/` existed, matches neither mapped move and is reported by name rather than moved.
33
-
34
- The same verb leaves `.canon/review/` holding only reviews. Feedback moves to `.canon/feedback/`, and the design, board, slides, and diagram renders move to `.canon/tmp/render/<kind>/`, off the records remote since the commands regenerate them. Reference images move to `.canon/picks/references/`. A branch report flattens from `review/branch/review-<slug>.md` to `review/branch-<slug>.md`, and a flat `review/ui-checklist-<slug>.md` moves into `.canon/tmp/handoff/ui-checklist/`. Each folder under `review/evidence/` is decided from what it holds: one directly carrying an `arm-<id>` capture or a `design-handoff.md` is a pick and moves to `.canon/picks/<slug>/`, and any other is evidence and moves to `.canon/evidence/<nn>-<slug>/`. Evidence folders are numbered by the oldest file each holds, continuing past any ordinal `evidence/` already carries. The dry run labels each derived destination `(pick)` or `(evidence)`, so a misfiled folder shows before `--write`, and one filed wrong moves back by hand. A bare mention of an emptied folder, such as `review/evidence/` with no slug or `review/branch/` with no report name, matches no row and stays as written.
59
+ - `install-and-sync.md`: the drift report that names these verbs as remedies
@@ -1,15 +1,13 @@
1
1
  ---
2
2
  title: Output shape
3
- description: Two framed shapes every command renders into, how JSON and --names modes keep stdout clean, and the exit discipline that lets piped output drain
3
+ description: The framed output shape every command renders into, the JSON and color modes, the exit discipline, the runtime catalogs, and a headless invocation per domain
4
4
  ---
5
5
 
6
6
  # Output shape
7
7
 
8
- Every CLI command renders into one of two framed shapes. Data goes to stdout. UI and logs go to stderr.
8
+ Data goes to stdout. UI and logs go to stderr. Help is the exception and prints to stdout so it can be piped.
9
9
 
10
- Help output is the exception. It prints to stdout so it can be piped and grepped.
11
-
12
- ## Data shape (lists, runs, errors)
10
+ ## Frame
13
11
 
14
12
  ```plaintext
15
13
  ┌
@@ -17,54 +15,71 @@ Help output is the exception. It prints to stdout so it can be piped and grepped
17
15
  │
18
16
  ├ Section
19
17
  │ ✓ item
20
- │ ✓ item
21
18
  └
22
19
  ```
23
20
 
24
- Rules:
25
-
26
- - `┌` opens the frame on stderr
27
- - `│ canon <domain>` is the command banner, one per invocation
28
- - `├ Section` headers introduce groups of items. `log_step` produces the blank `│` spacer before each.
29
- - `└` closes the frame on stderr, wired via `trap close_timeline EXIT`
30
- - Errors render as `│ ✗ message` inside the same frame. Never emit a lone error line without a frame.
21
+ - `┌` opens the frame, `│ canon <domain>` is the banner, and `├ Section` groups items
22
+ - `└` closes the frame on stderr
23
+ - An error renders as `│ ✗ message` inside the frame, never as a lone line
24
+ - Help skips the banner and puts `Usage:` directly on `├`
31
25
 
32
- ## Help shape
33
-
34
- ```plaintext
35
- ┌
36
- ├ Usage: canon <domain> [command]
37
- │
38
- │ Commands:
39
- │ ...
40
- └
41
- ```
26
+ A help request naming an unknown subcommand, under a group taking no operand, writes its refusal to stderr and exits 1.
42
27
 
43
- Help skips the banner. The `Usage:` line sits directly on `├`. Help writes to stdout because `--help` is documentation, not runtime UI. `--help --all` on a command prints each block unframed, one after another, and a help request naming an unknown subcommand, under a group that takes no operand of its own, writes its refusal to stderr and exits 1.
28
+ ## JSON and names modes
44
29
 
45
- ## JSON and `--names` modes
30
+ `--json` and `--names` keep stdout pure data. The frame still renders on stderr, and diagnostics reach stderr in every mode. A JSON refusal carries an action and a reason, so branch on the record rather than on stderr.
46
31
 
47
- `--json` and `--names` keep stdout clean and machine-readable. The frame still renders on stderr (open, banner, close) so the stream discipline is consistent across modes. Consumers that only read stdout see pure data.
32
+ A shell profile may wrap `canon` in a function that takes its status from a later command. Where a verb documents a record field, read the field rather than the exit.
48
33
 
49
34
  ## Color
50
35
 
51
- Escape sequences reach a destination that renders them and nowhere else. The question is asked per stream rather than once for the process, so a run piping its data while keeping a terminal on stderr still gets color on the frame.
52
-
53
- Either condition alone turns color off:
54
-
55
- - `NO_COLOR` is set to any non-empty value, whatever that value says
56
- - The destination is not a terminal, which covers a pipe, a file, and a captured session
57
-
58
- The frame survives both. `┌`, `│`, `├`, `└`, and the `✓ ! + - ✗` marks are structure rather than color, and they are what lets a captured run still read as one block. A caller wanting neither the frame nor the color reads `--json` instead.
59
-
60
- Terminal control is a separate question this section does not cover. The cursor and key sequences an interactive prompt writes run only where a terminal already exists.
61
-
62
- ## Process exit
63
-
64
- A command action sets `process.exitCode` and returns. Calling `process.exit()` there ends the process before a stdout write drains, which truncates piped output at the 64K pipe buffer while still reporting the right exit code. Redirecting to a file hides the truncation, so it surfaces only through a pipe, which is what a check has to use to catch it.
65
-
66
- The rule reaches an error path that writes to stderr alone, where the truncation has nothing to cut. Scoping it to the stdout writers was the alternative and it makes the floor depend on a detail that moves, since an action grows a stdout write long after its error branches are written. An action always has a return path, so the requirement costs it a line.
67
-
68
- The exit belongs to a helper that has no caller to unwind through. A prompt inside a promise executor and a wrapper propagating a child process status both qualify, and neither can hand a value back to a caller expecting one. A validation helper called from an action does not: it throws from a `never` return, which keeps its caller exhaustive to the compiler while the action catches and owns the code.
36
+ Escape sequences reach a destination that renders them and nowhere else, decided per stream. `NO_COLOR` set to any non-empty value turns color off, and so does a destination that is not a terminal. The frame glyphs and the `✓ ! + - ✗` marks survive both.
37
+
38
+ ## Exit discipline
39
+
40
+ A command action sets `process.exitCode` and returns. Calling `process.exit()` in an action truncates piped output at the 64K buffer. A file redirect hides the truncation, so test through a pipe.
41
+
42
+ ## Runtime catalogs
43
+
44
+ Discover names at runtime rather than hardcoding them.
45
+
46
+ | Command | Returns |
47
+ | --------------------------------- | ---------------------------------------------------------------- |
48
+ | `canon tooling list --json` | Stacks, extends chain, dep and script counts |
49
+ | `canon gov list --json` | Governance stacks, rule sets, evidence, and unreferenced rules |
50
+ | `canon gov detect --json` | Opt-in rules a target's dependencies and paths propose |
51
+ | `canon claude seeds list --json` | Seed doc sources with content |
52
+ | `canon claude skills list --json` | Plugin skills, descriptions, requirement flag, family vocabulary |
53
+ | `canon docs list --json` | Consumer docs plus per-domain context |
54
+ | `canon audits list --json` | Audits the set runs, the corpus each reads, and whether it gates |
55
+
56
+ - `gov list` expands each stack to its rules and carries `unreferenced`, the rules no stack reaches, which install only through `--add`
57
+ - `claude skills list` reports shipped skills only. Each carries `family` (or `null`) and `requirement`, and a `false` requirement is a gap to close. `--names` and `--by-family` change the render.
58
+ - A skill with unparseable frontmatter returns an empty description rather than failing the listing
59
+
60
+ ## Headless invocation
61
+
62
+ Set `CANON_NON_INTERACTIVE=1` to refuse every prompt.
63
+
64
+ ```bash
65
+ CANON_NON_INTERACTIVE=1 canon init --stack node --skip wiki /path/to/project
66
+ CANON_NON_INTERACTIVE=1 canon sync /path/to/project
67
+ CANON_NON_INTERACTIVE=1 canon gov install node --add astro,shadcn /path/to/project
68
+ CANON_NON_INTERACTIVE=1 canon gov sync /path/to/project
69
+ CANON_NON_INTERACTIVE=1 canon gov build /path/to/project
70
+ CANON_NON_INTERACTIVE=1 canon tooling diff astro /path/to/project
71
+ CANON_NON_INTERACTIVE=1 canon tooling sync astro /path/to/project --write
72
+ CANON_NON_INTERACTIVE=1 canon wiki init /path/to/project
73
+ canon tooling inject base /path/to/project --configs --seeds
74
+ canon tooling prune-gitignore base /path/to/project
75
+ canon tooling verify vite-react
76
+ canon audits run --json
77
+ canon secrets scan --json
78
+ canon deps audit --json
79
+ ```
69
80
 
70
- Diagnostics reach stderr in every mode, including `--json`. Name the file and the field that failed, because a JSON record carries an action and a reason and an operator reading stderr alone sees neither.
81
+ - `canon tooling sync` needs `--check` or `--write` headlessly. With neither it reports and exits 1.
82
+ - `--skip base` syncs a monorepo subtree without the layer the root owns
83
+ - `canon audits run` exits 2 on a fact and 3 for an audit that did not report
84
+ - `secrets scan` and `deps audit` exit 2 on findings. Only a credential fails `audits run`, and an advisory reports without moving the verdict.
85
+ - Both refuse with a `reason` when they have no corpus, `no-manifest` for the scan and `no-lockfile` for the audit
@@ -1,26 +1,50 @@
1
1
  ---
2
2
  title: Overview
3
- description: What this folder covers, the invocation rules every command inherits, and where domain behavior is documented instead
3
+ description: What this folder covers, the invocation rules every command inherits, and how canon docs resolves a topic name
4
4
  ---
5
5
 
6
6
  # Overview
7
7
 
8
- CLI catalog and invocation rules for an agent driving the `canon` CLI, in this repository or in any project that installed it.
8
+ Reference for an agent driving the `canon` CLI, in this repository or in any project that installed it. It covers invocation and output contracts, not domain behavior. Read the project's own `CLAUDE.md` for that.
9
9
 
10
- This folder is an index of what an agent can run and how to run it cleanly from a script. It does not cover domain behavior. Read the project's own `CLAUDE.md` for that. The `.claude/skills/internal-*` skills carry the per-domain editing guidance and live in the toolkit checkout alone, so a reader who installed the package resolves none of them.
10
+ `canon --help` is the command catalog. `canon <command> --help` lists subcommands, and `canon <command> <subcommand> --help` prints a leaf's flags, exit codes, and examples. `--help --all` prints both. A pipe gets the same text without the frame glyphs.
11
11
 
12
12
  ## Invocation rules
13
13
 
14
- `output-shape.md` holds the stream and exit contract. It applies to every command in this folder.
14
+ `output-shape.md` holds the stream and exit contract every command follows. Every command has a non-interactive path, and data on stdout pipes clean.
15
15
 
16
- ## Where to start
16
+ ## Reading a page by name
17
17
 
18
- - `output-shape.md`: the stream contract every command renders into and the exit discipline behind it, which is what a caller parsing stdout depends on
19
- - `commands.md`: the full command catalog, project-level and per-domain
20
- - `scripting.md`: the runtime catalogs that replace hardcoded names, plus headless invocation examples
18
+ `canon docs list [--json]` lists the consumer docs, plus the per-domain context entries when the install carries `canon/context/`. A registry install carries `docs/` alone. A clone or a linked worktree carries both.
21
19
 
22
- ## Related
20
+ `canon docs <topic>` prints one doc to stdout, and an unknown topic names the available ones on stderr and exits 1. Three spellings are tried in order, each across both roots before the next, with `docs/` ahead of `canon/context/`.
23
21
 
24
- - `CLAUDE.md`: project behaviors
25
- - `.claude/skills/internal-*`: domain-scoped guidance for editing work, in the toolkit checkout only
26
- - `docs/index.md`: full docs directory
22
+ - A sibling file, such as `docs/agents/indexes.md` for `indexes`
23
+ - A folder of that name, which prints its generated `index.md`
24
+ - A sub-area file one level down, such as `operating-model` reaching `docs/workflow/operating-model.md`
25
+
26
+ A bare name carried by two folders of one root resolves to neither and exits 1. Toolkit-internal topics resolve by name and stay off the list.
27
+
28
+ ## Commands with no page
29
+
30
+ `canon serve [dir]` binds loopback and prints the link that opens the directory.
31
+
32
+ - Read `url` off `--json`, since a busy port walks forward to the next free one
33
+ - `--entry` escaping the root refuses as `no-entry` before a port is taken
34
+ - Any other bind failure refuses as `bind-failed` carrying the error code
35
+ - `entryExists` reads true with no `--entry` and no root `index.html`
36
+
37
+ `canon inventory [subject]` reads `inventory.toml` at the project root and never gates. A missing server and an unmatched query refuse rather than list nothing.
38
+
39
+ ```toml
40
+ base-url = "http://localhost:4173"
41
+ routes = ["/", "/pricing"]
42
+
43
+ [subjects.focus]
44
+ query = "button, a[href], input"
45
+ ```
46
+
47
+ ## See also
48
+
49
+ - `output-shape.md`: the frame, `--json`, color, and exit discipline
50
+ - `docs/index.md`: the full docs directory
@@ -5,7 +5,7 @@ description: Reading per CLAUDE.md section how many bullets name a path, what co
5
5
 
6
6
  # Routing report
7
7
 
8
- `canon claude routing` reports, per `CLAUDE.md` section, how many top-level bullets name a path and how many of those a path-scoped rule already covers. It answers the firing axis of the tier test in `canon/context/context-model/overview.md`, whether a fact applies every session or fires on one path, and which until this verb existed was a judgment nothing counted. The tier test names two further axes, conditional presence and updatability, that this verb does not check.
8
+ `canon claude routing` reports, per `CLAUDE.md` section, how many top-level bullets name a path and how many of those a path-scoped rule already covers. It answers the firing axis of the tier test in `canon/context/context-model.md`, whether a fact applies every session or fires on one path, and which until this verb existed was a judgment nothing counted. The tier test names two further axes, conditional presence and updatability, that this verb does not check.
9
9
 
10
10
  ```bash
11
11
  canon claude routing
@@ -34,7 +34,7 @@ A citation reaches a reader as a backticked path, reported under the form `path`
34
34
 
35
35
  A call to the retired standards verb is no form here. A rule holding one fails the shipped-references stage of `canon gate run`, which reads every shipped file for it.
36
36
 
37
- A `path` is anchored on the whole backticked span rather than on a trailing pattern inside it. Cutting `tooling-reference.md` out of `internal/standards/tooling-reference.md` and resolving that against the root alone reports a file that exists as missing, which is a mistake made by hand while measuring this corpus before the stage was written.
37
+ A `path` is anchored on the whole backticked span rather than on a trailing pattern inside it. Cutting `tooling-reference.md` out of `.claude/skills/internal-tooling/references/tooling-reference.md` and resolving that against the root alone reports a file that exists as missing, which is a mistake made by hand while measuring this corpus before the stage was written.
38
38
 
39
39
  ## What is not a citation
40
40
 
@@ -52,7 +52,7 @@ A path a seed installs is disowned twice, under its own name and under the folde
52
52
  A correct citation and a defective one are the same string, and the sentence around it is the difference. A citation counts as decided when its line names the toolkit as the owner, matching the bodies that already spell it that way. The repair for a finding is to say whose copy the path is, never to delete the citation, since the paths name real documents a reader wants.
53
53
 
54
54
  ```markdown
55
- Read `canon/context/context-model/indexes.md` from the toolkit if context on the system is needed.
55
+ Read `canon/context/context-model.md` from the toolkit if context on the system is needed.
56
56
  ```
57
57
 
58
58
  A line mentioning the toolkit for an unrelated reason exempts a citation on it. That is the accepted cost of a word over a notation every future body would have to learn.
@@ -1,91 +1,39 @@
1
1
  ---
2
2
  title: Targets
3
- description: The projects this toolkit installed into, the record the install writes against the sweep that backs it, what bounds each answer, and the cross-target pull request read
3
+ description: The projects this toolkit installed into, where each answer comes from, and the cross-target pull request read
4
+ kind: reference
4
5
  ---
5
6
 
6
7
  # Targets
7
8
 
8
- ## List
9
+ `canon targets list` reports the projects this toolkit installed into. `canon targets pulls [paths…]` reports each target's open pull requests, or every target's when none is named. Both take `--json`. Read the record's fields, since a wrapping shell function can flatten the exit.
9
10
 
10
- `canon targets list` reports the projects this toolkit has installed into, with where each answer came from.
11
+ - `list` takes `--sweep <path…>`, `--depth <n>` (default 4), and `--record`, which seeds the index from swept stamps and needs `--sweep`
12
+ - Each stamping sync records its target in `$XDG_STATE_HOME/canon/targets.json`, and no row is removed
13
+ - A sweep finds installs the index never held
11
14
 
12
- ```bash
13
- canon targets list
14
- canon targets list --json
15
- canon targets list --sweep ~/repos --json
16
- canon targets list --sweep ~/repos --record
17
- ```
15
+ ## Output
18
16
 
19
- | Option | Behavior |
20
- | ----------------- | -------------------------------------------------------------------------------- |
21
- | `--json` | Add a machine-readable record on stdout |
22
- | `--sweep <path…>` | Also walk these roots for targets the record never held |
23
- | `--depth <n>` | How deep below each swept root to walk, defaulting to 4 |
24
- | `--record` | Seed the index from every swept checkout's own stamp, refusing without `--sweep` |
17
+ - `bound` on a sweep names the roots walked, the depth, and what it skipped. Read it before trusting a count.
18
+ - Clones sharing an `origin` share a row, and `pulls` reads one
19
+ - `legacyPaths` is the `paths` on the retired stamp path
25
20
 
26
- Exit codes: `0` the population was read, `1` refused. A refusal carries a `reason` of `bad-depth` or, for `--record` given with no `--sweep`, `record-without-sweep`. An absent index reports as unknown rather than as no targets.
21
+ | Field | Holds |
22
+ | ---------------- | -------------------------------------------------------- |
23
+ | `checks` | `passing`, `failing`, `pending`, or `null` when none ran |
24
+ | `review` | `open`, `closed`, or `null` when no pass has landed |
25
+ | `reviewReadable` | `false` when the review query failed |
27
26
 
28
- An exit code says nothing about a call made from a session, since a shell profile may wrap the binary in a function taking its status from a later command. Read the record's fields rather than the exit when a skill consumes this.
27
+ ## Refusals
29
28
 
30
- ## Where the answer comes from
29
+ `list` exits 1 when refused. `pulls` exits 0 when one target was read and 1 when all refused. An absent index reads as unknown.
31
30
 
32
- Every sync that stamps a target records it in a machine-level index at `$XDG_STATE_HOME/canon/targets.json`, falling back to `~/.local/state/canon/targets.json`. A project installed into since that shipped is therefore known without anyone naming it, and each row carries `stampedAt` from the sync that last touched it.
31
+ | Reason | Means |
32
+ | ---------------------- | --------------------------------------- |
33
+ | `bad-depth` | `--depth` is not a whole number |
34
+ | `record-without-sweep` | `--record` with no `--sweep` |
35
+ | `not-a-directory` | A named path is no directory |
36
+ | `gh-unavailable` | `gh` is not on the path |
37
+ | `list-failed` | The pull request list could not be read |
33
38
 
34
- `--sweep` walks the roots given and finds what the record never held, which is every target installed before the index existed. A row says which of the two found it, and a row the record knows keeps that source even when the sweep reaches it too.
35
-
36
- The record is the primary source and the sweep is the fallback, because they fail in opposite directions. A record only knows an install that ran after it shipped. A walk only knows the paths someone thought to name, which is how a hand census of this population was wrong in both directions at once: it counted two folders that had never been targets, counted one clone of a target already counted, and missed the clone a repair had actually run in.
37
-
38
- ## What bounds a sweep
39
-
40
- A `--sweep` run carries a `bound` object naming the roots walked, the depth, the folders the walk stopped at on reaching the cap, the roots it could not read, and the directory symlinks it did not follow. Read it before treating a count as the population.
41
-
42
- The bound a sweep can never state is the machine. It reads this one, so a target on another machine or under a path nobody named is outside every answer it gives. That is the same limit the hand census had, and the record above is what closes it going forward rather than the sweep.
43
-
44
- `--depth` refuses anything that is not a whole number rather than falling back to the default. A value that is not one leaves every depth test false, so the walk runs to the bottom of its root while the bound claims a cap it never applied.
45
-
46
- ## A project held in more than one clone
47
-
48
- A target cloned twice is one target. The sweep reads each checkout's `origin`, trims it to a form an ssh URL and an https URL of one repository agree on, and reports a single row holding every path.
49
-
50
- The row leads with the clone the record knows, because the record only names one a sync actually ran in. Every caller reading a single path takes the first, and picking that by sort order is the shape behind a repair that ran in one clone while a count was taken against another, leaving the target reported as untouched.
51
-
52
- Nothing removes a row. A project deleted, moved, or that dropped the toolkit stays in the index, so a count drifts upward over time. It surfaces on use rather than silently, since the read below refuses a path it cannot open.
53
-
54
- ## The retired stamp path
55
-
56
- Each row names the subset of its checkouts still carrying the install stamp at the retired path: `legacyPaths` in the JSON, a subset of `paths` in the same order. The render says `legacy stamp` plain when every checkout carries it and `legacy stamp (1 of 2 checkouts)` when only some do, which is the common case rather than the rare one.
57
-
58
- `--record` backfills the index from a sweep rather than from a sync, for a target the record never held. It seeds one row per checkout from that checkout's own installed stamp, taking `stampedAt` from the stamp itself rather than from the moment the backfill ran, so a backfilled row never claims a sync that did not happen. A checkout whose stamp cannot be read is skipped rather than dated by the backfill. It refuses without `--sweep` naming what to walk.
59
-
60
- ## Pulls
61
-
62
- `canon targets pulls` reports, per target, every open pull request with its checks and the heading its newest review pass carries.
63
-
64
- ```bash
65
- canon targets pulls
66
- canon targets pulls ../caret ../stackr --json
67
- ```
68
-
69
- Naming paths reads those and looks up nothing. Naming none reads every target `canon targets list` reports. One clone per project is read, since two checkouts sharing an origin answer the same query and reading both spends the rate limit to print one answer twice.
70
-
71
- Exit codes: `0` at least one target was read, `1` refused or every target refused.
72
-
73
- | Field | Holds |
74
- | ---------------- | ----------------------------------------------------------------------- |
75
- | `checks` | `passing`, `failing`, `pending`, or `null` when GitHub reported none |
76
- | `review` | `open`, `closed`, or `null` when no pass has landed |
77
- | `reviewReadable` | `false` when the review query failed, leaving `review` covering nothing |
78
-
79
- `checks` is `null` rather than `passing` when no check ran at all, which is not the same answer. A failure outranks a run still going, since a job that already failed cannot be cleared by one still in flight.
80
-
81
- `review` reads the first line of the newest pass carrying `## Review` or `## Review closed`, which `review-pr` owns and posts. A target leaves a wave on `closed` rather than on a worker's reply.
82
-
83
- A target that could not be read carries a `reason` rather than an empty pull list. Reading a failed query as no open work is what reports a target as done having read nothing, which is the failure mode of the hand-written shell loop this replaces.
84
-
85
- | Reason | Means |
86
- | ----------------- | ------------------------------------------------------ |
87
- | `not-a-directory` | the path is not a directory, so nothing was read there |
88
- | `gh-unavailable` | `gh` is not on the path |
89
- | `list-failed` | the open pull request list could not be read |
90
-
91
- The reads run one target at a time. They share one GitHub API quota, and a wave firing a dozen at once meets the secondary rate limit rather than an answer.
39
+ The last three fail only that target's row.
@@ -144,4 +144,4 @@ A `## States` table under `canon/wireframes/` is no longer checked against evide
144
144
 
145
145
  The toolkit stopped seeding a `canon/ARCHITECTURE.md`, stopped gating its caps, and retired the `architecture` standard and the rule generated from it. A project scaffolded earlier may hold the file and import it from `CLAUDE.md`. Both stay, since the record is project prose now and nothing syncs or deletes it. `canon gov sync` removes the generated rule, and `canon context audit` no longer reports the record or its caps.
146
146
 
147
- Decide what to do with the file yourself, since where a decision belongs takes judgment no sync has. A decision about how one domain is built goes to the `canon/context/` entry of the domain it constrains, under that entry's `## Decisions`. Once the file is empty, delete it and its `@canon/ARCHITECTURE.md` line in `CLAUDE.md`.
147
+ Decide what to do with the file yourself, since where a decision belongs takes judgment no sync has. A decision about how one domain is built is recorded by the pull request that made it, and a context entry carries no decisions. Move a trap a session would hit into that domain's `## Gotchas`. Once the file is empty, delete it and its `@canon/ARCHITECTURE.md` line in `CLAUDE.md`.
@@ -57,7 +57,7 @@ The chain is:
57
57
 
58
58
  - `canon init` installs base tooling, Claude seeds, and governance rules into `.claude/rules/` in the same pass
59
59
  - `canon tooling sync <stack> --write` adds stack-specific deps, scripts, and gitignore entries
60
- - The agent reads `canon tooling reference <stack>` (plus parents) as its audit context, follows it to generate eslint, vitest, playwright configs and the stack's setup script, and extends `canon/context/ci.md` and `canon/context/development.md` per the reference's extend sections <!-- audit-ignore-citations: canon/context/ci.md, canon/context/development.md -->
60
+ - The agent reads `canon tooling reference <stack>` (plus parents) as its audit context, follows it to generate oxlint, vitest, playwright configs and the stack's setup script, and extends `canon/context/ci.md` and `canon/context/development.md` per the reference's extend sections <!-- audit-ignore-citations: canon/context/ci.md, canon/context/development.md -->
61
61
  - The `verify` phase runs the installed `package.json` scripts (lint, typecheck, check, test, build) and reports pass or fail
62
62
  - The `indexes` phase bootstraps the `index.md` system over the project's own documentation folders, confirming candidate folders with the operator rather than running unattended
63
63
 
@@ -71,7 +71,7 @@ Keep the `## Scripts` table in `canon/context/development.md` current as scripts
71
71
 
72
72
  Scaffold installs tooling and seeds. It does not fill the planning docs or the design system. Complete those before the first feature session:
73
73
 
74
- 1. Fill `canon/REQUIREMENTS.md`. The seed asks for the problem in one line, then goals and non-goals, and the scope is yours to write. The seed states its own cap of 600 words, and `canon context audit` gates on it. Edit the number in the record to loosen it. A decision about how the project is built goes in the `canon/context/` entry of the domain it constrains.
74
+ 1. Fill `canon/REQUIREMENTS.md`. The seed asks for the problem in one line, then goals and non-goals, and the scope is yours to write. The seed states its own cap of 600 words, and `canon context audit` gates on it. Edit the number in the record to loosen it. A decision about how the project is built lives in the pull request that made it, and a `canon/context/` entry carries the domain's folders and traps.
75
75
  2. For a UI project, write `canon/DESIGN.md` from the seed template and name the project's stylesheet in its lead, or work the direction out with `canon:canvas-board` and carry the pick in. Skip for non-UI projects.
76
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 context index, the folder layout, 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.
@@ -134,5 +134,5 @@ When the toolkit updates, a target pulls changes per domain. A project scaffolde
134
134
  - [agents](../agents/index.md): CLI flags, exit codes, and JSON output shapes
135
135
  - [target migrations](migrations.md), [target sync](sync.md), [target scenarios](scenarios.md): the one-time moves, the recurring sync, and worked setups
136
136
  - [AI workflow](../workflow/ai-workflow.md): feature-development loop inside a toolkit-managed project
137
- - [tooling](../../canon/context/tooling/index.md), [governance](../../canon/context/governance/index.md), [claude plugin](../../canon/context/claude-plugin/index.md), [indexes](../../canon/context/context-model/indexes.md), [skill references](../../canon/context/claude-plugin/skill-references/index.md): per-domain mechanics
137
+ - [tooling](../../canon/context/tooling/index.md), [governance](../../canon/context/governance/index.md), [claude plugin](../../canon/context/claude-plugin/index.md), [indexes](../../canon/context/context-model.md), [skill references](../../canon/context/claude-plugin/skill-references/index.md): per-domain mechanics
138
138
  - [sandbox](../../canon/context/sandbox/index.md): scenario catalog for verifying domain flows
@@ -46,7 +46,7 @@ canon tooling sync vite-react ./frontend --skip base --write
46
46
  canon tooling sync python ./backend --skip base --write
47
47
  ```
48
48
 
49
- `--skip base` drops the `base` layer from each subtree sync, so husky, prettier, commitlint, and CI stay single at the repo root. The one exception is base's verify runner, `scripts/verify.ts` and `scripts/verify.json`, which every subtree still receives so it can verify on its own. Without it, every subtree re-drops husky, and since git honors only one `core.hooksPath` the extra hook dirs silently break. Each subtree still gets its own framework configs (eslint, vitest, tsconfig, vite), and its own stack reference reads through `canon tooling reference <stack>`.
49
+ `--skip base` drops the `base` layer from each subtree sync, so husky, oxfmt, commitlint, and CI stay single at the repo root. The one exception is base's verify runner, `scripts/verify.ts` and `scripts/verify.json`, which every subtree still receives so it can verify on its own. Without it, every subtree re-drops husky, and since git honors only one `core.hooksPath` the extra hook dirs silently break. Each subtree still gets its own framework configs (oxlint, vitest, tsconfig, vite), and its own stack reference reads through `canon tooling reference <stack>`.
50
50
 
51
51
  A sync whose target sits below the git root knows it is writing into a subfolder:
52
52
 
@@ -31,7 +31,7 @@ canon/
31
31
 
32
32
  A project scaffolded before the move keeps its records under `.claude/`, and every command reads either root. `canon migrate records` moves one project across and repoints what cites it, and `canon migrate record-tree` follows it to reach the citations inside the records themselves, which the first verb passes over because it enumerates through git. A project scaffolded before the surface move keeps its context and loose documents under `.claude/` the same way, and `canon migrate surface-roots` moves those to `canon/` with the history following each file.
33
33
 
34
- Three tiers of context load with different cost: always-loaded (root `CLAUDE.md` and `canon/REQUIREMENTS.md`), path-scoped lazy (`.claude/rules/<scope>.md` with `paths:` glob), and on-demand lookup (`canon/context/<domain>.md`, or `canon/context/<domain>/` once a domain outgrows one file, discovered via `canon/context/index.md`). See [the context model](../../canon/context/context-model/overview.md) for the full picture.
34
+ Three tiers of context load with different cost: always-loaded (root `CLAUDE.md` and `canon/REQUIREMENTS.md`), path-scoped lazy (`.claude/rules/<scope>.md` with `paths:` glob), and on-demand lookup (`canon/context/<domain>.md`, or `canon/context/<domain>/` once a domain outgrows one file, discovered via `canon/context/index.md`). See [the context model](../../canon/context/context-model.md) for the full picture.
35
35
 
36
36
  Run `canon init` to seed the `.claude/` directory, a root `CLAUDE.md` file, and `.claude/rules/` in one pass. `canon init` chains claude init and governance install. Claude Code auto-loads every file in `.claude/rules/` at session start, applying always-on rules unconditionally and path-scoped rules to files matching their `paths:` glob.
37
37
 
@@ -58,7 +58,7 @@ Then plan and build:
58
58
  - Invoke `canon:plan-feature` to scan for code-level conflicts and ambiguities, confirm approach before proceeding
59
59
  - Implement the feature, then Claude Code runs the commands defined in `CLAUDE.md`, fixes failures, and iterates until all pass
60
60
  - For UI changes, invoke `canon:ui-checklist` to write what a reviewer has to look at and name any behavior shipping without a test
61
- End the session once the feature works and tests pass. Invoke `canon:context-fold` to capture any decisions made during implementation before closing.
61
+ End the session once the feature works and tests pass. Invoke `canon:context-fold` before closing to refresh any context entry the diff left untrue.
62
62
 
63
63
  The routing test is whether the repository can answer an item today. A session grepping handles the yes, and a groundwork track handles the no.
64
64
 
@@ -54,7 +54,7 @@ A plan that ships is archived, never deleted. `canon tasks archive` moves it to
54
54
 
55
55
  An older branch review report takes the other route and is swept rather than archived. It sits flat in `.canon/review/` as `branch-<slug>.md`, the session addressing it read it once, and the durable record of what a review found is the comment `review-pr` posts on the pull request, so `canon:task-complete` 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:task-complete` decides which task closed by reading the diff rather than the conversation, as the ship-chain step after `canon:context-fold`. 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. Decisions stay session-sourced, because a diff cannot carry a judgment, and `canon:context-fold` folds them into the context entries. The requirements record is never folded. A direction change gets one report line naming `canon:document-health`, which reviews that record only when asked.
57
+ `canon:task-complete` decides which task closed by reading the diff rather than the conversation, as the ship-chain step after `canon:context-fold`. 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. `canon:context-fold` reads the same diff and rewrites a context entry only where a folder moved or a bullet or gotcha went untrue, and the pull request records each 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
  ## Shipping a fan-out
60
60
 
@@ -64,7 +64,7 @@ A fan-out of N worktrees produces N pull requests. The order they merge in matte
64
64
 
65
65
  - `CLAUDE.md`, since cross-domain behavior lives there
66
66
  - `tooling/**`, since stack manifests, golden configs, and seeds are tightly coupled
67
- - `canon/context/context-model/overview.md` and `docs/agents/`, which several domains cross-reference
67
+ - `canon/context/context-model.md` and `docs/agents/`, which several domains cross-reference
68
68
  - Any folder's `index.md`, since `canon indexes regen` rewrites it and two worktrees adding files to a regen-covered folder race on it. Resolve its conflict by running the regen over the rebased tree rather than by hand.
69
69
 
70
70
  Land any in-flight edit to a hotspot on `main` before fanning out where you can. A worktree on a stale `CLAUDE.md` costs more to rebase than it saved.
@@ -66,7 +66,7 @@ Each row sits under the group its skill's `metadata.family` names. The landing p
66
66
  | Skill | When to use |
67
67
  | --------------------- | ----------------------------------------------------------------------------------------------- |
68
68
  | `canon:git-ship` | To run the whole post-feature chain from the verify gate through open PR |
69
- | `canon:context-fold` | When decisions diverged from the plan, or the diff left a context entry stale |
69
+ | `canon:context-fold` | When the diff moved a folder or left a context entry's bullet or gotcha untrue |
70
70
  | `canon:task-complete` | After the fold, to mark the outcomes the diff shipped, or to archive a task the merge hook left |
71
71
  | `canon:docs-sync` | When a change since main left `README.md` or `docs/` stale |
72
72
  | `canon:git-stage` | When the staged set spans several concerns and wants one commit each |
@@ -22,7 +22,7 @@ Claude Code reads it and writes the implementation. Works for CLI tools, interna
22
22
 
23
23
  The toolkit seed in `tooling/claude/seeds/canon/DESIGN.md` ships an intent template with a starting set of roles, each naming its custom property, and `claude/skills/canvas-board/references/design.md` carries the same tables under `## Template` with placeholder rows. The column headers are what the parser reads, so they stay verbatim in either, while the rows are the project's own. The seed's lead asks for the project's own stylesheet, such as `src/styles/tokens.css` or a Tailwind `@theme` block, and falls back to `.claude/design/project/` only when the project has none.
24
24
 
25
- `canon design render` writes an HTML plus CSS preview to `.canon/tmp/render/design/` for eyeballing the current system without leaving Claude Code. See `canon/context/design/index.md`.
25
+ `canon design render` writes an HTML plus CSS preview to `.canon/tmp/render/design/` for eyeballing the current system without leaving Claude Code. See `canon/context/design.md`.
26
26
 
27
27
  A project wanting a neutral starting point to override runs `canon design install`, which copies one stylesheet to `.claude/design/base.css` carrying an achromatic token set as custom properties and two components built on them. Greys run from near-black to near-white and the accent is monochrome, so the only palette the project renders is one it writes itself. That file is toolkit-owned and `canon design sync` refreshes it, so a project overrides a value in `.claude/design/project/` instead, which sync never touches. Nothing arrives without that install, and the two channels are independent: a record the project wrote is its own, and the installed stylesheet is the toolkit's.
28
28
 
@@ -27,7 +27,12 @@ files = [".github/workflows"]
27
27
 
28
28
  ["dependencies"]
29
29
  deps = []
30
- files = ["**/package.json", "**/pyproject.toml", "**/go.mod", "**/composer.json"]
30
+ files = [
31
+ "**/package.json",
32
+ "**/pyproject.toml",
33
+ "**/go.mod",
34
+ "**/composer.json",
35
+ ]
31
36
 
32
37
  ["config-comments"]
33
38
  deps = []