@erclx/canon 4.63.0 → 4.64.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.
- package/claude/.claude-plugin/plugin.json +1 -1
- package/claude/skills/canon-record/REQUIREMENT.md +34 -0
- package/claude/skills/canon-record/SKILL.md +54 -0
- package/claude/skills/canon-screencast/REQUIREMENT.md +1 -1
- package/claude/skills/canon-screencast/SKILL.md +3 -3
- package/claude/skills/claude-autoship/REQUIREMENT.md +3 -1
- package/claude/skills/claude-autoship/SKILL.md +26 -12
- package/claude/skills/draft-readme/REQUIREMENT.md +36 -0
- package/claude/skills/draft-readme/SKILL.md +65 -0
- package/claude/skills/identity/REQUIREMENT.md +40 -0
- package/claude/skills/identity/SKILL.md +86 -0
- package/claude/skills/test-first/REQUIREMENT.md +34 -0
- package/claude/skills/test-first/SKILL.md +24 -0
- package/docs/agents/demo.md +2 -0
- package/docs/agents/review-classification.md +2 -2
- package/docs/workflow/ai-workflow.md +12 -8
- package/docs/workflow/visual-design-workflow.md +1 -0
- package/governance/rules/core/070-planning.md +1 -0
- package/package.json +3 -1
- package/scripts/core/regen-agent-fixture.sh +1 -1
- package/src/claude/cases/authoring.ts +4 -0
- package/src/claude/cases/claude-workflow.ts +5 -0
- package/src/claude/cases/misc.ts +10 -0
- package/standards/readme.md +2 -0
- package/tooling/astro/configs/eslint.config.js +7 -1
- package/tooling/astro/reference.md +1 -1
- package/tooling/nextjs/configs/eslint.config.js +3 -2
- package/tooling/nextjs/reference.md +1 -1
- package/tooling/web/configs/eslint.config.js +1 -1
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: canon-record
|
|
3
|
+
description: Why compiling and running a screencast draft needs a routed skill rather than an operator typing two verbs by hand, and why the unresolved-field refusal cannot be a suggestion
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Canon record requirement
|
|
7
|
+
|
|
8
|
+
## Gap
|
|
9
|
+
|
|
10
|
+
Without this skill, `canon-screencast` writes a draft and names `canon demo compile` as the next step, and nothing after that routes a session there or to `canon demo run`. An operator has to know both verbs, type them in order, and read the compile record for unresolved fields by hand. A session that fills one in on its own reproduces the exact failure `canon demo run`'s `plan-unresolved` reason exists to catch, one layer up where nothing enforces it.
|
|
11
|
+
|
|
12
|
+
## Must
|
|
13
|
+
|
|
14
|
+
- Resolve the default plan path the same way `canon demo compile` does, so a caller passing only the draft path reaches the plan without naming it
|
|
15
|
+
- Skip compiling when a plan already exists at that path, since its timing may be tuned by hand and a draft cannot reproduce that
|
|
16
|
+
- Report every unresolved field from the compile or run record and stop rather than filling one in
|
|
17
|
+
- Report every path a run wrote, video, mp4, gif, still, skipping any the record carries as null
|
|
18
|
+
|
|
19
|
+
## Must not
|
|
20
|
+
|
|
21
|
+
- Pass `--force` to compile
|
|
22
|
+
- Guess or fill a target, a URL, or any other unresolved field
|
|
23
|
+
- Drive the application through anything other than `canon demo run`
|
|
24
|
+
- Assume this skill's own invocation frequency needs no check. `canon-screencast`'s closing block names it by hand, but whether anything else reaches for it beyond that pointer or an operator typing its name has no answer at creation time, so a review pass some months in should read that back rather than take it on faith.
|
|
25
|
+
|
|
26
|
+
## Guards
|
|
27
|
+
|
|
28
|
+
- No draft path given: stop rather than guessing what to compile
|
|
29
|
+
|
|
30
|
+
## Out of scope
|
|
31
|
+
|
|
32
|
+
- Drafting the beats, which `canon-screencast` owns
|
|
33
|
+
- Filling an existing plan's target or URL, which is the operator's own edit
|
|
34
|
+
- Verifying a recording beyond its own caption, which nothing in the toolkit does yet
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: canon-record
|
|
3
|
+
description: Drives a screencast draft through to a recording. Compiles it with `canon demo compile` when no plan exists yet at the default path, skipping compile when one is already there, then runs `canon demo run` once nothing is unresolved. Reports every unresolved field from the compile or run record and stops rather than guessing one. Use when asked to "record the screencast", "run the demo", "compile and record this draft", or right after `canon-screencast` prints its next-step line. Do NOT use to draft the beats, which is `canon-screencast`, or to fill in a plan's target or URL, which is the operator's own edit.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Canon record
|
|
7
|
+
|
|
8
|
+
## Guards
|
|
9
|
+
|
|
10
|
+
- If no draft path is given, stop: `❌ No draft path. Pass the path canon-screencast printed.`
|
|
11
|
+
- Never guess or fill an unresolved field, a target, a URL, or anything else the compile or run record names. Report it and stop. Filling one in reproduces the failure `canon demo run`'s `plan-unresolved` reason exists to catch, one layer up where nothing enforces it.
|
|
12
|
+
- Never pass `--force` to compile. A plan already at the default output path may carry timing tuned by hand, and the draft cannot reproduce that, so leave it untouched.
|
|
13
|
+
- Drive the application through `canon demo run` alone. Never open a browser, click through the app, or write to the output paths some other way.
|
|
14
|
+
|
|
15
|
+
## Step 1: resolve the plan path
|
|
16
|
+
|
|
17
|
+
Derive the default plan path the same way `canon demo compile` does: `<out>/<slug>.json`, where `<out>` defaults to `demos` and `<slug>` defaults to the draft's filename with its extension stripped. `.canon/tmp/screencast/inline-edit.md` resolves to `demos/inline-edit.json`.
|
|
18
|
+
|
|
19
|
+
## Step 2: compile only when no plan exists yet
|
|
20
|
+
|
|
21
|
+
Check whether the resolved plan path already exists.
|
|
22
|
+
|
|
23
|
+
- **It exists.** A person may have tuned it by hand since compiling. Skip compiling and go to Step 3 with this path.
|
|
24
|
+
- **It does not exist.** Run:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
canon demo compile <draft> --json
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Branch on the record rather than the exit code:
|
|
31
|
+
- `reason: draft-missing` or `reason: draft-unreadable`: report the reason, plus the record's `message` when it carries one, and stop.
|
|
32
|
+
- No `reason` key, meaning the plan was written: read `unresolved` off the record.
|
|
33
|
+
- Non-empty: report the plan path and every field the array names, one per line, and stop. Do not proceed to Step 3.
|
|
34
|
+
- Empty: continue to Step 3 with the record's `plan` path.
|
|
35
|
+
|
|
36
|
+
## Step 3: run
|
|
37
|
+
|
|
38
|
+
Run:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
canon demo run <plan> --json
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Branch on the record's `reason`:
|
|
45
|
+
|
|
46
|
+
- `plan-unresolved`: report every field in `unresolved`, one per line, and stop. This is the path a pre-existing plan takes, since Step 2 skipped compiling and never read its fields.
|
|
47
|
+
- Any other reason (`plan-missing`, `plan-unreadable`, `no-output-requested`, `cursor-unreadable`, `engine-missing`, `browser-missing`): report the reason, plus the record's `message` or `install` line when it carries one, and stop.
|
|
48
|
+
- No `reason` key, meaning the run wrote its output: continue to Step 4.
|
|
49
|
+
|
|
50
|
+
## Step 4: output
|
|
51
|
+
|
|
52
|
+
The record carries `video`, `mp4`, `gif`, and `still`, each a path or `null`. Report each one that is not `null`, one per line, skipping the rest.
|
|
53
|
+
|
|
54
|
+
Say so plainly if `canon demo compile` or `canon demo run` is not available, rather than driving the application some other way. Both ship with the CLI and this skill ships with the plugin, so a project carrying one and not the other is a real state.
|
|
@@ -33,7 +33,7 @@ A draft that names the recording software, the editing software, or the window m
|
|
|
33
33
|
|
|
34
34
|
## Out of scope
|
|
35
35
|
|
|
36
|
-
- Producing the recording, which
|
|
36
|
+
- Producing the recording, which `canon-record` owns
|
|
37
37
|
- Refining an existing draft, which is a direct edit of the file
|
|
38
38
|
- Slide decks, which `canon-slides-draft` owns
|
|
39
39
|
- Where the recording ships, which the draft lists and the user decides
|
|
@@ -8,7 +8,7 @@ description: Drafts a screencast script with pre-seeded beats, defaults, and dec
|
|
|
8
8
|
## Guards
|
|
9
9
|
|
|
10
10
|
- If no topic is provided, stop: `❌ No screencast topic. Describe what you are recording.`
|
|
11
|
-
- Draft, then hand off. Do not edit video or generate captions, and do not drive the application. A recording is another
|
|
11
|
+
- Draft, then hand off. Do not edit video or generate captions, and do not drive the application. A recording is another skill's job rather than something forbidden: write the draft, name `canon-record` as the next step, and stop.
|
|
12
12
|
- Stack-agnostic in the draft. Never name a recording tool, an editing tool, a font, or a window manager. Keep selectors, URLs, wait conditions, and timings out of the beats too, since those four are exactly what the compiler adds in a plan of its own. A beat carrying them stops being a document a person can read and edit down.
|
|
13
13
|
|
|
14
14
|
## Step 1: read the project context
|
|
@@ -159,9 +159,9 @@ Print the file path on its own line and a one-line summary. Do not paraphrase th
|
|
|
159
159
|
Draft has 5 beats and pre-seeded defaults. Edit the beats and the resolved decisions.
|
|
160
160
|
|
|
161
161
|
To record it rather than shoot it by hand:
|
|
162
|
-
canon
|
|
162
|
+
canon-record .canon/tmp/screencast/<slug>.md
|
|
163
163
|
```
|
|
164
164
|
|
|
165
|
-
Name the
|
|
165
|
+
Name the skill and stop there. Do not compile the draft, do not run it, and do not generate captions. The operator edits the beats first, and the compiler reports which selectors and URLs they still owe it.
|
|
166
166
|
|
|
167
167
|
Say so plainly if `canon demo compile` is not available, rather than driving the application some other way. The command ships with the CLI and the skills ship with the plugin, so a project carrying one and not the other is a real state.
|
|
@@ -16,6 +16,7 @@ Review is the step that varies most. It gets skipped on a diff that needed one,
|
|
|
16
16
|
- Take the approved plan for the branch as the scope, and implement only what it describes
|
|
17
17
|
- Give every step a stop condition, and leave the code on the branch and the receipts on disk at each one
|
|
18
18
|
- Classify the changed-file list by path as well as by extension, so informational prose skips a code review with no signal on it and executable prose still reaches one
|
|
19
|
+
- Check the branch's committed history for a test-order violation between verify and review, and report any finding without gating on it, matching the verb's own contract
|
|
19
20
|
- Split findings by origin, stopping on a critical or should-fix one the branch inherited and repairing one this run caused
|
|
20
21
|
- Own the review receipt's lifetime, since this chain writes it, cites it in its own closing block, and is the only body that can read whether the step keeping it is still using it
|
|
21
22
|
- Delegate the ship sequence to `git-ship` rather than restating it, and name only what this chain adds to it
|
|
@@ -34,6 +35,7 @@ Review is the step that varies most. It gets skipped on a diff that needed one,
|
|
|
34
35
|
- Run the memory Apply phase. Promoting an entry changes how the agent operates and ships as its own change.
|
|
35
36
|
- Read an empty changed-file list as prose-only. It satisfies that test vacuously and would route the branch past review instead of through it.
|
|
36
37
|
- Read a markdown extension as evidence the change only informs. A skill body, a governance rule, and a standard are behavior written in prose.
|
|
38
|
+
- Stop the chain or rewrite a commit over a test-order finding. The verb reports and never gates, and a commit already in history is a different act from the work this run is building.
|
|
37
39
|
|
|
38
40
|
## Guards
|
|
39
41
|
|
|
@@ -47,4 +49,4 @@ Review is the step that varies most. It gets skipped on a diff that needed one,
|
|
|
47
49
|
|
|
48
50
|
- Writing the plan, which `claude-feature` owns. This chain starts from one already approved.
|
|
49
51
|
- The behavior of each step, owned by the skill invoked. This skill owns the order and the stop conditions.
|
|
50
|
-
- The ship sequence and the resume path after a stop, both of which `git-ship` owns. That skill is the tail of this chain, invoked at Step
|
|
52
|
+
- The ship sequence and the resume path after a stop, both of which `git-ship` owns. That skill is the tail of this chain, invoked at Step 8 rather than copied into it, so the overlap is one body reached two ways rather than two bodies stating one order.
|
|
@@ -17,7 +17,7 @@ Chain the post-plan pipeline in a single run. Every step has a stop condition. S
|
|
|
17
17
|
|
|
18
18
|
## Diff baseline
|
|
19
19
|
|
|
20
|
-
Step
|
|
20
|
+
Step 6 classifies the changed-file list to decide whether review runs. Resolve the base ref once:
|
|
21
21
|
|
|
22
22
|
```bash
|
|
23
23
|
git merge-base HEAD origin/main 2>/dev/null || git merge-base HEAD main 2>/dev/null
|
|
@@ -27,7 +27,7 @@ Prefer `origin/main` over local `main`. A local `main` trailing the remote pulls
|
|
|
27
27
|
|
|
28
28
|
The baseline is unusable when no merge base resolves against either ref. Stop: `❌ No diff baseline against main. Fetch origin, then re-run autoship.`
|
|
29
29
|
|
|
30
|
-
The base equalling HEAD stays usable here, unlike in the four read-only siblings carrying this section. Step
|
|
30
|
+
The base equalling HEAD stays usable here, unlike in the four read-only siblings carrying this section. Step 6 runs before anything is committed, since `git-stage` commits at Step 8, so the base equals HEAD on every ordinary run. The classifier diffs the base against the working tree rather than against HEAD, which keeps the uncommitted work in the set at correct scope. Do not port the sibling `base == HEAD` stop into this skill.
|
|
31
31
|
|
|
32
32
|
## Step 0: take the role, then enter a worktree
|
|
33
33
|
|
|
@@ -103,7 +103,21 @@ Run the verify commands defined in `CLAUDE.md` (lint, typecheck, tests). On fail
|
|
|
103
103
|
|
|
104
104
|
Do not loop. Do not bypass hooks.
|
|
105
105
|
|
|
106
|
-
## Step 4:
|
|
106
|
+
## Step 4: test order
|
|
107
|
+
|
|
108
|
+
Run `canon gov test-order --json` from the worktree this chain is building in, which is the one tree holding the branch's own commits. The Guards send a `.canon/plans/` and a `.canon/review/` read to the main worktree root and this is not one of those: that checkout sits on the trunk on an ordinary run, so the range closes on itself there and every finding the branch carries reads as clean.
|
|
109
|
+
|
|
110
|
+
The verb reads git history rather than the working tree, so a branch with nothing committed yet reads as clean, and what it catches is a violation that already reached this branch's history in an earlier session or an earlier round of this chain. It reports and never gates, since nothing wires its exit into a push, so branch on the record's `kind` and its `findings` array rather than on the exit, which reads 2 on a finding and 1 on a refusal and which a shell function wrapping `canon` can flatten to zero either way.
|
|
111
|
+
|
|
112
|
+
- `kind: 'measured'`, `findings` empty. Nothing on the branch reached history ahead of its test. Continue to Step 5.
|
|
113
|
+
- `kind: 'measured'`, `findings` non-empty. Report each pair's `subject` and `reason` to the user and continue to Step 5. Do not stop the chain and do not attempt a fix: the commit already reached history, and rewriting it here rewrites what an earlier run shipped rather than what this run is building.
|
|
114
|
+
- `kind: 'unreadable'`. Report the `message` and continue to Step 5. A shallow clone or a repository with no trunk is an ordinary state this check cannot read, not a reason to stop shipping.
|
|
115
|
+
|
|
116
|
+
### When the verb is absent
|
|
117
|
+
|
|
118
|
+
The verb ships with the CLI and this body ships with the plugin, matching Step 6's own fallback for the classify verb. Report that the check did not run rather than reading a missing subcommand as clean, and continue to Step 5.
|
|
119
|
+
|
|
120
|
+
## Step 5: UI test (conditional)
|
|
107
121
|
|
|
108
122
|
If the diff touches UI files (JSX, TSX, Vue, Svelte, HTML, or CSS under `src/`), invoke `canon:claude-ui-test`.
|
|
109
123
|
|
|
@@ -111,7 +125,7 @@ If `claude-ui-test` produces a manual checklist, stop: `❌ UI requires visual v
|
|
|
111
125
|
|
|
112
126
|
If all UI changes are covered by e2e tests, continue.
|
|
113
127
|
|
|
114
|
-
## Step
|
|
128
|
+
## Step 6: review
|
|
115
129
|
|
|
116
130
|
Classify the diff first. Take the union of `git diff --name-only <base>` and `git ls-files --others --exclude-standard`, resolving `<base>` per Diff baseline, then hand that set to the verb rather than reading it against the list below yourself:
|
|
117
131
|
|
|
@@ -121,7 +135,7 @@ canon autoship classify --json <path>...
|
|
|
121
135
|
|
|
122
136
|
The verb reads names only and touches git not at all, so the set stays the one this step already computed and no second baseline resolves to disagree with the first. Branch on the record's `decision` rather than on the exit code, which a shell function wrapping `canon` can flatten to zero.
|
|
123
137
|
|
|
124
|
-
- `skip`. Every path reads as prose and none states agent behavior. Skip review entirely and continue to Step
|
|
138
|
+
- `skip`. Every path reads as prose and none states agent behavior. Skip review entirely and continue to Step 8.
|
|
125
139
|
- `review`. Invoke `canon:claude-review`. The record names the `file` that decided it and the `test` it failed, `extension` for a path that is not prose and `behavior-path` for prose that states what an agent does.
|
|
126
140
|
- `refused`, carrying reason `no-changes`. The changed set was empty, so take the stop below.
|
|
127
141
|
|
|
@@ -137,7 +151,7 @@ The verb ships with the CLI and this body ships with the plugin, so a target hol
|
|
|
137
151
|
|
|
138
152
|
Never read an absent subcommand as a skip. Failing open is the exact defect the verb closes, and a shell that answers `command not found` reaching a body that skips on anything other than a `skip` record would ship every branch unreviewed.
|
|
139
153
|
|
|
140
|
-
The skip needs both tests to pass: every changed file matches `*.md` or `*.txt`, and no changed file sits under a behavior path. On a pass, skip review entirely and continue to Step
|
|
154
|
+
The skip needs both tests to pass: every changed file matches `*.md` or `*.txt`, and no changed file sits under a behavior path. On a pass, skip review entirely and continue to Step 8. Otherwise invoke `canon:claude-review`.
|
|
141
155
|
|
|
142
156
|
Behavior paths carry two spellings, the one a surface authors at and the one it reaches a session at, so the rule reads the same in a toolkit and in a project that consumed one:
|
|
143
157
|
|
|
@@ -156,9 +170,9 @@ The list covers this toolkit's authoring layout and the layout it installs, whic
|
|
|
156
170
|
|
|
157
171
|
The verb reads the same set from `src/autoship/paths.ts`, so a path added here belongs there too and a path added there belongs here. Two copies is what the fallback costs, and it stands until a release retires the written half.
|
|
158
172
|
|
|
159
|
-
## Step
|
|
173
|
+
## Step 7: evaluate findings
|
|
160
174
|
|
|
161
|
-
Skip this step when Step
|
|
175
|
+
Skip this step when Step 6 skipped review. Otherwise read `.canon/review/branch/review-<slug>.md` at the main worktree root. Split every finding by origin before parsing the summary line (`X critical, Y should-fix, Z minor`), since the stop exists for a defect the branch inherited rather than for one this run introduced.
|
|
162
176
|
|
|
163
177
|
- **This run caused it, at any severity.** Fix it, re-run the Step 3 verify commands, re-read the fixed file against what the finding claimed, and continue. Do not report it as a stop and do not offer the fix as a choice, which is the same stop wearing a proposal.
|
|
164
178
|
- **It predates this run, critical or should-fix.** Stop: `❌ Review found non-minor issues that predate this run. See .canon/review/branch/review-<slug>.md. Fix and run /git-ship.`
|
|
@@ -168,9 +182,9 @@ Read origin as causation rather than authorship. Staleness this run induced in a
|
|
|
168
182
|
|
|
169
183
|
Bound the repair at one pass, the way Step 3 bounds verify. When that re-read shows the finding still standing, stop: `❌ A self-introduced finding survived one fix pass. See .canon/review/branch/review-<slug>.md. Fix and run /git-ship.`
|
|
170
184
|
|
|
171
|
-
This chain owns the receipt's lifetime, which is what makes the Output block's citation resolve on a run that reaches it. `claude-docs` used to delete the current slug's receipt while running under Step
|
|
185
|
+
This chain owns the receipt's lifetime, which is what makes the Output block's citation resolve on a run that reaches it. `claude-docs` used to delete the current slug's receipt while running under Step 8 below, so the closing line named a file the same run had already removed. That sweep now reaches only reports whose branch is gone, which collects this one a branch later rather than during the run that wrote it. The cost is one receipt per live branch left in `.canon/review/branch/`, bounded by the branch count rather than by the lifetime of the checkout.
|
|
172
186
|
|
|
173
|
-
## Step
|
|
187
|
+
## Step 8: ship
|
|
174
188
|
|
|
175
189
|
Invoke `canon:git-ship`. That body owns the sequence, being the verify gate, memory capture, both doc syncs, staging, the commit grouping, the branch rename, the pull request, the CI watch, and the scoped memory review, along with the reason each step sits where it does. This step used to restate that list and the two drifted apart with nothing comparing them, so read the order there and never here.
|
|
176
190
|
|
|
@@ -201,11 +215,11 @@ Respond with up to five lines:
|
|
|
201
215
|
<Memory proposal at .canon/review/memory/memory-review-<slug>.md>
|
|
202
216
|
```
|
|
203
217
|
|
|
204
|
-
`<state>` is whatever the Step
|
|
218
|
+
`<state>` is whatever the Step 8 read returned, being `draft` or `ready, unsupervised`, rather than the state the undo asked for. Writing the word `draft` there unconditionally is what this line used to do, and it named a state no step had read.
|
|
205
219
|
|
|
206
220
|
Omit the second line if there were no minor findings, and the third if nothing routed. Omit the fourth and fifth if `claude-memory-capture` wrote no memory file this session, since an empty pen means no scoped review and no proposal. A run that routes every fact and writes none is the shape to expect, and it reports three lines.
|
|
207
221
|
|
|
208
|
-
This block replaces the one `git-ship` closes on rather than following it. The two carry the same three trailing lines and differ on the two above them, since the first names the state the read returned and the second reports the minor findings Step
|
|
222
|
+
This block replaces the one `git-ship` closes on rather than following it. The two carry the same three trailing lines and differ on the two above them, since the first names the state the read returned and the second reports the minor findings Step 7 kept, neither of which that body has a counterpart for. Emitting both reports one run twice and buries the state under a `✅ Shipped` that does not name it.
|
|
209
223
|
|
|
210
224
|
## Failure recovery
|
|
211
225
|
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: draft-readme
|
|
3
|
+
description: Why a README needs a project-type read and a confirm step, not the rewrite path docs-sync already owns
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Readme draft requirement
|
|
7
|
+
|
|
8
|
+
## Gap
|
|
9
|
+
|
|
10
|
+
Without this skill, a session drafting a README either copies the generic template from memory or reaches for `docs-sync`, which has nothing to diff a nonexistent page against and reports the topic as unrelated to any change. A scaffold-written stub meets the same dead end, since no diff touches it either. Either way the page ships with no read of `standards/readme.md`, no read of what the project actually is, and no badge chosen against its rendered value rather than its service name.
|
|
11
|
+
|
|
12
|
+
A README whose real documentation lives in `.claude/context/` or `docs/` was a second gap the standard itself carried until this build: nothing named a pointer page as complete, so a session drafting one either padded the page or read the required list as unsatisfied.
|
|
13
|
+
|
|
14
|
+
## Must
|
|
15
|
+
|
|
16
|
+
- Read `standards/readme.md` before drafting, since its `## Voice` section is scoped to a repository-root README and yields to `write-human`'s reference voice everywhere else
|
|
17
|
+
- Detect every project type the standard's `## Content` list applies to, from the manifest and the tree, rather than drafting against the closest single type
|
|
18
|
+
- Treat an existing README with no H1, or with headings that name only the scaffold that wrote it, as unedited generator output to draft over rather than a page to sync section by section
|
|
19
|
+
- Verify a candidate badge by the value it would render rather than by a fetch's status code, since a badge service answers 200 for a query it cannot satisfy
|
|
20
|
+
- Confirm the resolved path, the detected types, the badge candidates, and the full content with the user before writing, since project-type detection and badge selection are judgment calls with no diff to preview them against
|
|
21
|
+
|
|
22
|
+
## Must not
|
|
23
|
+
|
|
24
|
+
- Rewrite an authored README. One carrying an H1 that names the project refuses toward `docs-sync`.
|
|
25
|
+
- Offer to overwrite an authored README on the refusal path, or propose conforming it to what this skill would have drafted. A target project's own citations into its README are invisible from here, so the refusal reports rather than proposes.
|
|
26
|
+
- Assume this skill's own invocation frequency needs no check. Whether anything reaches for it beyond an author typing its name has no answer at creation time, so a review pass some months in should read that back rather than take the assumption on faith.
|
|
27
|
+
|
|
28
|
+
## Guards
|
|
29
|
+
|
|
30
|
+
- The target already exists and is authored, carrying an H1 that names the project: stop and point at `docs-sync` instead.
|
|
31
|
+
|
|
32
|
+
## Out of scope
|
|
33
|
+
|
|
34
|
+
- Rewriting or syncing an existing authored `README.md` against a diff since main: `docs-sync`
|
|
35
|
+
- The consumer-facing reference under `docs/`: `draft-docs`
|
|
36
|
+
- Product scope and goals, and every other surface `standards/readme.md` already scopes out of its own governance
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: draft-readme
|
|
3
|
+
description: Drafts a project's README.md against the readme standard, detecting project type and badge candidates, and confirming with the user before write. Use when asked to "write a README", "draft a README for this project", "add a README", or "create a README.md" where none exists yet or the existing one is unedited scaffold output. Do NOT use to rewrite or resync an existing authored README against a diff, which is `docs-sync`.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Readme draft
|
|
7
|
+
|
|
8
|
+
Drafts a project's `README.md` end to end: read the standard, detect the project's shape, confirm the draft with the user, then write.
|
|
9
|
+
|
|
10
|
+
Read these files in parallel:
|
|
11
|
+
|
|
12
|
+
- `${CLAUDE_SKILL_DIR}/../../standards/readme.md`: voice, structure, required and optional sections, badge selection, and what to link out to rather than carry. Voice is claimed here for a repository-root README, and `write-human` yields it there while keeping rhythm, density, and the machine-tell catalog everywhere, root README included.
|
|
13
|
+
- `${CLAUDE_SKILL_DIR}/../../standards/markdown.md`: banned words, punctuation, and formatting for all generated text
|
|
14
|
+
- The `write-human` skill: rhythm, density, and sentence construction for all generated text
|
|
15
|
+
|
|
16
|
+
## Guards
|
|
17
|
+
|
|
18
|
+
- Default the target to `README.md` at the repository root when no path is given. A caller naming a path under a folder, a harness, or an internal tool is drafting a nested README instead, which keeps the reference voice per the standard's `## Voice` section rather than the root voice below.
|
|
19
|
+
- Read the target if it exists.
|
|
20
|
+
- It carries an H1 naming the project: it is authored. Stop: `❌ <path> already exists and covers the project. Run canon:docs-sync instead.`
|
|
21
|
+
- It carries no H1, or its only headings restate the tool that scaffolded it rather than the project: it is unedited generator output. Continue, drafting over it rather than syncing its sections.
|
|
22
|
+
- It does not exist: continue.
|
|
23
|
+
- A hand-authored README opening with a badge block, or a title in some other form the H1 test misses, falls into the no-H1 branch the same as a scaffold page. The Confirm step below is what catches that case before the write happens, so treat it as load-bearing rather than a courtesy: never skip it on the reasoning that the guard already decided.
|
|
24
|
+
|
|
25
|
+
## Detect
|
|
26
|
+
|
|
27
|
+
- Read the project's manifest (`package.json`, `pyproject.toml`, `Cargo.toml`, or equivalent) for a `bin` field or CLI entry point, an installable package name, and its declared dependencies.
|
|
28
|
+
- Check for a `claude/skills/` or `.claude/skills/` folder, a `plugin.json`, or a marketplace manifest, each naming an agent-facing or marketplace-distributed surface.
|
|
29
|
+
- A project is often several of these at once. Note every type that applies rather than stopping at the first match, since the Draft step covers each one the project actually is.
|
|
30
|
+
|
|
31
|
+
## Draft
|
|
32
|
+
|
|
33
|
+
- Draft the page against `${CLAUDE_SKILL_DIR}/../../standards/readme.md`: H1, a 2-3 sentence description in plain text, then the required sections, then whichever optional sections and per-type content the Detect step found.
|
|
34
|
+
- Cover every applicable project type from the standard's `## Content` list rather than picking the closest one.
|
|
35
|
+
- Candidate badges: check for a published package (a registry field in the manifest), a CI workflow, and a `LICENSE` file.
|
|
36
|
+
- State each candidate's rendered value in the preview rather than trusting a fetch's status code, since a badge service answers 200 for a query it cannot satisfy.
|
|
37
|
+
- Pin a status badge to the branch the standard names and confirm the workflow actually triggers on that branch before offering it. Zero badges is a correct answer when nothing passes the test.
|
|
38
|
+
|
|
39
|
+
## Confirm
|
|
40
|
+
|
|
41
|
+
- Show the resolved path, the detected project types, the badge candidates and what backs each one, and the full drafted content before writing.
|
|
42
|
+
- Confirm with the user. This skill waits for that answer rather than treating the tool permission dialog as the gate, since project-type detection and badge selection are judgment calls with no diff to preview them against.
|
|
43
|
+
|
|
44
|
+
## Write
|
|
45
|
+
|
|
46
|
+
- Write the file at the confirmed path, creating the folder when it is absent.
|
|
47
|
+
- Run `canon markdown audit <path>`.
|
|
48
|
+
|
|
49
|
+
## Response format
|
|
50
|
+
|
|
51
|
+
### Preview
|
|
52
|
+
|
|
53
|
+
**Target:** `<path>` (root | nested)
|
|
54
|
+
**Detected:** `<project types>`
|
|
55
|
+
**Badges:** `<candidates, or none>`
|
|
56
|
+
|
|
57
|
+
```markdown
|
|
58
|
+
<drafted H1 and body>
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### After confirmation
|
|
62
|
+
|
|
63
|
+
```plaintext
|
|
64
|
+
✅ Drafted: <path>
|
|
65
|
+
```
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: identity
|
|
3
|
+
description: Why the mark and the card are one pick rather than two, and where the size sequence and the write folder come from before either is drafted
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Identity requirement
|
|
7
|
+
|
|
8
|
+
## Gap
|
|
9
|
+
|
|
10
|
+
Without this skill, a session asked for a logo and a social card either invents shapes with nothing behind them, or drafts the mark and the card as two separate decisions that can land on shapes that do not compose, which is the failure the task filing this skill measured by hand on every project it touched. A search across every shipped skill and standard found zero hits for `logo`, `og:image`, `og-image`, or Open Graph, so nothing in the catalog reached either output.
|
|
11
|
+
|
|
12
|
+
A session building this without a shared loop restates `draft-and-pick`'s render, hand-off, pick, and loop mechanics from scratch, which drifts from the shipped one with nothing comparing the two copies. It also guesses at the icon size sequence and the output folder rather than reading what the project already declares, and it produces one raster per size through a separate render call per size, which multiplies capture invocations for no reason `canon capture` cannot already batch.
|
|
13
|
+
|
|
14
|
+
## Must
|
|
15
|
+
|
|
16
|
+
- Detect the icon size sequence from the project's own HTML head or manifest before falling back to the stated default set
|
|
17
|
+
- Detect the write folder from the project's own static-asset convention before falling back to the project root, and announce which one decided it
|
|
18
|
+
- Draft every arm already composed inside the card frame, so one pick settles the mark's shape and its composition together
|
|
19
|
+
- Follow `draft-and-pick`'s Steps 2 through 5 for the render, hand-off, pick, and loop, rather than restating them
|
|
20
|
+
- Write the final mark as its own SVG source, not baked into a raster only
|
|
21
|
+
- Render every final size and the card in one capture call, by sharing one selector class across pages, each declared at half its target dimension to land on the literal size once the render engine's fixed 2x scale factor is applied
|
|
22
|
+
|
|
23
|
+
## Must not
|
|
24
|
+
|
|
25
|
+
- Restate `draft-and-pick`'s render, hand-off, pick, or loop mechanics
|
|
26
|
+
- Add a `## Logo` section to `standards/design.md`'s fixed section set. `src/design/parse.ts` reads a fixed key set, and no outcome behind this skill asks for a schema change.
|
|
27
|
+
- Modify `draft-and-pick`, `claude-design-extract`, `canon capture`, or `canon design render`. This skill composes all four and extending any of them is a separate change.
|
|
28
|
+
- Assume this skill's own invocation frequency needs no check. Whether anything reaches for it beyond an operator typing its name has no answer at creation time, so a review pass some months in should read that back rather than take it on faith.
|
|
29
|
+
|
|
30
|
+
## Guards
|
|
31
|
+
|
|
32
|
+
- `canon` not on PATH: stop, since the render loop and the finalize step both need it
|
|
33
|
+
- Fires on a direct request only. A run offering a logo to a project that never asked for one spends a render nobody wanted.
|
|
34
|
+
|
|
35
|
+
## Out of scope
|
|
36
|
+
|
|
37
|
+
- Wiring the produced files into a project's own HTML head or manifest, which is a separate edit this skill leaves for the operator to make against their own markup
|
|
38
|
+
- Recording the mark's construction rules in `standards/design.md`, which the task's own constraint keeps out of the fixed section set
|
|
39
|
+
- Mutating an existing logo file directly, which is a direct edit rather than a skill
|
|
40
|
+
- Auditing an implemented UI against its tokens, which `claude-ux-audit` owns
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: identity
|
|
3
|
+
description: Drafts a project's logo mark through draft-and-pick's render-and-pick loop, then composes the picked mark into an icon sequence and a 1200x630 social card. Use when asked to "make a logo", "design a logo mark", "create a favicon", "build the icon set", "generate a social card", "make an og:image", or "draft the logo and social card together". Do NOT use to mutate an existing logo file directly, which is a plain edit, or to record the mark's construction rules in DESIGN.md, which is out of scope.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Identity
|
|
7
|
+
|
|
8
|
+
One identity rendered twice: the same mark sized down to an icon sequence and composed with type into the social card sized up. Drafting both from one pick keeps the mark and its card composition from settling on shapes that do not match.
|
|
9
|
+
|
|
10
|
+
## Guards
|
|
11
|
+
|
|
12
|
+
- If `canon` is not on PATH, stop: `❌ canon CLI not found.`
|
|
13
|
+
- Draft no candidate for a mark the operator has not asked to make. This skill fires on a direct request, never on the model's own read that a project could use one.
|
|
14
|
+
|
|
15
|
+
## Step 1: read signal
|
|
16
|
+
|
|
17
|
+
Read these in parallel, skipping any that do not exist:
|
|
18
|
+
|
|
19
|
+
- `.claude/DESIGN.md`: the `## Personality`, `## Color`, and `## Typography` sections, the same three cells `claude-design-extract` Step 2 sources from
|
|
20
|
+
- `.claude/REQUIREMENTS.md`: the `## Personality` paragraph, when `.claude/DESIGN.md` carries none
|
|
21
|
+
- `CLAUDE.md`: the project's stated voice, when neither file above carries a personality signal
|
|
22
|
+
|
|
23
|
+
No signal from any of the three is not a stop. Draft against a neutral default and tag the color and type choices `? verify` per `${CLAUDE_SKILL_DIR}/../../standards/design.md`'s uncertainty tag.
|
|
24
|
+
|
|
25
|
+
## Step 2: detect the icon size sequence
|
|
26
|
+
|
|
27
|
+
Check the project's HTML entry points (`index.html`, `public/index.html`, `src/index.html`) for a `<link rel="icon">` or `<link rel="apple-touch-icon">` tag carrying a `sizes` attribute, and any `manifest.json` or `site.webmanifest` for an `icons` array. Take the union of every size found.
|
|
28
|
+
|
|
29
|
+
Fall back to the stated default when nothing is detected, since no `tooling/` stack scaffolds a `public/` folder, a favicon reference, or an `og:image` meta tag:
|
|
30
|
+
|
|
31
|
+
- `16x16`, `32x32`, `48x48`
|
|
32
|
+
- `180x180`
|
|
33
|
+
- `192x192`, `512x512`
|
|
34
|
+
|
|
35
|
+
This default set is raster-only. Step 6 already writes the vector source at `favicon.svg` regardless of which branch decided the sequence, so a project willing to reference an SVG favicon directly is covered either way.
|
|
36
|
+
|
|
37
|
+
Announce which of the two decided the sequence.
|
|
38
|
+
|
|
39
|
+
## Step 3: detect the write folder
|
|
40
|
+
|
|
41
|
+
Check for `public/`, `static/`, or a stack-declared asset folder, taking the first that exists. Fall back to the project root when none is detected, mirroring `claude-design-extract`'s own source-versus-greenfield split. Announce the folder so the operator can move the files if the project's own convention differs.
|
|
42
|
+
|
|
43
|
+
## Step 4: name the decision and the arms
|
|
44
|
+
|
|
45
|
+
Follow `${CLAUDE_SKILL_DIR}/../draft-and-pick/SKILL.md` Step 1, with the decision fixed rather than derived: "the project's logo mark and its composition into the social card." Vary the mark's shape or style across arms, keeping the card's type and layout fixed, per that skill's one-property rule. Draft each arm already inside the full 1200x630 card frame, mark and type together, so the pick settles the shape and the composition in one choice. Arm 0 is the current mark when the folder from Step 3 already holds a logo file (`favicon.svg`, `favicon.ico`, `logo.svg`, or similar). Arms start at 1 otherwise.
|
|
46
|
+
|
|
47
|
+
Structure every arm as a `.mark` element, the inline SVG alone, nested inside a `.card` element, the full composition, so Step 6 can address either without re-deriving them.
|
|
48
|
+
|
|
49
|
+
## Step 5: draft, render, pick, and loop
|
|
50
|
+
|
|
51
|
+
Follow `${CLAUDE_SKILL_DIR}/../draft-and-pick/SKILL.md` Steps 2 through 5 against the arms from Step 4: author the page, render and hand off, take the pick, and loop on it.
|
|
52
|
+
|
|
53
|
+
## Step 6: finalize
|
|
54
|
+
|
|
55
|
+
This step replaces `draft-and-pick`'s own Step 6, since the pick here produces several final files rather than one applied surface.
|
|
56
|
+
|
|
57
|
+
1. Extract the picked arm's `.mark` markup as the final vector source. Write it to `<write-folder>/favicon.svg`.
|
|
58
|
+
2. Under `<dest>/render/`, write one page per Step 2 size plus one for the card. Give every page's captured element the shared class `.render`, so one capture call renders the whole batch regardless of the size spread. `canon capture` opens every page at a fixed 2x device scale factor and screenshots the element at that scale, so declare each `.render` element at half its target dimension, `<w>/2` by `<h>/2`, to land the captured PNG on the literal target size rather than double it. Declare a machine-resolved font stack (`system-ui` behind a generic fallback) on each, since `canon capture` refuses a page naming no font at all.
|
|
59
|
+
- `icon-<w>x<h>.html`: the picked `.mark` markup, its `.render` wrapper sized `<w>/2` by `<h>/2`
|
|
60
|
+
- `og-image.html`: the picked `.card` markup, its `.render` wrapper sized 600x315 to capture at the native 1200x630
|
|
61
|
+
3. Render the batch:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
canon capture <dest>/render --selector .render --out <write-folder>
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
4. Report each written file's path and the dimensions `canon capture` printed for it, confirming each equals its Step 2 target rather than half of it.
|
|
68
|
+
5. Delete `<dest>`, per `draft-and-pick`'s own scratch-folder rule.
|
|
69
|
+
|
|
70
|
+
## Response format
|
|
71
|
+
|
|
72
|
+
```plaintext
|
|
73
|
+
📝 Wrote <write-folder>/favicon.svg
|
|
74
|
+
📝 Wrote <write-folder>/icon-16x16.png (16x16)
|
|
75
|
+
📝 Wrote <write-folder>/og-image.png (1200x630)
|
|
76
|
+
|
|
77
|
+
Write folder: <detected <path>|defaulted to project root>. Move the files if this project's own convention differs.
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## What this delegates
|
|
81
|
+
|
|
82
|
+
Cite these rather than restating them.
|
|
83
|
+
|
|
84
|
+
- `draft-and-pick` owns Steps 1 through 5 of the render-and-pick loop, cited above
|
|
85
|
+
- `claude-design-extract` owns building `.claude/DESIGN.md`. This skill only reads it.
|
|
86
|
+
- `canon capture` owns the render mechanics, its font refusal, and its reported dimensions
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: test-first
|
|
3
|
+
description: Why the loop exists and where it stops short of a debugging session or a visual check
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Test first requirement
|
|
7
|
+
|
|
8
|
+
## Gap
|
|
9
|
+
|
|
10
|
+
Without this skill, a session implementing a planned change writes the test after the code, or writes both in one motion and never runs the test against the code as it stood before. Either way, nothing showed that the test would have caught the defect it exists to catch, so a test added after the fact protects nothing beyond what the author was already confident about.
|
|
11
|
+
|
|
12
|
+
## Must
|
|
13
|
+
|
|
14
|
+
- Write or extend the test before the implementation it covers, for any behavior whose shape is already known
|
|
15
|
+
- Run the test before implementing and confirm it fails for the missing behavior, not for an unrelated mistake in the test itself
|
|
16
|
+
- Implement the minimum the current test demands, and start a new test before extending past it
|
|
17
|
+
- Re-run the test after implementing and confirm the pass is the one the test was written to prove
|
|
18
|
+
|
|
19
|
+
## Must not
|
|
20
|
+
|
|
21
|
+
- Write the implementation and the test together with the test never run red first
|
|
22
|
+
- Treat a test that already passes before any code change as evidence for the new behavior
|
|
23
|
+
- Restate the reproducing-test step `canon:systematic-debugging` already owns for a failure with no known cause
|
|
24
|
+
- Decide whether a change looks right visually, which runs after implementation as a separate check
|
|
25
|
+
|
|
26
|
+
## Guards
|
|
27
|
+
|
|
28
|
+
- A test failing for a reason other than the missing behavior blocks moving to implementation. Fix the test first.
|
|
29
|
+
|
|
30
|
+
## Out of scope
|
|
31
|
+
|
|
32
|
+
- Finding the cause of an unexplained failure: `canon:systematic-debugging`
|
|
33
|
+
- Confirming visual output after a change lands: `070-planning.md` states the order and `claude-ui-test` covers it
|
|
34
|
+
- The mechanical audit of whether an implementation reached history ahead of its test: `canon gov test-order`, invoked from `claude-autoship`
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: test-first
|
|
3
|
+
description: Write the failing test for a behavior before writing the code that satisfies it, confirm it fails for the right reason, then implement the smallest change that turns it green. Auto-triggers before implementing a planned feature, adding a function or an endpoint, or extending existing behavior whose new shape is already decided. Do NOT use for a failure with no known cause, which is canon:systematic-debugging, or when the test for the behavior already exists and already passes.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Test first
|
|
7
|
+
|
|
8
|
+
## The loop
|
|
9
|
+
|
|
10
|
+
1. Find or write the test for the behavior before touching the code it covers. Follow the pairing convention the project already uses, which is commonly a test sitting beside its subject under one name, so that `foo.ts` takes `foo.test.ts` beside it.
|
|
11
|
+
2. Write the test against the behavior as it should exist once the change lands, naming the case for what it proves rather than for the function it calls.
|
|
12
|
+
3. Run only that test and read the failure. Confirm it fails because the behavior is missing, not because of a typo, a missing import, or a signature the test itself got wrong. A test failing for the wrong reason still reads green the moment any code exists to satisfy that wrong reason, so treat any other failure as a defect in the test and fix the test before moving on.
|
|
13
|
+
4. Implement the smallest change that turns the failure into a pass. Do not add behavior the test does not ask for. A second behavior wants its own test written first, not a shortcut folded into the change already open.
|
|
14
|
+
5. Run the test again and confirm it passes for the reason it was written for, not by accident. Then run the surrounding suite so a change made to satisfy this test has not broken another.
|
|
15
|
+
|
|
16
|
+
## Extending existing behavior
|
|
17
|
+
|
|
18
|
+
- Changing what a function already does starts with changing what its test asserts. Run that changed test once before touching the implementation, and confirm it fails against the code as it stands today.
|
|
19
|
+
- A test that already passes before any code changes proves nothing about the new behavior. Widen the assertion or add a case until the suite fails against the current implementation.
|
|
20
|
+
|
|
21
|
+
## What this skill does not cover
|
|
22
|
+
|
|
23
|
+
- A failure with no known cause. Route through `canon:systematic-debugging` first, whose own fix phase already writes the reproducing test as part of finding the cause. This skill starts once the shape of the fix or the feature is already decided.
|
|
24
|
+
- Confirming a change looks right once it has landed, which is a separate concern from whether the test passed and runs after implementation rather than before it.
|
package/docs/agents/demo.md
CHANGED
|
@@ -23,6 +23,8 @@ So `canon demo compile` writes a second artifact rather than adding fields to a
|
|
|
23
23
|
|
|
24
24
|
The plan is committed, not scratch. Its timing is a starting point tuned by watching a recording, and the draft cannot reproduce a tuned value, so a recompile over an existing plan refuses and names `--force`.
|
|
25
25
|
|
|
26
|
+
`canon-record` is the routed way to run both verbs from a draft path: it compiles only when no plan exists yet, then runs, stopping to report any field still unresolved rather than guessing one.
|
|
27
|
+
|
|
26
28
|
| Option | Behavior |
|
|
27
29
|
| --------------- | ----------------------------------------------------------------- |
|
|
28
30
|
| `--out <dir>` | Directory the plan and its output paths point at, default `demos` |
|
|
@@ -64,13 +64,13 @@ An empty set refuses with `no-changes` rather than skipping. Both tests are univ
|
|
|
64
64
|
|
|
65
65
|
## Why it is a verb
|
|
66
66
|
|
|
67
|
-
The decision was three sentences in `claude-autoship`
|
|
67
|
+
The decision was three sentences in `claude-autoship`'s review step, applied by a session reading a bulleted list of paths. It failed three times. A driven arm on 2026-08-30 staged `.claude/skills/deploy-check/SKILL.md`, which that list names, and the chain skipped review and opened a draft pull request anyway. The rule was correct and the session did not apply it, and the two fixes before that one were each a rewrite of the same prose.
|
|
68
68
|
|
|
69
69
|
A rule a session can talk itself out of moves into a verb. That is the same argument the quiz-order draw in `canon teach lesson` was decided on: an instruction is a hope where a verb is a check.
|
|
70
70
|
|
|
71
71
|
## The written fallback
|
|
72
72
|
|
|
73
|
-
The verb ships with the CLI and Step
|
|
73
|
+
The verb ships with the CLI and Step 6 ships with the plugin, so a target holding an older binary meets a missing subcommand. The skill body keeps the written list and applies it by hand there, naming which of the two decided the run.
|
|
74
74
|
|
|
75
75
|
The fallback is never a skip. Failing open is the exact defect the verb closes, so a body that skips on anything other than a `skip` record would ship every branch unreviewed the moment the subcommand went absent.
|
|
76
76
|
|
|
@@ -157,7 +157,7 @@ The list stays written in the skill body as the fallback for a target whose inst
|
|
|
157
157
|
|
|
158
158
|
#### Memory in the chain
|
|
159
159
|
|
|
160
|
-
`git-ship` runs its verify gate and then opens on `claude-memory-capture`, which sends what the session learned to the surface that owns it. `autoship` reaches the same step by invoking that skill at its Step
|
|
160
|
+
`git-ship` runs its verify gate and then opens on `claude-memory-capture`, which sends what the session learned to the surface that owns it. `autoship` reaches the same step by invoking that skill at its Step 8 rather than restating the order. A fact about a domain carrying an entry in `.claude/context/index.md` is routed to that entry, and `claude-docs` folds it in on the next step, so it ships in the same pull request. Anything no entry owns stays a file in `.canon/memory/`.
|
|
161
161
|
|
|
162
162
|
Capture leads rather than trails because a routed fact edits a tracked file, which has to reach the branch before the commit steps run.
|
|
163
163
|
|
|
@@ -219,13 +219,14 @@ This section is the corpus the coverage claim is measured against: every name `c
|
|
|
219
219
|
|
|
220
220
|
### Build the feature
|
|
221
221
|
|
|
222
|
-
| Skill | When to use
|
|
223
|
-
| ---------------------------- |
|
|
224
|
-
| `canon:claude-worktree` | At the plan-to-execute boundary, to get an isolated tree and branch
|
|
225
|
-
| `canon:claude-autoship` | After plan approval, to chain implement, verify, review, draft PR
|
|
226
|
-
| `canon:project-commands` | When the project's own command needs running
|
|
227
|
-
| `canon:
|
|
228
|
-
| `canon:
|
|
222
|
+
| Skill | When to use |
|
|
223
|
+
| ---------------------------- | ------------------------------------------------------------------------- |
|
|
224
|
+
| `canon:claude-worktree` | At the plan-to-execute boundary, to get an isolated tree and branch |
|
|
225
|
+
| `canon:claude-autoship` | After plan approval, to chain implement, verify, review, draft PR |
|
|
226
|
+
| `canon:project-commands` | When the project's own command needs running |
|
|
227
|
+
| `canon:test-first` | Before implementing a planned change, to write and run its test red first |
|
|
228
|
+
| `canon:systematic-debugging` | When a test fails or a bug surfaces, to force root cause first |
|
|
229
|
+
| `canon:claude-ui-test` | After a UI change, to generate e2e tests and a visual checklist |
|
|
229
230
|
|
|
230
231
|
### Check the work before it leaves the branch
|
|
231
232
|
|
|
@@ -294,11 +295,14 @@ This section is the corpus the coverage claim is measured against: every name `c
|
|
|
294
295
|
| `canon:draft-docs` | For a brand-new `docs/*.md` page, drafted against `standards/docs.md` |
|
|
295
296
|
| `canon:draft-context` | For a brand-new `.claude/context/<domain>.md` entry, drafted against `standards/context.md` |
|
|
296
297
|
| `canon:draft-wireframes` | For a brand-new `.claude/wireframes/<surface>.md` file, drafted against `standards/wireframes.md` |
|
|
298
|
+
| `canon:draft-readme` | For a project's `README.md`, drafted against `standards/readme.md` |
|
|
297
299
|
| `canon:bash-script` | For an interactive, human-facing shell tool |
|
|
298
300
|
| `canon:bash-cli-script` | For a non-interactive automation, CI, or pipeline script |
|
|
299
301
|
| `canon:ci-workflow` | For a GitHub Actions workflow file |
|
|
300
302
|
| `canon:canon-slides-draft` | For a deck, drafted as `.claude/SLIDES.md` and rendered to PowerPoint |
|
|
301
303
|
| `canon:canon-screencast` | For a recording script with beats and defaults already seeded |
|
|
304
|
+
| `canon:canon-record` | For compiling and running a screencast draft into a recording and a still |
|
|
305
|
+
| `canon:identity` | For a project's logo mark and its social card, drafted through `draft-and-pick`'s pick loop |
|
|
302
306
|
|
|
303
307
|
### Answer a question at any point
|
|
304
308
|
|
|
@@ -40,6 +40,7 @@ A cell no source anchors ends in `? verify`, and the preview shows that marker b
|
|
|
40
40
|
- `canon:claude-ux-audit` for UX gap detection on existing surfaces
|
|
41
41
|
- `canon:claude-ux-measure` for what a running surface costs to paint, read against published thresholds
|
|
42
42
|
- `canon:draft-and-pick` for a call settled by looking, drafting several candidates onto one page and taking your pick
|
|
43
|
+
- `canon:identity` to draft a project's logo mark and compose it into an icon sequence and a social card, through `draft-and-pick`'s own render-and-pick loop
|
|
43
44
|
- Anthropic's `frontend-design` plugin optional for light visual steering
|
|
44
45
|
|
|
45
46
|
### When to pick
|
|
@@ -13,6 +13,7 @@ description: Enforce planning standards before implementation
|
|
|
13
13
|
- Propose the simplest solution that satisfies the requirement before implementing complex patterns.
|
|
14
14
|
- Write or update tests as part of every implementation plan.
|
|
15
15
|
- Write the test for a behavior before the code that implements it. Confirm visual output after implementing it, not before.
|
|
16
|
+
- Load the `canon:test-first` skill before writing the implementation for a behavior whose test does not exist yet, and report it rather than proceeding silently when the skill does not resolve.
|
|
16
17
|
- Run `canon gov test-order` before shipping a branch. Fix what it names as reaching history ahead of its test.
|
|
17
18
|
- Load the `canon:systematic-debugging` skill before proposing a fix for a failing test, a surfaced bug, or behavior nobody has explained yet, and report it rather than proceeding silently when the skill does not resolve.
|
|
18
19
|
- Do not modify code without a confirmed plan.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@erclx/canon",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "4.
|
|
4
|
+
"version": "4.64.0",
|
|
5
5
|
"description": "Infrastructure and quality tooling for developer workflows",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"bin": {
|
|
@@ -62,9 +62,11 @@
|
|
|
62
62
|
"@tailwindcss/vite": "^4.2.4",
|
|
63
63
|
"@testing-library/jest-dom": "^6.9.1",
|
|
64
64
|
"@types/bun": "^1.2.10",
|
|
65
|
+
"@types/micromatch": "^4.0.10",
|
|
65
66
|
"astro": "^6.1.9",
|
|
66
67
|
"cspell": "^8.17.1",
|
|
67
68
|
"husky": "^9.1.7",
|
|
69
|
+
"micromatch": "^4.0.8",
|
|
68
70
|
"prettier": "^3.8.1",
|
|
69
71
|
"prettier-plugin-astro": "^0.14.1",
|
|
70
72
|
"prettier-plugin-tailwindcss": "^0.7.2",
|
|
@@ -202,7 +202,7 @@ const summary = {
|
|
|
202
202
|
}
|
|
203
203
|
|
|
204
204
|
const fixture = {
|
|
205
|
-
// Read by web/src/components/
|
|
205
|
+
// Read by web/src/components/agent-view.astro. Every field below is either a
|
|
206
206
|
// live read or a hand transcription, and this header is what says which.
|
|
207
207
|
generatedBy: "scripts/core/regen-agent-fixture.sh",
|
|
208
208
|
readAt: READ_AT,
|
|
@@ -42,6 +42,10 @@ export const AUTHORING_CASES: readonly SkillCase[] = [
|
|
|
42
42
|
'Write a brand-new docs page for the capture command, nothing under docs/ covers it yet.',
|
|
43
43
|
expect: 'draft-docs',
|
|
44
44
|
},
|
|
45
|
+
{
|
|
46
|
+
prompt: 'This project has no README.md at all, write one from scratch.',
|
|
47
|
+
expect: 'draft-readme',
|
|
48
|
+
},
|
|
45
49
|
{
|
|
46
50
|
prompt:
|
|
47
51
|
'Write a context entry for the payments domain, there is no .claude/context page for it yet.',
|
|
@@ -79,6 +79,11 @@ export const CLAUDE_WORKFLOW_CASES: readonly SkillCase[] = [
|
|
|
79
79
|
prompt: 'Post a formal review with findings on that open pull request.',
|
|
80
80
|
expect: 'claude-pr-review',
|
|
81
81
|
},
|
|
82
|
+
{
|
|
83
|
+
prompt:
|
|
84
|
+
'The screencast draft is finished. Turn it into an actual video now.',
|
|
85
|
+
expect: 'canon-record',
|
|
86
|
+
},
|
|
82
87
|
{
|
|
83
88
|
prompt:
|
|
84
89
|
'Look over everything that changed on this branch for bugs and edge cases.',
|
package/src/claude/cases/misc.ts
CHANGED
|
@@ -12,6 +12,11 @@ export const MISC_CASES: readonly SkillCase[] = [
|
|
|
12
12
|
'Show me a few different treatments for this callout so I can pick one by looking.',
|
|
13
13
|
expect: 'draft-and-pick',
|
|
14
14
|
},
|
|
15
|
+
{
|
|
16
|
+
prompt:
|
|
17
|
+
'This project has no logo yet. Draft one and give me a social card to go with it.',
|
|
18
|
+
expect: 'identity',
|
|
19
|
+
},
|
|
15
20
|
{
|
|
16
21
|
prompt: 'Fire up the dev server the way this project documents it.',
|
|
17
22
|
expect: 'project-commands',
|
|
@@ -29,6 +34,11 @@ export const MISC_CASES: readonly SkillCase[] = [
|
|
|
29
34
|
prompt: "This test just started failing and I don't know why yet.",
|
|
30
35
|
expect: 'systematic-debugging',
|
|
31
36
|
},
|
|
37
|
+
{
|
|
38
|
+
prompt:
|
|
39
|
+
"I'm about to write the retry helper we settled on and nothing covers it yet, so get the failing case in first.",
|
|
40
|
+
expect: 'test-first',
|
|
41
|
+
},
|
|
32
42
|
{
|
|
33
43
|
prompt: 'Does our github about text still match what the readme says?',
|
|
34
44
|
expect: 'repo-metadata',
|
package/standards/readme.md
CHANGED
|
@@ -46,6 +46,8 @@ Scoped to the README at a repository root. A nested README documenting a folder,
|
|
|
46
46
|
- Do not include license text. Reference the `LICENSE` file.
|
|
47
47
|
- Do not include detailed contribution guidelines. Reference `CONTRIBUTING.md`.
|
|
48
48
|
- Do not include extensive troubleshooting guides. Use a wiki or separate documentation.
|
|
49
|
+
- A README that points to the project's own context entries instead of restating them satisfies the required list by routing rather than carrying. A repository documented in `docs/` or `.claude/context/` names the entry point and the listing command, then stops. The reader is one hop away, the same way `## Badges` treats zero as complete.
|
|
50
|
+
- A README missing an H1, or whose headings restate the tool that scaffolded it rather than the project, is unedited generator output rather than a page anyone wrote. Draft over it. Nothing here asks a session to preserve a section a scaffold wrote and nobody replaced.
|
|
49
51
|
|
|
50
52
|
### Badges
|
|
51
53
|
|
|
@@ -50,10 +50,16 @@ export default defineConfig([
|
|
|
50
50
|
],
|
|
51
51
|
'check-file/folder-naming-convention': [
|
|
52
52
|
'error',
|
|
53
|
-
{ 'src/**/!(__tests__
|
|
53
|
+
{ 'src/**/!(__tests__)/': 'KEBAB_CASE' },
|
|
54
54
|
],
|
|
55
55
|
},
|
|
56
56
|
},
|
|
57
|
+
{
|
|
58
|
+
files: ['src/pages/**/*.{ts,tsx,astro}'],
|
|
59
|
+
rules: {
|
|
60
|
+
'check-file/folder-naming-convention': 'off',
|
|
61
|
+
},
|
|
62
|
+
},
|
|
57
63
|
{
|
|
58
64
|
files: ['**/*.{jsx,tsx}'],
|
|
59
65
|
plugins: {
|
|
@@ -21,7 +21,7 @@ The astro stack covers Astro + TypeScript projects: content sites, marketing sit
|
|
|
21
21
|
- `vitest.config.ts`: uses `getViteConfig` from `astro/config` (not `mergeConfig`). jsdom, globals, setup file, `passWithNoTests: true`, v8 coverage, `**/*.astro` in coverage excludes.
|
|
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
|
-
- `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`
|
|
24
|
+
- `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 `.claude/context/tooling.md` for the measurement.
|
|
25
25
|
|
|
26
26
|
## Typecheck
|
|
27
27
|
|
|
@@ -59,15 +59,16 @@ export default defineConfig([
|
|
|
59
59
|
],
|
|
60
60
|
'check-file/folder-naming-convention': [
|
|
61
61
|
'error',
|
|
62
|
-
{ 'src/**/!(__tests__)': 'KEBAB_CASE' },
|
|
62
|
+
{ 'src/**/!(__tests__)/': 'KEBAB_CASE' },
|
|
63
63
|
],
|
|
64
64
|
},
|
|
65
65
|
},
|
|
66
66
|
{
|
|
67
|
-
// App Router route and layout files export non-component values (metadata, route handlers), which
|
|
67
|
+
// App Router route and layout files export non-component values (metadata, route handlers) and use bracket, paren, and at-sign folder syntax (dynamic segments, route groups, parallel slots), which these rules flag as violations.
|
|
68
68
|
files: ['src/app/**/*.{ts,tsx}'],
|
|
69
69
|
rules: {
|
|
70
70
|
'react-refresh/only-export-components': 'off',
|
|
71
|
+
'check-file/folder-naming-convention': 'off',
|
|
71
72
|
},
|
|
72
73
|
},
|
|
73
74
|
{
|
|
@@ -19,7 +19,7 @@ The nextjs stack covers Next.js + TypeScript projects using the App Router. It s
|
|
|
19
19
|
- `next.config.ts`: `agentRules: false` stops Next from regenerating `AGENTS.md`/`CLAUDE.md` on every run, which would otherwise compete with the root `CLAUDE.md`. `turbopack.root: import.meta.dirname` pins the workspace root, silencing Next's multi-lockfile inference warning in any checkout carrying more than one lockfile above the project, a worktree included.
|
|
20
20
|
- `vitest.config.ts`: plain `defineConfig`, no `mergeConfig` or `getViteConfig` since Next has no Vite config to merge from. jsdom, globals, setup file, `passWithNoTests: true`, v8 coverage, `.next/**` in test excludes.
|
|
21
21
|
- `playwright.config.ts`: all browsers, `webServer` runs `bun run build && bun run preview` on port `3000` plus `WORKTREE_PORT_OFFSET`, `reuseExistingServer: false`. `DIST_PREBUILT` drops the `build` half, matching the astro stack's flag.
|
|
22
|
-
- `eslint.config.js`: overrides the web layer with `.next` and `next-env.d.ts` added to `globalIgnores`, keeping `react-hooks`/`react-refresh` since this stack still ships React components. `react-refresh/only-export-components` is `off` for `src/app/**`, since route and layout files export non-component values the rule would otherwise flag.
|
|
22
|
+
- `eslint.config.js`: overrides the web layer with `.next` and `next-env.d.ts` added to `globalIgnores`, keeping `react-hooks`/`react-refresh` since this stack still ships React components. `react-refresh/only-export-components` is `off` for `src/app/**`, since route and layout files export non-component values the rule would otherwise flag. `check-file/folder-naming-convention` is `off` for the same subtree, since App Router's bracket, paren, and at-sign folder syntax (dynamic segments, route groups, parallel slots) fails `KEBAB_CASE`.
|
|
23
23
|
|
|
24
24
|
## Port
|
|
25
25
|
|