@erclx/canon 4.119.0 → 4.121.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 (112) hide show
  1. package/README.md +2 -2
  2. package/claude/.claude-plugin/plugin.json +1 -1
  3. package/claude/skills/auto-ship/SKILL.md +29 -115
  4. package/claude/skills/auto-ship/references/draft-mark.md +30 -0
  5. package/claude/skills/auto-ship/references/failure-recovery.md +27 -0
  6. package/claude/skills/auto-ship/references/tier-failures.md +26 -0
  7. package/claude/skills/auto-ship/references/verb-absent.md +37 -0
  8. package/claude/skills/auto-ship/references/worktree-name.md +22 -0
  9. package/claude/skills/bash-script/SKILL.md +1 -1
  10. package/claude/skills/bash-script/references/patterns.md +0 -99
  11. package/claude/skills/bash-script/references/prompts.md +100 -0
  12. package/claude/skills/create-skill/SKILL.md +3 -2
  13. package/claude/skills/create-snippet/SKILL.md +1 -1
  14. package/claude/skills/create-standard/SKILL.md +1 -1
  15. package/claude/skills/design-extract/SKILL.md +1 -1
  16. package/claude/skills/design-taste/REQUIREMENT.md +2 -2
  17. package/claude/skills/docs-sync/SKILL.md +1 -1
  18. package/claude/skills/draft-context/SKILL.md +1 -1
  19. package/claude/skills/draft-docs/SKILL.md +1 -1
  20. package/claude/skills/draft-figure/SKILL.md +1 -1
  21. package/claude/skills/draft-readme/SKILL.md +1 -1
  22. package/claude/skills/draft-wiki/SKILL.md +1 -1
  23. package/claude/skills/draft-wireframes/SKILL.md +1 -1
  24. package/claude/skills/git-issue/SKILL.md +1 -1
  25. package/claude/skills/git-issue/references/issue.md +1 -1
  26. package/claude/skills/git-pr/REQUIREMENT.md +1 -0
  27. package/claude/skills/git-pr/SKILL.md +35 -5
  28. package/claude/skills/git-stage/SKILL.md +1 -1
  29. package/claude/skills/memory-capture/SKILL.md +1 -1
  30. package/claude/skills/restate-plainly/REQUIREMENT.md +1 -1
  31. package/claude/skills/review-address/SKILL.md +4 -3
  32. package/claude/skills/review-branch/REQUIREMENT.md +1 -0
  33. package/claude/skills/review-branch/SKILL.md +5 -6
  34. package/claude/skills/review-craft/REQUIREMENT.md +43 -0
  35. package/claude/skills/review-craft/SKILL.md +50 -0
  36. package/claude/skills/review-craft/references/security.md +21 -0
  37. package/claude/skills/review-craft/references/ui.md +72 -0
  38. package/claude/skills/review-pr/REQUIREMENT.md +1 -0
  39. package/claude/skills/review-pr/SKILL.md +14 -243
  40. package/claude/skills/review-pr/references/close-out.md +30 -0
  41. package/claude/skills/review-pr/references/post.md +145 -0
  42. package/claude/skills/review-pr/references/scope.md +82 -0
  43. package/claude/skills/role-orchestrator/REQUIREMENT.md +9 -16
  44. package/claude/skills/role-orchestrator/SKILL.md +9 -153
  45. package/claude/skills/role-orchestrator/references/orchestrator-dispatch.md +4 -193
  46. package/claude/skills/role-orchestrator/references/orchestrator-handback.md +22 -0
  47. package/claude/skills/role-orchestrator/references/orchestrator-launch.md +85 -0
  48. package/claude/skills/role-orchestrator/references/orchestrator-output.md +61 -0
  49. package/claude/skills/role-orchestrator/references/orchestrator-parked.md +2 -2
  50. package/claude/skills/role-orchestrator/references/orchestrator-poll.md +1 -1
  51. package/claude/skills/role-orchestrator/references/orchestrator-refill.md +56 -0
  52. package/claude/skills/role-orchestrator/references/orchestrator-review-fallback.md +18 -0
  53. package/claude/skills/role-orchestrator/references/orchestrator-sweep.md +1 -1
  54. package/claude/skills/role-planner/REQUIREMENT.md +2 -2
  55. package/claude/skills/standards-audit/SKILL.md +1 -1
  56. package/claude/skills/write-human/REQUIREMENT.md +7 -4
  57. package/claude/skills/write-human/SKILL.md +4 -2
  58. package/claude/skills/write-human/references/machine-tells.md +1 -1
  59. package/claude/skills/write-human/references/source-material.md +5 -2
  60. package/docs/agents/audits.md +1 -1
  61. package/docs/agents/commands.md +3 -2
  62. package/docs/agents/counts.md +1 -1
  63. package/docs/agents/index.md +8 -3
  64. package/docs/agents/markdown-audit.md +13 -19
  65. package/docs/agents/pr-evidence.md +19 -3
  66. package/docs/agents/pr-local.md +105 -0
  67. package/docs/agents/pr-preview.md +2 -2
  68. package/docs/agents/records-push.md +61 -0
  69. package/docs/agents/records-validate.md +73 -0
  70. package/docs/agents/records.md +3 -119
  71. package/docs/agents/sessions-transfer.md +91 -0
  72. package/docs/agents/sessions.md +3 -82
  73. package/docs/agents/skills-audit.md +2 -2
  74. package/docs/agents/teach-authoring.md +112 -0
  75. package/docs/agents/teach.md +3 -103
  76. package/docs/target-projects.md +2 -2
  77. package/docs/workflow/ai-workflow.md +2 -1
  78. package/docs/workflow/visual-design-workflow.md +1 -1
  79. package/governance/rules/claude/500-prose.md +1 -1
  80. package/governance/rules/claude/501-markdown.md +3 -3
  81. package/governance/rules/claude/570-skill.md +2 -1
  82. package/package.json +1 -1
  83. package/scripts/core/check-ignore-parity.sh +1 -1
  84. package/scripts/lib/sandbox-git.sh +1 -1
  85. package/src/autoship/paths.ts +3 -2
  86. package/src/claude/cases/workflow.ts +5 -0
  87. package/src/commands/audits.ts +2 -2
  88. package/src/commands/markdown.ts +7 -9
  89. package/src/commands/pr.ts +331 -2
  90. package/src/context/classify/extract.ts +2 -2
  91. package/src/counts/scan.ts +1 -1
  92. package/src/design/tokens.ts +1 -1
  93. package/src/gate/measures.ts +4 -4
  94. package/src/gate/stages.ts +2 -3
  95. package/src/markdown/bans.ts +11 -68
  96. package/src/markdown/gate.ts +1 -1
  97. package/src/markdown/scan.ts +7 -88
  98. package/src/pr/evidence.ts +42 -2
  99. package/src/pr/local.ts +125 -0
  100. package/standards/docs.md +1 -1
  101. package/standards/index.md +2 -1
  102. package/standards/markdown.md +5 -7
  103. package/standards/pr.md +1 -1
  104. package/standards/publish.md +1 -1
  105. package/standards/readme.md +2 -2
  106. package/standards/skill-requirement.md +72 -0
  107. package/standards/skill.md +34 -152
  108. package/tooling/astro/reference.md +1 -1
  109. package/tooling/base/configs/.github/workflows/pr-local-preview.yml +32 -0
  110. package/tooling/base/configs/scripts/verify.sh +2 -2
  111. package/tooling/base/seeds/canon/context/development.md +1 -1
  112. package/tooling/claude/seeds/.claude/hooks/standards-audit.sh +5 -6
@@ -7,7 +7,7 @@ description: Claude skill structure and authoring rules
7
7
 
8
8
  ## Overview
9
9
 
10
- Skills give Claude Code domain-specific constraints and rules inline, so it can act immediately without reading all docs. Each skill body contains actionable rules for its domain. Full reference docs are the fallback for edge cases and deeper context. Skills use progressive disclosure: Claude reads only frontmatter at session start (~100 tokens each), matches a query against descriptions, then loads the full skill body.
10
+ Skills give Claude Code domain-specific constraints and rules inline, so it can act immediately without reading all docs.
11
11
 
12
12
  ## Scope
13
13
 
@@ -15,12 +15,12 @@ Governs a skill folder under `skills/` as one artifact: `SKILL.md`, its siblings
15
15
 
16
16
  Does not govern:
17
17
 
18
+ - What a `REQUIREMENT.md` must answer, its sections, and its template: `skill-requirement.md`
18
19
  - Path-scoped coding rules, which load on a file match rather than on a request match: `rule.md`
19
20
  - Single-purpose chat prompts carrying no frontmatter, references, or scripts: `snippets.md`
20
21
  - Voice, rhythm, and sentence construction in a skill body: the `write-human` skill
21
22
  - Punctuation, formatting, and word choice in a skill body: `markdown.md`
22
23
  - The transform from a branch name to a slug a skill carries in a filename: `slug.md`
23
- - The domain conventions a skill cites, each of which belongs to the standard that owns it
24
24
  - Whether a new skill earns its place: the three-question test in the `create-skill` skill and the clause in `570-skill.md`
25
25
 
26
26
  ## Changing a skill
@@ -32,15 +32,13 @@ Answer all four before editing, and carry the answers into wherever the change i
32
32
  - What deterministic check catches a regression? Name it, or say none exists and the step holds on a session reading it.
33
33
  - What does this collide with? Name the sibling skill, rule, or requirement it contradicts, or state that nothing does.
34
34
 
35
- The second question is the one that decides between a body and a rule, which the next section tests in two parts.
36
-
37
35
  ## Whether a rule belongs beside the skill
38
36
 
39
- A skill fires when a session invokes it or its description matches the request. A path-scoped rule fires when a session reads a file matching its glob, with no decision from the session at all. The two are layers rather than alternatives, so the rule is the floor and the skill is the depth.
37
+ A skill fires when a session invokes it or its description matches the request. A path-scoped rule fires when a session reads a file matching its glob, with no decision from the session at all. The rule is the floor and the skill is the depth.
40
38
 
41
- Run the two-part test over what the body states before calling the skill finished. Does the invariant fire when a specific path is edited, and does violating it ship silently? An invariant passing both halves belongs in a rule as well, because a session that never invoked the skill still edits that path and needs the floor under it. An invariant failing either half stays here, which is most of a body, since procedure and orientation are what a rule cannot carry.
39
+ Run the two-part test over what the body states before calling the skill finished. Does the invariant fire when a specific path is edited, and does violating it ship silently? An invariant passing both halves belongs in a rule as well, since a session that never invoked the skill still edits that path. An invariant failing either half stays here, which is most of a body.
42
40
 
43
- Write that rule to the shape `rule.md` sets and leave the procedure here, since the two carry one invariant at two depths rather than two copies of it. Nothing checks the split. The checkpoint is a judgment prompt rather than an invariant, so it ships as prose with no gate behind it, and a skill that skips it fails silently in the same way the invariants it is meant to catch do.
41
+ Write that rule to the shape `rule.md` sets and leave the procedure here, since the two carry one invariant at two depths rather than two copies of it. Nothing checks the split.
44
42
 
45
43
  ## Skill types
46
44
 
@@ -49,23 +47,7 @@ Pick the type before writing. It decides the body shape.
49
47
  - Reference: conventions, patterns, and domain knowledge Claude applies inline. The body is rule bullets grouped by concern.
50
48
  - Task: step-by-step workflows Claude executes as actions. The body is numbered steps plus the rules constraining them.
51
49
 
52
- Reference template:
53
-
54
- ```markdown
55
- ---
56
- name: <skill-name>
57
- description: <what it does, when to use it, trigger phrases>
58
- ---
59
-
60
- # <Topic>
61
-
62
- ## <Concern group>
63
-
64
- - <actionable constraint>
65
- - <preference in X over Y form>
66
- ```
67
-
68
- Task template:
50
+ A task skill takes the template below. A reference skill takes the same frontmatter and replaces `## Steps` and `## Rules` with one H2 per concern group, each holding constraint bullets.
69
51
 
70
52
  ```markdown
71
53
  ---
@@ -90,97 +72,37 @@ allowed-tools: <tools required>
90
72
  ## Structure
91
73
 
92
74
  - Skill is a folder named in kebab-case containing `SKILL.md` (required), `REQUIREMENT.md` (required), `EVAL.md` (optional), `scripts/` (optional), `references/` (optional), `assets/` (optional)
75
+ - Create a new skill with its `REQUIREMENT.md` beside it, even where nobody contests its scope. A requirement present for some skills and absent for others cannot be scanned, since an absence reads as a gap rather than as a verdict
93
76
  - Name a file sitting directly in the skill folder in capitals and a bundled folder in lowercase, so the parts a reader opens are distinct from the ones a skill loads
94
- - `EVAL.md` holds prompts and a judging rubric a person runs by hand, which is the path open to everyone. `claude plugin eval` is the automated one and it is gated in early access, refusing before it parses a target, so write the hand-run rubric and know that the runner exists rather than that it does not
77
+ - `EVAL.md` holds prompts and a judging rubric a person runs by hand, since the automated `claude plugin eval` runner is gated in early access
95
78
  - `SKILL.md` must start with YAML frontmatter between `---` delimiters
96
79
  - No `README.md` inside the skill folder
97
80
  - No spaces, capitals, or underscores in folder or skill name
98
81
 
99
- ## Requirement
100
-
101
- `REQUIREMENT.md` states what a skill is for, so a proposed change can be argued against something and the corpus can be read to decide whether a skill should exist at all. This standard governs shape across the corpus and the requirement governs scope and behavior for one skill. Claude Code loads `SKILL.md` as the entry and ignores the sibling, so the file costs a target session nothing.
102
-
103
- The file serves a second purpose beside the argument. A skill body is procedural by design, so what the skill is for sits spread across its steps rather than stated in one place. The requirement is the compressed statement a reader gets before opening the body, and that purpose holds whether or not the skill's scope is contested.
104
-
105
- Read it before editing the skill. When a change closes no gap the requirement states, change the requirement first or drop the change.
106
-
107
- Write the gaps from what the skill is for, then compare the body against them. Deriving the requirement from the body is circular, because a requirement reverse-engineered from an overfitted skill records the overfitting as the requirement. That failure costs more under the orientation purpose than under the argument one, since a file summarizing the body misinforms whoever reads it in place of the body rather than merely failing to gate a change.
108
-
109
- Every skill carries one. Coverage was selective while the file existed only to disambiguate a contested boundary, and a file present for some skills and absent for others cannot be scanned, because an absence reads as a gap rather than as a verdict. A skill whose scope nobody contests still owes the statement, since the reader deciding whether a skill should exist reads the corpus rather than one entry. A new skill is created with the sibling beside it rather than acquiring one in a later sweep.
110
-
111
- ### What a working requirement looks like
112
-
113
- A requirement works when a proposed change to the skill can be settled by reading it alone, without re-deriving what the skill is for:
114
-
115
- - Does this change close a gap the file states?
116
- - Does a line already in the body trace to one of those gaps?
117
- - Does this behavior belong to this skill or to a sibling the file names?
118
-
119
- A requirement that leaves any of the three open is non-conforming regardless of whether it satisfies every shape rule below. The third question is what makes a requirement worth more than a restated description, because a boundary stated only in prose is never checked against the skill on the other side of it.
120
-
121
- - State each gap as an observed failure, not an intent. "Without this skill a session invents its own filename" can be shown wrong. "This skill helps manage tasks" cannot fail, so it constrains nothing.
122
- - Trace everything under `## Must` to a stated gap. A `Must` with no gap behind it is the padding the file exists to prevent.
123
- - Keep it high level. A requirement that outgrows one file has stopped being a requirement, and `references/` already holds detail.
124
- - Use `name` and `description` frontmatter, matching `SKILL.md` so the pair is consistent.
125
-
126
- ```markdown
127
- ---
128
- name: <skill-name>
129
- description: <one line, distinct from the SKILL.md description>
130
- ---
131
-
132
- # <Skill name> requirement
133
-
134
- ## Gap
135
-
136
- Without this skill, a session <observed failure>, <observed failure>.
137
-
138
- ## Must
139
-
140
- - <behavior that closes a named gap>
141
-
142
- ## Must not
143
-
144
- - <behavior that would be wrong even though it closes a gap>
145
-
146
- ## Guards
147
-
148
- - <the refusal condition and its message>
149
-
150
- ## Out of scope
151
-
152
- - <the adjacent thing this deliberately does not cover, and what covers it>
153
- ```
154
-
155
82
  ## Frontmatter
156
83
 
157
84
  - `name` (required): kebab-case, matches folder name, no spaces or capitals
158
85
  - `description` (required): what it does + when to use it, under 1024 chars, no XML tags
159
- - `disable-model-invocation: true`: user-invoked only, Claude will not auto-trigger. Set it on a skill that starts a process the operator owns, never on one reachable by a matched trigger. The field marks that boundary, not a style preference.
86
+ - `disable-model-invocation: true`: user-invoked only, Claude will not auto-trigger. Set it on a skill that starts a process the operator owns, never on one reachable by a matched trigger.
160
87
  - `allowed-tools`: restrict tool access when the skill is active
161
88
  - `metadata`: optional key-value pairs (`author`, `version`, `mcp-server`)
162
89
 
163
90
  ## Description
164
91
 
165
- - Structure: `[What it does] + [When to use it] + [Key trigger phrases]`
166
- - Include specific phrases users would say to trigger it
92
+ - Structure: `[What it does] + [When to use it] + [Key trigger phrases]`, quoting phrases users would say
167
93
  - Be specific, not vague. Claude routes based on this field alone.
168
94
  - Add negative triggers if skill is over-triggering: `Do NOT use for X`
169
95
 
170
96
  ## Body
171
97
 
172
- ### Voice and headings
173
-
174
- - Use imperative voice throughout
175
- - Use sentence case for all headings (H1, H2, H3)
176
-
177
98
  ### Rule content and scope
178
99
 
100
+ - Use imperative voice throughout, and sentence case for every heading
179
101
  - Front-load critical instructions
180
102
  - Contain only behavioral rules (what to do, what not to do) and pointers to reference docs. Narrative descriptions of what files are or how the system works belong in `docs/`, not in the skill body.
181
103
  - State rules, not inventories. Reference docs for lists that change, and phrase a rule as a ban on the forbidden shape rather than an enumeration of allowed options, so it stays stable as categories change.
182
104
  - Cut any rule that resists crisp one-line phrasing. Vague guidance is worse than none.
183
- - State the current rule only, in the body and in every file under `references/`. The incident and the date that earned a rule go in `REQUIREMENT.md` under `Gap`, or stay in git. A date inside a fence or a code span is example data and stays. `canon claude skills audit` names every other ISO date.
105
+ - State the current rule only, in the body and in every file under `references/`. The incident and the date that earned a rule go in `REQUIREMENT.md` under `Gap`, or stay in git. A date inside a fence or a code span is example data and stays.
184
106
  - Group bullets under H2 headings by domain concern. Keep dos and don'ts together under the topic they belong to rather than splitting them into flat rules and constraints sections.
185
107
  - One actionable constraint per bullet. Prefer the `X over Y` form for preferences.
186
108
  - Do not include code examples unless a one to three line inline snippet captures a pattern the model cannot infer.
@@ -188,17 +110,17 @@ Without this skill, a session <observed failure>, <observed failure>.
188
110
 
189
111
  ### Progressive disclosure
190
112
 
191
- - Look at a body once it passes 150 lines. The number prompts a look rather than gating a build, so nothing enforces it and a body carrying nothing but procedure stays whole at any length.
192
- - Move a catalog, a table of cases, or a format spec running past roughly 15 lines to `references/`. Procedure prose stays, since a session sent to a reference for its own steps pays two reads for one job.
193
- - Name the branch that skips a block before moving it. Body lines are paid on every invocation and a reference only when the body sends the session to it, so a block every run dereferences costs a read and saves nothing.
113
+ - Keep `SKILL.md` and each file under `references/` at or under the 300 rendered line ceiling `markdown.md` sets for a whole document. The ceiling binds procedure as much as reference material.
114
+ - Look at a body once it passes 150 lines. That number prompts a look and gates nothing.
115
+ - Move a catalog, a table of cases, or a format spec running past roughly 15 lines to `references/` at any body length.
116
+ - Below the ceiling, name the branch that skips a block before moving it. A block every run dereferences costs a read and saves nothing.
117
+ - Past the ceiling, move a whole step to a reference, preferring a step a named branch skips. Keep the step heading in the body with one line naming the file to read on reaching it, so the body still shows every step in order.
118
+ - Name every file under `references/` in the body at the point a session reads it, since an unnamed reference is never loaded.
194
119
  - Keep the trigger, the skip condition, and the guard in the body. A run that never reaches the block has to decide that without opening the reference.
195
120
  - Never point one skill at a sibling skill's folder for a reference both read. Each skill carries its own copy under `references/`, generated rather than hand-copied by the rule in `## Path resolution`.
196
- - Use progressive disclosure: `SKILL.md` for core instructions, `references/` for detail, `scripts/` for deterministic operations
197
- - Link to `references/` files explicitly so Claude knows to load them
198
121
 
199
122
  ### Reading and running commands
200
123
 
201
- - Reference a bundled `references/` or `scripts/` file with `${CLAUDE_SKILL_DIR}/<path>`, never a bare relative path. A bare path resolves against the session cwd and fails when a plugin skill runs from another project. `${CLAUDE_SKILL_DIR}` expands to the skill's own directory at render time and resolves from any cwd.
202
124
  - When referencing project files, include "from the project root" in the read instruction
203
125
  - When executing multiple independent operations (file reads, shell commands), run them in parallel to reduce latency
204
126
 
@@ -206,97 +128,57 @@ Without this skill, a session <observed failure>, <observed failure>.
206
128
 
207
129
  - Avoid flags that dispatch between alternate flows. The model misreads them and runs the vanilla path. Dry-run-style toggles are fine. For alternate flows, prefer a separate skill or manual invocation of two skills in sequence.
208
130
  - When a skill should fire from multiple callers, rely on description matching with strong trigger phrases. Do not hardcode `Skill` calls in sibling skills that could trigger it naturally.
209
- - Before collapsing a manual multi-step flow into a skill, ask what the manual pauses do. Pauses that carry external timing, error-surfacing, or judgment weight are the feature. Prefer a snippet over a skill, or require explicit per-step confirmation.
131
+ - Before collapsing a manual multi-step flow into a skill, ask what the manual pauses do. Where a pause carries external timing, error-surfacing, or judgment weight, prefer a snippet or explicit per-step confirmation.
210
132
 
211
133
  ### Output and tuning
212
134
 
213
135
  - Skill success lines emit the full relative path from the project root (`<dir>/<file>`) for any file written, updated, or deleted. A bare filename names a file the reader cannot open. The `## Output` section of the project's instruction file sets the form that path takes, so a skill body states which path is emitted and leaves the form to that section.
214
- - Before a skill writes anything, decide whether the output is a deliverable the project keeps or a toolkit session record. A deliverable lands among the project's own tracked files. A session record lands under `.canon/`, in the named subfolder for its kind (`tasks/`, `plans/`, `review/`, `memory/`, `groundwork/`, `intake/`, `proposals/`, `diagrams/`, `teach/`, `ready/`, `feedback/`, `picks/`, `evidence/`, `transcripts/`, or `walkthroughs/`, with `tmp/` for scratch nothing else claims), never in a folder the body invents. A `review/` writer names its file `<kind>-<slug>.md` and writes it flat, and an `evidence/` folder takes the next two-digit ordinal as `<nn>-<slug>/`, numbered in the order the folders first appeared. `canon/ARCHITECTURE.md`'s per-folder decisions are the precedent for which kind takes which folder.
136
+ - Before a skill writes anything, decide whether the output is a deliverable the project keeps or a toolkit session record. A deliverable lands among the project's own tracked files. A session record lands under `.canon/`, in the named subfolder for its kind (`tasks/`, `plans/`, `review/`, `memory/`, `groundwork/`, `intake/`, `proposals/`, `diagrams/`, `teach/`, `ready/`, `feedback/`, `picks/`, `evidence/`, `transcripts/`, or `walkthroughs/`, with `tmp/` for scratch nothing else claims), never in a folder the body invents. A `review/` writer names its file `<kind>-<slug>.md` and writes it flat, and an `evidence/` folder takes the next two-digit ordinal as `<nn>-<slug>/`, numbered in the order the folders first appeared.
215
137
  - Codify a skill's posted or generated output as a fenced template, and keep the body consistent with every capability the frontmatter description names.
216
138
  - When a skill gathers user input or pre-seeds a template, attach a concrete proposed default to every question, derived from project context. Accept "use defaults" as a bulk-confirm.
217
- - Separate correctness axes (routing, sourcing, escalation, decline) from shape axes (line count, formatting, variant sprawl) when tuning a skill. Tighten only on correctness regressions. Do not convert soft caps to hard caps for aesthetic drift when correctness passes.
139
+ - Separate correctness axes (routing, sourcing, escalation, decline) from shape axes (line count, formatting, variant sprawl) when tuning a skill. Tighten only on correctness regressions, never turning a soft cap hard for aesthetic drift.
218
140
 
219
141
  ## Scripts
220
142
 
221
143
  - Use `scripts/` for operations that must be deterministic or repetitive
222
- - Claude executes scripts and receives stdout. Scripts are not loaded into context.
223
144
  - Use XML tags in script output for reliable parsing: `<SECTION>content</SECTION>`
224
145
  - Use `#!/usr/bin/env bash` shebang
225
146
  - Always include `2>/dev/null || echo "FALLBACK"` guards on git and shell commands
226
147
 
227
148
  ## Path resolution
228
149
 
229
- A skill reads from two roots. Know which one a file lives under before referencing it.
150
+ A skill reads from two roots, so know which one a file lives under before referencing it.
230
151
 
231
- - Bundled skill assets (`references/`, `scripts/`, `assets/`) resolve against the skill's own directory in the source clone. Reference them with `${CLAUDE_SKILL_DIR}/<path>`, never a bare relative path, so a plugin skill running from another project still finds them.
152
+ - Bundled skill assets (`references/`, `scripts/`, `assets/`) resolve against the skill's own directory. Reference them with `${CLAUDE_SKILL_DIR}/<path>`, never a bare relative path, which resolves against the session cwd and fails when a plugin skill runs from another project.
232
153
  - Installed shared docs (`.claude/rules/`, `canon/context/`) resolve against the target project cwd, where install placed them. Reference them by that path.
233
- - Do not hand-copy a standard into a skill. A hand-copied file drifts from its source and belongs to no owner. If a skill must carry its own copy, generate it from the single source and reference it through `${CLAUDE_SKILL_DIR}`, so one owner keeps every copy in sync.
154
+ - Do not hand-copy a standard into a skill. If a skill must carry its own copy, generate it from the single source and reference it through `${CLAUDE_SKILL_DIR}`, so one owner keeps every copy in sync.
234
155
 
235
156
  ### Citing a standard
236
157
 
237
158
  No standard installs into a project, so a body cites one place rather than choosing between two.
238
159
 
239
- - Cite `${CLAUDE_SKILL_DIR}/../../standards/X.md`. The plugin ships the whole standards folder beside `skills/`, so the path resolves in every install and needs no fallback behind it.
240
- - Never cite `.claude/standards/X.md` from a shipped body. A target holds no such folder, and one left behind by an older toolkit is a stale copy no resolver reads. <!-- audit-ignore-citations: .claude/standards/X.md -->
160
+ - Cite `${CLAUDE_SKILL_DIR}/../../standards/X.md`. The plugin ships the whole standards folder beside `skills/`, so the path resolves in every install.
161
+ - Never cite `.claude/standards/X.md` from a shipped body. A target holds no such folder. <!-- audit-ignore-citations: .claude/standards/X.md -->
241
162
  - Name `canon standards X` instead where the body wants the document rather than a path to open, such as a value it captures or reports. That verb resolves `standards/` at the project root and then the corpus inside the package.
242
163
  - State the path once per body, at the site that reads the standard. A later mention of a standard the body already read stays bare, since repeating the path at every mention is noise rather than instruction.
243
164
  - A guard on a standard's presence names the file rather than the folder holding it, since a folder test answers for a sibling that happens to be there.
244
- - Use `${CLAUDE_SKILL_DIR}`, never a bare `../../` and never `${CLAUDE_PLUGIN_ROOT}`. Only `${CLAUDE_SKILL_DIR}` is expanded before the body reaches the model. The other two leave the model to infer a base path, which it may resolve against the session cwd instead.
245
- - Cite a shared procedure, never restate it. A procedure two or more skills execute gets one definition in a standard and a citation in each body. Nothing catches a restatement that drifts, because the drift assertion covers generated copies and a hand-written one is not generated, so the guarantee is only that a single definition exists to correct.
165
+ - Use `${CLAUDE_SKILL_DIR}`, never a bare `../../` and never `${CLAUDE_PLUGIN_ROOT}`, since only the first expands before the body reaches the model.
166
+ - Cite a shared procedure, never restate it. A procedure two or more skills execute gets one definition in a standard and a citation in each body.
246
167
  - Keep the trigger in the body and the procedure in the standard. The citing skill states when the procedure runs and what it runs against, since that varies per skill and the standard cannot know it.
247
168
 
248
169
  ## Invocation
249
170
 
250
- - Skills auto-trigger when Claude matches the request against the description
251
- - Invoke manually with `/skill-name` or `/<plugin>:skill-name` for plugin skills
252
- - Plugin skills are namespaced: `plugin-name:skill-name`
253
- - Priority order when names conflict: enterprise > personal > project > plugin
254
-
255
- ## Execution
256
-
257
- - Task skills with preview+execute patterns must execute commands immediately after outputting the preview. Do not include "confirm before running" language or pause for user input.
258
- - Claude Code's tool permission dialog is the confirmation gate. The user hits Enter to approve or Escape to interrupt and revise.
171
+ - Invoke a plugin skill by its namespaced name, `/<plugin>:<skill-name>`.
172
+ - Task skills with preview+execute patterns execute commands immediately after outputting the preview, with no "confirm before running" pause, since the tool permission dialog is the confirmation gate.
259
173
 
260
174
  ## Examples
261
175
 
262
176
  ### Correct
263
177
 
264
- ```markdown
265
- ---
266
- name: code-review
267
- description: Reviews code for bugs, clarity, and standards compliance. Use when asking to review code, check a PR, or asking "does this look right".
268
- ---
269
-
270
- # Code review
271
-
272
- Before reviewing, read from the project root:
273
-
274
- - `CLAUDE.md`: project conventions and behavior rules
275
- - `.claude/rules/`: path-scoped coding rules
276
-
277
- ## Guards
278
-
279
- - If no file or diff is provided, stop: `❌ No code to review. Provide a file or diff.`
280
-
281
- ## Response format
282
-
283
- - **Issues found:** <count>
284
- - **Summary:** <one line>
285
-
286
- List each issue with file, line, and suggested fix.
287
- ```
178
+ - `description: Reviews code for bugs and clarity. Use when asked to "review this" or "check the PR".` # names the action, then the trigger phrases
179
+ - `Read ${CLAUDE_SKILL_DIR}/references/post.md on reaching this step.` # a moved step keeps its heading and one load line
288
180
 
289
181
  ### Incorrect
290
182
 
291
- ```markdown
292
- ---
293
- name: code-review
294
- description: Handles all code-related tasks in scripts/, src/, and lib/. Also activate when user mentions bugs, refactoring, testing, linting, formatting, or any file ending in .ts .js .py .sh. # path-focused + keyword-stuffed
295
- ---
296
-
297
- # Code review
298
-
299
- A good code review should check for bugs, performance issues, security vulnerabilities,
300
- code style, naming conventions, test coverage, documentation, error handling,
301
- edge cases, and adherence to SOLID principles... # dumps everything inline instead of referencing standards
302
- ```
183
+ - `description: Handles all code tasks in scripts/, src/, and lib/, and any file ending in .ts .js .py .sh.` # path-focused and keyword-stuffed
184
+ - `A good review checks bugs, performance, security, style, naming, coverage, docs, and SOLID...` # dumps everything inline instead of citing a standard
@@ -22,7 +22,7 @@ The astro stack covers Astro + TypeScript projects: content sites, marketing sit
22
22
  - `playwright.config.ts`: all browsers, `webServer` runs `bun run build && bun run preview` on port `4321` plus `WORKTREE_PORT_OFFSET`, `reuseExistingServer: false`. Astro's dev/prod gap is wide (MDX, island hydration, asset optimization), so E2E always tests the built `dist/`. `DIST_PREBUILT` set in the environment drops the `build` half, running `bun run preview` alone against a `dist/` a prior CI job already produced.
23
23
  - `tsconfig.json`: extends `astro/tsconfigs/strict`, adds `skipLibCheck`, `vitest/globals` and `@testing-library/jest-dom` in types, `@/` paths.
24
24
  - `card.config.mjs`, `card-src/pages/og-card.astro`, and `scripts/check-card-exclusion.sh`: the social card route, its structural build exclusion, and the check enforcing it. See `## Social card route` below.
25
- - `eslint.config.js`: overrides the web layer. Adds `eslint-plugin-astro` (`.astro` parser via `astro-eslint-parser`). React-hooks scoped to `.jsx`/`.tsx` only (`.astro` is not React). The shared block's `files` selector includes `.astro`, so `check-file/filename-naming-convention` reaches `.ts`, `.tsx`, and `.astro` under `KEBAB_CASE`, overriding Astro's own PascalCase component convention deliberately, on the ground that a component's name in markup comes from the import binding rather than the filename. `.js` and `.jsx` stay out of the rule's own pattern, matching `web` and `nextjs`. `check-file/folder-naming-convention` reaches every `src/**` folder except `__tests__` and the whole `pages/` subtree, which carries its own off-block for the bracket-named dynamic routes and nested slug folders Astro's file-based routing produces. See `canon/context/tooling.md` for the measurement.
25
+ - `eslint.config.js`: overrides the web layer. Adds `eslint-plugin-astro` (`.astro` parser via `astro-eslint-parser`). React-hooks scoped to `.jsx`/`.tsx` only (`.astro` is not React). The shared block's `files` selector includes `.astro`, so `check-file/filename-naming-convention` reaches `.ts`, `.tsx`, and `.astro` under `KEBAB_CASE`, overriding Astro's own PascalCase component convention deliberately, on the ground that a component's name in markup comes from the import binding rather than the filename. `.js` and `.jsx` stay out of the rule's own pattern, matching `web` and `nextjs`. `check-file/folder-naming-convention` reaches every `src/**` folder except `__tests__` and the whole `pages/` subtree, which carries its own off-block for the bracket-named dynamic routes and nested slug folders Astro's file-based routing produces. See `canon/context/tooling/stacks.md` for the measurement.
26
26
 
27
27
  ## Typecheck
28
28
 
@@ -0,0 +1,32 @@
1
+ name: PR Local Preview Cleanup
2
+
3
+ on:
4
+ pull_request:
5
+ types: [closed]
6
+
7
+ permissions:
8
+ pull-requests: write
9
+
10
+ jobs:
11
+ remove-local-preview:
12
+ name: 🖥️ Remove Local Preview Link
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ # A fork pull request gets a read-only token, so the edit cannot land.
16
+ # Say so and pass rather than failing a close nobody can fix.
17
+ - name: Skip a fork pull request
18
+ if: github.event.pull_request.head.repo.full_name != github.repository
19
+ run: echo "::notice::Fork pull request, so the token cannot edit the evidence comment. The local preview line stays."
20
+
21
+ - name: Setup Bun
22
+ if: github.event.pull_request.head.repo.full_name == github.repository
23
+ uses: oven-sh/setup-bun@v2
24
+ with:
25
+ bun-version: latest
26
+
27
+ - name: Replace the local preview line on the evidence comment
28
+ if: github.event.pull_request.head.repo.full_name == github.repository
29
+ env:
30
+ GH_TOKEN: ${{ github.token }}
31
+ GH_REPO: ${{ github.repository }}
32
+ run: bunx -y @erclx/canon pr local ${{ github.event.pull_request.number }} --remove --json
@@ -48,14 +48,14 @@ check_markdown_bans() {
48
48
 
49
49
  case "$code" in
50
50
  0)
51
- log_info "No banned character, word, or spelling"
51
+ log_info "No banned character"
52
52
  ;;
53
53
  1)
54
54
  log_info "Skipped: canon markdown audit refused and measured nothing."
55
55
  ;;
56
56
  2)
57
57
  echo "$output" | pipe_output
58
- log_error "Markdown prose carries a banned character, word, or spelling, or a relative link resolves to nothing on disk"
58
+ log_error "Markdown prose carries a banned character, or a relative link resolves to nothing on disk"
59
59
  ;;
60
60
  3)
61
61
  echo "$output" | pipe_output
@@ -34,4 +34,4 @@ All `.sh` files live under `scripts/`. Do not place shell scripts outside `scrip
34
34
 
35
35
  - `pre-commit` runs `lint-staged` (prettier, cspell, shfmt, shellcheck on staged files).
36
36
  - `commit-msg` runs `commitlint` against the conventional commit format.
37
- - `pre-push` runs `bun run check`. When a markdown-bans audit tool is on PATH, it also gates on banned characters, words, and spellings across every tracked markdown file except `CHANGELOG.md`. After pushing, run `git status`. If files changed, commit the diff as `style(<scope>):` and push again.
37
+ - `pre-push` runs `bun run check`. When a markdown-bans audit tool is on PATH, it also gates on banned characters across every tracked markdown file except `CHANGELOG.md`. After pushing, run `git status`. If files changed, commit the diff as `style(<scope>):` and push again.
@@ -28,12 +28,11 @@ esac
28
28
 
29
29
  [ -f "$file" ] || exit 0
30
30
 
31
- # The audit verb owns the ban sets, so this hook carries no copy of them. The
32
- # awk this replaces parsed the word bans out of the project's own standards,
33
- # hardcoded the em-dash and semicolon, and reached none of the spellings, so a
34
- # British spelling passed at edit time and a corpus check caught it later with
35
- # nothing in between explaining the difference. A ban class added to the verb
36
- # now reaches this hook without an edit here.
31
+ # The audit verb owns the ban set, so this hook carries no copy of it. The awk
32
+ # this replaces parsed its bans out of the project's own standards and
33
+ # hardcoded the rest, so edit time and a later corpus check could disagree with
34
+ # nothing in between explaining the difference. A ban added to the verb now
35
+ # reaches this hook without an edit here.
37
36
  #
38
37
  # The verb resolves its own paths under the cwd, so the project root is named
39
38
  # rather than inherited. The payload carries an absolute file path, which is