@erclx/canon 4.98.0 → 4.100.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/README.md +24 -6
- package/claude/.claude-plugin/plugin.json +1 -1
- package/claude/skills/auto-ship/SKILL.md +6 -4
- package/claude/skills/draft-and-pick/REQUIREMENT.md +1 -1
- package/claude/skills/draft-and-pick/SKILL.md +1 -1
- package/claude/skills/draft-ready/SKILL.md +3 -3
- package/claude/skills/git-pr/SKILL.md +41 -21
- package/claude/skills/test-craft/REQUIREMENT.md +1 -1
- package/claude/skills/test-first/REQUIREMENT.md +1 -1
- package/claude/skills/ui-checklist/REQUIREMENT.md +49 -0
- package/claude/skills/ui-checklist/SKILL.md +71 -0
- package/claude/skills/ux-audit/REQUIREMENT.md +1 -1
- package/claude/skills/ux-measure/REQUIREMENT.md +1 -1
- package/docs/agents/capture.md +6 -2
- package/docs/agents/demo.md +3 -1
- package/docs/agents/pr-evidence.md +34 -11
- package/docs/agents/pr-preview.md +4 -3
- package/docs/agents/tasks.md +3 -1
- package/docs/workflow/ai-workflow.md +4 -4
- package/docs/workflow/visual-design-workflow.md +2 -2
- package/package.json +1 -1
- package/scripts/core/regen-hero.sh +36 -3
- package/src/claude/cases/workflow.ts +3 -2
- package/src/commands/demo.ts +4 -3
- package/src/commands/pr.ts +53 -1
- package/src/commands/tasks.ts +16 -0
- package/src/demo/compile.ts +20 -0
- package/src/demo/drive.ts +1 -0
- package/src/migrate/skill-names.ts +14 -6
- package/src/pr/evidence.ts +36 -1
- package/src/sandbox/expect.ts +2 -1
- package/src/tasks/archive.ts +115 -3
- package/standards/ready.md +2 -2
- package/standards/tasks.md +4 -2
- package/tooling/web/configs/e2e/screenshot.ts +155 -11
- package/tooling/web/reference.md +2 -2
- package/claude/skills/ui-test/REQUIREMENT.md +0 -48
- package/claude/skills/ui-test/SKILL.md +0 -87
package/README.md
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
<div align="center">
|
|
2
2
|
|
|
3
|
-
<
|
|
3
|
+
<picture>
|
|
4
|
+
<source media="(prefers-color-scheme: dark)" srcset="assets/brand/mark-accent.svg">
|
|
5
|
+
<img src="assets/brand/mark-accent-light.svg" alt="canon" width="56" height="56">
|
|
6
|
+
</picture>
|
|
4
7
|
|
|
5
8
|
# canon
|
|
6
9
|
|
|
@@ -14,7 +17,10 @@ canon is a CLI and Claude Code plugin that stops your AI conventions drifting ap
|
|
|
14
17
|
|
|
15
18
|
</div>
|
|
16
19
|
|
|
17
|
-
|
|
20
|
+
<picture>
|
|
21
|
+
<source media="(prefers-color-scheme: dark)" srcset="assets/evidence/arrival.png">
|
|
22
|
+
<img src="assets/evidence/arrival-light.png" alt="The first screen of the canon landing page, a project before and after one canon init, with the file counts each step lays down">
|
|
23
|
+
</picture>
|
|
18
24
|
|
|
19
25
|
The page is one real session the toolkit ran on itself, and every count on it is read from the repo when the page builds.
|
|
20
26
|
|
|
@@ -39,7 +45,10 @@ claude plugin marketplace add https://github.com/erclx/canon
|
|
|
39
45
|
claude plugin install canon@canon
|
|
40
46
|
```
|
|
41
47
|
|
|
42
|
-
|
|
48
|
+
<picture>
|
|
49
|
+
<source media="(prefers-color-scheme: dark)" srcset="assets/evidence/install.png">
|
|
50
|
+
<img src="assets/evidence/install-light.png" alt="Adding the canon marketplace and installing the plugin in Claude Code">
|
|
51
|
+
</picture>
|
|
43
52
|
|
|
44
53
|
The skills land as `/canon:<name>`. If your session was already open, run `/reload-plugins` to pick them up.
|
|
45
54
|
|
|
@@ -67,15 +76,24 @@ Each domain has a canonical source in this repo and a thin install or sync CLI o
|
|
|
67
76
|
| Transcripts | A YouTube transcript with metadata frontmatter | `canon transcripts <url>` writes it into any repo |
|
|
68
77
|
| Sandbox | Scenario scaffolds that provision an isolated project state for verifying each domain flow | `canon sandbox` |
|
|
69
78
|
|
|
70
|
-
|
|
79
|
+
<picture>
|
|
80
|
+
<source media="(prefers-color-scheme: dark)" srcset="assets/evidence/catalog.png">
|
|
81
|
+
<img src="assets/evidence/catalog-light.png" alt="The canon catalog as a ledger of five rows, with the count each ships and a few real names: skills, rules, standards, commands, and stacks">
|
|
82
|
+
</picture>
|
|
71
83
|
|
|
72
84
|
Every count in that image is read from the catalogs when it is built, so they're what the repo ships today. A tooling stack lands as real files under version control, because a config is something your build reads and your project owns. A standard stays here and is opened by name, so there is no copy in your repo to drift from this one. Governance is the third shape. A rule with a path glob loads only when a matching path is edited, and a rule with none loads every session. Run `canon gov list` to see the glob beside each rule.
|
|
73
85
|
|
|
74
86
|
Two of the outputs are documents you open rather than files you run. A `SLIDES.md` renders to a deck, and a learning workspace renders to a small site.
|
|
75
87
|
|
|
76
|
-
|
|
88
|
+
<picture>
|
|
89
|
+
<source media="(prefers-color-scheme: dark)" srcset="examples/slides/evidence/showcase-dark-04.png">
|
|
90
|
+
<img src="examples/slides/evidence/showcase-light-04.png" alt="A slide from the showcase deck rendered by canon slides render, a bulleted list under a heading on a warm background">
|
|
91
|
+
</picture>
|
|
77
92
|
|
|
78
|
-
|
|
93
|
+
<picture>
|
|
94
|
+
<source media="(prefers-color-scheme: dark)" srcset="examples/teach/evidence/root-listing.png">
|
|
95
|
+
<img src="examples/teach/evidence/root-listing-light.png" alt="The learning workspace listing rendered by canon teach, three workspaces with their lesson and term counts, one still a stub">
|
|
96
|
+
</picture>
|
|
79
97
|
|
|
80
98
|
## It runs on itself
|
|
81
99
|
|
|
@@ -117,13 +117,15 @@ The verb reads git history rather than the working tree, so a branch with nothin
|
|
|
117
117
|
|
|
118
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
119
|
|
|
120
|
-
## Step 5: UI
|
|
120
|
+
## Step 5: UI checklist (conditional)
|
|
121
121
|
|
|
122
|
-
If the diff touches UI files (JSX, TSX, Vue, Svelte, HTML, or CSS under `src/`), invoke `canon:ui-
|
|
122
|
+
If the diff touches UI files (JSX, TSX, Vue, Svelte, HTML, or CSS under `src/`), invoke `canon:ui-checklist`.
|
|
123
123
|
|
|
124
|
-
If `ui-
|
|
124
|
+
If `ui-checklist` produces a checklist, stop: `❌ UI requires visual verification. Checklist at .canon/tmp/handoff/ui-checklist/<slug>.md, which reaches the pull request once /git-ship runs. Verify manually, then run /git-ship.`
|
|
125
125
|
|
|
126
|
-
|
|
126
|
+
The stop is unchanged by that skill's shrink. The checklist is now the step's whole output rather than the visual remainder beside the tests it wrote, so the stop is the only thing that makes the operator look before `git-ship`.
|
|
127
|
+
|
|
128
|
+
If there is nothing to verify visually and nothing shipping untested, continue.
|
|
127
129
|
|
|
128
130
|
## Step 6: review
|
|
129
131
|
|
|
@@ -68,7 +68,7 @@ The refusal strings sit in the body, since the runtime loads that file and ignor
|
|
|
68
68
|
- `plan-feature` plans the work once the answer is settled, and declares the pull request boundary its plan carries. This produces the answer to pick from and stops before the plan.
|
|
69
69
|
- `ux-audit` reads source to find roughness and reports it. This takes its input from the operator and changes nothing until they pick.
|
|
70
70
|
- `ux-measure` measures what a running interface costs to paint. This measures whatever a visual claim depends on, which is usually geometry or contrast rather than cost.
|
|
71
|
-
- `ui-
|
|
71
|
+
- `ui-checklist` writes what to look at on a change already made. This runs before there is a change to look at.
|
|
72
72
|
- `draft-screencast` scripts a recording of something already built. This has nothing built yet.
|
|
73
73
|
- `canon capture`, `canon serve`, and `canon drive` own the render, the address, and the probes, and are invoked rather than reimplemented.
|
|
74
74
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: draft-and-pick
|
|
3
|
-
description: Drafts several candidates for a decision judged by looking, renders them side by side on one page, hands the operator the addresses, takes the pick through the structured question surface, and loops on the pick until they stop. Use when asked to "draft some options", "show me a few versions", "try a few variations", "mock up alternatives", "give me candidates for X", or when a choice is taste rather than correctness. Do NOT use when the request already names the answer and asks for it to be built, which is `plan-feature`. Do NOT use to read source for roughness, which is `ux-audit`, to measure what a running interface costs to paint, which is `ux-measure`, to write
|
|
3
|
+
description: Drafts several candidates for a decision judged by looking, renders them side by side on one page, hands the operator the addresses, takes the pick through the structured question surface, and loops on the pick until they stop. Use when asked to "draft some options", "show me a few versions", "try a few variations", "mock up alternatives", "give me candidates for X", or when a choice is taste rather than correctness. Do NOT use when the request already names the answer and asks for it to be built, which is `plan-feature`. Do NOT use to read source for roughness, which is `ux-audit`, to measure what a running interface costs to paint, which is `ux-measure`, to write what to look at on a change already made, which is `ui-checklist`, to script a recording, which is `draft-screencast`, or to inspect a running app across many findings, which is `ux-walkthrough`.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Draft and pick
|
|
@@ -73,7 +73,7 @@ Write `<main-root>/.canon/tasks/<label>-<slug>.md` by heredoc, from the label St
|
|
|
73
73
|
canon tasks plan-link <task-stem> .canon/plans/feature-<slug>.md --json
|
|
74
74
|
```
|
|
75
75
|
|
|
76
|
-
Branch on the record rather than on the exit. `Ready:`
|
|
76
|
+
Branch on the record rather than on the exit. The `Ready:` line orients a worker reading the task, and `canon tasks archive` reads it to move the folder on ship.
|
|
77
77
|
|
|
78
78
|
A task file with no row is a dropped task, so place the row in the same pass. The plan exists, so the row takes `## Run now` when `canon tasks plan-reach` reports nothing claimed and `## Up next` otherwise, with the held path in its `Waiting on` cell, per the tests in `${CLAUDE_SKILL_DIR}/../../standards/tasks.md`. Check the roster the way `canon:task-board` Step 4 does, reading `canon sessions list --self --json` for this session and `canon sessions list --json` for a row from the same repository, under another `sessionId`, whose `name` starts with `orchestrator-`. Treat a refused read as a roster read that failed.
|
|
79
79
|
|
|
@@ -106,10 +106,10 @@ Fix what the records name in the files this run wrote and re-run once. Report a
|
|
|
106
106
|
Plan: .canon/plans/feature-<slug>.md
|
|
107
107
|
Task: .canon/tasks/<label>-<slug>.md
|
|
108
108
|
Row: <label> <title>, <written under ## Run now | reported to <orchestrator name> | left for the operator to place>, <reason>
|
|
109
|
-
Archive on ship:
|
|
109
|
+
Archive on ship: canon tasks archive moves the folder to .canon/ready/archive/<nn>-<slug>/
|
|
110
110
|
```
|
|
111
111
|
|
|
112
|
-
Name the archive move every time
|
|
112
|
+
Name the archive move every time, so whoever ships knows the verb carries the folder and needs no step of their own.
|
|
113
113
|
|
|
114
114
|
## Rules
|
|
115
115
|
|
|
@@ -152,54 +152,72 @@ rm -rf .canon/tmp/pr/body
|
|
|
152
152
|
printf 'number=%s\nurl=%s\n' "$pr_number" "$pr_url"
|
|
153
153
|
```
|
|
154
154
|
|
|
155
|
-
###
|
|
155
|
+
### Find the UI checklist
|
|
156
156
|
|
|
157
|
-
`ui-
|
|
157
|
+
`ui-checklist` writes a visual checklist to `.canon/tmp/handoff/ui-checklist/<slug>.md` at the main worktree root when a change needs visual verification, with `<slug>` derived per `${CLAUDE_SKILL_DIR}/../../standards/slug.md`. This skill is the file's sole consumer. Resolve the main root the way `session-worktree` does (`git worktree list --porcelain | grep -m 1 '^worktree ' | cut -d' ' -f2-`, falling back to `pwd`) and check for the file there. A missing file means no checklist was produced, and the two steps below each skip their checklist half.
|
|
158
158
|
|
|
159
|
-
When it exists, scan it against `${CLAUDE_SKILL_DIR}/../../standards/publish.md` before
|
|
159
|
+
When it exists, scan it against `${CLAUDE_SKILL_DIR}/../../standards/publish.md` before either step posts it, the same as the pull request body above.
|
|
160
|
+
|
|
161
|
+
Where it lands is decided by the evidence step below rather than here, since a checklist reads next to the screenshots it annotates and posting it on its own is the fallback for a branch that changed no screenshot.
|
|
162
|
+
|
|
163
|
+
### Post the evidence comparison
|
|
164
|
+
|
|
165
|
+
Run the verb once against the number the pull request step above resolved, passing `--checklist` when the step above found a file and leaving it off when it did not:
|
|
160
166
|
|
|
161
167
|
```bash
|
|
162
|
-
|
|
168
|
+
canon pr evidence <number> --checklist <main-root>/.canon/tmp/handoff/ui-checklist/<slug>.md --json
|
|
163
169
|
```
|
|
164
170
|
|
|
165
|
-
|
|
171
|
+
One call answers both questions because a checklist does not decide `no-evidence`. The verb reports `no-evidence` on a diff carrying no evidence image whether or not a checklist came with it, so the branch below reads the same `reason` it would have read without the flag, and the checklist is folded in only on the path that has a comparison to fold it into.
|
|
166
172
|
|
|
167
|
-
|
|
173
|
+
Pass `--checklist` only for a file that exists. The verb refuses as `unreadable-checklist` on a path it cannot read or one holding nothing, which is a caller bug rather than a transient failure, so stop and repair the path rather than posting a body with the checklist silently dropped.
|
|
174
|
+
|
|
175
|
+
Read `reason` on the record rather than the exit code.
|
|
176
|
+
|
|
177
|
+
- `no-evidence`: nothing changed under an `evidence/` segment, so there is no comparison to post and no body was rendered. Say nothing about the evidence and fall through to the checklist step below.
|
|
178
|
+
- `ok`: write `body` to `.canon/tmp/pr/evidence/body-<number>.md` at the main worktree root (resolved the way `session-worktree` does), then post or update the comment:
|
|
168
179
|
|
|
169
180
|
```bash
|
|
170
|
-
|
|
181
|
+
gh pr comment <number> --body-file <main-root>/.canon/tmp/pr/evidence/body-<number>.md
|
|
171
182
|
```
|
|
172
183
|
|
|
184
|
+
When the record carries a `commentId`, edit that comment in place instead of posting a second one, reading the body field from the tmp file with `@`:
|
|
185
|
+
|
|
173
186
|
```bash
|
|
174
|
-
|
|
187
|
+
gh api -X PATCH repos/{owner}/{repo}/issues/comments/<commentId> -f body=@<main-root>/.canon/tmp/pr/evidence/body-<number>.md
|
|
175
188
|
```
|
|
176
189
|
|
|
177
|
-
|
|
190
|
+
Delete the handoff file once that call reports success, per the cleanup below, since the checklist now lives on the pull request. Clean up the tmp body file the same way.
|
|
178
191
|
|
|
179
|
-
|
|
192
|
+
Any other `reason` is one of the mirrored git refusals (`gh-missing`, `gh-failed`, `no-base`, `unreadable-tree`, `unreadable-changes`). Report it and move on without stopping the chain: a branch that carries no evidence images most of the time should not fail here on a transient git or `gh` read. Fall through to the checklist step, which posts the checklist alone rather than losing it to a transient read.
|
|
180
193
|
|
|
181
|
-
|
|
194
|
+
### Post the UI checklist alone
|
|
182
195
|
|
|
183
|
-
|
|
184
|
-
- `ok`: write `body` to `.canon/tmp/pr/evidence/body-<number>.md` at the main worktree root (resolved the way `session-worktree` does), then post or update the comment:
|
|
196
|
+
Run this step only when the evidence step above did not carry the checklist, meaning it reported `no-evidence` or one of the git refusals, and a checklist file exists. Post it as its own comment on `<number>`:
|
|
185
197
|
|
|
186
198
|
```bash
|
|
187
|
-
gh pr comment <number> --body-file <main-root>/.canon/tmp/
|
|
199
|
+
gh pr comment <number> --body-file <main-root>/.canon/tmp/handoff/ui-checklist/<slug>.md
|
|
188
200
|
```
|
|
189
201
|
|
|
190
|
-
|
|
202
|
+
Run the cleanup below only once the call that carried the checklist reports success, whichever of the two steps that was. On a failure, stop and leave the file in place: a retry needs the checklist to still be there, and deleting it on a failed post loses the only copy with nothing landed on the pull request.
|
|
203
|
+
|
|
204
|
+
From a linked worktree the file-editing tools refuse a main-root path, so the cleanup goes out through `Bash` as two plain commands, the file and then the folder, rather than joined by `&&`, which is refused as compound:
|
|
191
205
|
|
|
192
206
|
```bash
|
|
193
|
-
|
|
207
|
+
rm <main-root>/.canon/tmp/handoff/ui-checklist/<slug>.md
|
|
194
208
|
```
|
|
195
209
|
|
|
196
|
-
|
|
210
|
+
```bash
|
|
211
|
+
rmdir <main-root>/.canon/tmp/handoff/ui-checklist 2>/dev/null || true
|
|
212
|
+
```
|
|
197
213
|
|
|
198
|
-
|
|
214
|
+
The `rmdir` is a no-op when another branch's pending checklist still sits in the folder, which keeps this step from deleting a handoff that is not its own.
|
|
215
|
+
|
|
216
|
+
Deleting the file is what makes the later re-render safe. `git-followup` re-runs `canon pr evidence` with no `--checklist`, and the verb carries the checklist forward out of the comment it is editing, so the boxes a reviewer already ticked survive the push.
|
|
199
217
|
|
|
200
218
|
### Post the preview address
|
|
201
219
|
|
|
202
|
-
Run this step only when the evidence step above returned `ok` or
|
|
220
|
+
Run this step only when the evidence step above returned `ok` or a checklist was posted, by either step. Either one means the pull request changes a rendered surface, and a reviewer holding a checklist with no screenshots needs the live page most. Otherwise skip it silently.
|
|
203
221
|
|
|
204
222
|
The evidence comment is already posted, so the reviewer has the screenshots while the deploy runs. Mint the preview against the same `<number>`:
|
|
205
223
|
|
|
@@ -250,9 +268,11 @@ Add a further line only when the labelling command printed its warning, quoting
|
|
|
250
268
|
|
|
251
269
|
`⚠️ Labels not applied: <what gh reported>`
|
|
252
270
|
|
|
253
|
-
Add a line when
|
|
271
|
+
Add a line when a checklist was posted, naming the pull request it landed on and which comment carries it:
|
|
272
|
+
|
|
273
|
+
`📋 Posted the UI checklist to <number>, in the evidence comment.`
|
|
254
274
|
|
|
255
|
-
`📋 Posted the UI checklist to <number
|
|
275
|
+
`📋 Posted the UI checklist to <number>, on its own.`
|
|
256
276
|
|
|
257
277
|
Add a line when the preview step returned an address:
|
|
258
278
|
|
|
@@ -49,7 +49,7 @@ Moving the guidance into a path-scoped rule does not reach the session that need
|
|
|
49
49
|
- Structure floors for every test: the core testing rule
|
|
50
50
|
- Runner choice, file suffix, placement, and query conventions: the TypeScript and Python testing rules
|
|
51
51
|
- Settle, guard, and run-scope rules inside an end to end file: the end to end reliability and test scope rules
|
|
52
|
-
- Writing a UI change's
|
|
52
|
+
- Writing a UI change's visual checklist, and naming the behaviors it ships untested for this skill to place: `ui-checklist`
|
|
53
53
|
- Grading the tests a pull request adds: `review-pr`
|
|
54
54
|
- Whether the guidance moves where a session puts a test, which needs a measured with-and-without run rather than a rule here
|
|
55
55
|
|
|
@@ -32,5 +32,5 @@ Without this skill, a session implementing a planned change writes the test afte
|
|
|
32
32
|
|
|
33
33
|
- Choosing the layer a test belongs at and judging whether it is a good test: `canon:test-craft`, loaded at step 1 rather than restated here
|
|
34
34
|
- Finding the cause of an unexplained failure: `canon:systematic-debugging`
|
|
35
|
-
- Confirming visual output after a change lands: `070-planning.md` states the order and `ui-
|
|
35
|
+
- Confirming visual output after a change lands: `070-planning.md` states the order and `ui-checklist` writes the list to confirm against
|
|
36
36
|
- The mechanical audit of whether an implementation reached history ahead of its test: `canon gov test-order`, invoked from `auto-ship`
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ui-checklist
|
|
3
|
+
description: Why the visual half of a UI change needs a written record a reviewer can open, why that record travels with the screenshots it annotates, and why writing the tests belongs elsewhere now
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# UI checklist requirement
|
|
7
|
+
|
|
8
|
+
## Gap
|
|
9
|
+
|
|
10
|
+
Without this skill, UI work ships on the confidence of the session that wrote it. Nobody states which part of the change an eye has to judge, so a reviewer opens the diff and reads the automatable half, which the tests already cover, and never looks at the half that only rendering shows.
|
|
11
|
+
|
|
12
|
+
The visual half is where the record is lost. A checklist printed into chat scrolls away before anyone verifies it, so the ship step has nothing to gate on and the work reads as verified because a list was produced. Written from a linked worktree against `pwd`, the file lands where the caller does not look.
|
|
13
|
+
|
|
14
|
+
Writing the checklist correctly to disk does not close the gap either. The file sits under a gitignored folder on the machine that authored it, so a pull request reviewer, on that machine or another, never sees it. A record that only the author can open reads as verified for the same reason a record that never existed does.
|
|
15
|
+
|
|
16
|
+
Posting it as a comment of its own is the next failure. The screenshots the checklist annotates sit in a second comment, so a reviewer reads "the hero settles without a jump" with no picture of the hero beside it and scrolls looking for one. Two comments describing one change also drift: a later push re-renders the screenshots and leaves the checklist claiming what an older head showed.
|
|
17
|
+
|
|
18
|
+
The automatable half has its own gap, and it is no longer this skill's to close by writing the tests. `test-first` writes a behavior's test while the code is written, and `test-craft` owns which layer it belongs at. A skill writing tests after implementation duplicates both, and what it produces is the test the session already skipped rather than the test the behavior needed. What stays open is that nobody names the behaviors shipping untested, which is a list rather than a test.
|
|
19
|
+
|
|
20
|
+
## Must
|
|
21
|
+
|
|
22
|
+
- Split every change into visual-only and automatable before writing anything
|
|
23
|
+
- Write the checklist for the visual-only half, each item an action and the result a person is looking for
|
|
24
|
+
- Name every automatable change shipping with no test, with the layer `test-craft` would place it at, as a section of the same file
|
|
25
|
+
- Write the file to the `.canon/tmp/handoff/ui-checklist/<slug>.md` handoff at the main worktree root, overwriting
|
|
26
|
+
- Report that there is nothing to verify rather than manufacturing a checklist to show work
|
|
27
|
+
|
|
28
|
+
## Must not
|
|
29
|
+
|
|
30
|
+
- Write a test at any layer, which is `test-first` while the code is written and `test-craft` for where it goes
|
|
31
|
+
- Read a project's test config or runner in order to write against it
|
|
32
|
+
- Try to assert a visual property programmatically
|
|
33
|
+
- Repeat the full checklist in chat, which is what made it evaporate
|
|
34
|
+
- Stage or commit the checklist, which is gitignored scratch
|
|
35
|
+
- Talk to GitHub directly. Posting the checklist belongs to `git-pr`, the sole consumer of the handoff file
|
|
36
|
+
- Move the handoff path to match this skill's name, which strands a checklist an older binary wrote
|
|
37
|
+
|
|
38
|
+
## Guards
|
|
39
|
+
|
|
40
|
+
- No implementation context in the session: stop, since there is nothing to split
|
|
41
|
+
- Nothing visual and nothing untested: skip the file write and report the coverage
|
|
42
|
+
|
|
43
|
+
## Out of scope
|
|
44
|
+
|
|
45
|
+
- Judging whether the UI is any good, which `ux-audit` owns
|
|
46
|
+
- The rules for choosing a layer, which `test-craft` owns
|
|
47
|
+
- Writing the test itself, which is `test-first`
|
|
48
|
+
- Deciding whether an outstanding checklist blocks the ship, which the calling pipeline gates on
|
|
49
|
+
- Performing the visual verification, which needs a person
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ui-checklist
|
|
3
|
+
description: Writes the visual checklist a reviewer reads beside the evidence screenshots, and names each changed behavior shipping with no test so `test-craft` can place one. Use after implementing UI changes, or when asked "what should I look at", "what do I verify", or "give me a visual checklist". Do NOT use in empty sessions with no implementation context, and do NOT use to write the tests themselves.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# UI checklist
|
|
7
|
+
|
|
8
|
+
## Guards
|
|
9
|
+
|
|
10
|
+
- If no implementation context exists in the session, stop: `❌ No implementation context. Describe what you built first.`
|
|
11
|
+
- This skill writes no test. When a behavior needs one, name it and let `canon:test-craft` place it.
|
|
12
|
+
|
|
13
|
+
## Analysis
|
|
14
|
+
|
|
15
|
+
Review the session to identify what was built or changed. Split each change two ways:
|
|
16
|
+
|
|
17
|
+
- **Visual-only:** spacing, alignment, color, typography, layout proportions, animation timing. These are what the checklist exists for, since nothing asserts them programmatically.
|
|
18
|
+
- **Automatable:** interactions, state transitions, form submissions, keyboard handling, conditional rendering, loading, empty, and error states, plus journeys across routes and behavior only a real browser renders.
|
|
19
|
+
|
|
20
|
+
An automatable change already covered by a test written during implementation is done. What is left is the missing-test list below.
|
|
21
|
+
|
|
22
|
+
## The checklist
|
|
23
|
+
|
|
24
|
+
Group visual items by feature area. Use `- [ ]` checkbox syntax, and write each item as the action and the result a person is looking for, so a reviewer who did not build the change can run it.
|
|
25
|
+
|
|
26
|
+
```markdown
|
|
27
|
+
**What to verify visually:**
|
|
28
|
+
|
|
29
|
+
**<Feature area>**
|
|
30
|
+
|
|
31
|
+
- [ ] <action> → <expected visual result>
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## The missing-test list
|
|
35
|
+
|
|
36
|
+
Name every automatable change this branch ships with no test, one per line, with the layer `test-craft` would place it at. Do not write the test and do not read the project's test config to write one against.
|
|
37
|
+
|
|
38
|
+
Route each through the `test-craft` layer table: a journey or a browser-only behavior to end to end, a rendered state to a component test, and logic that renders nothing to a unit test. When the project has no runner at that layer, say so on the line rather than moving the item to a layer that does.
|
|
39
|
+
|
|
40
|
+
This list ships inside the checklist file, below the visual items, so a reviewer reads what is untested next to what to look at:
|
|
41
|
+
|
|
42
|
+
```markdown
|
|
43
|
+
**Shipping without a test:**
|
|
44
|
+
|
|
45
|
+
- <behavior> → <layer> (<runner, or the runner that is missing>)
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Omit the heading when every automatable change is covered.
|
|
49
|
+
|
|
50
|
+
## Persist the checklist
|
|
51
|
+
|
|
52
|
+
Derive `<slug>` per `${CLAUDE_SKILL_DIR}/../../standards/slug.md`. Fall back to `latest` on an empty result.
|
|
53
|
+
|
|
54
|
+
When a checklist is produced, write it directly to `.canon/tmp/handoff/ui-checklist/<slug>.md` at the main worktree root, not the current worktree. Resolve that root the way `session-worktree` does. Create the directory if it does not exist. Always overwrite. This is a handoff file rather than a deliverable: `git-pr` renders it into the evidence comment once a pull request opens, then removes it, and nothing here talks to `gh` directly.
|
|
55
|
+
|
|
56
|
+
The path names the artifact rather than this skill, so it does not move when the skill is renamed. A checklist written by an older binary still lands where the consumer looks.
|
|
57
|
+
|
|
58
|
+
From a linked worktree the file-editing tools refuse that path, so the checklist goes out through `Bash`. Send the `mkdir -p` and the heredoc as two plain commands rather than joining them with `&&`, which is refused as compound.
|
|
59
|
+
|
|
60
|
+
Skip the file write when there is nothing to verify visually and nothing shipping untested.
|
|
61
|
+
|
|
62
|
+
The `.canon/tmp/` directory is gitignored. Do not stage or commit the file.
|
|
63
|
+
|
|
64
|
+
## Output order
|
|
65
|
+
|
|
66
|
+
1. If a checklist was produced, write it to file, then output only the file path in chat:
|
|
67
|
+
`📝 Wrote .canon/tmp/handoff/ui-checklist/<slug>.md`
|
|
68
|
+
2. Name the count of visual items and the count of behaviors shipping without a test, on one line each
|
|
69
|
+
3. If nothing was produced: `✅ Nothing to verify visually and nothing shipping untested.`
|
|
70
|
+
|
|
71
|
+
Do not repeat the full checklist in chat.
|
|
@@ -35,6 +35,6 @@ The pass slides into fixing what it finds, and then the audit and the change lan
|
|
|
35
35
|
|
|
36
36
|
- Fixing what it found, which is a separate change with its own review
|
|
37
37
|
- Feature planning, which `plan-feature` owns
|
|
38
|
-
- Verifying one specific change, which `ui-
|
|
38
|
+
- Verifying one specific change, which `ui-checklist` owns
|
|
39
39
|
- Defining the intent it audits against, which `design-extract` and the wireframes own
|
|
40
40
|
- Measuring what a running interface costs to paint, block, or shift, which `ux-measure` owns. Contrast stays here rather than going with it, being computable from two color values this skill already reads off the token table.
|
|
@@ -44,5 +44,5 @@ A session that does start one picks a runner on the spot. The reading then comes
|
|
|
44
44
|
- Judging the interface against stated intent, which `ux-audit` owns
|
|
45
45
|
- Contrast, which is computable from two color values in the token table `ux-audit` already reads. A contrast failure from a color computed at runtime stays invisible to that reader, and the cost is accepted rather than overlooked.
|
|
46
46
|
- Network waterfall, bundle size, and accessibility, which no version of this measures
|
|
47
|
-
- Writing behavioral tests against the interface, which `
|
|
47
|
+
- Writing behavioral tests against the interface, which `test-first` and `test-craft` own
|
|
48
48
|
- Fixing what the reading found
|
package/docs/agents/capture.md
CHANGED
|
@@ -18,9 +18,13 @@ canon capture https://example.com --selector .window --out preview.png
|
|
|
18
18
|
|
|
19
19
|
## What this repository captures
|
|
20
20
|
|
|
21
|
-
A capture set here spans two folders. `assets/captures/` holds
|
|
21
|
+
A capture set here spans two folders. `assets/captures/` holds five sources and the three templates they are written from, and `assets/evidence/` holds their images and the built-page capture a document points at with the stamp answering for each, under the segment `canon pr evidence` compares. One run over the source folder rebuilds every image, and it takes `--out assets/evidence` to put each PNG where its document points rather than beside the markup it rendered. None of the sources is edited by hand. `scripts/core/regen-hero.sh` writes each `.html` from the template beside it, filling one shared value map into all of them, and `bun run check` regenerates them and fails on the difference.
|
|
22
22
|
|
|
23
|
-
Two of the three take catalog data, so a stack gaining a rule moves the frame on the next run. `install.html` is the exception, since it holds terminal text from a real run in its template rather than derived from a live catalog at build time. `assets/evidence/arrival.png` is the one image with no source here: it is the built page's `.fold` element captured in dark mode against a local `web/` preview, since `canon capture` takes no color scheme and the page follows the browser's default of light, so it is retaken by hand when the page's first screen changes.
|
|
23
|
+
Two of the three templates take catalog data, so a stack gaining a rule moves the frame on the next run. `install.html` is the exception, since it holds terminal text from a real run in its template rather than derived from a live catalog at build time. `assets/evidence/arrival.png` is the one image with no source here: it is the built page's `.fold` element captured in dark mode against a local `web/` preview, since `canon capture` takes no color scheme and the page follows the browser's default of light, so it is retaken by hand when the page's first screen changes.
|
|
24
|
+
|
|
25
|
+
The README shows each still in two themes through `<picture>`, so a frame is a pair named `<name>` and `<name>-light`. `catalog` and `install` take the light half from the same template, which `regen-hero.sh` fills a second time with the plain color roles pointed at the light ones, and each half is its own capture set with its own stamp. `arrival-light.png` is the same `.fold` capture of the same address taken without forcing dark, so it is retaken by hand alongside `arrival.png`, and nothing catches one drifting from the other.
|
|
26
|
+
|
|
27
|
+
A stamp for a URL source digests the address string rather than the page it served, so two themes of one address carry one `source-sha256` and only `image-sha256` tells the frames apart. That holds for `examples/teach/evidence/root-listing-light.png`, which is retaken by serving a copy of the fixture with `data-theme="light"` on its `<html>` element at the same address, since the page follows the dark default and the command takes no scheme.
|
|
24
28
|
|
|
25
29
|
`assets/captures/` is read flat and never descends, by the regeneration script, by this command, and by the drift stage alike. A source nested a further folder down is skipped by all three with nothing reported, so a new frame is a template dropped directly in rather than a folder of its own. The split is what retired the name prefix the flat layout used to need: a frame is named for itself now, since `assets/captures/` no longer mixes markup in with the images.
|
|
26
30
|
|
package/docs/agents/demo.md
CHANGED
|
@@ -24,13 +24,15 @@ So `canon demo compile` writes a second artifact rather than adding fields to a
|
|
|
24
24
|
|
|
25
25
|
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`.
|
|
26
26
|
|
|
27
|
+
A plan can carry an optional `colorScheme` of `light` or `dark`, which the recording context starts in so a page following the system preference paints that scheme with no click beat of its own. An absent field keeps the engine's default, which is light, and `compile` never seeds it. Any other value makes the plan unreadable. A page keyed on a stored theme rather than the preference ignores the field.
|
|
28
|
+
|
|
27
29
|
`record-screencast` 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.
|
|
28
30
|
|
|
29
31
|
| Option | Behavior |
|
|
30
32
|
| --------------- | ----------------------------------------------------------------- |
|
|
31
33
|
| `--out <dir>` | Directory the plan and its output paths point at, default `demos` |
|
|
32
34
|
| `--slug <slug>` | Plan name, defaulting to the draft filename |
|
|
33
|
-
| `--force` | Overwrite an existing plan, losing any
|
|
35
|
+
| `--force` | Overwrite an existing plan, losing any field set by hand |
|
|
34
36
|
| `--json` | Add a record on stdout carrying the beats and what is unfilled |
|
|
35
37
|
|
|
36
38
|
## What a run does
|
|
@@ -46,17 +46,18 @@ image or marks the case new.
|
|
|
46
46
|
|
|
47
47
|
`reason` on the record is what a caller branches on, not the exit code:
|
|
48
48
|
|
|
49
|
-
| Reason
|
|
50
|
-
|
|
|
51
|
-
| `ok`
|
|
52
|
-
| `no-evidence`
|
|
53
|
-
| `
|
|
54
|
-
| `gh-
|
|
55
|
-
| `
|
|
56
|
-
| `no-
|
|
57
|
-
| `no-
|
|
58
|
-
| `
|
|
59
|
-
| `unreadable-
|
|
49
|
+
| Reason | What it means |
|
|
50
|
+
| ---------------------- | ----------------------------------------------------------------------------- |
|
|
51
|
+
| `ok` | A body was rendered. `commentId` is set when a marked comment already exists. |
|
|
52
|
+
| `no-evidence` | Nothing in the diff carries an `evidence/` segment. An ordinary silent no-op. |
|
|
53
|
+
| `unreadable-checklist` | `--checklist` named a path that could not be read, or one holding nothing. |
|
|
54
|
+
| `gh-missing` | `gh` is not on the path, so no pull request could be resolved. |
|
|
55
|
+
| `gh-failed` | `gh` could not answer for this repository or branch, or read its comments. |
|
|
56
|
+
| `no-branch` | The pull request carries no head branch name. |
|
|
57
|
+
| `no-object-head` | The pull request object reported no head commit. |
|
|
58
|
+
| `no-base` | No base resolves against the trunk. |
|
|
59
|
+
| `unreadable-tree` | git could not read the tree at the base commit. |
|
|
60
|
+
| `unreadable-changes` | git could not list what this branch changed. |
|
|
60
61
|
|
|
61
62
|
`no-evidence` is not a refusal a caller reports. A project on a stack that
|
|
62
63
|
carries no evidence path, such as `base` or `python`, hits this reason on
|
|
@@ -107,6 +108,28 @@ no evidence in the diff and an address in hand, the body is the address and the
|
|
|
107
108
|
marker alone, reported as `ok`. `canon docs pr-preview` covers where the
|
|
108
109
|
address comes from.
|
|
109
110
|
|
|
111
|
+
## The checklist line
|
|
112
|
+
|
|
113
|
+
`--checklist <path>` closes the body with a visual checklist, below the
|
|
114
|
+
comparison it annotates, so one comment carries the preview address, the
|
|
115
|
+
screenshots, and what a reviewer has to look at. The file is what
|
|
116
|
+
`canon:ui-checklist` writes to `.canon/tmp/handoff/ui-checklist/<slug>.md`, and
|
|
117
|
+
`git-pr` passes it here rather than posting it as a second comment.
|
|
118
|
+
|
|
119
|
+
A run without the option carries forward whatever checklist the marked comment
|
|
120
|
+
already holds, the same way the preview address is carried. That is what keeps
|
|
121
|
+
`git-followup`'s re-render after a push from wiping boxes a reviewer has
|
|
122
|
+
already ticked, since `git-pr` deletes the handoff once the first post reports
|
|
123
|
+
success and no later call has a file to pass.
|
|
124
|
+
|
|
125
|
+
The option does not decide `no-evidence`. A branch with a checklist and no
|
|
126
|
+
changed evidence image still reports `no-evidence`, and the caller posts the
|
|
127
|
+
checklist on its own, which is what it did before this option existed. A path
|
|
128
|
+
that cannot be read, or one holding nothing, refuses as
|
|
129
|
+
`unreadable-checklist` rather than rendering without it: the caller deletes the
|
|
130
|
+
handoff once a post succeeds, so a silently dropped checklist is the only copy
|
|
131
|
+
gone.
|
|
132
|
+
|
|
110
133
|
## What a collapsed comment still leaves to GitHub
|
|
111
134
|
|
|
112
135
|
GitHub already draws its own before-and-after comparison on the Files Changed
|
|
@@ -81,13 +81,14 @@ going, so the preview may still land after the verb has given up on it.
|
|
|
81
81
|
|
|
82
82
|
`canon pr evidence --preview <url>` puts `**Preview:** <url>` on the first line
|
|
83
83
|
of the evidence body. With no evidence image in the diff, the body is that line
|
|
84
|
-
and the trailing marker alone, so a pull request
|
|
85
|
-
|
|
84
|
+
and the trailing marker alone, so a pull request whose screenshots did not
|
|
85
|
+
change still gets one comment a later call can find and edit.
|
|
86
86
|
|
|
87
87
|
A later `canon pr evidence` run without `--preview` reads the address off the
|
|
88
88
|
marked comment and carries it into the new body. `git-followup` re-renders the
|
|
89
89
|
comment after every push, and without that carry the first push would delete
|
|
90
|
-
the link.
|
|
90
|
+
the link. A visual checklist folded in through `--checklist` carries the same
|
|
91
|
+
way, which is what keeps that push from wiping boxes a reviewer already ticked.
|
|
91
92
|
|
|
92
93
|
## Removing a preview
|
|
93
94
|
|
package/docs/agents/tasks.md
CHANGED
|
@@ -54,7 +54,9 @@ An outcome whose body is struck reads as cut rather than open or closed, whateve
|
|
|
54
54
|
|
|
55
55
|
The task carries its plan with it. When the closing task is the last live one whose `Plan:` line resolves onto that file, the plan moves to `.canon/plans/archive/` under its own name and the archived task's line is rewritten as `Plan: [feature-<slug>](../../plans/archive/feature-<slug>.md)`, a folder deeper than the live task wrote it. The `plan` field on the success record carries that `from` and `to`, and is `null` when nothing moved.
|
|
56
56
|
|
|
57
|
-
|
|
57
|
+
The ready folder the task's `Ready:` line names moves with the plan to `.canon/ready/archive/`, falling back to a `.canon/ready/<nn>-<slug>/` path in the plan when the line is absent. The `Ready:` line and the plan's literal path to the folder are retargeted, and the `ready` field on the success record carries `from` and `to`, or `null` when nothing moved. A folder that resolves to nothing, sits already archived, or meets a taken destination moves nothing and refuses nothing.
|
|
58
|
+
|
|
59
|
+
A plan several tasks share stays where it is, and its ready folder with it, and the task archives anyway. Moving it on the first task to close strands every sibling's pointer at a path that has gone, and `.canon/plans/` is gitignored so no history recovers the target. A `Plan:` line resolving to no file leaves the plan alone too, since a pointer somebody typed wrong is not a plan to move and holding the whole archive over it would park the board behind a repair the merge cannot make.
|
|
58
60
|
|
|
59
61
|
The merge is what settles a plan. `.husky/post-merge` reads the pull request number off the squash subject and calls this verb, so both halves close in one act with nobody naming a file. That is why the move sits inside this verb rather than in a second call the hook would make after it, which could leave the task archived and the plan live.
|
|
60
62
|
|
|
@@ -58,7 +58,7 @@ Work in Claude Code directly. It reads `CLAUDE.md` automatically and has full fi
|
|
|
58
58
|
- When the current state is unmeasured and more than one approach is live, invoke `canon:plan-groundwork` first. It opens a track folder under `.canon/groundwork/<nn>-<slug>/` and ends in a decision, which may be to do nothing. Skip it when the approach is already settled.
|
|
59
59
|
- Invoke `canon:plan-feature` to scan for code-level conflicts and ambiguities, confirm approach before proceeding
|
|
60
60
|
- Implement the feature, then Claude Code runs the commands defined in `CLAUDE.md`, fixes failures, and iterates until all pass
|
|
61
|
-
- For UI changes, invoke `canon:ui-
|
|
61
|
+
- For UI changes, invoke `canon:ui-checklist` to write what a reviewer has to look at and name any behavior shipping without a test
|
|
62
62
|
End the session once the feature works and tests pass. Invoke `canon:docs-fold` to capture any decisions made during implementation before closing.
|
|
63
63
|
|
|
64
64
|
The routing test is whether the repository can answer an item today. A session grepping handles the yes, and a groundwork track handles the no.
|
|
@@ -81,7 +81,7 @@ When features are independent, run them in parallel instead of sequentially. Use
|
|
|
81
81
|
|
|
82
82
|
- Create a worktree per feature, then start a Claude Code session in each
|
|
83
83
|
- Invoke `canon:plan-feature` in each session. Plans land at the main worktree root as `.canon/plans/feature-<slug>.md`, one per feature, no collisions. Small features stay in chat and skip the file.
|
|
84
|
-
- Implement, verify, and review each feature independently. `review-branch` writes a per-branch report at the main worktree root (`review/branch-<slug>.md`), and `ui-
|
|
84
|
+
- Implement, verify, and review each feature independently. `review-branch` writes a per-branch report at the main worktree root (`review/branch-<slug>.md`), and `ui-checklist` writes a per-branch checklist handoff there too (`tmp/handoff/ui-checklist/<slug>.md`) that `git-pr` posts to the pull request and removes, so parallel sessions do not overwrite each other. The slug is the branch name with any leading type segment dropped, so `feat/jwt-expiration` and the plan at `feature-jwt-expiration.md` meet on one name
|
|
85
85
|
- Ship each worktree separately with `canon:git-ship`
|
|
86
86
|
- For full autonomy per worktree, invoke `canon:auto-ship` instead of the manual chain. Approve the plan, walk away, come back to a pull request the chain marked as a draft and then read the flag back on. The mark says the work has had no review yet, and it holds no window, since readying a pull request to merge lifts it directly, an act reserved to the operator or to the controlling session that closed the review.
|
|
87
87
|
|
|
@@ -174,7 +174,7 @@ The receipt is collected once every item on it has been decided, and it survives
|
|
|
174
174
|
|
|
175
175
|
### UI polish
|
|
176
176
|
|
|
177
|
-
Verify the change manually in the browser. Invoke `canon:ui-
|
|
177
|
+
Verify the change manually in the browser. Invoke `canon:ui-checklist` if you need a written list of what to look at. For the fix itself, describe the change in Claude Code directly.
|
|
178
178
|
|
|
179
179
|
### Quick fix
|
|
180
180
|
|
|
@@ -235,7 +235,7 @@ This section is the corpus the coverage claim is measured against: every name `c
|
|
|
235
235
|
| `canon:test-first` | Before implementing a planned change, to run its test red, green, then refactor |
|
|
236
236
|
| `canon:test-craft` | When writing or changing any test, to pick its layer and filter what it asserts |
|
|
237
237
|
| `canon:systematic-debugging` | When a test fails or a bug surfaces, to force root cause first |
|
|
238
|
-
| `canon:ui-
|
|
238
|
+
| `canon:ui-checklist` | After a UI change, to write what to look at and name what ships untested |
|
|
239
239
|
|
|
240
240
|
### Check the work before it leaves the branch
|
|
241
241
|
|