@erclx/canon 4.103.0 → 4.105.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 (60) hide show
  1. package/claude/.claude-plugin/plugin.json +1 -1
  2. package/claude/skills/canon-cli/SKILL.md +3 -77
  3. package/claude/skills/canon-operator/REQUIREMENT.md +2 -2
  4. package/claude/skills/canon-operator/SKILL.md +5 -5
  5. package/claude/skills/design-taste/references/craft.md +1 -1
  6. package/claude/skills/design-taste/references/preflight.md +2 -2
  7. package/claude/skills/design-taste/references/tells.md +1 -1
  8. package/claude/skills/git-followup/SKILL.md +1 -1
  9. package/claude/skills/git-issue/SKILL.md +2 -2
  10. package/{standards → claude/skills/git-issue/references}/issue.md +3 -8
  11. package/claude/skills/git-pr/SKILL.md +2 -2
  12. package/claude/skills/index-lookup/REQUIREMENT.md +2 -2
  13. package/claude/skills/project-commands/REQUIREMENT.md +1 -1
  14. package/claude/skills/seed-sync/REQUIREMENT.md +1 -1
  15. package/claude/skills/target-check/REQUIREMENT.md +1 -1
  16. package/claude/skills/target-setup/REQUIREMENT.md +56 -0
  17. package/claude/skills/target-setup/SKILL.md +163 -0
  18. package/claude/skills/target-setup/references/detect.md +80 -0
  19. package/claude/skills/{setup-indexes/SKILL.md → target-setup/references/indexes.md} +59 -23
  20. package/claude/skills/target-setup/references/verify.md +95 -0
  21. package/docs/agents/sandbox.md +1 -1
  22. package/docs/agents/scripting.md +3 -2
  23. package/docs/agents/tasks.md +13 -11
  24. package/docs/target-projects.md +11 -11
  25. package/docs/workflow/ai-workflow.md +8 -13
  26. package/governance/rules/ui/400-ui.md +0 -5
  27. package/governance/rules/ui/410-a11y.md +5 -0
  28. package/governance/rules/ui/440-surface-capture.md +7 -1
  29. package/governance/rules/ui/460-design-taste.md +1 -1
  30. package/governance/rules/ui/465-interface-casing.md +31 -0
  31. package/governance/stacks/astro.toml +1 -1
  32. package/governance/stacks/react.toml +1 -1
  33. package/package.json +1 -1
  34. package/scripts/core/regen-hero.sh +1 -1
  35. package/src/claude/cases/setup.ts +12 -11
  36. package/src/commands/sync.ts +1 -1
  37. package/src/commands/tasks.ts +1 -0
  38. package/src/design/document.ts +2 -0
  39. package/src/design/tokens.ts +4 -0
  40. package/src/gate/measures.ts +57 -0
  41. package/src/gate/stages.ts +10 -14
  42. package/src/gov/list.ts +1 -1
  43. package/src/sandbox/census.ts +3 -3
  44. package/src/shipped/references.ts +1 -1
  45. package/src/tasks/validate.ts +68 -0
  46. package/standards/design.md +1 -1
  47. package/standards/index.md +0 -1
  48. package/claude/skills/setup-gov/REQUIREMENT.md +0 -37
  49. package/claude/skills/setup-gov/SKILL.md +0 -77
  50. package/claude/skills/setup-indexes/REQUIREMENT.md +0 -48
  51. package/claude/skills/setup-init/REQUIREMENT.md +0 -46
  52. package/claude/skills/setup-init/SKILL.md +0 -133
  53. package/claude/skills/setup-plugins/REQUIREMENT.md +0 -42
  54. package/claude/skills/setup-plugins/SKILL.md +0 -81
  55. package/claude/skills/setup-plugins/references/plugin-catalog.md +0 -53
  56. package/claude/skills/setup-smoke/REQUIREMENT.md +0 -38
  57. package/claude/skills/setup-smoke/SKILL.md +0 -53
  58. package/claude/skills/setup-verify/REQUIREMENT.md +0 -39
  59. package/claude/skills/setup-verify/SKILL.md +0 -51
  60. package/scripts/core/regen-tooling-paths.sh +0 -61
@@ -1,25 +1,32 @@
1
1
  ---
2
- name: setup-indexes
3
- description: Bootstraps the toolkit's `index.md` system in a target project. Scans for markdown-heavy folders, drafts `title` and `description` frontmatter, scaffolds `index.md` per chosen folder, and runs `canon indexes regen` to validate. Use when asked to "set up indexes", "bootstrap indexes", "add index.md to this project", or "install indexes". Assumes the `canon` CLI is on PATH.
2
+ title: Indexes bootstrap
3
+ description: The scan, frontmatter drafting, scaffold, validate, and convention seed phases that add the index.md system to a project
4
4
  ---
5
5
 
6
- # Indexes install
6
+ # Indexes bootstrap
7
7
 
8
- Adds the index.md system to a project that does not have it. Operates in the active Claude session: Claude reads files, drafts frontmatter, confirms with the user, and writes. The CLI handles validation and regeneration only.
8
+ Adds the `index.md` system to a project that does not have it. Operates in the
9
+ active Claude session: Claude reads files, drafts frontmatter, confirms with the
10
+ user, and writes. The CLI handles validation and regeneration only.
9
11
 
10
- Read `canon docs indexes` from the toolkit if context on the system is needed before scanning.
12
+ Read `canon docs indexes` from the toolkit if context on the system is needed
13
+ before scanning.
11
14
 
12
15
  ## Scope
13
16
 
14
17
  - Bootstrap un-indexed folders only. Skip folders that already contain an `index.md`.
15
18
  - All-or-nothing per chosen folder. Every `*.md` sibling in a chosen folder gets `title` and `description` injected, or none does. Partial migration creates folders that hard-error on regen.
16
- - This is where `setup-init` sends an install that wants the Claude layer without the tooling chain, once `canon claude init` has seeded the docs. The work is the same either way, since the scan below prunes `.claude` and reads the project's own documentation folders whichever route reached it.
19
+ - This phase is where an install wanting the Claude layer without the tooling chain arrives, once `canon claude init` has seeded the docs. The work is the same either way, since the scan below prunes `.claude` and reads the project's own documentation folders whichever route reached it.
17
20
 
18
21
  ## Scan
19
22
 
20
- Walk the project root for folders containing three or more sibling `*.md` files. Prune `.git`, `node_modules`, `.claude`, `snippets`, anything matched by `.gitignore`, and any folder that already contains an `index.md`.
23
+ Walk the project root for folders containing three or more sibling `*.md` files.
24
+ Prune `.git`, `node_modules`, `.claude`, `snippets`, anything matched by
25
+ `.gitignore`, and any folder that already contains an `index.md`.
21
26
 
22
- Skip `.claude/snippets/`. Snippets are invoked by reference (`@snippet-name`) rather than browsed, so they need neither `index.md` nor per-file frontmatter. Adding them creates noise that targets keep reporting.
27
+ Skip `.claude/snippets/`. Snippets are invoked by reference (`@snippet-name`)
28
+ rather than browsed, so they need neither `index.md` nor per-file frontmatter.
29
+ Adding them creates noise that targets keep reporting.
23
30
 
24
31
  For each candidate, capture:
25
32
 
@@ -35,7 +42,9 @@ If the scan found no candidate, report the flat result and skip ahead:
35
42
  No folder has three or more markdown siblings without an index.md already. Nothing to bootstrap.
36
43
  ```
37
44
 
38
- Skip past the ask below and every step between it and the seed offer, straight to `## Offer the convention seed`. There is no candidate to ask about, so this stops rather than opening a prompt with nothing in it.
45
+ Skip past the ask below and every step between it and the seed offer, straight
46
+ to `## Offer the convention seed`. There is no candidate to ask about, so this
47
+ stops rather than opening a prompt with nothing in it.
39
48
 
40
49
  Output one line per candidate:
41
50
 
@@ -45,7 +54,12 @@ Output one line per candidate:
45
54
  - references/ (3 files, 0/3 with frontmatter)
46
55
  ```
47
56
 
48
- Ask the user which to bootstrap. Accept folder paths, `all`, or `none`. The user can also force a folder with fewer than three siblings by naming it explicitly.
57
+ Ask the user which to bootstrap. Accept folder paths, `all`, or `none`. The user
58
+ can also force a folder with fewer than three siblings by naming it explicitly.
59
+
60
+ `--all` and `--folders <a>,<b>` answer this ask ahead of time, which is what
61
+ keeps the phase non-interactive. With neither, and with no TTY, report the
62
+ candidate list and stop rather than choosing on the operator's behalf.
49
63
 
50
64
  ## Draft frontmatter
51
65
 
@@ -62,9 +76,13 @@ docs/architecture.md
62
76
  description: System boundaries, data flow, and module responsibilities
63
77
  ```
64
78
 
65
- The user accepts, edits, or rejects per file. Offer "accept all remaining" once the user confirms two in a row to keep the loop short.
79
+ The user accepts, edits, or rejects per file. Offer "accept all remaining" once
80
+ the user confirms two in a row to keep the loop short.
66
81
 
67
- Never write drafts before the user confirms. Drafted text is a proposal, not a commit.
82
+ Never write drafts before the user confirms. Drafted text is a proposal, not a
83
+ commit. A run that took `--all` or `--folders` confirmed the folder set rather
84
+ than each draft, so surface the drafts as a batch and write them without a
85
+ second ask.
68
86
 
69
87
  ## Scaffold the folder index
70
88
 
@@ -81,9 +99,12 @@ Surface the proposed `title` and `subtitle` and let the user edit before writing
81
99
 
82
100
  ## Inject
83
101
 
84
- After all confirmations, write frontmatter into each sibling and `index.md` into each folder. Use a single batched write per file.
102
+ After all confirmations, write frontmatter into each sibling and `index.md` into
103
+ each folder. Use a single batched write per file.
85
104
 
86
- Preserve existing content below the frontmatter block. If a sibling already has frontmatter without `title` or `description`, merge in the missing fields. Do not touch files the user rejected.
105
+ Preserve existing content below the frontmatter block. If a sibling already has
106
+ frontmatter without `title` or `description`, merge in the missing fields. Do not
107
+ touch files the user rejected.
87
108
 
88
109
  ## Validate
89
110
 
@@ -93,22 +114,28 @@ Run from the project root:
93
114
  canon indexes regen --dry-run --json
94
115
  ```
95
116
 
96
- Parse the JSON. On any `error` action, surface the file and reason and stop. On `would-write` for the bootstrapped folders, the dry-run is healthy. Run for real:
117
+ Parse the JSON. On any `error` action, surface the file and reason and stop. On
118
+ `would-write` for the bootstrapped folders, the dry-run is healthy. Run for real:
97
119
 
98
120
  ```bash
99
121
  canon indexes regen --json
100
122
  ```
101
123
 
102
- Count the `written` actions in that record and report the number. Read the real run the same way the dry run is read, since the exit carries nothing reliable back to a session. An operator's shell profile may wrap `canon` in a function that runs the binary and then a second command and takes the second status, so a regen that errored on a sibling missing `title` arrives here as a clean pass.
124
+ Count the `written` actions in that record and report the number. Read the real
125
+ run the same way the dry run is read, since the exit carries nothing reliable
126
+ back to a session. An operator's shell profile may wrap `canon` in a function
127
+ that runs the binary and then a second command and takes the second status, so a
128
+ regen that errored on a sibling missing `title` arrives here as a clean pass.
103
129
 
104
130
  ## Offer the convention seed
105
131
 
106
- First check whether `CLAUDE.md` exists in the project root. If absent, do not scaffold one. Skip the seed install with this exact message:
132
+ First check whether `CLAUDE.md` exists in the project root. If absent, do not
133
+ scaffold one. Skip the seed install with this exact message:
107
134
 
108
135
  ```plaintext
109
136
  No CLAUDE.md in the project. Skipping convention seed.
110
137
  To add the convention later, run `canon tooling sync` or `canon init`,
111
- then re-invoke this skill.
138
+ then re-invoke this phase.
112
139
  ```
113
140
 
114
141
  If `CLAUDE.md` exists, check it for an existing `## Indexes` section:
@@ -119,7 +146,10 @@ grep -l '^## Indexes' CLAUDE.md 2>/dev/null
119
146
 
120
147
  If the section is present, skip the seed silently.
121
148
 
122
- If `CLAUDE.md` exists but has no `## Indexes` section, offer to install the canonical convention block. The text below is the source of truth and is mirrored in the toolkit's `tooling/claude/seeds/CLAUDE.md`. Paste it verbatim. Do not rewrite, paraphrase, condense, or add punctuation.
149
+ If `CLAUDE.md` exists but has no `## Indexes` section, offer to install the
150
+ canonical convention block. The text below is the source of truth and is
151
+ mirrored in the toolkit's seed `CLAUDE.md`. Paste it verbatim. Do not rewrite,
152
+ paraphrase, condense, or add punctuation.
123
153
 
124
154
  ```markdown
125
155
  - When a folder has an `index.md`, check it before reading individual files in that folder.
@@ -127,11 +157,16 @@ If `CLAUDE.md` exists but has no `## Indexes` section, offer to install the cano
127
157
  - Every `index.md` carries its own frontmatter (`title`, `subtitle`) that the walker preserves. To keep a folder's `index.md` hand-edited, add `auto: false` to its frontmatter.
128
158
  ```
129
159
 
130
- Append a new `## Indexes` section at the end of the file containing the three lines. Do not touch any other section.
160
+ Append a new `## Indexes` section at the end of the file containing the three
161
+ lines. Do not touch any other section.
131
162
 
132
163
  ## Closeout
133
164
 
134
- Always emit this block as the final message of the skill run. Do not skip it regardless of how the seed step concluded (installed, already present, declined, or skipped because no `CLAUDE.md` exists). Output exactly one closeout, even if the seed step paused for user input. Resume the flow after the user responds and emit the closeout next.
165
+ Always emit this block as the final message of the phase. Do not skip it
166
+ regardless of how the seed step concluded (installed, already present, declined,
167
+ or skipped because no `CLAUDE.md` exists). Output exactly one closeout, even if
168
+ the seed step paused for user input. Resume the flow after the user responds and
169
+ emit the closeout next.
135
170
 
136
171
  Format:
137
172
 
@@ -144,14 +179,15 @@ Folders bootstrapped:
144
179
  Drafts: <n> accepted, <n> edited, <n> rejected
145
180
  Convention seed: <installed | already present | declined | skipped (no CLAUDE.md)>
146
181
 
147
- Optional maintenance (opt in, the skill does not configure these):
182
+ Optional maintenance (opt in, the phase does not configure these):
148
183
  - lint-staged entry in .lintstagedrc.json:
149
184
  "**/*.md": "canon indexes regen"
150
185
  - Claude Code PostToolUse hook on Edit and Write matching **/*.md running:
151
186
  canon indexes regen
152
187
  ```
153
188
 
154
- Replace bracketed values with the values from this run. Drop the "Folders bootstrapped" line if zero folders were chosen.
189
+ Replace bracketed values with the values from this run. Drop the "Folders
190
+ bootstrapped" line if zero folders were chosen.
155
191
 
156
192
  ## Reference
157
193
 
@@ -0,0 +1,95 @@
1
+ ---
2
+ title: Verify depths
3
+ description: The two verification depths and the script chain each runs against a freshly scaffolded project
4
+ ---
5
+
6
+ # Verify depths
7
+
8
+ Runs the local verification chain against a freshly scaffolded project. Catches
9
+ config typos, missing deps, and wiring mistakes before the user ever sees them.
10
+
11
+ Two depths over one contract. Both read the `scripts` block from the project's
12
+ own `package.json` and run what is declared there, so neither hardcodes a script
13
+ name and a stack exposing a different set is covered without an edit here.
14
+
15
+ ## Guards
16
+
17
+ - If `package.json` does not exist at the project root, stop: `❌ No package.json found. Cannot verify.`
18
+ - If `node_modules/` does not exist, run `bun install` first, then proceed.
19
+
20
+ ## Step 1: read scripts
21
+
22
+ Read `package.json` from the project root and extract the `scripts` block. Do
23
+ not hardcode script names. Different stacks expose different scripts.
24
+
25
+ ## Step 2: run the chain
26
+
27
+ Run the scripts for the requested depth in order. Stop on the first failure and
28
+ surface the error. Skip any script not present in `package.json`. Do not invent
29
+ a fallback command. Run each as `bun run <script>` from the project root.
30
+
31
+ ### Default depth
32
+
33
+ Every script is a leaf command, so failures point at the exact break and the
34
+ exit code is the whole verdict.
35
+
36
+ | Order | Script | Skip if |
37
+ | ----- | ----------- | --------------------------- |
38
+ | 1 | `lint:fix` | absent |
39
+ | 2 | `typecheck` | absent |
40
+ | 3 | `check` | absent |
41
+ | 4 | `test:run` | absent, fall back to `test` |
42
+ | 5 | `build` | absent |
43
+
44
+ Do not run composite scripts like `check:full`. Do not run `dev`, `preview`,
45
+ `test:e2e`, `test:ui`, or `screenshot` at this depth. They belong to `deep`
46
+ below.
47
+
48
+ ### Deep depth
49
+
50
+ The checks a scaffold's leaf scripts cannot cover: whether the dev and preview
51
+ servers actually start, whether the end-to-end suite passes against a real
52
+ server, and whether the screenshot harness produces output.
53
+
54
+ | Order | Script | Skip if | How judged |
55
+ | ----- | ------------ | ------- | ----------------------- |
56
+ | 1 | `dev` | absent | server smoke, see below |
57
+ | 2 | `preview` | absent | server smoke, see below |
58
+ | 3 | `test:e2e` | absent | leaf script: exit code |
59
+ | 4 | `screenshot` | absent | leaf script: exit code |
60
+
61
+ `deep` runs the four above and not the five leaf scripts, which the default
62
+ depth already covers. The two sets are disjoint, so running both depths runs
63
+ every declared script exactly once.
64
+
65
+ Take `deep` on request rather than by default. A dev server that starts slowly
66
+ reads as a failure here, which is too flaky to fail an unattended scaffold check
67
+ on, and the end-to-end stage needs a browser install the chain does not make.
68
+
69
+ ### Server smoke
70
+
71
+ `dev` and `preview` run until stopped, so there is no exit code to read. Start
72
+ the script backgrounded, wait 5 seconds, then check two things: the process is
73
+ still running, and its captured output carries no string matching `error`,
74
+ `Error`, or `fatal`. Kill the process either way once judged. Report a failure
75
+ on either check failing.
76
+
77
+ This is weaker than a real readiness probe. No manifest key exposes a generic
78
+ port to poll across stacks, so port-probing is out of reach here.
79
+
80
+ ## Step 3: report
81
+
82
+ For each script run, report one of:
83
+
84
+ - `✅ <script>`
85
+ - `❌ <script>` followed by the failing output (last 40 lines) or, for a server script, the reason judged (process died, or a fatal string in its output)
86
+
87
+ End with a summary line naming the depth that ran:
88
+
89
+ - On pass: `✅ Scaffold verified at <depth> (<n> scripts passed).`
90
+ - On fail: `❌ Scaffold failed at <script>. Fix the error and re-run the verify phase.`
91
+
92
+ ## Out of scope
93
+
94
+ - Generating the configs these scripts drive, which the tooling stack reference owns.
95
+ - CI workflow validation. It runs in GitHub Actions on a pull request rather than locally. The `deep` depth runs the same end-to-end and screenshot stages locally, as the closest proxy.
@@ -65,7 +65,7 @@ The record carries every scenario with the arms that declare, plus `totalScenari
65
65
 
66
66
  `--skills` answers what the scenario count cannot, which is whether anything can fail a given skill. It adds `skills`, `totalSkills`, `asserted`, `shouldBeAsserted`, `exempt`, `staleExemptions`, and `supersededExemptions` to the record, and keeps the scenario view rather than replacing it. The two denominators disagree on purpose: an armed scenario under `infra/` or `tooling/` exercises a CLI domain and pairs with no skill at all.
67
67
 
68
- A skill pairs to a scenario by filename, `<category>-<command>` first and bare `<command>` second, so `claude/setup-init.sh` reaches the `setup-init` skill. `should-be-asserted` is the default rather than a queue to drain, and which of those skills earns an arm is a project decision the census does not make.
68
+ A skill pairs to a scenario by filename, `<category>-<command>` first and bare `<command>` second, so `claude/target-setup.sh` reaches the `target-setup` skill. `should-be-asserted` is the default rather than a queue to drain, and which of those skills earns an arm is a project decision the census does not make.
69
69
 
70
70
  `exempt` means no arm should be written and holds only with a reason, declared in `scripts/sandbox/exempt.toml` and limited to a harness limit the checker cannot reach past or a skill that writes no artifact. An armed arm outranks an exemption. An exemption naming no shipped skill, or naming one an arm now asserts, exits 1 without `--strict`. Each armed arm reports as `<category>:<command>/<arm>`, so two same-named arms under different scenarios stay distinct.
71
71
 
@@ -145,5 +145,6 @@ overwrites every golden config a stack ships, which reaches the CI workflow, the
145
145
  git hooks, the end-to-end harness, and the shell scripts under `scripts/`, so a
146
146
  headless run carrying neither `--check` nor `--write` reports what it would
147
147
  replace and exits 1 rather than applying it. Run `--check` first to read the
148
- list, then `--write` to apply it. `canon tooling sync --help` names both, and the
149
- full per-stack path list sits in the `canon-cli` skill.
148
+ list, then `--write` to apply it. `canon tooling sync --help` names both, and
149
+ `canon tooling diff <stack> <target>` reports the per-stack path list resolved
150
+ against a real target.
@@ -325,22 +325,24 @@ canon tasks validate
325
325
  canon tasks validate --json
326
326
  ```
327
327
 
328
- Seven checks run. Plan and Collisions reach one half each of the `## Run now` test the board standard states. Mapping and Grouping test the folder contract and hold for every group, and Shape holds for every group too, ahead of the four. Ordering reaches only the `## Needs a plan` rows, and Blockers reaches every row outside `## Run now`:
329
-
330
- | Check | What it reports |
331
- | ---------- | ----------------------------------------------------------------------------------------------------------------------- |
332
- | Shape | A row whose cell count disagrees with its table's header, or one stranded behind a table a blank line already closed |
333
- | Plan | A `## Run now` row whose Plan column carries no link, resolves to no file, or disagrees with the task's own line |
334
- | Mapping | A row or backlog line naming no task file |
335
- | Grouping | A task carrying a row in more than one readiness group, or on both surfaces |
336
- | Ordering | A `## Needs a plan` row whose stated position disagrees with where it actually sits, or which states no position at all |
337
- | Collisions | Two `## Run now` rows whose Touches columns name a path in common |
338
- | Blockers | A parked row whose blocker has stopped holding, whose cited task resolves nowhere, or whose cited task was declined |
328
+ Seven checks run. Collisions reaches one half of the `## Run now` test the board standard states, and Plan reaches every group, reading the Plan column under `## Run now` and the task file's own line under the other two. Mapping and Grouping test the folder contract and hold for every group, and Shape holds for every group too, ahead of the four. Ordering reaches only the `## Needs a plan` rows, and Blockers reaches every row outside `## Run now`:
329
+
330
+ | Check | What it reports |
331
+ | ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
332
+ | Shape | A row whose cell count disagrees with its table's header, or one stranded behind a table a blank line already closed |
333
+ | Plan | A `## Run now` row whose Plan column carries no link, resolves to no file, or disagrees with the task's own line, a `## Needs a plan` row whose task cites a live plan, or an `## Up next` row whose task cites none |
334
+ | Mapping | A row or backlog line naming no task file |
335
+ | Grouping | A task carrying a row in more than one readiness group, or on both surfaces |
336
+ | Ordering | A `## Needs a plan` row whose stated position disagrees with where it actually sits, or which states no position at all |
337
+ | Collisions | Two `## Run now` rows whose Touches columns name a path in common |
338
+ | Blockers | A parked row whose blocker has stopped holding, whose cited task resolves nowhere, or whose cited task was declined |
339
339
 
340
340
  Shape runs before any other check reads a row, since a row failing it carries no dependable fields for the rest to check. A blank or prose line closes the table above it, so the walk treats the next pipe line as a fresh header candidate rather than as a continuation. That candidate counts as a header only when the line behind it is a separator carrying the same cell count, and one that fails is `row-untabled`, stranded behind a table that already closed. Cell count still has to match the header on every row that clears that test, and a row whose count disagrees is `row-misshapen`, the shape a dropped pipe or a merged column produces.
341
341
 
342
342
  The Plan check reads the row and the task file both, because the two are written by different hands and only the task's own `Plan:` line reaches the archive. A row carrying a plan whose task states none is `plan-uncited`, and a pair naming two different plans is `plan-mismatched`. Both sides resolve against the board and against the project root before they compare, so a row writing `../plans/x.md` and a task writing `.canon/plans/x.md` name one file rather than two.
343
343
 
344
+ The other two groups have no Plan column, so the same check reads the task file's own `Plan:` line against what the group name claims. A `## Needs a plan` row whose task cites a plan that sits live on disk is `plan-parked`, since the group says no such plan exists and the row is either misplaced or its plan is stale and belongs in the archive. An `## Up next` row whose task cites no live plan is `plan-absent`, since that group says one is written. A plan already archived, or a cited path with no file behind it, reads as not live on both sides. A row whose task file is gone is left to `task-unresolved`. An `## Up next` row with nothing left to build, waiting on an act only a person can take, reports `plan-absent` once its plan archives while the task stays live. That report is expected, since the check reads the task file and not the `Waiting on` prose, so a row in that state moves to `## Needs a plan` or closes.
345
+
344
346
  Mapping spans two surfaces, because a task sits on `priority.md` when it would plausibly be planned soon and on `backlog.md` otherwise. A row or a backlog line naming no task file is `task-unresolved`, and a file both surfaces name is `row-duplicated` for the reason a task in two groups is: it claims two things about itself and only one can hold. A task file neither surface names is `unplaced` rather than a finding, since that is the normal state between a session filing it and a live orchestrator placing it on the board. One check across both is what lets a task move between them without the move reading as a dropped file.
345
347
 
346
348
  A backlog line is a bullet carrying a link to a sibling task, since the backlog is a flat unordered list rather than a table. A bullet holding prose is skipped rather than reported, which keeps the file's own intro out of the findings, and the task that bullet meant to name still lands in the `unplaced` array below rather than the findings. A project carrying no `backlog.md` reads as an empty backlog rather than a refusal, which leaves the one-to-one mapping this check ran before the second surface existed.
@@ -51,19 +51,19 @@ claude --plugin-dir <toolkit>/claude
51
51
  Two steps, in order:
52
52
 
53
53
  1. Run the framework's own scaffold if the project needs one, such as `bun init`, `npm create vite`, or `npm create astro`. The toolkit does not wrap framework scaffolding.
54
- 2. Invoke `canon:setup-init` in Claude Code. The skill detects the stack, resolves flags, previews the full chain, and runs it end-to-end.
54
+ 2. Invoke `canon:target-setup` in Claude Code. The skill detects the stack, resolves flags, previews the full chain, and runs it end-to-end.
55
55
 
56
56
  The chain is:
57
57
 
58
58
  - `canon init` installs base tooling, Claude seeds, and governance rules into `.claude/rules/` in the same pass
59
59
  - `canon tooling sync <stack> --write` adds stack-specific deps, scripts, and gitignore entries
60
60
  - The agent reads `canon tooling reference <stack>` (plus parents) as its audit context, follows it to generate eslint, vitest, playwright configs and the stack's setup script, and extends `canon/context/ci.md` and `canon/context/development.md` per the reference's extend sections <!-- audit-ignore-citations: canon/context/development.md -->
61
- - `setup-verify` runs the installed `package.json` scripts (lint, typecheck, check, test, build) and reports pass or fail
62
- - `setup-indexes` bootstraps the `index.md` system over the project's own documentation folders, confirming candidate folders with the operator rather than running unattended
61
+ - The `verify` phase runs the installed `package.json` scripts (lint, typecheck, check, test, build) and reports pass or fail
62
+ - The `indexes` phase bootstraps the `index.md` system over the project's own documentation folders, confirming candidate folders with the operator rather than running unattended
63
63
 
64
- The chain stops at the project edge. `repo-metadata` and `git-commit` also ship, reaching a remote and the project's history respectively, and neither runs as part of it. The chain serves a fresh scaffold and names a destination for the three states it does not. An existing project goes to `canon:canon-operator`, which reads what the project already carries before naming a per-domain command. An install wanting the Claude layer without the tooling chain runs `canon claude init` for the seed docs and then `canon:setup-indexes` for the index system. A language the toolkit ships no stack for is the one of the three the chain still runs for, on `base`, with the fallback marked in the preview so it can be declined there.
64
+ The chain stops at the project edge. `repo-metadata` and `git-commit` also ship, reaching a remote and the project's history respectively, and neither runs as part of it. The chain serves a fresh scaffold and names a destination for the three states it does not. An existing project goes to `canon:canon-operator`, which reads what the project already carries before naming a per-domain command. An install wanting the Claude layer without the tooling chain runs `canon claude init` for the seed docs and then `canon:target-setup indexes` for the index system. A language the toolkit ships no stack for is the one of the three the chain still runs for, on `base`, with the fallback marked in the preview so it can be declined there.
65
65
 
66
- Run `canon:setup-smoke` by hand once `setup-verify` passes, for the heavier server smoke, end-to-end, and screenshot pass, since the same flakiness reasons that excluded those stages from `setup-verify` keep it out of this unattended chain too.
66
+ Run `canon:target-setup verify deep` by hand once the default depth passes, for the heavier server smoke, end-to-end, and screenshot pass, since the same flakiness reasons that keep those stages out of the default depth keep them out of this unattended chain too.
67
67
 
68
68
  Keep the `## Scripts` table in `canon/context/development.md` current as scripts are added. Base tooling seeds that entry with the commands it installs, and each stack reference extends the table. `project-commands` reads it to start the app or run a check on request, so a command missing from the table cannot be run that way. A project whose entry outgrew one file and split into `canon/context/development/` keeps the table in `overview.md`, which is where the skill looks next. <!-- audit-ignore-citations: canon/context/development.md -->
69
69
 
@@ -86,13 +86,13 @@ Each diagram entry records the commit and date it was last verified against, and
86
86
 
87
87
  The default path is `base`. `canon init` on `base` installs base tooling configs, Claude seeds, and governance core rules, and scaffolds an empty `.claude/wiki/`. Most projects need nothing more.
88
88
 
89
- Escalate only for real web apps. The `setup-init` skill reads `package.json` and root configs, then picks the matching tooling stack (`canon tooling list --json` names the current set) and the matching governance stack (`react`, `astro`, `node`).
89
+ Escalate only for real web apps. The `target-setup` skill reads `package.json` and root configs, then picks the matching tooling stack (`canon tooling list --json` names the current set) and the matching governance stack (`react`, `astro`, `node`).
90
90
 
91
91
  `node-server` is named rather than detected. It carries the server-side security and persistence rules for a project writing request handlers or a persistence layer in TypeScript, and the detect step matches a runtime or a framework against stack names, so nothing there marks a project as a backend. Pass it deliberately with `canon init --stack node-server` or `canon gov install node-server <target>`.
92
92
 
93
93
  Markdown-heavy projects, CLI tools, docs sites, research notebooks, and scripting repos stay on `base`. Escalation is a ceiling move, not a default.
94
94
 
95
- A project the toolkit ships no stack for lands on `base` the same way, and the skill marks that resolution as a fallback in its preview rather than reporting it as a match. Configs, seeds, and gitignore entries land either way, and the JavaScript development dependencies, scripts, and hook activation land only where a `package.json` exists to carry them. A project outside that ecosystem declines at the preview and takes `canon:setup-gov` for the governance layer alone, which is language-neutral.
95
+ A project the toolkit ships no stack for lands on `base` the same way, and the skill marks that resolution as a fallback in its preview rather than reporting it as a match. Configs, seeds, and gitignore entries land either way, and the JavaScript development dependencies, scripts, and hook activation land only where a `package.json` exists to carry them. A project outside that ecosystem declines at the preview and takes `canon:target-setup gov` for the governance layer alone, which is language-neutral.
96
96
 
97
97
  Run `canon tooling list --json` and `canon gov list --json` to see the current catalogs. Never hardcode stack names.
98
98
 
@@ -115,9 +115,9 @@ The plugin corpus carries runtime behavior rather than reference prose alone, be
115
115
 
116
116
  When a new need appears after scaffold, install the one domain without re-running `canon init`.
117
117
 
118
- - Governance rule for a newly adopted library: invoke `canon:setup-gov`, or run `canon gov install <stack> --add <rule> <path>`
118
+ - Governance rule for a newly adopted library: invoke `canon:target-setup gov`, or run `canon gov install <stack> --add <rule> <path>`
119
119
  - Project-specific rule the toolkit does not ship: invoke `canon:create-rule`. It scaffolds a rule into `.claude/rules/` with a non-colliding number, and `canon gov sync` leaves it untouched.
120
- - Index.md system for a markdown-heavy folder that emerged: invoke `canon:setup-indexes`
120
+ - Index.md system for a markdown-heavy folder that emerged: invoke `canon:target-setup indexes`
121
121
 
122
122
  Standards and snippets are not on that list, and there is nothing to add for either. Neither installs into a project, by default or by flag, so a session reads a standard with `canon standards <name>` and a snippet through its `@` reference off the live plugin symlink, both resolving against the toolkit rather than a project copy. A project holding a `.claude/standards/` or `.claude/snippets/` folder from an older toolkit is carrying a stale artifact nothing reads, and deleting it is safe.
123
123
 
@@ -300,7 +300,7 @@ cd <your-project>
300
300
  claude
301
301
  ```
302
302
 
303
- In the session, invoke `canon:setup-init`. The skill detects no framework and resolves tooling to `base` and governance to `base`. The preview marks both stacks as fallbacks, since neither came from a match, then the chain runs `canon init`.
303
+ In the session, invoke `canon:target-setup`. The skill detects no framework and resolves tooling to `base` and governance to `base`. The preview marks both stacks as fallbacks, since neither came from a match, then the chain runs `canon init`.
304
304
 
305
305
  Ongoing: run `canon sync --check .` to see what has drifted, then invoke `canon:seed-sync` for seed drift or `canon sync .` for a catch-all refresh.
306
306
 
@@ -311,7 +311,7 @@ bun create vite my-app && cd my-app
311
311
  claude
312
312
  ```
313
313
 
314
- Invoke `canon:setup-init`. The skill reads `package.json` and the Vite config, resolves tooling to `vite-react` and governance to `react`, and runs `canon init` with the resolved flags.
314
+ Invoke `canon:target-setup`. The skill reads `package.json` and the Vite config, resolves tooling to `vite-react` and governance to `react`, and runs `canon init` with the resolved flags.
315
315
 
316
316
  Ongoing maintenance:
317
317
 
@@ -200,19 +200,14 @@ This section is the corpus the coverage claim is measured against: every name `c
200
200
 
201
201
  ### Set up a project
202
202
 
203
- | Skill | When to use |
204
- | ---------------------- | --------------------------------------------------------------------------------------------------------------- |
205
- | `canon:setup-init` | On a fresh scaffold, to detect the stack and run the whole install chain in one pass |
206
- | `canon:canon-operator` | On a project that already exists, to read what it carries before an install is picked |
207
- | `canon:setup-gov` | When the governance rules are wanted without the tooling chain |
208
- | `canon:setup-indexes` | When a markdown-heavy folder needs an `index.md` a session can browse |
209
- | `canon:setup-plugins` | On a new machine, to install the community and official plugins user-scoped |
210
- | `canon:setup-verify` | After the agent generates configs, to run the installed scripts and report pass or fail |
211
- | `canon:setup-smoke` | After `setup-verify` passes, to check the dev and preview servers, end-to-end tests, and the screenshot harness |
212
- | `canon:sketch-design` | Before `design-extract`'s greenfield path, to trace a design direction from reference images or URLs |
213
- | `canon:design-extract` | Before the first UI feature, to draft `canon/DESIGN.md` |
214
- | `canon:draft-diagram` | Once the architecture is written, to draft per-kind entries under `.canon/diagrams/` |
215
- | `canon:repo-metadata` | When the GitHub About text, homepage, or topics may have drifted, to reconcile them against the README |
203
+ | Skill | When to use |
204
+ | ---------------------- | ------------------------------------------------------------------------------------------------------ |
205
+ | `canon:target-setup` | On a fresh scaffold, to detect the stack and run the install chain, or to reach one phase of it alone |
206
+ | `canon:canon-operator` | On a project that already exists, to read what it carries before an install is picked |
207
+ | `canon:sketch-design` | Before `design-extract`'s greenfield path, to trace a design direction from reference images or URLs |
208
+ | `canon:design-extract` | Before the first UI feature, to draft `canon/DESIGN.md` |
209
+ | `canon:draft-diagram` | Once the architecture is written, to draft per-kind entries under `.canon/diagrams/` |
210
+ | `canon:repo-metadata` | When the GitHub About text, homepage, or topics may have drifted, to reconcile them against the README |
216
211
 
217
212
  ### Decide what to build
218
213
 
@@ -9,11 +9,6 @@ paths:
9
9
 
10
10
  # UI copy standards
11
11
 
12
- ## Casing
13
-
14
- - Use sentence case for all rendered UI text: headings, labels, nav items, tab titles, and dialog titles.
15
- - Retain original casing for proper nouns and product names: `GitHub`, `macOS`, `TypeScript`.
16
-
17
12
  ## Punctuation
18
13
 
19
14
  - Do not use em dashes (`—`). Use a comma or period, or restructure the sentence.
@@ -55,3 +55,8 @@ paths:
55
55
  - Alt text for functional images (icons, buttons) should describe the action, not the graphic.
56
56
  - Give the visual boundary of a control and every graphic that carries meaning at least 3:1 contrast against adjacent colors (WCAG Non-text Contrast, 1.4.11).
57
57
  - Never make color the only carrier of a state, error, or distinction. Pair it with text, an icon, or a pattern (WCAG Use of Color, 1.4.1).
58
+
59
+ ## Reflow
60
+
61
+ - Let content reflow at a viewport 320 CSS pixels wide with no loss of content or function and no two-dimensional scrolling. Only content whose meaning depends on both axes, such as a data table, a map, or a diagram, may scroll sideways (WCAG Reflow, 1.4.10, Level AA).
62
+ - Treat 320 as the criterion's own test condition rather than a device width. It is equivalent to a 1280 pixel window at 400 percent zoom, so a layout that breaks there breaks for a person who zooms.
@@ -25,7 +25,13 @@ paths:
25
25
 
26
26
  ## What a capture covers
27
27
 
28
- - Capture the full page at the viewport its case declares. Do not capture a component in isolation.
28
+ - Capture the full page. Do not capture a component in isolation.
29
+ - Declare the widths a layout case captures. Always include 320, the reflow floor from the reflow criterion in `410-a11y`, then add each breakpoint bucket the project writes rules for, read from the `## Layout` section of `DESIGN.md`.
30
+ - Fall back to the 320 floor alone when the project has no `DESIGN.md` or its record carries no `## Layout` section. Do not impose another project's breakpoints.
31
+ - Apply the declaration to a case that covers layout only. A case driving a menu open or an answer chosen tests a state, so it takes one width rather than the full set.
32
+ - Read a capture at 320 as proof that a frame was taken there, not that the page reflows correctly. The criterion is stated in `410-a11y` and nothing here enforces it.
33
+ - Write the capture into a folder named `evidence`. The image is collected for the pull request comment when any segment of its path is literally `evidence` and its filename carries an image extension, so the folder name is fixed and its position in the tree is the project's own.
34
+ - Several `evidence/` folders in one project is the ordinary shape rather than a problem to consolidate. One per surface is how a project with more than one rendered surface ends up.
29
35
  - Drive a state a screenshot cannot reach. An initial render reports nothing about a menu that opens, an answer that is chosen, or a rail that tracks scrolling.
30
36
  - Add a case to the capture record when adding a surface.
31
37
  - Remove a surface's case in the change that removes the surface.
@@ -25,5 +25,5 @@ paths:
25
25
 
26
26
  - Accessibility, keyboard interaction and ARIA are a separate topic. `410-a11y` routes them, on every rendered path.
27
27
  - States, empty and loading coverage, and destructive confirmation are a separate topic. `430-ux-completeness` routes them.
28
- - Rendered copy casing, button labels and error wording are a separate topic. `400-ui` routes them.
28
+ - Rendered copy casing is a separate topic. `465-interface-casing` routes it. Button labels and error wording are separate too, and `400-ui` routes them.
29
29
  - The floor those three carry is not restated in the skill, and it is not traded against a preference where the two collide.
@@ -0,0 +1,31 @@
1
+ ---
2
+ description: Enforce casing for interface text in markup, MDX, and content modules, where copy lives in a content folder
3
+ paths:
4
+ - '**/*.tsx'
5
+ - '**/*.jsx'
6
+ - '**/*.astro'
7
+ - '**/*.html'
8
+ - '**/*.mdx'
9
+ - '**/content/**/*.ts'
10
+ ---
11
+
12
+ # Interface casing standards
13
+
14
+ ## Sentence case
15
+
16
+ - Use sentence case for all rendered interface text: headings, labels, nav items, tab titles, and dialog titles.
17
+ - Retain original casing for proper nouns and product names: `GitHub`, `macOS`, `TypeScript`.
18
+ - Treat title case on every heading as a template tell, since it reads as a default rather than a choice.
19
+
20
+ ## Uppercase labels
21
+
22
+ - Keep small uppercase labels above headings to one per three sections, with the first screen counting as one. More than `ceil(sections / 3)` is too many, and the fix is usually to delete the label, since a section's position already says what it is.
23
+ - Treat the count as a judgment, since a glob cannot check it.
24
+
25
+ ## Where it applies
26
+
27
+ - The rule covers markup, MDX, and content modules under a `content/` folder. Copy kept elsewhere, such as a locale file, is not reached, so apply the same casing there without the rule firing.
28
+
29
+ ## Overriding
30
+
31
+ - Depart from sentence case where the case needs it, such as an acronym, a brand mark, or a set-in-caps identity the design chose on purpose.
@@ -1,2 +1,2 @@
1
1
  extends = "node"
2
- rules = ["210-astro", "300-testing-ts", "305-e2e-reliability", "306-test-scope", "350-security-web", "400-ui", "410-a11y", "420-forms", "430-ux-completeness", "440-surface-capture", "450-link-behavior", "460-design-taste", "470-motion"]
2
+ rules = ["210-astro", "300-testing-ts", "305-e2e-reliability", "306-test-scope", "350-security-web", "400-ui", "410-a11y", "420-forms", "430-ux-completeness", "440-surface-capture", "450-link-behavior", "460-design-taste", "465-interface-casing","470-motion"]
@@ -1,2 +1,2 @@
1
1
  extends = "node"
2
- rules = ["200-react", "230-nextjs", "250-tailwind", "300-testing-ts", "305-e2e-reliability", "306-test-scope", "310-zod", "350-security-web", "400-ui", "410-a11y", "420-forms", "430-ux-completeness", "440-surface-capture", "450-link-behavior", "460-design-taste", "470-motion"]
2
+ rules = ["200-react", "230-nextjs", "250-tailwind", "300-testing-ts", "305-e2e-reliability", "306-test-scope", "310-zod", "350-security-web", "400-ui", "410-a11y", "420-forms", "430-ux-completeness", "440-surface-capture", "450-link-behavior", "460-design-taste", "465-interface-casing","470-motion"]
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@erclx/canon",
3
3
  "type": "module",
4
- "version": "4.103.0",
4
+ "version": "4.105.0",
5
5
  "description": "Infrastructure and quality tooling for developer workflows",
6
6
  "license": "MIT",
7
7
  "bin": {
@@ -197,7 +197,7 @@ const FEATURED_SKILLS = [
197
197
  "review-pr",
198
198
  "task-board",
199
199
  "git-ship",
200
- "setup-init",
200
+ "target-setup",
201
201
  "systematic-debugging",
202
202
  ]
203
203
 
@@ -1,39 +1,40 @@
1
1
  import type { SkillCase } from '@/claude/skills-rank'
2
2
 
3
3
  /**
4
- * `setup-*`, `migration-*`, `canon-*`, and `create-rule`: scaffolding,
4
+ * `target-setup`, `migration-*`, `canon-*`, and `create-rule`: scaffolding,
5
5
  * proposal-only migrations, and the toolkit's own reference and feedback
6
6
  * surfaces.
7
+ *
8
+ * The five `target-setup` cases are one skill read through five entry phrasings
9
+ * rather than five rows that collapsed to a duplicate. Each names a different
10
+ * phase, and the merged description has to carry every one of them, which is
11
+ * the discrimination the six-skill family failed at from the other direction.
7
12
  */
8
13
  export const SETUP_CASES: readonly SkillCase[] = [
9
14
  {
10
15
  prompt:
11
16
  'This project has no rules installed yet, get the right governance in place.',
12
- expect: 'setup-gov',
17
+ expect: 'target-setup',
13
18
  },
14
19
  {
15
20
  prompt:
16
21
  "Get the index.md system bootstrapped across this project's folders.",
17
- expect: 'setup-indexes',
22
+ expect: 'target-setup',
18
23
  },
19
24
  {
20
25
  prompt:
21
26
  'This is a brand-new project, get the toolkit bootstrapped in one shot.',
22
- expect: 'setup-init',
23
- },
24
- {
25
- prompt: 'Get the usual Claude Code plugins provisioned on this machine.',
26
- expect: 'setup-plugins',
27
+ expect: 'target-setup',
27
28
  },
28
29
  {
29
30
  prompt:
30
31
  "Run through the generated scaffold's scripts and confirm each one passes.",
31
- expect: 'setup-verify',
32
+ expect: 'target-setup',
32
33
  },
33
34
  {
34
35
  prompt:
35
36
  'Check that the dev server actually starts and the end-to-end suite passes against the scaffold.',
36
- expect: 'setup-smoke',
37
+ expect: 'target-setup',
37
38
  },
38
39
  {
39
40
  prompt:
@@ -76,7 +77,7 @@ export const SETUP_CASES: readonly SkillCase[] = [
76
77
  {
77
78
  prompt:
78
79
  "Whatever the right toolkit command is, get this project's rules installed.",
79
- expect: 'setup-gov',
80
+ expect: 'target-setup',
80
81
  },
81
82
  {
82
83
  prompt: