@erclx/canon 5.34.0 → 5.36.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 (248) hide show
  1. package/README.md +15 -17
  2. package/claude/.claude-plugin/plugin.json +1 -1
  3. package/claude/skills/api-design/REQUIREMENT.md +1 -1
  4. package/claude/skills/auto-ship/references/draft-mark.md +1 -1
  5. package/claude/skills/canon-cli/REQUIREMENT.md +2 -2
  6. package/claude/skills/canon-cli/SKILL.md +12 -12
  7. package/claude/skills/canvas-board/REQUIREMENT.md +1 -1
  8. package/claude/skills/canvas-board/SKILL.md +2 -2
  9. package/claude/skills/canvas-board/references/design.md +53 -36
  10. package/claude/skills/codebase-layout/REQUIREMENT.md +1 -1
  11. package/claude/skills/codebase-layout/SKILL.md +2 -2
  12. package/claude/skills/create-rule/REQUIREMENT.md +6 -8
  13. package/claude/skills/create-rule/SKILL.md +8 -8
  14. package/claude/skills/create-rule/references/rule.md +11 -23
  15. package/claude/skills/create-skill/SKILL.md +2 -1
  16. package/claude/skills/create-skill/references/skill-paths.md +12 -15
  17. package/{standards/standard.md → claude/skills/create-skill/references/skill-reference.md} +50 -45
  18. package/claude/skills/create-skill/references/skill.md +9 -3
  19. package/claude/skills/design-taste/REQUIREMENT.md +6 -6
  20. package/claude/skills/design-taste/SKILL.md +2 -2
  21. package/claude/skills/design-taste/references/craft.md +1 -1
  22. package/claude/skills/design-taste/references/preflight.md +2 -2
  23. package/claude/skills/design-taste/references/tells.md +1 -1
  24. package/claude/skills/draft-and-pick/SKILL.md +1 -1
  25. package/claude/skills/draft-identity/SKILL.md +3 -2
  26. package/claude/skills/git-commit/references/versioning.md +13 -13
  27. package/claude/skills/git-pr/SKILL.md +1 -1
  28. package/claude/skills/git-pr/references/publish.md +1 -1
  29. package/claude/skills/markdown-craft/references/markdown.md +3 -2
  30. package/claude/skills/plan-feature/SKILL.md +1 -1
  31. package/claude/skills/review-address/REQUIREMENT.md +1 -1
  32. package/claude/skills/review-address/SKILL.md +2 -2
  33. package/claude/skills/review-craft/references/ui.md +1 -1
  34. package/claude/skills/review-pr/SKILL.md +3 -3
  35. package/claude/skills/review-pr/references/post.md +1 -1
  36. package/claude/skills/review-ui/REQUIREMENT.md +1 -1
  37. package/claude/skills/review-ui/SKILL.md +1 -1
  38. package/claude/skills/role-orchestrator/REQUIREMENT.md +2 -2
  39. package/claude/skills/role-orchestrator/SKILL.md +11 -12
  40. package/claude/skills/role-orchestrator/references/orchestrator-cloud-launch.md +3 -1
  41. package/claude/skills/role-orchestrator/references/orchestrator-dispatch.md +11 -8
  42. package/claude/skills/role-orchestrator/references/orchestrator-handback.md +10 -4
  43. package/claude/skills/role-orchestrator/references/orchestrator-launch.md +2 -2
  44. package/claude/skills/role-orchestrator/references/orchestrator-poll.md +11 -12
  45. package/claude/skills/role-orchestrator/references/orchestrator-review-dispatch.md +12 -15
  46. package/claude/skills/role-orchestrator/references/orchestrator-reviewer-launch.md +6 -4
  47. package/claude/skills/role-orchestrator/scripts/poll.ts +50 -1
  48. package/claude/skills/role-reviewer/REQUIREMENT.md +17 -7
  49. package/claude/skills/role-reviewer/SKILL.md +17 -10
  50. package/claude/skills/role-worker/REQUIREMENT.md +1 -1
  51. package/claude/skills/role-worker/SKILL.md +6 -6
  52. package/claude/skills/session-compact/references/handoff-note.md +1 -1
  53. package/claude/skills/target-setup/SKILL.md +2 -2
  54. package/claude/skills/target-setup/references/detect.md +3 -3
  55. package/claude/skills/test-craft/SKILL.md +2 -2
  56. package/claude/skills/ux-audit/REQUIREMENT.md +1 -1
  57. package/claude/skills/ux-audit/SKILL.md +2 -2
  58. package/claude/skills/ux-measure/REQUIREMENT.md +1 -1
  59. package/claude/skills/write-human/references/machine-tells.md +12 -0
  60. package/docs/agents/audits.md +1 -1
  61. package/docs/agents/commands.md +14 -13
  62. package/docs/agents/comments.md +1 -1
  63. package/docs/agents/counts.md +5 -6
  64. package/docs/agents/drift-surfaces.md +15 -19
  65. package/docs/agents/gov-detect.md +1 -1
  66. package/docs/agents/index.md +2 -3
  67. package/docs/agents/install-and-sync.md +10 -34
  68. package/docs/agents/markdown-audit.md +22 -12
  69. package/docs/agents/migrate.md +1 -1
  70. package/docs/agents/output-shape.md +1 -1
  71. package/docs/agents/overview.md +2 -2
  72. package/docs/agents/records-stale.md +1 -1
  73. package/docs/agents/records-validate.md +11 -23
  74. package/docs/agents/records.md +1 -1
  75. package/docs/agents/routing.md +1 -1
  76. package/docs/agents/rule-citations.md +9 -17
  77. package/docs/agents/scripting.md +2 -20
  78. package/docs/agents/state-scoped-risk.md +1 -1
  79. package/docs/agents/tasks-validate.md +1 -1
  80. package/docs/agents/teach.md +1 -1
  81. package/docs/target/index.md +1 -0
  82. package/docs/target/migrations.md +4 -0
  83. package/docs/target/projects.md +10 -10
  84. package/docs/target/scenarios.md +5 -6
  85. package/docs/target/standards-moved.md +32 -0
  86. package/docs/target/sync.md +5 -5
  87. package/docs/workflow/ai-workflow.md +1 -1
  88. package/docs/workflow/operating-model.md +16 -18
  89. package/docs/workflow/skill-map.md +1 -1
  90. package/docs/workflow/visual-design-workflow.md +3 -3
  91. package/governance/detect.toml +32 -36
  92. package/governance/renames.toml +44 -1
  93. package/governance/rules/lib/{305-e2e-reliability.md → e2e-reliability.md} +1 -1
  94. package/governance/rules/lib/{306-test-scope.md → test-scope.md} +2 -2
  95. package/governance/rules/ui/{410-a11y.md → a11y.md} +1 -1
  96. package/governance/rules/ui/{440-surface-capture.md → surface-capture.md} +3 -3
  97. package/governance/stacks/base.toml +15 -8
  98. package/governance/stacks/go.toml +2 -0
  99. package/governance/stacks/node.toml +1 -1
  100. package/governance/stacks/php.toml +2 -0
  101. package/governance/stacks/python.toml +1 -1
  102. package/package.json +1 -4
  103. package/scripts/core/install-check.sh +4 -10
  104. package/src/audits/catalog.ts +0 -9
  105. package/src/capture/frame-values.ts +3 -6
  106. package/src/claude/routing.ts +1 -1
  107. package/src/claude/skills-reach.ts +4 -6
  108. package/src/cli/help-all.ts +96 -0
  109. package/src/cli/help.ts +29 -29
  110. package/src/cli.ts +8 -3
  111. package/src/commands/claude.ts +29 -0
  112. package/src/commands/design.ts +22 -1
  113. package/src/commands/gov.ts +29 -11
  114. package/src/commands/init.ts +10 -1
  115. package/src/commands/labels.ts +4 -44
  116. package/src/commands/markdown.ts +96 -3
  117. package/src/commands/migrate.ts +1 -1
  118. package/src/commands/records.ts +5 -21
  119. package/src/commands/sync.ts +11 -0
  120. package/src/commands/tooling.ts +10 -4
  121. package/src/counts/catalogs.ts +0 -6
  122. package/src/design/budget.ts +14 -10
  123. package/src/design/document.ts +5 -5
  124. package/src/design/parse.ts +21 -4
  125. package/src/design/render.ts +3 -3
  126. package/src/gate/boundaries.ts +2 -2
  127. package/src/gate/measures.ts +7 -29
  128. package/src/gate/sequencer.ts +51 -2
  129. package/src/gate/stages.ts +0 -18
  130. package/src/gov/citations.ts +16 -71
  131. package/src/gov/stacks.ts +3 -3
  132. package/src/inventory/subjects.ts +1 -1
  133. package/src/markdown/bans.ts +1 -1
  134. package/src/markdown/ceiling.ts +6 -1
  135. package/src/markdown/colons.ts +86 -0
  136. package/src/markdown/gate.ts +15 -0
  137. package/src/markdown/heading-case.ts +74 -0
  138. package/src/migrate/scratch-evidence.ts +2 -2
  139. package/src/records/validate.ts +6 -194
  140. package/src/sandbox/provision.ts +0 -5
  141. package/src/secrets/shipped.ts +1 -2
  142. package/src/serve/static.ts +1 -2
  143. package/src/shipped/references.ts +42 -93
  144. package/src/sync/check.ts +18 -14
  145. package/src/sync/copy.ts +4 -5
  146. package/src/tooling/inject.ts +6 -37
  147. package/src/tooling/read.ts +2 -3
  148. package/src/tooling/scan.ts +4 -17
  149. package/src/tooling/subfolder.ts +2 -66
  150. package/tooling/astro/manifest.toml +0 -1
  151. package/tooling/astro/reference.md +0 -8
  152. package/tooling/base/configs/scripts/verify.json +1 -1
  153. package/tooling/base/configs/scripts/verify.ts +22 -17
  154. package/tooling/base/manifest.toml +7 -7
  155. package/tooling/base/reference.md +19 -32
  156. package/tooling/base/seeds/.github/workflows/verify.yml +0 -9
  157. package/tooling/base/seeds/.lintstagedrc +2 -4
  158. package/tooling/base/seeds/canon/context/ci.md +4 -6
  159. package/tooling/base/seeds/canon/context/development.md +2 -2
  160. package/tooling/claude/reference.md +1 -1
  161. package/tooling/claude/seeds/.claude/hooks/review-post-scan.sh +13 -1
  162. package/tooling/claude/seeds/.claude/hooks/scratch-guard.sh +1 -1
  163. package/tooling/claude/seeds/.claude/hooks/standards-audit.sh +27 -2
  164. package/tooling/claude/seeds/CLAUDE.md +1 -1
  165. package/tooling/claude/seeds/canon/DESIGN.md +24 -37
  166. package/tooling/go/reference.md +1 -1
  167. package/tooling/php/reference.md +1 -1
  168. package/tooling/python/reference.md +2 -2
  169. package/tooling/shell/configs/.github/workflows/shell.yml +30 -0
  170. package/tooling/shell/manifest.toml +12 -0
  171. package/tooling/shell/reference.md +46 -0
  172. package/tooling/vite-react/manifest.toml +0 -1
  173. package/tooling/vite-react/reference.md +0 -8
  174. package/tooling/web/configs/.github/workflows/readme-screenshot.yml +3 -5
  175. package/tooling/web/configs/.github/workflows/verify.yml +0 -9
  176. package/tooling/web/manifest.toml +1 -2
  177. package/tooling/web/reference.md +4 -6
  178. package/docs/agents/standards-audit.md +0 -40
  179. package/governance/rules/tooling/765-spelling.md +0 -19
  180. package/governance/stacks/astro.toml +0 -2
  181. package/governance/stacks/nextjs.toml +0 -2
  182. package/governance/stacks/node-server.toml +0 -2
  183. package/governance/stacks/python-fastapi.toml +0 -2
  184. package/governance/stacks/react.toml +0 -2
  185. package/src/commands/standards.ts +0 -278
  186. package/src/labels/spelling.ts +0 -120
  187. package/src/standards/audit.ts +0 -146
  188. package/src/standards/list.ts +0 -33
  189. package/src/standards/read.ts +0 -177
  190. package/src/standards/scope.ts +0 -56
  191. package/standards/index.md +0 -10
  192. package/tooling/base/configs/.vscode/extensions.json +0 -9
  193. package/tooling/base/configs/.vscode/settings.json +0 -3
  194. package/tooling/base/configs/scripts/verify.sh +0 -2
  195. package/tooling/base/seeds/.cspell/project-terms.txt +0 -0
  196. package/tooling/base/seeds/.cspell/tech-stack.txt +0 -25
  197. package/tooling/base/seeds/cspell.json +0 -20
  198. package/tooling/go/seeds/.cspell/tech-stack.txt +0 -16
  199. package/tooling/nextjs/seeds/.cspell/tech-stack.txt +0 -3
  200. package/tooling/php/seeds/.cspell/tech-stack.txt +0 -5
  201. package/tooling/python/seeds/.cspell/tech-stack.txt +0 -18
  202. package/tooling/vite-react/seeds/.cspell/project-terms.txt +0 -1
  203. package/tooling/vite-react/seeds/.cspell/tech-stack.txt +0 -2
  204. package/tooling/web/configs/.vscode/extensions.json +0 -13
  205. package/tooling/web/configs/.vscode/settings.json +0 -10
  206. package/tooling/web/seeds/.cspell/tech-stack.txt +0 -21
  207. /package/governance/rules/canon/{606-git.md → git.md} +0 -0
  208. /package/governance/rules/canon/{611-indexes.md → indexes.md} +0 -0
  209. /package/governance/rules/canon/{604-scratch.md → scratch.md} +0 -0
  210. /package/governance/rules/canon/{602-tasks.md → task-scope.md} +0 -0
  211. /package/governance/rules/canon/{605-worktrees.md → worktrees.md} +0 -0
  212. /package/governance/rules/claude/{566-output.md → output.md} +0 -0
  213. /package/governance/rules/code/{000-code.md → routing.md} +0 -0
  214. /package/governance/rules/code/{010-testing.md → testing.md} +0 -0
  215. /package/governance/rules/framework/{210-astro.md → astro.md} +0 -0
  216. /package/governance/rules/framework/{220-fastapi.md → fastapi.md} +0 -0
  217. /package/governance/rules/framework/{230-nextjs.md → nextjs.md} +0 -0
  218. /package/governance/rules/framework/{200-react.md → react.md} +0 -0
  219. /package/governance/rules/framework/{260-shadcn.md → shadcn.md} +0 -0
  220. /package/governance/rules/framework/{250-tailwind.md → tailwind.md} +0 -0
  221. /package/governance/rules/lang/{130-go.md → go.md} +0 -0
  222. /package/governance/rules/lang/{140-php.md → php.md} +0 -0
  223. /package/governance/rules/lang/{110-python.md → python.md} +0 -0
  224. /package/governance/rules/lang/{100-typescript.md → typescript.md} +0 -0
  225. /package/governance/rules/lib/{370-database.md → database.md} +0 -0
  226. /package/governance/rules/lib/{340-pydantic.md → pydantic.md} +0 -0
  227. /package/governance/rules/lib/{360-security-server.md → security-server.md} +0 -0
  228. /package/governance/rules/lib/{350-security-web.md → security-web.md} +0 -0
  229. /package/governance/rules/lib/{320-tanstack-query.md → tanstack-query.md} +0 -0
  230. /package/governance/rules/lib/{335-testing-go.md → testing-go.md} +0 -0
  231. /package/governance/rules/lib/{336-testing-php.md → testing-php.md} +0 -0
  232. /package/governance/rules/lib/{330-testing-py.md → testing-py.md} +0 -0
  233. /package/governance/rules/lib/{300-testing-ts.md → testing-ts.md} +0 -0
  234. /package/governance/rules/lib/{310-zod.md → zod.md} +0 -0
  235. /package/governance/rules/tooling/{700-ci-workflow.md → ci-workflow.md} +0 -0
  236. /package/governance/rules/tooling/{790-code-comments.md → code-comments.md} +0 -0
  237. /package/governance/rules/tooling/{780-config-comments.md → config-comments.md} +0 -0
  238. /package/governance/rules/tooling/{775-dependencies.md → dependencies.md} +0 -0
  239. /package/governance/rules/ui/{480-canvas.md → canvas.md} +0 -0
  240. /package/governance/rules/ui/{400-ui.md → copy.md} +0 -0
  241. /package/governance/rules/ui/{460-design-taste.md → design-taste.md} +0 -0
  242. /package/governance/rules/ui/{420-forms.md → forms.md} +0 -0
  243. /package/governance/rules/ui/{465-interface-casing.md → interface-casing.md} +0 -0
  244. /package/governance/rules/ui/{450-link-behavior.md → link-behavior.md} +0 -0
  245. /package/governance/rules/ui/{470-motion.md → motion.md} +0 -0
  246. /package/governance/rules/ui/{430-ux-completeness.md → ux-completeness.md} +0 -0
  247. /package/tooling/{base → shell}/configs/.editorconfig +0 -0
  248. /package/tooling/{base → shell}/configs/.shellcheckrc +0 -0
@@ -6,10 +6,9 @@ import { SURFACE_ROOTS } from '@/roots/surface'
6
6
  /**
7
7
  * The authoring roots this repository owns and no install channel delivers.
8
8
  *
9
- * Every entry is a folder a target never holds under that spelling. Standards
10
- * install nowhere and are reached through the plugin corpus,
11
- * rules install under `.claude/rules/`, and the rest are this repository's
12
- * own source, docs, and catalogs.
9
+ * Every entry is a folder a target never holds under that spelling. Rules
10
+ * install under `.claude/rules/`, and the rest are this repository's own
11
+ * source, docs, and catalogs.
13
12
  *
14
13
  * `src/`, `scripts/`, and bare `docs/` are deliberately absent. A body naming
15
14
  * one of those is describing the reader's own tree, so listing them would
@@ -28,7 +27,6 @@ const AUTHORING_ROOTS = [
28
27
  'docs/agents/',
29
28
  'governance/',
30
29
  'internal/',
31
- 'standards/',
32
30
  'tooling/',
33
31
  'wiki/',
34
32
  ] as const
@@ -51,7 +49,7 @@ const TOKEN = /`([^`\s]+)`/g
51
49
  *
52
50
  * Requires an extension and a separator, and admits no `<`, `$`, or `*`. A
53
51
  * body writes `canon/context/<domain>.md` to name a shape rather than a
54
- * file, and `${CLAUDE_SKILL_DIR}/../../standards/<name>.md` to resolve
52
+ * file, and `${CLAUDE_SKILL_DIR}/../<skill>/references/<name>.md` to resolve
55
53
  * against the plugin root, which is self-contained by construction.
56
54
  */
57
55
  const CONCRETE = /^[.A-Za-z0-9_][A-Za-z0-9._/-]*\.[a-z]{1,4}$/
@@ -0,0 +1,96 @@
1
+ import type { Command } from 'commander'
2
+
3
+ export type HelpRoute =
4
+ | { kind: 'parse' }
5
+ | { kind: 'top' }
6
+ | { kind: 'all'; command: Command }
7
+ | { kind: 'unknown'; name: string }
8
+
9
+ const HELP_FLAGS = new Set(['-h', '--help'])
10
+
11
+ // Commander exposes no getter for a disabled help option, and `canon sandbox`
12
+ // disables its own to forward `--help` to a bash script.
13
+ function hasHelpOption(command: Command): boolean {
14
+ return command.helpInformation().includes('--help')
15
+ }
16
+
17
+ // A group with its own action, or with a default subcommand such as
18
+ // `inventory run`, takes an operand that names no subcommand. Commander keeps
19
+ // both on private fields.
20
+ function takesOperand(command: Command): boolean {
21
+ const internals = command as unknown as {
22
+ _actionHandler: unknown
23
+ _defaultCommandName: unknown
24
+ }
25
+ return (
26
+ command.registeredArguments.length > 0 ||
27
+ internals._actionHandler !== null ||
28
+ internals._defaultCommandName !== null
29
+ )
30
+ }
31
+
32
+ function visibleChildren(command: Command): Command[] {
33
+ return command
34
+ .createHelp()
35
+ .visibleCommands(command)
36
+ .filter((child) => command.commands.includes(child))
37
+ }
38
+
39
+ function leaves(command: Command): Command[] {
40
+ return visibleChildren(command).flatMap((child) =>
41
+ visibleChildren(child).length === 0 ? [child] : leaves(child),
42
+ )
43
+ }
44
+
45
+ // `outputHelp` rather than `helpInformation`, since only the former emits the
46
+ // blocks `addHelpText` registers, which carry every verb's exit codes and
47
+ // examples.
48
+ function captureHelp(command: Command): string {
49
+ const config = command.configureOutput()
50
+ const { writeOut } = config
51
+ let text = ''
52
+ command.configureOutput({ writeOut: (chunk) => (text += chunk) })
53
+ try {
54
+ command.outputHelp()
55
+ } finally {
56
+ command.configureOutput({ writeOut })
57
+ }
58
+ return text.trimEnd()
59
+ }
60
+
61
+ // Each block opens on its own `Usage:` line, so a blank line is the whole
62
+ // separator and a reader splits on the usage header.
63
+ export function renderAll(command: Command): string {
64
+ const blocks = [command, ...leaves(command)].map(captureHelp)
65
+ return `${blocks.join('\n\n')}\n`
66
+ }
67
+
68
+ // Reads argv ahead of commander, which prints a group's help for an unknown
69
+ // subcommand because it answers `--help` before it resolves operands. Walking
70
+ // stops at the first option, so an option's value is never read as a name.
71
+ export function routeHelp(program: Command, args: string[]): HelpRoute {
72
+ if (!args.some((arg) => HELP_FLAGS.has(arg))) return { kind: 'parse' }
73
+
74
+ let command = program
75
+ let depth = 0
76
+ for (const arg of args) {
77
+ if (arg.startsWith('-')) break
78
+ const child = command.commands.find((c) => c.name() === arg)
79
+ if (child === undefined) {
80
+ const isGroupOnly =
81
+ command !== program &&
82
+ command.commands.length > 0 &&
83
+ !takesOperand(command) &&
84
+ arg !== 'help'
85
+ if (isGroupOnly) return { kind: 'unknown', name: arg }
86
+ break
87
+ }
88
+ command = child
89
+ depth += 1
90
+ }
91
+
92
+ if (!args.includes('--all')) return { kind: 'parse' }
93
+ if (depth === 0) return { kind: 'top' }
94
+ if (!hasHelpOption(command)) return { kind: 'parse' }
95
+ return { kind: 'all', command }
96
+ }
package/src/cli/help.ts CHANGED
@@ -20,62 +20,61 @@ export const COMMAND_GROUPS: { title: string; rows: CommandRow[] }[] = [
20
20
  ['sync [path]', 'Sync all installed domains in a project'],
21
21
  ['upgrade', 'Reinstall the CLI with the manager that installed it'],
22
22
  ['migrate [cmd]', 'Move a project off a retired name or layout'],
23
- ['targets [cmd]', 'Projects this toolkit installed into (list, pulls)'],
23
+ ['targets [cmd]', 'Projects this toolkit installed into'],
24
24
  ],
25
25
  },
26
26
  {
27
27
  title: 'Domains',
28
28
  rows: [
29
- ['gov [cmd]', 'Governance rules (install, sync, list)'],
30
- ['standards [cmd]', 'Standards (list, <name>)'],
31
- ['tooling [cmd]', 'Tooling stacks (sync, ref, create)'],
32
- ['claude [cmd]', 'Claude workflow (init, sync, setup)'],
33
- ['wiki [cmd]', 'Wiki pages (init)'],
34
- ['indexes [cmd]', 'Regenerate index.md files (regen)'],
35
- ['docs [cmd|topic]', 'Emit toolkit reference docs (list, <topic>)'],
29
+ ['gov [cmd]', 'Governance rules'],
30
+ ['tooling [cmd]', 'Tooling stacks'],
31
+ ['claude [cmd]', 'Claude workflow'],
32
+ ['wiki [cmd]', 'Wiki pages'],
33
+ ['indexes [cmd]', 'Regenerate index.md files'],
34
+ ['docs [cmd|topic]', 'Emit toolkit reference docs'],
36
35
  ],
37
36
  },
38
37
  {
39
38
  title: 'Author and render',
40
39
  rows: [
41
- ['design [cmd]', 'Design system (render, regen)'],
42
- ['slides [cmd]', 'Slide decks (render, list)'],
40
+ ['design [cmd]', 'Design system'],
41
+ ['slides [cmd]', 'Slide decks'],
43
42
  ['capture [source]', 'Render HTML capture sources to PNG'],
44
43
  ['serve [dir]', 'Serve a directory on localhost, print the link'],
45
- ['demo [cmd]', 'Record a running app (compile, run)'],
44
+ ['demo [cmd]', 'Record a running app'],
46
45
  ['inventory [subj]', 'Report one computed property across every route'],
47
46
  ['drive <url> <run>', 'Walk a page through interactions, measure each'],
48
47
  ['transcripts <url>', 'Fetch a YouTube transcript with frontmatter'],
49
- ['teach [cmd]', 'Learning workspaces (list, open, resource, glossary)'],
50
- ['canvas [cmd]', 'Local canvas of pages and frames (serve, list)'],
48
+ ['teach [cmd]', 'Learning workspaces'],
49
+ ['canvas [cmd]', 'Local canvas of pages and frames'],
51
50
  ],
52
51
  },
53
52
  {
54
53
  title: 'Session and ship',
55
54
  rows: [
56
55
  ['sandbox [cat:cmd]', 'Provision and run sandbox scenarios'],
57
- ['tasks [cmd]', 'Task board (validate, archive)'],
58
- ['intake [cmd]', 'Intake folders under .canon/intake/ (list, answer)'],
59
- ['records [cmd]', 'Session records (validate, size, push, pull)'],
56
+ ['tasks [cmd]', 'Task board'],
57
+ ['intake [cmd]', 'Intake folders under .canon/intake/'],
58
+ ['records [cmd]', 'Session records'],
60
59
  ['sessions [cmd]', 'Resolve live sessions to worktree and branch'],
61
60
  ['worktrees [cmd]', 'Reclaim worktrees whose branches merged'],
62
- ['hooks [cmd]', 'Run the steps a git hook drives (post-merge)'],
63
- ['pr [cmd]', 'Read a pull request (key-changes, head, checks)'],
64
- ['upstream [cmd]', 'Read Claude Code releases (fetch, catalog, advance)'],
61
+ ['hooks [cmd]', 'Run the steps a git hook drives'],
62
+ ['pr [cmd]', 'Read a pull request'],
63
+ ['upstream [cmd]', 'Read Claude Code releases'],
65
64
  ['feedback', 'File toolkit feedback as a GitHub issue'],
66
65
  ],
67
66
  },
68
67
  {
69
68
  title: 'Repo reports',
70
69
  rows: [
71
- ['audits [cmd]', 'Run every health check as one set (run, list)'],
72
- ['gate [cmd]', 'Run the merge gate stage by stage (run)'],
73
- ['secrets [cmd]', 'Scan the shipped tree for credentials (scan)'],
74
- ['deps [cmd]', 'Read the dependency set for advisories (audit)'],
75
- ['labels [cmd]', 'Read a changed set against the label map (audit)'],
76
- ['comments [cmd]', 'Measure comment density and trend (scan)'],
77
- ['context [cmd]', 'Report context folder health (audit)'],
78
- ['markdown [cmd]', 'Report markdown against the standards (audit)'],
70
+ ['audits [cmd]', 'Run every health check as one set'],
71
+ ['gate [cmd]', 'Run the merge gate stage by stage'],
72
+ ['secrets [cmd]', 'Scan the shipped tree for credentials'],
73
+ ['deps [cmd]', 'Read the dependency set for advisories'],
74
+ ['labels [cmd]', 'Read a changed set against the label map'],
75
+ ['comments [cmd]', 'Measure comment density and trend'],
76
+ ['context [cmd]', 'Report context folder health'],
77
+ ['markdown [cmd]', 'Report markdown against the shipped bans'],
79
78
  ['census [path]', 'Report file count, extensions, and line totals'],
80
79
  ],
81
80
  },
@@ -91,10 +90,10 @@ const SANDBOX_ROWS: CommandRow[] = [
91
90
  const EXAMPLES = [
92
91
  'canon sync ../my-app',
93
92
  'canon sandbox git:commit',
94
- 'canon gov install react',
93
+ 'canon gov install node',
95
94
  'canon gov sync ../my-app',
96
95
  'canon gov restated --json',
97
- 'canon standards markdown',
96
+ 'canon markdown audit docs/',
98
97
  'canon init ../my-app',
99
98
  'canon tooling sync base',
100
99
  'canon claude init',
@@ -112,6 +111,7 @@ const EXAMPLES = [
112
111
  'canon drive http://localhost:4173 run.json --json',
113
112
  'pbpaste | canon feedback',
114
113
  'canon transcripts https://youtu.be/VIDEO_ID',
114
+ 'canon tasks --help --all',
115
115
  'canon tasks archive --pull-request 673 --json',
116
116
  'canon intake list toolkit-overview --unread --json',
117
117
  'canon teach list --json',
package/src/cli.ts CHANGED
@@ -5,7 +5,6 @@ import { register as init } from '@/commands/init'
5
5
  import { register as sandbox } from '@/commands/sandbox'
6
6
  import { register as sync } from '@/commands/sync'
7
7
  import { register as gov } from '@/commands/gov'
8
- import { register as standards } from '@/commands/standards'
9
8
  import { register as tooling } from '@/commands/tooling'
10
9
  import { register as claude } from '@/commands/claude'
11
10
  import { register as wiki } from '@/commands/wiki'
@@ -44,6 +43,7 @@ import { register as targets } from '@/commands/targets'
44
43
  import { register as upgrade } from '@/commands/upgrade'
45
44
  import { readInstalled, UNKNOWN_LABEL } from '@/version/installed'
46
45
  import { renderHelp } from '@/cli/help'
46
+ import { renderAll, routeHelp } from '@/cli/help-all'
47
47
 
48
48
  function showHelp(): void {
49
49
  console.log(renderHelp(process.stdout))
@@ -66,7 +66,6 @@ init(program)
66
66
  sandbox(program)
67
67
  sync(program)
68
68
  gov(program)
69
- standards(program)
70
69
  tooling(program)
71
70
  claude(program)
72
71
  wiki(program)
@@ -104,4 +103,10 @@ audits(program)
104
103
  gate(program)
105
104
  upgrade(program)
106
105
 
107
- program.parse()
106
+ const route = routeHelp(program, process.argv.slice(2))
107
+ if (route.kind === 'top') showHelp()
108
+ else if (route.kind === 'all') process.stdout.write(renderAll(route.command))
109
+ else if (route.kind === 'unknown') {
110
+ console.error(`error: unknown command '${route.name}'`)
111
+ process.exitCode = 1
112
+ } else program.parse()
@@ -212,6 +212,20 @@ export function register(program: Command): void {
212
212
  .description('Seed .claude/ workflow docs into a project')
213
213
  .argument('[target]', 'Target directory', '.')
214
214
  .helpOption('-h, --help', 'Show this help message')
215
+ .addHelpText(
216
+ 'after',
217
+ [
218
+ '',
219
+ 'Copies each workflow seed the target lacks, CLAUDE.md included, and',
220
+ 'leaves one already present alone. Then adds the .gitignore entries',
221
+ 'the claude manifest lists.',
222
+ '',
223
+ 'Exit codes:',
224
+ ' 0 initialized, already initialized, or the prompt was cancelled',
225
+ ' 1 the target is missing or is the toolkit root',
226
+ '',
227
+ ].join('\n'),
228
+ )
215
229
  .action(async (target: string) => {
216
230
  process.exitCode = await runInit(target)
217
231
  })
@@ -221,6 +235,21 @@ export function register(program: Command): void {
221
235
  .description('Reconcile .gitignore against the claude manifest')
222
236
  .argument('[target]', 'Target directory', '.')
223
237
  .helpOption('-h, --help', 'Show this help message')
238
+ .addHelpText(
239
+ 'after',
240
+ [
241
+ '',
242
+ 'Writes .gitignore alone: adds the entries the claude manifest lists',
243
+ 'and drops ones under its headers that the manifest no longer lists.',
244
+ 'A seeded file is reported, never rewritten, and a missing one points',
245
+ 'at `canon claude init`.',
246
+ '',
247
+ 'Exit codes:',
248
+ ' 0 synced, already up to date, or the prompt was cancelled',
249
+ ' 1 the target is missing or is the toolkit root',
250
+ '',
251
+ ].join('\n'),
252
+ )
224
253
  .action(async (target: string) => {
225
254
  process.exitCode = await runSync(target)
226
255
  })
@@ -161,7 +161,13 @@ export function register(program: Command): void {
161
161
  `overrides a value by writing ${join(DESIGN_INSTALL_DIR, DESIGN_PROJECT_SUBDIR)}/`,
162
162
  'itself, which sync never touches. Nothing arrives on a project that',
163
163
  'has not run this, so a design value reaches a target on an install',
164
- 'rather than on the next sync.',
164
+ 'rather than on the next sync. A base stylesheet already installed is',
165
+ 'replaced.',
166
+ '',
167
+ 'Exit codes:',
168
+ ' 0 the stylesheet was installed',
169
+ ' 1 the target is missing or is the toolkit root, or the toolkit',
170
+ ' source is absent',
165
171
  '',
166
172
  ].join('\n'),
167
173
  )
@@ -176,6 +182,21 @@ export function register(program: Command): void {
176
182
  )
177
183
  .argument('[target]', 'Target directory', '.')
178
184
  .helpOption('-h, --help', 'Show this help message')
185
+ .addHelpText(
186
+ 'after',
187
+ [
188
+ '',
189
+ 'Replaces the shipped design files under .claude/design/ with the',
190
+ 'toolkit copy, edited or not, and leaves',
191
+ `${join(DESIGN_INSTALL_DIR, DESIGN_PROJECT_SUBDIR)}/ alone. It deletes nothing it finds no`,
192
+ 'source for.',
193
+ '',
194
+ 'Exit codes:',
195
+ ' 0 synced, already up to date, or the prompt was cancelled',
196
+ ' 1 the target is missing or is the toolkit root',
197
+ '',
198
+ ].join('\n'),
199
+ )
179
200
  .action(async (target: string) => {
180
201
  process.exitCode = await runDomainSync(
181
202
  createDesignAdapter(PROJECT_ROOT),
@@ -143,7 +143,7 @@ export function register(program: Command): void {
143
143
  gov
144
144
  .command('install')
145
145
  .description('Install a governance stack into .claude/rules/canon/')
146
- .argument('[stack]', 'Stack name (e.g. base, node, react)')
146
+ .argument('[stack]', 'Stack name (e.g. base, node, python)')
147
147
  .argument('[target]', 'Target directory', '.')
148
148
  .helpOption('-h, --help', 'Show this help message')
149
149
  .option('--add <rules>', 'Comma-separated rules to layer on the stack')
@@ -152,15 +152,23 @@ export function register(program: Command): void {
152
152
  [
153
153
  '',
154
154
  'Examples:',
155
- ' canon gov install react',
155
+ ' canon gov install node',
156
156
  ' canon gov install node ../my-app',
157
- ' canon gov install astro --add 200-react,260-shadcn ../my-app',
157
+ ' canon gov install node --add astro,shadcn ../my-app',
158
158
  ' canon gov install --add tasks,plan ../my-app',
159
159
  '',
160
160
  'With --add and no stack, the named rules install alone. A first',
161
161
  'positional naming a stack is read as the stack, so pass . or a path',
162
162
  'carrying a slash to force a target that shares a stack name.',
163
163
  '',
164
+ 'Copies each rule into .claude/rules/canon/, replacing a copy already',
165
+ 'there. Rules under .claude/rules/project/ are never read.',
166
+ '',
167
+ 'Exit codes:',
168
+ ' 0 installed, the stack held no rules, or the prompt was cancelled',
169
+ ' 1 refused: no stack named headlessly, an unknown stack, no --add',
170
+ ' rule resolved, or a missing target or the toolkit root',
171
+ '',
164
172
  ].join('\n'),
165
173
  )
166
174
  .action(
@@ -178,6 +186,21 @@ export function register(program: Command): void {
178
186
  .description('Update rules already installed under .claude/rules/canon/')
179
187
  .argument('[target]', 'Target directory', '.')
180
188
  .helpOption('-h, --help', 'Show this help message')
189
+ .addHelpText(
190
+ 'after',
191
+ [
192
+ '',
193
+ 'Replaces an edited rule under .claude/rules/canon/ with the shipped',
194
+ 'copy, deletes a rule the toolkit retired, and moves a renamed one.',
195
+ 'It adds no new rule, which is `canon gov install`, and never touches',
196
+ '.claude/rules/project/.',
197
+ '',
198
+ 'Exit codes:',
199
+ ' 0 synced, already up to date, or the prompt was cancelled',
200
+ ' 1 the target is missing or is the toolkit root',
201
+ '',
202
+ ].join('\n'),
203
+ )
181
204
  .action(async (target: string) => {
182
205
  process.exitCode = await runDomainSync(
183
206
  createGovAdapter(PROJECT_ROOT),
@@ -307,7 +330,7 @@ export function register(program: Command): void {
307
330
  'members a closed catalog holds, then compares the stated figure',
308
331
  'against what the tree actually counts.',
309
332
  '',
310
- 'Catalogs read: skills, governance rules, standards, CLI commands,',
333
+ 'Catalogs read: skills, governance rules, CLI commands,',
311
334
  'and audit ids. Closed rather than derived, so widening the',
312
335
  'set is a deliberate change rather than a side effect of a new list',
313
336
  'command shipping elsewhere.',
@@ -440,21 +463,16 @@ export function register(program: Command): void {
440
463
  'internal corpus ships nowhere, which makes the tree it governs the tree',
441
464
  'present and the question answerable.',
442
465
  '',
443
- 'Forms read, with where each resolves:',
444
- ' standard canon standards <name> , against standards/ alone, which',
445
- ' is where the verb itself looks. internal/standards/ is not',
446
- ' tried, since a name resolving only there refuses for the',
447
- ' session that opens the citation.',
466
+ 'Form read, with where it resolves:',
448
467
  ' path a backticked path carrying a directory segment and a file',
449
468
  ' extension, against the root',
450
- " sibling a bare <nnn>-<slug>.md , against the citing rule's folder",
451
469
  '',
452
470
  'Not read, each a shape the corpus writes and none of them a citation:',
453
471
  ' a placeholder or glob segment, which describes a shape rather than',
454
472
  ' naming a file, such as canon/context/<domain>.md or app/**/route.ts',
455
473
  ' a bare filename naming a convention, such as route.ts or manifest.toml',
456
474
  ' a span carrying no file extension, which is a folder or a module',
457
- ' specifier, such as src/pages/ , next/font , or claude/standards',
475
+ ' specifier, such as src/pages/ , next/font , or claude/skills',
458
476
  ' a fenced block, which displays a path rather than pointing at one',
459
477
  '',
460
478
  'Exempt, reported by name rather than dropped:',
@@ -37,10 +37,19 @@ export function register(program: Command): void {
37
37
  '',
38
38
  'Passing any option skips the confirmation prompt.',
39
39
  '',
40
+ 'Runs `canon tooling sync base --write` first, which replaces every',
41
+ 'base golden config the target holds, then `canon claude init`,',
42
+ '`canon gov install`, and `canon wiki init`. Refuses a target that is',
43
+ 'not a directory or is the toolkit root.',
44
+ '',
45
+ 'Exit codes:',
46
+ ' 0 every domain installed, or the prompt was cancelled',
47
+ ' 1 the target was refused, or a domain failed, named on stderr',
48
+ '',
40
49
  'Examples:',
41
50
  ' canon init',
42
51
  ' canon init ../my-app',
43
- ' canon init --stack astro --add 260-shadcn ../my-app',
52
+ ' canon init --stack node --add astro,shadcn ../my-app',
44
53
  ' canon init --skip governance ../my-app',
45
54
  '',
46
55
  ].join('\n'),
@@ -10,7 +10,6 @@ import { checkTitleFormat, type TitleFormatIssue } from '@/labels/format'
10
10
  import { MAP_REL } from '@/labels/map'
11
11
  import { isReleasePullRequest, scanPhaseLabels } from '@/labels/phase'
12
12
  import { checkSections } from '@/labels/sections'
13
- import { scanTitleSpelling } from '@/labels/spelling'
14
13
  import { BAN_SETS } from '@/markdown/bans'
15
14
  import { bodyLines, scanBans } from '@/markdown/scan'
16
15
  import { intro, logInfo, logStep, logWarn, outro, plural } from '@/cli/ui'
@@ -169,7 +168,7 @@ export function register(program: Command): void {
169
168
  labels
170
169
  .command('scan')
171
170
  .description(
172
- 'Fail a pull request or a posted review whose title, body, or review comment carries a phase label, a board identifier, a session link, or a title with an unspelled word',
171
+ 'Fail a pull request or a posted review whose title, body, or review comment carries a phase label, a board identifier, or a session link',
173
172
  )
174
173
  .helpOption('-h, --help', 'Show this help message')
175
174
  .option(
@@ -188,7 +187,7 @@ export function register(program: Command): void {
188
187
  'after',
189
188
  [
190
189
  '',
191
- 'Reads canon standards versioning for the two namespaces and sorts every',
190
+ 'Reads the git-commit versioning reference for the two namespaces and sorts every',
192
191
  'version-shaped token this pull request carries into the one the pull',
193
192
  'request is allowed to hold. A release-please pull request, read off its',
194
193
  'own fixed head branch and title, may carry semver references. Every',
@@ -212,13 +211,6 @@ export function register(program: Command): void {
212
211
  'session and for no other reader, which no clone repairs, so it is read',
213
212
  'on a release pull request too, where the board identifier is not.',
214
213
  '',
215
- "It also spell-checks the title alone against this repository's own",
216
- 'cspell config, since release-please copies the title into',
217
- 'CHANGELOG.md and nothing else spell-checks it first. The check shells',
218
- "this repository's own resolved cspell binary and reports nothing when",
219
- 'a target project carries none, rather than reaching the network or',
220
- 'forcing a new dependency.',
221
- '',
222
214
  "It also grades the title alone against claude/skills/git-pr/references/pr.md's ## Title",
223
215
  'section: the `<type>(<scope>)[!]: <subject>` structure, lowercase casing',
224
216
  'for the type, the scope, and the first subject word, and a 72-',
@@ -234,11 +226,11 @@ export function register(program: Command): void {
234
226
  'request or a review, outside a code span or a link.',
235
227
  '',
236
228
  'Exit codes:',
237
- ' 0 none of the seven found',
229
+ ' 0 none of the six found',
238
230
  ' 1 refused, with the reason on stderr or in the JSON record',
239
231
  ' 2 the title or body carries a phase label, a board identifier, a',
240
232
  ' session link, a banned character, a heading outside the closed',
241
- ' list or a required one missing, a title word no dictionary holds, or a title',
233
+ ' list or a required one missing, or a title',
242
234
  " breaking claude/skills/git-pr/references/pr.md's format, casing, or length",
243
235
  '',
244
236
  'Examples:',
@@ -532,7 +524,6 @@ async function runScan(opts: ScanOptions): Promise<number> {
532
524
  }
533
525
 
534
526
  const result = scanPhaseLabels(resolved)
535
- const spelling = await scanTitleSpelling(resolved.title, process.cwd())
536
527
  // A scan given no title, whatever produced that absence, has nothing to
537
528
  // grade and would otherwise fail as `structure` for the wrong reason.
538
529
  const titleFormat =
@@ -579,34 +570,6 @@ async function runScan(opts: ScanOptions): Promise<number> {
579
570
  for (const link of result.sessionLinks) logWarn(link)
580
571
  }
581
572
 
582
- const spellingChecked = spelling.kind === 'checked'
583
- const unspelledWords =
584
- spelling.kind === 'checked' ? spelling.unknownWords : []
585
-
586
- logStep(
587
- spelling.kind === 'unavailable'
588
- ? 'Spelling unavailable'
589
- : unspelledWords.length === 0
590
- ? 'Clean'
591
- : 'Unspelled word found',
592
- )
593
- if (spelling.kind === 'unavailable' && spelling.reason === 'no-binary') {
594
- logInfo(
595
- `no node_modules/.bin/cspell resolved walking up from ${spelling.probedFrom}, so the title was not checked`,
596
- )
597
- } else if (spelling.kind === 'unavailable') {
598
- logInfo(
599
- `cspell did not exit clean or with issues found (${spelling.message}), so the title was not checked`,
600
- )
601
- } else if (unspelledWords.length === 0) {
602
- logInfo('no word in the title is absent from every dictionary')
603
- } else {
604
- logWarn(
605
- `${plural(unspelledWords.length, 'word')} in the title absent from every dictionary. Fix the spelling, or add jargon and project-specific terms to .cspell/project-terms.txt and dependency vocabulary to .cspell/tech-stack.txt.`,
606
- )
607
- for (const word of unspelledWords) logWarn(word)
608
- }
609
-
610
573
  const titleFormatIssues = titleFormat?.issues ?? []
611
574
 
612
575
  // A review carries its own headings, a release-please body opens on a
@@ -707,8 +670,6 @@ async function runScan(opts: ScanOptions): Promise<number> {
707
670
  semverTags: result.semverTags,
708
671
  boardReferences: result.boardReferences,
709
672
  sessionLinks: result.sessionLinks,
710
- unspelledWords,
711
- spellingChecked,
712
673
  titleFormatIssues,
713
674
  sections: { checked: sectionsChecked, ...sections },
714
675
  bannedCharacters,
@@ -719,7 +680,6 @@ async function runScan(opts: ScanOptions): Promise<number> {
719
680
  return result.phaseLabels.length === 0 &&
720
681
  result.boardReferences.length === 0 &&
721
682
  result.sessionLinks.length === 0 &&
722
- unspelledWords.length === 0 &&
723
683
  titleFormatIssues.length === 0 &&
724
684
  sections.outside.length === 0 &&
725
685
  sections.missing.length === 0 &&