@erclx/canon 4.103.0 → 4.104.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 (52) 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/target-projects.md +11 -11
  24. package/docs/workflow/ai-workflow.md +8 -13
  25. package/governance/rules/ui/400-ui.md +0 -5
  26. package/governance/rules/ui/460-design-taste.md +1 -1
  27. package/governance/rules/ui/465-interface-casing.md +31 -0
  28. package/governance/stacks/astro.toml +1 -1
  29. package/governance/stacks/react.toml +1 -1
  30. package/package.json +1 -1
  31. package/scripts/core/regen-hero.sh +1 -1
  32. package/src/claude/cases/setup.ts +12 -11
  33. package/src/commands/sync.ts +1 -1
  34. package/src/gate/measures.ts +57 -0
  35. package/src/gate/stages.ts +10 -14
  36. package/src/gov/list.ts +1 -1
  37. package/src/sandbox/census.ts +3 -3
  38. package/src/shipped/references.ts +1 -1
  39. package/standards/index.md +0 -1
  40. package/claude/skills/setup-gov/REQUIREMENT.md +0 -37
  41. package/claude/skills/setup-gov/SKILL.md +0 -77
  42. package/claude/skills/setup-indexes/REQUIREMENT.md +0 -48
  43. package/claude/skills/setup-init/REQUIREMENT.md +0 -46
  44. package/claude/skills/setup-init/SKILL.md +0 -133
  45. package/claude/skills/setup-plugins/REQUIREMENT.md +0 -42
  46. package/claude/skills/setup-plugins/SKILL.md +0 -81
  47. package/claude/skills/setup-plugins/references/plugin-catalog.md +0 -53
  48. package/claude/skills/setup-smoke/REQUIREMENT.md +0 -38
  49. package/claude/skills/setup-smoke/SKILL.md +0 -53
  50. package/claude/skills/setup-verify/REQUIREMENT.md +0 -39
  51. package/claude/skills/setup-verify/SKILL.md +0 -51
  52. 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.
@@ -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.
@@ -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.104.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:
@@ -109,7 +109,7 @@ function renderCheck(report: CheckReport): void {
109
109
  logStep('Not a toolkit project')
110
110
  logWarn('No .claude/ directory and no CLAUDE.md at the target.')
111
111
  logInfo(
112
- 'Run `canon init` to install, or /canon:setup-init to resolve a stack.',
112
+ 'Run `canon init` to install, or /canon:target-setup to resolve a stack.',
113
113
  )
114
114
  outro()
115
115
  return
@@ -629,6 +629,63 @@ export const shippedReferences: Measure = async (ctx) => {
629
629
  }
630
630
  }
631
631
 
632
+ const RAW_FIELD_FILE_REFERENCE = /(?:^|\s)(?:-f|--raw-field)[ =]\S+=@/
633
+
634
+ /**
635
+ * A `gh api` raw-string flag carrying a file reference, over the seven shipped
636
+ * corpora.
637
+ *
638
+ * `-f body=@<path>` sends the literal path as the field value, so a comment
639
+ * edited that way is overwritten with the path itself and loses the marker a
640
+ * later read resolves it by. `-F` is the flag that reads the file. The pattern
641
+ * requires `=@`, so `-F`, `--field`, and a raw string such as `-f body="text"`
642
+ * all pass.
643
+ *
644
+ * It scans prose rather than parsing a command, so a body quoting the wrong
645
+ * spelling to explain it fails too. Reword it rather than exempting it, since an
646
+ * exemption is what lets a real occurrence hide.
647
+ */
648
+ export const rawFieldFileReference: Measure = async (ctx) => {
649
+ const files = shippedCorpusFiles(ctx.root)
650
+
651
+ if (files.length === 0) {
652
+ return {
653
+ emissions: [],
654
+ unmeasured: `No corpus under ${SHIPPED_CORPORA.join(', ')} is present, so no shipped file was read.`,
655
+ }
656
+ }
657
+
658
+ const found = files.flatMap((file) =>
659
+ readFileSync(join(ctx.root, file), 'utf8')
660
+ .split('\n')
661
+ .flatMap((text, index) =>
662
+ RAW_FIELD_FILE_REFERENCE.test(text) ? [`${file}:${index + 1}`] : [],
663
+ ),
664
+ )
665
+
666
+ if (found.length === 0) {
667
+ return {
668
+ emissions: [
669
+ info(
670
+ `No raw-field file reference across ${files.length} files in ${SHIPPED_CORPORA.length} shipped corpora`,
671
+ ),
672
+ ],
673
+ }
674
+ }
675
+
676
+ return {
677
+ emissions: found.map((location) =>
678
+ warn(
679
+ `${location} passes a file reference through a raw-string flag, which posts the path as the field value. Use -F instead`,
680
+ ),
681
+ ),
682
+ failure:
683
+ found.length === 1
684
+ ? 'One raw-field file reference in the shipped corpora. Change -f or --raw-field to -F or --field where the value reads a file with @, or reword a prose line quoting the wrong spelling.'
685
+ : `${found.length} raw-field file references in the shipped corpora. Change -f or --raw-field to -F or --field where the value reads a file with @, or reword a prose line quoting the wrong spelling.`,
686
+ }
687
+ }
688
+
632
689
  /**
633
690
  * Every git-tracked file quoting a listed client command with the wrong
634
691
  * argument, over the whole tree rather than one corpus, since a wrong