@erclx/canon 5.44.0 → 5.46.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 (253) hide show
  1. package/README.md +1 -1
  2. package/claude/.claude-plugin/plugin.json +1 -1
  3. package/claude/skills/api-design/REQUIREMENT.md +15 -31
  4. package/claude/skills/auto-ship/REQUIREMENT.md +14 -25
  5. package/claude/skills/backlog-triage/REQUIREMENT.md +12 -23
  6. package/claude/skills/build-in-slices/REQUIREMENT.md +15 -25
  7. package/claude/skills/canon-cli/REQUIREMENT.md +15 -27
  8. package/claude/skills/canon-cli/SKILL.md +0 -1
  9. package/claude/skills/canon-feedback/REQUIREMENT.md +10 -18
  10. package/claude/skills/canon-feedback-triage/REQUIREMENT.md +10 -15
  11. package/claude/skills/canvas-board/REQUIREMENT.md +14 -28
  12. package/claude/skills/ci-workflow/REQUIREMENT.md +12 -21
  13. package/claude/skills/code-craft/REQUIREMENT.md +14 -28
  14. package/claude/skills/codebase-layout/REQUIREMENT.md +14 -31
  15. package/claude/skills/context-fold/REQUIREMENT.md +15 -39
  16. package/claude/skills/context-fold/references/context.md +3 -3
  17. package/claude/skills/create-rule/REQUIREMENT.md +10 -24
  18. package/claude/skills/create-rule/SKILL.md +3 -0
  19. package/claude/skills/create-skill/REQUIREMENT.md +10 -21
  20. package/claude/skills/decision-escalate/REQUIREMENT.md +12 -24
  21. package/claude/skills/deploy-app/REQUIREMENT.md +12 -22
  22. package/claude/skills/deprecation-migration/REQUIREMENT.md +14 -42
  23. package/claude/skills/design-identity/REQUIREMENT.md +14 -20
  24. package/claude/skills/design-taste/REQUIREMENT.md +16 -57
  25. package/claude/skills/docs-sync/REQUIREMENT.md +14 -23
  26. package/claude/skills/document-health/REQUIREMENT.md +15 -29
  27. package/claude/skills/document-health/SKILL.md +2 -2
  28. package/claude/skills/document-repair/REQUIREMENT.md +32 -0
  29. package/claude/skills/document-repair/SKILL.md +76 -0
  30. package/claude/skills/document-repair/references/batches.md +44 -0
  31. package/claude/skills/draft-and-pick/REQUIREMENT.md +4 -3
  32. package/claude/skills/draft-doc/REQUIREMENT.md +4 -3
  33. package/claude/skills/draft-figure/REQUIREMENT.md +4 -3
  34. package/claude/skills/draft-identity/REQUIREMENT.md +4 -3
  35. package/claude/skills/draft-ready/REQUIREMENT.md +4 -3
  36. package/claude/skills/draft-screencast/REQUIREMENT.md +4 -3
  37. package/claude/skills/draft-slides/REQUIREMENT.md +4 -3
  38. package/claude/skills/draw-figure/REQUIREMENT.md +15 -39
  39. package/claude/skills/git-branch/REQUIREMENT.md +12 -26
  40. package/claude/skills/git-commit/REQUIREMENT.md +11 -15
  41. package/claude/skills/git-followup/REQUIREMENT.md +11 -22
  42. package/claude/skills/git-issue/REQUIREMENT.md +9 -15
  43. package/claude/skills/git-pr/REQUIREMENT.md +13 -32
  44. package/claude/skills/git-pr/SKILL.md +10 -2
  45. package/claude/skills/git-pr/references/closing-issues.md +47 -0
  46. package/claude/skills/git-pr/references/pr.md +4 -0
  47. package/claude/skills/git-ship/REQUIREMENT.md +13 -26
  48. package/claude/skills/git-split/REQUIREMENT.md +10 -17
  49. package/claude/skills/git-stage/REQUIREMENT.md +12 -18
  50. package/claude/skills/git-worktree/REQUIREMENT.md +15 -19
  51. package/claude/skills/make-deck/REQUIREMENT.md +13 -21
  52. package/claude/skills/markdown-craft/REQUIREMENT.md +9 -3
  53. package/claude/skills/pick-by-eye/REQUIREMENT.md +17 -67
  54. package/claude/skills/plan-feature/REQUIREMENT.md +15 -24
  55. package/claude/skills/plan-groundwork/REQUIREMENT.md +12 -28
  56. package/claude/skills/plan-groundwork/SKILL.md +5 -2
  57. package/claude/skills/plan-groundwork/references/output.md +47 -1
  58. package/claude/skills/plan-intake/REQUIREMENT.md +11 -26
  59. package/claude/skills/plan-intake/references/intake.md +2 -2
  60. package/claude/skills/plan-intake-answer/REQUIREMENT.md +14 -29
  61. package/claude/skills/plan-intake-answer/SKILL.md +7 -1
  62. package/claude/skills/plan-ready/REQUIREMENT.md +17 -36
  63. package/claude/skills/pr-evidence/REQUIREMENT.md +11 -17
  64. package/claude/skills/read-frames/REQUIREMENT.md +3 -8
  65. package/claude/skills/record-screencast/REQUIREMENT.md +14 -17
  66. package/claude/skills/review-address/REQUIREMENT.md +14 -38
  67. package/claude/skills/review-craft/REQUIREMENT.md +14 -32
  68. package/claude/skills/review-pr/REQUIREMENT.md +15 -34
  69. package/claude/skills/review-ui/REQUIREMENT.md +14 -39
  70. package/claude/skills/role-orchestrator/REQUIREMENT.md +16 -99
  71. package/claude/skills/role-orchestrator/references/orchestrator-refill.md +5 -0
  72. package/claude/skills/role-orchestrator/references/orchestrator-review-dispatch.md +9 -0
  73. package/claude/skills/role-planner/REQUIREMENT.md +15 -73
  74. package/claude/skills/role-reviewer/REQUIREMENT.md +15 -65
  75. package/claude/skills/role-reviewer/SKILL.md +5 -1
  76. package/claude/skills/role-worker/REQUIREMENT.md +13 -41
  77. package/claude/skills/role-worker/SKILL.md +2 -0
  78. package/claude/skills/script-screencast/REQUIREMENT.md +10 -16
  79. package/claude/skills/search-craft/REQUIREMENT.md +12 -36
  80. package/claude/skills/search-craft/SKILL.md +1 -1
  81. package/claude/skills/search-craft/references/adopted.md +2 -2
  82. package/claude/skills/session-compact/REQUIREMENT.md +13 -23
  83. package/claude/skills/session-map/REQUIREMENT.md +13 -29
  84. package/claude/skills/session-relay/REQUIREMENT.md +14 -58
  85. package/claude/skills/session-relay/SKILL.md +6 -0
  86. package/claude/skills/session-resume/REQUIREMENT.md +13 -27
  87. package/claude/skills/session-worktree/REQUIREMENT.md +14 -43
  88. package/claude/skills/systematic-debugging/REQUIREMENT.md +13 -34
  89. package/claude/skills/target-check/REQUIREMENT.md +16 -23
  90. package/claude/skills/target-setup/REQUIREMENT.md +11 -34
  91. package/claude/skills/target-setup/SKILL.md +2 -2
  92. package/claude/skills/target-setup/references/detect.md +0 -1
  93. package/claude/skills/target-setup/references/verify.md +2 -2
  94. package/claude/skills/task-board/REQUIREMENT.md +13 -22
  95. package/claude/skills/task-board/SKILL.md +7 -0
  96. package/claude/skills/task-board/references/tasks.md +1 -1
  97. package/claude/skills/task-complete/REQUIREMENT.md +11 -24
  98. package/claude/skills/task-complete/references/archive.md +1 -0
  99. package/claude/skills/teach-workspace/REQUIREMENT.md +14 -45
  100. package/claude/skills/teach-workspace/references/promotion.md +5 -5
  101. package/claude/skills/test-craft/REQUIREMENT.md +15 -46
  102. package/claude/skills/test-first/REQUIREMENT.md +14 -20
  103. package/claude/skills/ui-checklist/REQUIREMENT.md +14 -29
  104. package/claude/skills/ux-audit/REQUIREMENT.md +3 -7
  105. package/claude/skills/ux-measure/REQUIREMENT.md +14 -28
  106. package/claude/skills/video-craft/REQUIREMENT.md +14 -27
  107. package/claude/skills/write-doc/REQUIREMENT.md +14 -24
  108. package/claude/skills/write-human/REQUIREMENT.md +15 -27
  109. package/claude/skills/youtube-transcripts/REQUIREMENT.md +9 -15
  110. package/docs/agents/context-audit.md +19 -12
  111. package/docs/agents/install-and-sync.md +2 -2
  112. package/docs/agents/markdown-audit.md +15 -10
  113. package/docs/agents/output-shape.md +1 -2
  114. package/docs/target/migrations.md +18 -0
  115. package/docs/target/projects.md +3 -2
  116. package/docs/target/scenarios.md +4 -1
  117. package/docs/workflow/skill-map-on-request.md +1 -1
  118. package/docs/workflow/skill-map.md +6 -5
  119. package/governance/detect.toml +4 -0
  120. package/governance/ledger/lang/go.md +61 -0
  121. package/governance/ledger/lang/php.md +50 -0
  122. package/governance/ledger/lang/python.md +68 -0
  123. package/governance/ledger/lang/typescript.md +64 -0
  124. package/governance/ledger/lib/database.md +65 -0
  125. package/governance/ledger/lib/e2e-reliability.md +57 -0
  126. package/governance/ledger/lib/pydantic.md +61 -0
  127. package/governance/ledger/lib/security-server.md +62 -0
  128. package/governance/ledger/lib/security-web.md +51 -0
  129. package/governance/ledger/lib/tanstack-query.md +57 -0
  130. package/governance/ledger/lib/test-scope.md +43 -0
  131. package/governance/ledger/lib/testing-go.md +57 -0
  132. package/governance/ledger/lib/testing-php.md +51 -0
  133. package/governance/ledger/lib/testing-py.md +67 -0
  134. package/governance/ledger/lib/testing-ts.md +63 -0
  135. package/governance/ledger/lib/zod.md +47 -0
  136. package/governance/ledger/tooling/ci-workflow.md +33 -0
  137. package/governance/ledger/tooling/code-comments.md +48 -0
  138. package/governance/ledger/tooling/config-comments.md +27 -0
  139. package/governance/ledger/tooling/dependencies.md +38 -0
  140. package/governance/ledger/ui/a11y.md +55 -0
  141. package/governance/ledger/ui/copy.md +49 -0
  142. package/governance/ledger/ui/design-reference.md +42 -0
  143. package/governance/ledger/ui/design-taste.md +19 -0
  144. package/governance/ledger/ui/forms.md +71 -0
  145. package/governance/ledger/ui/interface-casing.md +47 -0
  146. package/governance/ledger/ui/keyboard.md +68 -0
  147. package/governance/ledger/ui/link-behavior.md +29 -0
  148. package/governance/ledger/ui/motion.md +33 -0
  149. package/governance/ledger/ui/surface-capture.md +69 -0
  150. package/governance/ledger/ui/ux-completeness.md +79 -0
  151. package/governance/renames.toml +0 -2
  152. package/governance/rules/claude/output.md +5 -1
  153. package/governance/rules/code/routing.md +5 -1
  154. package/governance/rules/lang/go.md +7 -16
  155. package/governance/rules/lang/php.md +3 -3
  156. package/governance/rules/lang/python.md +9 -18
  157. package/governance/rules/lang/typescript.md +9 -19
  158. package/governance/rules/lib/database.md +5 -5
  159. package/governance/rules/lib/e2e-reliability.md +4 -6
  160. package/governance/rules/lib/pydantic.md +14 -16
  161. package/governance/rules/lib/security-server.md +4 -4
  162. package/governance/rules/lib/security-web.md +6 -10
  163. package/governance/rules/lib/tanstack-query.md +10 -12
  164. package/governance/rules/lib/test-scope.md +4 -4
  165. package/governance/rules/lib/testing-go.md +1 -2
  166. package/governance/rules/lib/testing-php.md +4 -5
  167. package/governance/rules/lib/testing-py.md +11 -19
  168. package/governance/rules/lib/testing-ts.md +7 -16
  169. package/governance/rules/lib/zod.md +6 -8
  170. package/governance/rules/tooling/code-comments.md +2 -4
  171. package/governance/rules/tooling/config-comments.md +1 -4
  172. package/governance/rules/tooling/dependencies.md +1 -1
  173. package/governance/rules/ui/a11y.md +16 -45
  174. package/governance/rules/ui/copy.md +6 -9
  175. package/governance/rules/ui/forms.md +13 -19
  176. package/governance/rules/ui/interface-casing.md +5 -7
  177. package/governance/rules/ui/keyboard.md +38 -0
  178. package/governance/rules/ui/link-behavior.md +3 -3
  179. package/governance/rules/ui/motion.md +3 -3
  180. package/governance/rules/ui/surface-capture.md +15 -27
  181. package/governance/rules/ui/ux-completeness.md +16 -39
  182. package/governance/stacks/base.toml +0 -1
  183. package/package.json +1 -1
  184. package/scripts/core/install-check.sh +1 -1
  185. package/src/claude/cases/workflow.ts +12 -0
  186. package/src/cli/help.ts +0 -1
  187. package/src/cli.ts +0 -2
  188. package/src/commands/context.ts +57 -3
  189. package/src/commands/gov.ts +4 -0
  190. package/src/commands/init.ts +2 -2
  191. package/src/commands/labels.ts +83 -3
  192. package/src/commands/markdown.ts +188 -21
  193. package/src/commands/sessions.ts +36 -3
  194. package/src/commands/tasks.ts +180 -0
  195. package/src/commands/tooling.ts +18 -5
  196. package/src/commands/worktrees.ts +2 -0
  197. package/src/context/coverage.ts +210 -0
  198. package/src/context/gate.ts +12 -3
  199. package/src/design/components.ts +1 -1
  200. package/src/gate/stages.ts +1 -1
  201. package/src/gov/audit.ts +22 -2
  202. package/src/init/plan.ts +1 -8
  203. package/src/init/steps.ts +44 -7
  204. package/src/intake/items.ts +14 -0
  205. package/src/inventory/subjects.ts +1 -1
  206. package/src/labels/closing.ts +46 -0
  207. package/src/markdown/gated.ts +250 -0
  208. package/src/markdown/scope.ts +119 -2
  209. package/src/migrate/rename.ts +6 -0
  210. package/src/migrate/scratch-evidence.ts +12 -4
  211. package/src/records/backup.ts +3 -3
  212. package/src/records/validate.ts +3 -3
  213. package/src/roots/record.ts +17 -8
  214. package/src/sessions/claim.ts +7 -0
  215. package/src/sessions/live.ts +53 -6
  216. package/src/sessions/registry.ts +11 -0
  217. package/src/sessions/resolve.ts +32 -5
  218. package/src/tasks/closes.ts +136 -0
  219. package/src/tasks/record.ts +1 -1
  220. package/src/tooling/inject.ts +26 -7
  221. package/src/tooling/package.ts +32 -0
  222. package/src/tooling/read.ts +46 -3
  223. package/src/tooling/scan.ts +8 -2
  224. package/src/worktrees/reclaim.ts +16 -1
  225. package/tooling/astro/reference.md +64 -93
  226. package/tooling/base/configs/.github/workflows/phase-label-gate.yml +1 -1
  227. package/tooling/base/configs/scripts/verify.ts +2 -2
  228. package/tooling/base/reference.md +1 -9
  229. package/tooling/base/seeds/canon/context/{ci.md → development/ci.md} +1 -1
  230. package/tooling/base/seeds/canon/context/development/index.md +11 -0
  231. package/tooling/base/seeds/canon/context/{development.md → development/setup.md} +8 -12
  232. package/tooling/base/seeds/canon/context/index.md +1 -2
  233. package/tooling/claude/manifest.toml +1 -5
  234. package/tooling/claude/reference.md +36 -59
  235. package/tooling/claude/seeds/.claude/hooks/board-validate.sh +1 -1
  236. package/tooling/claude/seeds/.claude/hooks/index-reminder.sh +2 -7
  237. package/tooling/claude/seeds/.claude/hooks/pr-create-log.sh +2 -7
  238. package/tooling/claude/seeds/.claude/hooks/scratch-guard.sh +3 -10
  239. package/tooling/claude/seeds/.claude/hooks/search-reminder.sh +2 -7
  240. package/tooling/claude/seeds/.claude/hooks/standards-audit.sh +2 -4
  241. package/tooling/claude/seeds/CLAUDE.md +2 -2
  242. package/tooling/nextjs/reference.md +0 -6
  243. package/tooling/php/reference.md +0 -4
  244. package/tooling/web/configs/.github/workflows/verify.yml +28 -0
  245. package/tooling/web/configs/.oxlintrc.json +7 -0
  246. package/tooling/web/configs/e2e/capture-types.ts +35 -0
  247. package/tooling/web/configs/e2e/screenshot.ts +23 -72
  248. package/tooling/web/manifest.toml +1 -1
  249. package/tooling/web/reference.md +77 -124
  250. package/tooling/web/seeds/e2e/capture/cases.ts +47 -0
  251. package/governance/rules/canon/task-scope.md +0 -12
  252. package/src/commands/wiki.ts +0 -100
  253. package/src/wiki/init.ts +0 -85
@@ -12,6 +12,7 @@ import {
12
12
  import {
13
13
  collectDeps,
14
14
  collectScripts,
15
+ declaresInstalls,
15
16
  type DepState,
16
17
  readPackage,
17
18
  type ScriptState,
@@ -48,6 +49,7 @@ export interface ScanResult {
48
49
  readonly deps: readonly DepState[]
49
50
  readonly gitignore: readonly EntryState[]
50
51
  readonly hasPackageJson: boolean
52
+ readonly newManifest: boolean
51
53
  readonly totalChanges: number
52
54
  }
53
55
 
@@ -128,8 +130,10 @@ export function scan(chain: readonly Manifest[], target: string): ScanResult {
128
130
 
129
131
  const packagePath = join(target, 'package.json')
130
132
  const pkg = readPackage(packagePath)
131
- const scripts = pkg ? collectScripts(chain, pkg) : []
132
- const deps = pkg ? collectDeps(chain, pkg) : []
133
+ const newManifest = !existsSync(packagePath) && declaresInstalls(chain)
134
+ const basis = pkg ?? (newManifest ? {} : undefined)
135
+ const scripts = basis ? collectScripts(chain, basis) : []
136
+ const deps = basis ? collectDeps(chain, basis) : []
133
137
 
134
138
  const gitignorePath = join(target, '.gitignore')
135
139
  const gitignoreContent = existsSync(gitignorePath)
@@ -138,6 +142,7 @@ export function scan(chain: readonly Manifest[], target: string): ScanResult {
138
142
  const gitignore = scanGitignore(chain, gitignoreContent)
139
143
 
140
144
  const totalChanges =
145
+ (newManifest ? 1 : 0) +
141
146
  configs.filter((entry) => entry.state !== 'matching').length +
142
147
  seeds.filter((entry) => entry.state === 'missing').length +
143
148
  scripts.filter((entry) => entry.state !== 'matching').length +
@@ -152,6 +157,7 @@ export function scan(chain: readonly Manifest[], target: string): ScanResult {
152
157
  deps,
153
158
  gitignore,
154
159
  hasPackageJson: pkg !== undefined,
160
+ newManifest,
155
161
  totalChanges,
156
162
  }
157
163
  }
@@ -37,7 +37,11 @@ export type Refusal =
37
37
  | 'held-by-session'
38
38
 
39
39
  /** Why the whole reading was refused, so no verdict was produced at all. */
40
- export type Unreadable = 'gh-missing' | 'gh-failed' | 'sessions-unreadable'
40
+ export type Unreadable =
41
+ | 'gh-missing'
42
+ | 'gh-failed'
43
+ | 'sessions-unreadable'
44
+ | 'sessions-unchecked'
41
45
 
42
46
  /**
43
47
  * Which removal shape applies. `session` removes the background session and its
@@ -395,6 +399,17 @@ export async function reclaimReport(
395
399
  }
396
400
  }
397
401
 
402
+ // A foreign-namespace record whose socket is gone reads dead, but a reader
403
+ // that cannot see the pid may also be unable to see the socket, so it may be
404
+ // a live holder. The roster drops it, and a removal on that reading is final.
405
+ if (sessions.foreignDead > 0) {
406
+ return {
407
+ kind: 'unreadable',
408
+ reason: 'sessions-unchecked',
409
+ detail: `${sessions.foreignDead} session records come from another pid namespace and no socket answers for them, so nothing was read about whether they still hold a worktree.`,
410
+ }
411
+ }
412
+
398
413
  const byBranch = new Map(
399
414
  merged.merged.map((request) => [request.branch, request.number]),
400
415
  )
@@ -6,8 +6,6 @@
6
6
 
7
7
  The astro stack covers Astro + TypeScript projects, being content sites, marketing sites, blogs, and docs. Interactive islands use React only and output is static.
8
8
 
9
- It ships golden configs for `astro.config.mjs`, `vitest.config.ts`, `playwright.config.ts` (preview-server backed), and a `tsconfig.json` extending `astro/tsconfigs/strict`. An `eslint.config.js` keeps ESLint for this stack alone, and a `.prettierrc` formats `.astro` files alone.
10
-
11
9
  ## Scaffold checklist
12
10
 
13
11
  1. Scaffold with `bunx create-astro@latest`. Choose `TypeScript: Strict`. Skip git init and install.
@@ -17,65 +15,90 @@ It ships golden configs for `astro.config.mjs`, `vitest.config.ts`, `playwright.
17
15
  5. Extend the `ci` and `development` context entries under `canon/context/` per the web reference's extend sections plus the astro rows below.
18
16
  6. Run `bun run lint:fix`, then `bun run format`, then `bun run check`.
19
17
 
20
- ## What ships as golden configs
18
+ ## Astro config
21
19
 
22
- ### Astro and test configs
20
+ - `astro.config.mjs` adds `@astrojs/react`, `@tailwindcss/vite` in `vite.plugins`, the `@/` alias via `vite.resolve.alias`, and `ASTRO_SITE` for the `site` field
21
+ - It serves port `4321` plus `WORKTREE_PORT_OFFSET` at `server.port`, with `strictPort` under `vite.server` and `vite.preview`
22
+ - Keep the port at the top level and the bind guarantee under `vite`, since Astro feeds `server.port` through as the preview port but merges the `vite` block into both servers
23
23
 
24
- The configs below wire Astro into the web layer's test setup.
24
+ ## TypeScript
25
25
 
26
- - `astro.config.mjs` adds `@astrojs/react`, `@tailwindcss/vite` in `vite.plugins`, the `@/` alias via `vite.resolve.alias`, and `ASTRO_SITE` for the `site` field.
27
- - It serves port `4321` plus `WORKTREE_PORT_OFFSET` at `server.port`, with `strictPort` under `vite.server` and `vite.preview`.
28
- - Astro feeds `server.port` through as the preview port but merges the `vite` block into the config backing both servers, so the port sits at the top level and the bind guarantee under `vite`.
29
- - `vitest.config.ts` uses `getViteConfig` from `astro/config`, not `mergeConfig`, with jsdom, globals, the setup file, `passWithNoTests: true`, v8 coverage, and `**/*.astro` in coverage excludes.
30
- - `tsconfig.json` adds `skipLibCheck`, `vitest/globals` and `@testing-library/jest-dom/vitest` in types, and `@/` paths.
26
+ - `tsconfig.json` extends `astro/tsconfigs/strict` and adds `skipLibCheck`, `vitest/globals` and `@testing-library/jest-dom/vitest` in types, and `@/` paths
27
+ - Typecheck with `astro check` in place of `tsc --noEmit`, since `tsc` cannot parse `.astro` files
28
+ - `build` runs `astro check && astro build`
31
29
 
32
- ### Playwright config
30
+ ## Vitest
33
31
 
34
- `playwright.config.ts` runs all browsers, with `webServer` running `bun run build && bun run preview` on port `4321` plus `WORKTREE_PORT_OFFSET` and `reuseExistingServer: false`.
32
+ - `vitest.config.ts` uses `getViteConfig` from `astro/config`, not `mergeConfig`, with jsdom, globals, the setup file, `passWithNoTests: true`, and v8 coverage
33
+ - Exclude `**/*.astro` from coverage, and unit-test React island components (`.tsx`) alone, since Playwright verifies page-level behavior against rendered output
34
+ - Keep Vitest at `^5` from the web manifest, which supports the Vite 8 that Astro 7 bundles
35
35
 
36
- - Astro's dev/prod gap is wide (MDX, island hydration, asset optimization), so E2E always tests the built `dist/`.
37
- - `DIST_PREBUILT` in the environment drops the `build` half, running `bun run preview` alone against a `dist/` a prior CI job produced.
36
+ ## Playwright
38
37
 
39
- ### ESLint config
38
+ - `playwright.config.ts` runs all browsers, with `webServer` running `bun run build && bun run preview` on port `4321` plus `WORKTREE_PORT_OFFSET` and `reuseExistingServer: false`
39
+ - Test the built `dist/`, since Astro's dev and production gap is wide across MDX, island hydration, and asset optimization
40
+ - Set `DIST_PREBUILT` to drop the `build` half, running `bun run preview` alone against a `dist/` a prior CI job produced
40
41
 
41
- `eslint.config.js` is this stack's own flat config, since the web layer lints with oxlint, which parses no `.astro` file. It adds `eslint-plugin-astro` with `astro-eslint-parser`.
42
+ ## ESLint
42
43
 
43
- - React hooks apply to `.jsx` and `.tsx` only, since `.astro` is not React.
44
- - `check-file/filename-naming-convention` reaches `.ts`, `.tsx`, and `.astro` under `KEBAB_CASE`, overriding Astro's PascalCase on purpose, since markup names a component by its import binding.
45
- - `.js` and `.jsx` stay out of that rule, matching `web` and `nextjs`.
46
- - `check-file/folder-naming-convention` reaches every `src/**` folder except `__tests__` and the `pages/` subtree, which has its own off-block for bracket-named dynamic routes and slug folders.
47
- - `canon/context/surfaces/tooling.md` carries the measurement behind both naming rules.
44
+ - Lint with this stack's own flat `eslint.config.js`, since the web layer's oxlint parses no `.astro` file. It adds `eslint-plugin-astro` with `astro-eslint-parser`.
45
+ - Expect `lint` and `lint:fix` overridden back to `eslint . --max-warnings 0`, and the web layer's `.oxlintrc.json` in the target with nothing running it
46
+ - Install `eslint@^9`, `@eslint/js`, `typescript-eslint`, `eslint-config-prettier`, `eslint-plugin-react-hooks`, `eslint-plugin-vitest`, and `globals`, since the web layer ships none of them
47
+ - Pin `eslint@^9`, because ESLint 10 dropped the `LegacyESLint` shim `typescript-eslint@8` still imports
48
48
 
49
- The social card files also ship as golden configs, being `card.config.mjs`, `card-src/pages/og-card.astro`, and `scripts/check-card-exclusion.sh`. See `## Social card route` below.
49
+ ## ESLint naming rules
50
50
 
51
- ## Typecheck
51
+ - Apply React hooks rules to `.jsx` and `.tsx` alone, since `.astro` is not React
52
+ - Name `.ts`, `.tsx`, and `.astro` files in `KEBAB_CASE`, overriding Astro's PascalCase, since markup names a component by its import binding
53
+ - Keep `.js` and `.jsx` out of that rule, matching `web` and `nextjs`
54
+ - Name every `src/**` folder in kebab case except `__tests__` and the `pages/` subtree, whose own off-block allows bracket-named dynamic routes and slug folders
52
55
 
53
- `astro check` replaces `tsc --noEmit` because `tsc` cannot parse `.astro` files. `build` runs `astro check && astro build`.
56
+ ## Formatting (extend)
54
57
 
55
- ## Vitest scope
58
+ - Format `.astro` files with Prettier and every other file with oxfmt, which loads no Prettier plugin and cannot parse `.astro`
59
+ - Load `prettier-plugin-astro` first in `.prettierrc`'s plugins and `prettier-plugin-tailwindcss` last, with a parser override for `.astro` files
60
+ - Ignore `**/*.astro` in this stack's `.oxfmtrc.json`, so the two formatters never touch one file
61
+ - Expect this stack's `.oxfmtrc.json` to replace base's whole file, so a base option change reaches a target only once this stack copies it
62
+ - Override `check:format` and `format` to run oxfmt, then Prettier over `**/*.astro`
56
63
 
57
- Unit-test React island components (`.tsx`) only. Do not test `.astro` files, since Playwright verifies page-level behavior against rendered output.
64
+ ## Social card route
58
65
 
59
- Vitest is pinned to `^5` in the web manifest, which supports the Vite 8 that Astro 7 bundles. The earlier `^3` pin dodged `^4` bundling rolldown-vite, which ignored the esbuild JSX config in `@vitejs/plugin-react`. Astro bundling Vite 8 itself ended that conflict.
66
+ - Keep the social card as a route the project owns, so a re-render after a rename is one string edit and a re-capture rather than another `design-identity` pick loop
67
+ - Expect `canon:design-identity` to write the picked composition into the route and capture it through the card server
68
+ - `card.config.mjs` is a second Astro config whose `srcDir` points at `./card-src`, which the main page router never reads, so the published build excludes the card structurally
69
+ - It serves on base port `4421` plus `WORKTREE_PORT_OFFSET`, outside the band `astro.config.mjs` serves from, so a worktree's card and dev servers never contend
70
+ - `bun run card:dev` serves the route and `bun run card:check` runs the exclusion check, which base's `scripts/verify.ts` also runs after its build stage
60
71
 
61
- ## Formatting (extend)
72
+ ## Card exclusion and size
62
73
 
63
- - Format `.astro` files with Prettier and every other file with oxfmt, which loads no Prettier plugin and cannot parse `.astro`.
64
- - Load `prettier-plugin-astro` first in `.prettierrc`'s plugins and `prettier-plugin-tailwindcss` last, with a parser override for `.astro` files.
65
- - Ignore `**/*.astro` in this stack's `.oxfmtrc.json`, so the two formatters never touch one file.
66
- - Copy every other option from base's `.oxfmtrc.json` by hand. Scan takes the child config over the parent's whole file, so a change to base's options is lost here until copied.
67
- - Override `check:format` and `format` to run oxfmt, then Prettier over `**/*.astro`.
74
+ - `scripts/check-card-exclusion.sh` fails when the route's `<meta name="og-card-marker">` tag reaches `dist/`, and when the route dropped the tag the leak test reads
75
+ - Keep the exclusion a check rather than a convention, since the card server and the capture read the route and the published build must not carry it
76
+ - Declare `.card` at 600x315, half the 1200x630 target, since `canon capture` shoots at a fixed 2x device scale and 1200x630 would capture at 2400x1260
68
77
 
69
- ## ESLint
78
+ ## Card stylesheet and tokens
79
+
80
+ - `card-src/pages/og-card.astro` ships as a working placeholder, so it serves before any pick
81
+ - It imports `@/styles/global.css` for real tokens and fonts, and a project keeping its stylesheet elsewhere retargets that one line
82
+ - It uses `--color-background` and `--color-text` as `canon design css` emits them, and sets no `font-family`, so the card inherits the body font
83
+ - Expect an unresolved stylesheet path to refuse the card server by name, rather than capture an unstyled card that reports success
84
+ - Name only properties `canon design css` emits, since an undefined one silently takes its fallback, and check the names against a retargeted stylesheet
85
+
86
+ ## Card route scope
87
+
88
+ - Expect no card route on another web stack, since Astro is the one whose config gives a route a structural build exclusion
89
+ - Next's App Router has none and needs none, since `ImageResponse` is its production mechanism and a card route there is meant to be served
90
+ - `vite-react` builds a single-page app with no page router, so a card there is a second Rollup entry rather than a route
70
91
 
71
- - Override `lint` and `lint:fix` back to `eslint . --max-warnings 0`, since the web layer sets them to oxlint.
72
- - Install `eslint@^9`, `@eslint/js`, `typescript-eslint`, `eslint-config-prettier`, `eslint-plugin-react-hooks`, `eslint-plugin-vitest`, and `globals`, since the web layer no longer ships them.
73
- - Pin `eslint@^9`, because ESLint 10 dropped the `LegacyESLint` shim `typescript-eslint@8` still imports.
74
- - Expect the web layer's `.oxlintrc.json` in the target. Nothing runs it here.
92
+ ## Scenario switcher
93
+
94
+ - Expect `src/components/dev/scenarios.astro` overwritten on every sync, since it is toolkit-authored infrastructure rather than a file a project hand-edits
95
+ - Import it into a page under test to drive candidate treatments of one decision by hand, selected by a query parameter, with a switcher between them
96
+ - Rely on its `import.meta.env.DEV` guard, so it renders nothing and ships nothing in a production build
97
+ - Expect it on Astro alone, since it uses `is:inline`, `define:vars`, and `set:html`, which only the `.astro` format parses
75
98
 
76
99
  ## Development docs (extend)
77
100
 
78
- Append these rows to the `## Scripts` table.
101
+ - Append these rows to the `## Scripts` table
79
102
 
80
103
  | Command | Purpose |
81
104
  | ------------------- | --------------------------------------------------------------- |
@@ -87,57 +110,5 @@ Append these rows to the `## Scripts` table.
87
110
 
88
111
  ## CI docs (extend)
89
112
 
90
- In `canon/context/development/ci.md`, the Typecheck row asserts `` `astro check` passes `` and the Build row asserts `` `astro build` succeeds ``. <!-- audit-ignore-citations: canon/context/development/ci.md -->
91
-
92
- ## Social card route
93
-
94
- The social card is a route the project keeps rather than a page a render writes and deletes. Re-rendering it after a rename is an edit to one string and a re-capture, not another pass through the `design-identity` pick loop.
95
-
96
- `canon:design-identity` writes the picked composition into the route and captures it through the server below.
97
-
98
- ### What ships
99
-
100
- The route is a second config, an exclusion check, and two scripts. The page itself is covered below.
101
-
102
- - `card.config.mjs` is a second Astro config whose `srcDir` points at `./card-src`, which the main config's page router never reads. That excludes the card from the published build structurally.
103
- - `card.config.mjs` uses base port `4421` plus `WORKTREE_PORT_OFFSET`, outside the band `astro.config.mjs` serves from, so a worktree's card and dev servers never contend.
104
- - `scripts/check-card-exclusion.sh` fails when the route's `<meta name="og-card-marker">` tag reaches `dist/`, and when the route dropped the tag, since the leak test reads it.
105
- - `bun run card:dev` serves the route and `bun run card:check` runs the exclusion check, which base's `scripts/verify.ts` also runs after its build stage when the script is installed.
106
-
107
- ### Stylesheet and tokens
108
-
109
- `card-src/pages/og-card.astro` ships as a working placeholder, so it serves before any pick. It imports the project's global stylesheet to read real tokens and fonts, uses `--color-background` and `--color-text` as `canon design css` emits them, and sets no `font-family`, so the card inherits the body font.
110
-
111
- - The import points at `@/styles/global.css`. A project keeping its stylesheet elsewhere retargets that one line.
112
- - An unresolved path refuses the card server by name. That is the loud direction, replacing a card captured against no stylesheet that renders unstyled and reports success.
113
-
114
- - A custom property the stylesheet does not define fails the same silent way. It takes its fallback, captures cleanly, and ships typed values.
115
- - So the route names only properties `canon design css` emits, and a project retargeting the import checks the names against its own stylesheet.
116
-
117
- ### Exclusion and card size
118
-
119
- The exclusion is a check rather than a convention because the route has three consumers and only one can be enforced. The card server reads it, the capture reads it, and the published build must not carry it.
120
-
121
- `.card` is declared at 600x315, half of the 1200x630 target. `canon capture` opens every page at a fixed 2x device scale factor with no flag to change it, so a half-size element lands the PNG on the literal size. Declaring 1200x630 captures at 2400x1260.
122
-
123
- ### Why v1 is Astro-only
124
-
125
- Astro is the one web stack whose config gives a route a structural build exclusion.
126
-
127
- - Next's App Router has no build-time route exclusion, and needs none on its path, since `ImageResponse` is that framework's production mechanism and a card route there is meant to be served.
128
- - `vite-react` builds a single-page app with no page router, so a card is a second Rollup entry rather than a route.
129
-
130
- ## Gitignore (extend)
131
-
132
- These `[gitignore]` groups mirror the manifest.
133
-
134
- - `"# Astro" = [".astro/"]`
135
- - `"# Social card" = ["card-dist/"]`
136
-
137
- ## Scenario switcher
138
-
139
- `src/components/dev/scenarios.astro` ships as a golden config, always overwritten on sync, since it is toolkit-authored infrastructure rather than a file a project hand-edits.
140
-
141
- - Import it into a page under test to drive candidate treatments of one decision by hand, selected by a query parameter, with a switcher between them.
142
- - It is guarded by `import.meta.env.DEV`, so it renders nothing and ships nothing in a production build.
143
- - It is Astro-only, using `is:inline`, `define:vars`, and `set:html`, which only the `.astro` format parses. `vite-react` gets no equivalent until a real decision drives one.
113
+ - Assert `` `astro check` passes `` on the Typecheck row of `canon/context/development/ci.md` <!-- audit-ignore-citations: canon/context/development/ci.md -->
114
+ - Assert `` `astro build` succeeds `` on its Build row
@@ -19,7 +19,7 @@ jobs:
19
19
  name: 🏷️ Phase Label Gate
20
20
  runs-on: ubuntu-latest
21
21
  # Dependabot bodies carry upstream release notes that read as phase labels
22
- if: github.event.pull_request.user.login != 'dependabot[bot]' && (github.event_name == 'workflow_dispatch' || github.event.pull_request.base.ref == 'main')
22
+ if: github.event.pull_request.user.login != 'dependabot[bot]' && github.event.pull_request.user.login != 'renovate[bot]' && (github.event_name == 'workflow_dispatch' || github.event.pull_request.base.ref == 'main')
23
23
  steps:
24
24
  - name: Checkout
25
25
  uses: actions/checkout@v7
@@ -225,7 +225,7 @@ function readPhaseList(): PhaseList {
225
225
 
226
226
  function readDeclaredScripts(): Set<string> {
227
227
  if (!existsSync('package.json')) {
228
- fail("No package.json here. Run 'bun init', then sync the stack again")
228
+ fail('No package.json here. Sync the stack to write one')
229
229
  }
230
230
  return new Set(
231
231
  Object.keys(asRecord(asRecord(readJson('package.json')).scripts)),
@@ -323,7 +323,7 @@ function checkMarkdownBans(): void {
323
323
  case 2:
324
324
  pipeOutput(output)
325
325
  fail(
326
- 'Markdown prose carries a banned character, or a relative link resolves to nothing on disk',
326
+ 'Markdown prose carries a banned character, a relative link resolves to nothing on disk, or a gated path breaks a density limit',
327
327
  )
328
328
  break
329
329
  case 3:
@@ -18,7 +18,6 @@ Two configs fix how output looks and how commits read.
18
18
  - The `astro` stack repeats those options in its own copy, so copy a change here into it.
19
19
  - `commitlint.config.js` is an ESM default export extending `@commitlint/config-conventional`. It sets `header-max-length: 72`, `scope-case: lower-case`, and `subject-full-stop: never`.
20
20
  - Its `subject-case` rule is off.
21
- - `.husky/` holds `pre-commit`, `commit-msg`, `pre-push`, `post-merge`, and `post-rewrite`.
22
21
 
23
22
  ### Verify runner
24
23
 
@@ -39,7 +38,7 @@ Seeds live in `tooling/base/seeds/`. Sync drops each once on first install and n
39
38
  - `.lintstagedrc` holds the glob map below.
40
39
  - `.github/workflows/verify.yml` runs on pull requests targeting `main` and on `workflow_dispatch`. A multi-root project adds its own jobs here.
41
40
  - `.github/pull_request_template.md` has `## Summary`, `## Key changes`, `## Technical context`, and `## Testing`. A project adds its own checklist lines.
42
- - `canon/context/` holds the `ci` and `development` entries. Extend them with project-specific commands, workflows, or deploy steps, and keep canonical rationale in this reference.
41
+ - `canon/context/development/` holds the `setup` and `ci` entries under a folder index. Extend them with project-specific commands and workflows, and keep canonical rationale here.
43
42
 
44
43
  ## Tool pairing
45
44
 
@@ -83,13 +82,6 @@ The seeded baseline globs.
83
82
  - Steps are checkout, setup Bun at latest, `bun install --frozen-lockfile`, then `check:format`.
84
83
  - CI asserts and never writes, so format must be clean before push.
85
84
 
86
- ## Gitignore
87
-
88
- - `# System`: `.DS_Store`
89
- - `# Dependencies`: `node_modules/`
90
- - `# Secrets`: `.env`, `.env.*`, `*.local`, `!.env.example`
91
- - `# VSCode`: `.vscode/`
92
-
93
85
  ## Anti-patterns
94
86
 
95
87
  Negative knowledge that costs a failed run to relearn.
@@ -7,7 +7,7 @@ description: GitHub Actions workflow triggers and checks
7
7
 
8
8
  ## Overview
9
9
 
10
- Owns the GitHub Actions workflow that gates a merge, being which events start a run and which checks have to pass before the branch can land. The checks call package scripts rather than defining commands of their own, so what each one runs is the development entry's subject.
10
+ Owns the GitHub Actions workflow that gates a merge, being which events start a run and which checks have to pass before the branch can land. The checks call package scripts rather than defining commands of their own, so what each one runs is the setup entry's subject.
11
11
 
12
12
  ## Layout
13
13
 
@@ -0,0 +1,11 @@
1
+ ---
2
+ title: Development
3
+ subtitle: The local loop and CI
4
+ ---
5
+
6
+ # Development
7
+
8
+ The local loop and CI
9
+
10
+ - [CI](ci.md): GitHub Actions workflow triggers and checks
11
+ - [Setup](setup.md): Local dev workflow, scripts, and husky hooks
@@ -1,19 +1,24 @@
1
1
  ---
2
- title: Development
2
+ title: Setup
3
3
  description: Local dev workflow, scripts, and husky hooks
4
4
  ---
5
5
 
6
- # Development
6
+ # Setup
7
7
 
8
8
  ## Overview
9
9
 
10
10
  Owns how the project runs on a developer machine, being the toolchain install, the scripts that verify a change, and the git hooks that run them before a commit or a push leaves. CI calls the same scripts from a workflow, which is the CI entry's subject.
11
11
 
12
+ Install [Bun](https://bun.sh) with `curl -fsSL https://bun.sh/install | bash` and run `bun install`, then use the package scripts below. They call the shell scripts in `scripts/`, which holds every one since none belongs outside it.
13
+
12
14
  ## Layout
13
15
 
14
16
  ### `scripts/`
15
17
 
16
- Holds every shell script, since none belongs outside this folder. The package scripts below call them.
18
+ | Command | Purpose |
19
+ | ---------------- | ---------------------------------------------------------------------------------------- |
20
+ | `bun run check` | Gates locally and writes nothing. Fails on formatting drift until `bun run format` runs. |
21
+ | `bun run format` | Auto-fix oxfmt formatting. |
17
22
 
18
23
  ### `.husky/`
19
24
 
@@ -23,15 +28,6 @@ Holds the git hooks that run the checks before a commit or a push leaves.
23
28
  - `commit-msg` runs `commitlint` against the conventional commit format
24
29
  - `pre-push` runs `bun run check`, and also gates on banned characters across every tracked markdown file except `CHANGELOG.md` when a markdown-bans audit tool is on PATH
25
30
 
26
- ### Scripts
27
-
28
- Install [Bun](https://bun.sh) with `curl -fsSL https://bun.sh/install | bash` and run `bun install`, then use these commands.
29
-
30
- | Command | Purpose |
31
- | ---------------- | ---------------------------------------------------------------------------------------- |
32
- | `bun run check` | Gates locally and writes nothing. Fails on formatting drift until `bun run format` runs. |
33
- | `bun run format` | Auto-fix oxfmt formatting. |
34
-
35
31
  ## Gotchas
36
32
 
37
33
  - A push fails on formatting drift until `bun run format` runs, since the `pre-push` hook writes nothing
@@ -7,5 +7,4 @@ subtitle: Per-domain narrative loaded on demand
7
7
 
8
8
  Per-domain narrative loaded on demand
9
9
 
10
- - [CI](ci.md): GitHub Actions workflow triggers and checks
11
- - [Development](development.md): Local dev workflow, scripts, and husky hooks
10
+ - [Development](development/index.md): The local loop and CI
@@ -21,8 +21,4 @@ scaffold = ""
21
21
  # array no longer tells it to ignore them, so the first sign is a memory file or
22
22
  # a task board appearing in someone's commit.
23
23
  [gitignore]
24
- "# Claude" = [
25
- ".canon/",
26
- ".claude/worktrees/",
27
- ".claude/.tmp/", # canon-keep-record-root
28
- ]
24
+ "# Claude" = [".canon/", ".claude/worktrees/"]
@@ -2,59 +2,49 @@
2
2
 
3
3
  ## Overview
4
4
 
5
- The claude stack installs the `.claude/` workflow directory into a project. Tooling writes state docs once and never overwrites them. `CLAUDE.md` is one of those seeds, and a project fills it in after init.
5
+ The claude stack installs the Claude Code workflow into a project through `canon claude`. Every file it ships is a seed, written once and never overwritten, so a project fills `CLAUDE.md` in after init.
6
6
 
7
- ## Structure
7
+ ## Seeded records
8
8
 
9
- ```plaintext
10
- CLAUDE.md ← seeded. Project context and rules, auto-loaded by Claude Code each session
9
+ - `CLAUDE.md` holds project context and rules, auto-loaded by Claude Code each session
10
+ - `canon/REQUIREMENTS.md` holds the project's problem, goals, and non-goals
11
+ - `canon/DESIGN.md` holds the visual intent and the decisions behind it
12
+ - `canon/context/` holds per-domain narrative, with `index.md` as the discovery anchor
13
+ - `.claude/settings.json` holds project-level Claude Code config. User-level config installs separately through `canon claude setup`.
11
14
 
12
- canon/
13
- ├── REQUIREMENTS.md ← seeded. Project problem, goals, non-goals
14
- ├── DESIGN.md ← seeded. Visual intent and the decisions behind it
15
- └── context/ ← seeded. Per-domain narrative. `index.md` is the discovery anchor.
15
+ ## Record folders
16
16
 
17
- .claude/
18
- ├── GOV.md ← retired. Removed by `canon gov sync` if present from a prior install
19
- ├── settings.json ← seeded. Project-level Claude Code config (PreToolUse and PostToolUse hooks). User-level config installed separately via `canon claude setup`.
20
- └── worktrees/ ← gitignored. Where EnterWorktree creates a linked worktree, which is why it did not move.
17
+ - `.canon/tasks/` holds one file per task plus a generated `index.md`, local scratch only, with `archive/` holding the tasks that shipped
18
+ - `.canon/plans/` holds execution detail for multi-step tasks, and `canon tasks archive` moves a `feature-*.md` plan into `archive/` when the `post-merge` hook archives its task
19
+ - `.canon/review/` holds one subfolder per producer, with `design/` for `canon design render`
20
+ - `.canon/tmp/` is ephemeral scratch, safe to delete without loss
21
+ - `.claude/worktrees/` is where `EnterWorktree` creates a linked worktree, which is why it stays under `.claude/`
21
22
 
22
- .canon/
23
- ├── tasks/ ← seeded. One file per task plus a generated index.md, local scratch only. `archive/` holds the tasks that shipped.
24
- ├── plans/ ← execution detail for multi-step tasks. `feature-*.md` entries moved into `archive/` by `canon tasks archive` when the `post-merge` hook archives their task.
25
- ├── review/ ← one subfolder per producer. `branch/` no longer written, `design/` for canon design render.
26
- └── tmp/ ← ephemeral scratch space, safe to delete without loss
27
- ```
23
+ ## Ignored roots
28
24
 
29
- One ignore entry covers `.canon/` whole, so nothing under it is named separately and nothing tracked may land there. A project scaffolded before the move keeps its records under `.claude/`, and every command reads either root.
25
+ The `# Claude` group ignores `.canon/` whole, so nothing tracked may land there and a record folder added later needs no new entry.
26
+
27
+ - Keep `.claude/worktrees/` as its own entry, since the harness requires a worktree's target to sit under `.claude/`
28
+ - Expect a project scaffolded before the move to keep its records under `.claude/`, since every command reads either root
29
+ - Expect `canon gov sync` to remove a retired `.claude/GOV.md` left by a prior install
30
30
 
31
31
  ## Moving the records to `.canon/`
32
32
 
33
33
  A project installed before the split holds its records under `.claude/`. `canon migrate records` moves them and repoints every tracked file that cites one, reporting the plan until `--write` is passed.
34
34
 
35
35
  - Run `canon tooling sync claude . --write` first. The verb refuses until the project ignores `.canon/`, since a relocated folder under a tracked root commits the task board and plans.
36
- - Until the move runs, the records sit at a root the shipped ignore set no longer names, so a `git add -A` in that window picks them up.
37
- - An installed binary answers `unknown command` until a published release carries the verb. Meanwhile run `bun src/cli.ts migrate records --root <project> --write` from a canon checkout.
38
- - Read the `ok` field out of `--json` rather than the exit code, which a shell wrapper around `canon` can flatten.
36
+ - Move soon after the sync, since until then the records sit at a root the shipped ignore set no longer names and a `git add -A` picks them up
37
+ - Run `bun src/cli.ts migrate records --root <project> --write` from a canon checkout while the installed binary answers `unknown command`
38
+ - Read the `ok` field out of `--json` rather than the exit code, which a shell wrapper around `canon` can flatten
39
39
 
40
40
  ## Upgrading from a single-file board
41
41
 
42
- A project installed before the board became a folder still holds `.claude/TASKS.md`, and nothing migrates it. `canon claude init` seeds an empty `.canon/tasks/index.md` beside it and leaves the old file untouched, so every skill reads the empty catalog while the real board sits unreferenced.
43
-
44
- Convert by hand, once per project.
42
+ A project installed before the board became a folder still holds `.claude/TASKS.md`, and nothing migrates it. `canon claude init` seeds an empty `.canon/tasks/index.md` beside it, so every skill reads the empty catalog while the real board sits unreferenced.
45
43
 
46
44
  1. Split each `###` block into `.canon/tasks/vXX.Y-<slug>.md`, adding the `title` and `description` frontmatter the `task-board` skill requires. Compare each new file against its source block.
47
45
  2. Run `canon indexes regen --no-stage --root . .canon/tasks/<any-task>.md` to build the catalog.
48
46
  3. Delete `.claude/TASKS.md`, and swap its `.gitignore` entry for `.canon/tasks/`.
49
47
 
50
- ## Gitignore
51
-
52
- The `# Claude` group holds three entries, being `.canon/`, `.claude/worktrees/`, and `.claude/.tmp/`. <!-- canon-keep-record-root -->
53
-
54
- - The first entry covers the whole record root, so a record folder added later needs no line here and no sync.
55
- - The second is the carve-out the harness owns, since it creates a worktree under `.claude/` and requires its target to sit there.
56
- - The third is the scratch rule's fallback spelling, carried for a project the record move has not reached and retired once none is left.
57
-
58
48
  ## CLI
59
49
 
60
50
  | Command | What it does |
@@ -65,37 +55,24 @@ The `# Claude` group holds three entries, being `.canon/`, `.claude/worktrees/`,
65
55
 
66
56
  ## CLAUDE.md
67
57
 
68
- - It ships as a seed with placeholder project name, description, and key paths, to fill in after init.
69
- - Its sections are `Context`, `Commands`, and `Key paths`. Each groups rules that share a surface, so skills can detect, extend, or skip by heading.
70
- - The `Context` section points at `.claude/` state docs in one line. `plan-feature` does the parallel read when invoked, so the seed does not re-list every file.
58
+ - Fill in the seed's placeholder project name, description, and key paths after init
59
+ - Keep its sections `Context`, `Commands`, and `Key paths`, since skills detect, extend, or skip by heading
60
+ - Keep the `Context` section to one line pointing at the state docs, since `plan-feature` does the parallel read when invoked
71
61
 
72
62
  ## Seed docs
73
63
 
74
- Seed docs ship with a guidelines preamble above the first H2. Claude internalizes those instructions before filling in the sections below, and they are not sections to populate.
64
+ - Read a seed doc's guidelines preamble above the first H2 as instructions for filling the sections below, never as a section to populate
75
65
 
76
66
  ## settings.json
77
67
 
78
- The project and user files split what is project-specific from what is personal.
79
-
80
- ### Project seed
81
-
82
- The seed at `tooling/claude/seeds/.claude/settings.json` ships hooks that pair with scripts under `.claude/hooks/`.
83
-
84
- - Three PreToolUse hooks pair with `index-reminder.sh`, `search-reminder.sh`, and `scratch-guard.sh`.
85
- - A PostToolUse hook pairs with `standards-audit.sh`.
86
- - Project settings layer over user settings, so a project file carries only what is project-specific.
87
-
88
- ### Session defaults
89
-
90
- The seed also sets two defaults every session in the target runs under.
91
-
92
- - `permissions.deny` holds `Agent` and `Task`, so no session spawns a subagent. Parallel work runs as separate background sessions instead.
93
- - `autoMemoryEnabled` is `false`. A person turns it back on for themselves in `settings.local.json`.
94
- - `canon migrate session-defaults` adds both to a target seeded before them, since sync never rewrites an existing settings file.
95
-
96
- ### User template
68
+ - Pair the seed's three PreToolUse hooks with `index-reminder.sh`, `search-reminder.sh`, and `scratch-guard.sh`, and its PostToolUse hook with `standards-audit.sh`, all under `.claude/hooks/`
69
+ - Keep only what is project-specific in the project file, since project settings layer over user settings
70
+ - Expect `permissions.deny` to hold `Agent` and `Task`, so no session spawns a subagent and parallel work runs as separate background sessions
71
+ - Expect `autoMemoryEnabled` to be `false`. A person turns it back on for themselves in `settings.local.json`.
72
+ - Run `canon migrate session-defaults` on a target seeded before those two defaults, since sync never rewrites an existing settings file
97
73
 
98
- The template at `tooling/claude/user/settings.template.json` is installed once per machine by `canon claude setup`.
74
+ ## User settings
99
75
 
100
- - It allows `Bash(bun run *)` under `permissions.allow`.
101
- - Its `permissions.deny` holds `Read(**/.env)` and `Read(**/.env.*)`, blocking accidental secret exposure across any project.
76
+ - `canon claude setup` installs `tooling/claude/user/settings.template.json` once per machine
77
+ - It allows `Bash(bun run *)` under `permissions.allow`
78
+ - Its `permissions.deny` holds `Read(**/.env)` and `Read(**/.env.*)`, blocking accidental secret exposure across any project
@@ -51,7 +51,7 @@ fi
51
51
  # Exit 2 carries findings, so the status is read off the record rather than
52
52
  # the exit code.
53
53
  record=$(canon tasks validate --json --root "$root" 2>/dev/null)
54
- ok=$(printf '%s' "$record" | jq -r '.ok // empty' 2>/dev/null)
54
+ ok=$(printf '%s' "$record" | jq -r '.ok | tostring' 2>/dev/null)
55
55
 
56
56
  if [ "$ok" = false ]; then
57
57
  report "canon tasks validate refused the board after this edit: $(printf '%s' "$record" | jq -r '.message // .reason')"
@@ -40,14 +40,9 @@ done
40
40
 
41
41
  session=$(printf '%s' "$input" | jq -r '.session_id // "none"')
42
42
  key=$(printf '%s__%s' "$session" "$index" | tr -c 'A-Za-z0-9' '_')
43
- # The marker is scratch, so it follows the scratch folder to whichever record
44
- # root the project carries rather than creating a second one beside it.
43
+ # The marker is scratch, so it lives under `.canon/tmp/`.
45
44
  project="${CLAUDE_PROJECT_DIR:-.}"
46
- if [ -d "$project/.canon" ]; then
47
- marker_dir="$project/.canon/tmp/hooks/index-reminder"
48
- else
49
- marker_dir="$project/.claude/.tmp/hooks/index-reminder"
50
- fi
45
+ marker_dir="$project/.canon/tmp/hooks/index-reminder"
51
46
  marker="$marker_dir/$key"
52
47
  [ -f "$marker" ] && exit 0
53
48
  mkdir -p "$marker_dir"
@@ -46,13 +46,8 @@ root="${CLAUDE_PROJECT_DIR:-.}"
46
46
  case "$root" in
47
47
  */.claude/worktrees/*) root="${root%/.claude/worktrees/*}" ;;
48
48
  esac
49
- # The log is scratch, so it follows the scratch folder to whichever record root
50
- # the project carries rather than creating a second one beside it.
51
- if [ -d "$root/.canon" ]; then
52
- log_dir="$root/.canon/tmp/pr/log"
53
- else
54
- log_dir="$root/.claude/.tmp/pr/log"
55
- fi
49
+ # The log is scratch, so it lives under `.canon/tmp/`.
50
+ log_dir="$root/.canon/tmp/pr/log"
56
51
  mkdir -p "$log_dir"
57
52
  session=$(printf '%s' "$input" | jq -r '.session_id // "unknown"')
58
53
  printf -- '- %s session=%s pr=%s\n' "$(date -u +%Y-%m-%dT%H:%M:%SZ)" "$session" "$url" >>"$log_dir/log.md"