@erclx/canon 4.85.0 → 4.87.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/claude/.claude-plugin/plugin.json +1 -1
  2. package/claude/skills/auto-ship/SKILL.md +6 -6
  3. package/claude/skills/canon-feedback-file/SKILL.md +2 -2
  4. package/claude/skills/design-extract/SKILL.md +3 -3
  5. package/claude/skills/docs-fold/SKILL.md +3 -3
  6. package/claude/skills/draft-and-pick/REQUIREMENT.md +2 -1
  7. package/claude/skills/draft-and-pick/SKILL.md +4 -3
  8. package/claude/skills/draft-and-pick/references/live-arms.md +19 -0
  9. package/claude/skills/draft-diagram/SKILL.md +2 -2
  10. package/claude/skills/draft-slides/SKILL.md +1 -1
  11. package/claude/skills/git-ship/SKILL.md +1 -1
  12. package/claude/skills/memory-capture/SKILL.md +1 -1
  13. package/claude/skills/memory-review/SKILL.md +13 -13
  14. package/claude/skills/memory-review/references/receipt-format.md +1 -1
  15. package/claude/skills/review-branch/SKILL.md +3 -3
  16. package/claude/skills/role-worker/SKILL.md +2 -1
  17. package/claude/skills/sketch-design/SKILL.md +4 -4
  18. package/claude/skills/ux-walkthrough/SKILL.md +2 -2
  19. package/claude/skills/ux-walkthrough/references/candidate-pages.md +1 -16
  20. package/docs/agents/commands.md +100 -95
  21. package/docs/agents/design-board.md +7 -7
  22. package/docs/workflow/ai-workflow.md +3 -3
  23. package/docs/workflow/visual-design-workflow.md +1 -1
  24. package/governance/rules/claude/563-ready.md +11 -0
  25. package/governance/rules/core/045-memory.md +1 -1
  26. package/package.json +1 -1
  27. package/src/cli.ts +1 -1
  28. package/src/commands/design.ts +3 -3
  29. package/src/commands/feedback.ts +12 -12
  30. package/src/commands/migrate.ts +168 -3
  31. package/src/commands/slides.ts +2 -2
  32. package/src/design/board.ts +17 -10
  33. package/src/migrate/evidence-ordinal.ts +79 -0
  34. package/src/migrate/record-layout.ts +599 -0
  35. package/src/migrate/record-tree.ts +1 -1
  36. package/src/migrate/scratch-evidence.ts +57 -30
  37. package/src/record-root.ts +4 -0
  38. package/standards/index.md +1 -0
  39. package/standards/memory.md +1 -1
  40. package/standards/plan.md +2 -0
  41. package/standards/publish.md +1 -1
  42. package/standards/ready.md +105 -0
  43. package/standards/skill.md +1 -1
  44. package/tooling/claude/seeds/.claude/hooks/memory-index.sh +10 -0
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "canon",
3
3
  "description": "Automated governance, versioning, and discovery tools for Claude Code.",
4
- "version": "4.85.0",
4
+ "version": "4.87.0",
5
5
  "author": {
6
6
  "name": "Eric Le",
7
7
  "url": "https://github.com/erclx"
@@ -172,17 +172,17 @@ The verb reads the same set from `src/autoship/paths.ts`, so a path added here b
172
172
 
173
173
  ## Step 7: evaluate findings
174
174
 
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.
175
+ Skip this step when Step 6 skipped review. Otherwise read `.canon/review/branch-<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.
176
176
 
177
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.
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.`
178
+ - **It predates this run, critical or should-fix.** Stop: `❌ Review found non-minor issues that predate this run. See .canon/review/branch-<slug>.md. Fix and run /git-ship.`
179
179
  - **It predates this run, minor only.** Continue. The minor findings stay in the on-disk review receipt. Fold any a reviewer needs into the PR's `## Technical Context`. Do not add a separate review-notes section to the PR body.
180
180
 
181
181
  Read origin as causation rather than authorship. Staleness this run induced in a file it never opened is a finding it caused, and the plan's "Files to touch" list scopes what the run builds rather than what it may repair.
182
182
 
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.`
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-<slug>.md. Fix and run /git-ship.`
184
184
 
185
- This chain owns the receipt's lifetime, which is what makes the Output block's citation resolve on a run that reaches it. `docs-fold` 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.
185
+ This chain owns the receipt's lifetime, which is what makes the Output block's citation resolve on a run that reaches it. `docs-fold` 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 `branch-<slug>.md` receipt per live branch left in `.canon/review/`, bounded by the branch count rather than by the lifetime of the checkout.
186
186
 
187
187
  ## Step 8: ship
188
188
 
@@ -209,10 +209,10 @@ Respond with up to five lines:
209
209
 
210
210
  ```plaintext
211
211
  ✅ Autoshipped (<state>): <PR url>
212
- <N minor findings kept in .canon/review/branch/review-<slug>.md>
212
+ <N minor findings kept in .canon/review/branch-<slug>.md>
213
213
  <N facts routed to context entries>
214
214
  <N memories captured in .canon/memory/>
215
- <Memory proposal at .canon/review/memory/memory-review-<slug>.md>
215
+ <Memory proposal at .canon/memory/review/memory-review-<slug>.md>
216
216
  ```
217
217
 
218
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.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: canon-feedback-file
3
- description: Format a paste-back report about something broken, missing, or off in canon and write it directly to the toolkit's `.canon/review/feedback/` folder via `canon feedback`. Use when asked to "send this to the toolkit", "report this to canon", "file toolkit feedback", or "give the toolkit feedback about X". Do NOT use for general complaints about other tooling, IDE issues, or in-project bugs that do not implicate canon surfaces.
3
+ description: Format a paste-back report about something broken, missing, or off in canon and write it directly to the toolkit's `.canon/feedback/` folder via `canon feedback`. Use when asked to "send this to the toolkit", "report this to canon", "file toolkit feedback", or "give the toolkit feedback about X". Do NOT use for general complaints about other tooling, IDE issues, or in-project bugs that do not implicate canon surfaces.
4
4
  ---
5
5
 
6
6
  # Canon feedback file
@@ -93,7 +93,7 @@ cat <<'EOF' | canon feedback
93
93
  EOF
94
94
  ```
95
95
 
96
- It writes to `.canon/review/feedback/feedback-<slug>-<ts>.md` and prints the absolute path on stdout. Report the printed path back to the user on its own line, in the form the project's instruction file sets under `## Output`.
96
+ It writes to `.canon/feedback/feedback-<slug>-<ts>.md` and prints the absolute path on stdout. Report the printed path back to the user on its own line, in the form the project's instruction file sets under `## Output`.
97
97
 
98
98
  If `canon` is not on PATH, fall back: print the block in chat and tell the user `📋 Copy the block above into a toolkit-repo session.`
99
99
 
@@ -39,7 +39,7 @@ On the source path, also read the UI surfaces matched in Step 1 plus `canon docs
39
39
 
40
40
  On the greenfield path, also read `canon/ARCHITECTURE.md` for platform, tech stack, and surface type. Do not scan `src/`, stylesheets, or UI modules. Step 1 already established they hold nothing.
41
41
 
42
- On the greenfield path, also check `.canon/review/evidence/*/design-handoff.md` for a file the `sketch-design` skill wrote, taking the most recently modified match when more than one exists. Read it when found. Its presence is what Step 4 traces cells from instead of proposing them.
42
+ On the greenfield path, also check `.canon/picks/*/design-handoff.md` for a file the `sketch-design` skill wrote, taking the most recently modified match when more than one exists. Read it when found. Its presence is what Step 4 traces cells from instead of proposing them.
43
43
 
44
44
  Run these reads in parallel. Do not speculatively recurse into every directory.
45
45
 
@@ -94,13 +94,13 @@ Write the filled template to `canon/DESIGN.md` from the project root. Then run:
94
94
  canon design render
95
95
  ```
96
96
 
97
- The command writes an HTML plus CSS preview to `.canon/review/design/`. Output the path in chat so the user can open it.
97
+ The command writes an HTML plus CSS preview to `.canon/tmp/render/design/`. Output the path in chat so the user can open it.
98
98
 
99
99
  ## Response format
100
100
 
101
101
  ```plaintext
102
102
  📝 Wrote canon/DESIGN.md
103
- 📝 Wrote .canon/review/design/index.html
103
+ 📝 Wrote .canon/tmp/render/design/index.html
104
104
 
105
105
  Ran the <source|greenfield> path. N cells marked `? verify`. Open the preview and confirm before committing.
106
106
  ```
@@ -220,15 +220,15 @@ Plans are not swept here. A plan is settled by the merge rather than by an outco
220
220
 
221
221
  ### Reviews
222
222
 
223
- Leave the current branch's review receipt where it is. `auto-ship` Step 6 keeps minor findings in `.canon/review/branch/review-<slug>.md` and its closing block hands the reader that path, so deleting it here removes the file the chain that invoked this skill is still citing. Seven runs recorded that collision across two days before a sandbox fixture asserted the receipt and could pass only on a run the chain stopped early.
223
+ Leave the current branch's review receipt where it is. `auto-ship` Step 6 keeps minor findings in `.canon/review/branch-<slug>.md` and its closing block hands the reader that path, so deleting it here removes the file the chain that invoked this skill is still citing. Seven runs recorded that collision across two days before a sandbox fixture asserted the receipt and could pass only on a run the chain stopped early.
224
224
 
225
225
  The body that writes a receipt owns its lifetime. This skill sweeps on behalf of whatever called it and has no way to read whether a file is still in use, where the chain that wrote this one cites it in its own output and knows. What reaps it is the branch sweep below, one branch later, once the branch it names is gone.
226
226
 
227
- Sweep the branch reports this session never opened. List `.canon/review/branch/review-*.md`, run the slug transform in `${CLAUDE_SKILL_DIR}/../../standards/slug.md` over every name `git branch --format='%(refname:short)'` prints, and delete a report whose slug matches none of them. Take the names from that format rather than from `git branch --list`, which marks the current branch with `* ` and a branch checked out in another worktree with `+ `, so a transform reading the marked lines as written turns a live branch into a slug nothing matches and sweeps a report a sibling worktree is still working from. A branch report is read once, by the session addressing it, and the durable record of what a review found is the comment `review-pr` posts on the pull request, so a report outliving its branch is holding nothing. Skipping this leaves them accumulating for the life of the checkout, since a slug is unique per feature and no later branch ever looks for one.
227
+ Sweep the branch reports this session never opened. List `.canon/review/branch-*.md`, run the slug transform in `${CLAUDE_SKILL_DIR}/../../standards/slug.md` over every name `git branch --format='%(refname:short)'` prints, and delete a report whose slug matches none of them. Take the names from that format rather than from `git branch --list`, which marks the current branch with `* ` and a branch checked out in another worktree with `+ `, so a transform reading the marked lines as written turns a live branch into a slug nothing matches and sweeps a report a sibling worktree is still working from. A branch report is read once, by the session addressing it, and the durable record of what a review found is the comment `review-pr` posts on the pull request, so a report outliving its branch is holding nothing. Skipping this leaves them accumulating for the life of the checkout, since a slug is unique per feature and no later branch ever looks for one.
228
228
 
229
229
  What that removes is a local-only review on a branch deleted before it opened a pull request. `review-branch` says so where a reader meets the report, and the sweep runs anyway rather than keeping every report against the one case, since nothing else ever clears them.
230
230
 
231
- Memory receipts sweep board-wide rather than by slug. Scan every `.canon/review/memory/memory-review-*.md`, not only the one matching this slug. `memory-review` writes its receipt after this skill has run in every ship chain, so a sweep keyed on the current slug looks for a file that does not exist yet, and no later branch looks for it either because a slug is unique per feature. Scanning the folder is what makes the sweep fire at all.
231
+ Memory receipts sweep board-wide rather than by slug. Scan every `.canon/memory/review/memory-review-*.md`, not only the one matching this slug. `memory-review` writes its receipt after this skill has run in every ship chain, so a sweep keyed on the current slug looks for a file that does not exist yet, and no later branch looks for it either because a slug is unique per feature. Scanning the folder is what makes the sweep fire at all.
232
232
 
233
233
  For each receipt, count the H2 items still marked 📝 pending:
234
234
 
@@ -19,11 +19,12 @@ Without this skill, a session facing a decision nobody can settle from a diff:
19
19
  - Reads a driver record as a verdict and drops an arm on it. `canon drive` reports findings and never gates, so a run filtering the arms on a probe reading has made a claim the probe catalog has not earned.
20
20
  - Reads a color without compositing its alpha, samples a round control at the corner of its bounding box, or confirms a panel's dimensions while it sits above the viewport. Each reads as a passing measurement about something no reader sees.
21
21
  - Meets a machine with no browser binary and reports on the arms anyway, since nothing in the default flow separates a render that failed from one that was never attempted.
22
+ - Hand-writes a mockup of a surface a running app already serves, which drifts from what ships by a few pixels and a few words the moment the app's own markup or stylesheet moves on.
22
23
 
23
24
  ## Must
24
25
 
25
26
  - Produce three to five arms with the shipping state among them, each carrying an id, a label, and what the arm costs.
26
- - Author the whole candidate set as one self-contained page and render it once, so the comparison arrives as one image.
27
+ - Author the whole candidate set as one self-contained page and render it once, so the comparison arrives as one image, except where the surface under decision is a running app: there the page links a copy of the built stylesheet rather than inlining it, per `references/live-arms.md`.
27
28
  - Vary one property across the arms, so the answer names a difference.
28
29
  - Render before reporting on any arm, and report a missing browser binary as a refusal naming the repair rather than describing an arm nobody has seen.
29
30
  - Take the pick through the structured question surface, with the recommendation ranked first and marked, and every option carrying its cost.
@@ -28,8 +28,9 @@ Write every arm side by side on one self-contained HTML page at `<dest>/candidat
28
28
  - One page for the pick, never a set of separate images handed to the operator to compare from memory. The comparison they judge is `candidates.html`, which Step 3 renders and Step 4 asks about. The per-arm files exist only for Step 6's archival capture, once the pick is made, and only the last pass through this step is what Step 6 finds there.
29
29
  - Wrap each arm's markup in the same class on both files, chosen once per run and reused everywhere, so one selector addresses an arm on the combined page and on its own standalone file alike.
30
30
  - Label each arm on the page with its id and its cost, so the render carries what the question will ask about.
31
- - Inline every style, script, and asset the page needs. The render reads the file off disk, so a page reaching for a build step or a network font renders without it and the arms differ by something nobody chose.
32
- - Declare a font stack the machine resolves, such as `system-ui` behind a generic fallback. The render refuses a page that would rewrap against a substitute rather than shipping a false comparison, so a page naming no font at all is refused on whatever the default resolves to.
31
+ - Take the live-app branch instead when the surface under decision is a running app: lift the rendered markup and link a copy of the built stylesheet rather than inlining, per `${CLAUDE_SKILL_DIR}/references/live-arms.md`.
32
+ - On the default path, inline every style, script, and asset the page needs. The render reads the file off disk, so a page reaching for a build step or a network font renders without it and the arms differ by something nobody chose.
33
+ - On the default path, declare a font stack the machine resolves, such as `system-ui` behind a generic fallback. The render refuses a page that would rewrap against a substitute rather than shipping a false comparison, so a page naming no font at all is refused on whatever the default resolves to.
33
34
  - Vary one property across the arms. A page whose arms differ in three ways answers no question, since the pick cannot say which difference decided it.
34
35
 
35
36
  ## Step 3: render and hand off
@@ -68,7 +69,7 @@ Put the choice to the operator through the structured question surface, since a
68
69
  1. Apply the winning arm to the real surface, in one change.
69
70
  2. Close out whatever document stated the decision as open, in the same change, naming the arm that won and the ones that stayed defensible. A pick that changes a surface and records nothing about why leaves the next reader to re-derive it from a diff. Skip this where nothing stated the decision.
70
71
  3. Batch-capture the final round's arm files, when `<dest>` is the scratch path: `canon capture <dest>/arms --selector <wrapper-class> --out <archive-dir>`, naming Step 2's chosen class. This is the directory-batch convention `draft-identity` Step 6 already uses.
71
- 4. Resolve `<archive-dir>` as `.canon/review/evidence/<slug>/` against the main worktree root, since shared session scratch resolves there rather than against a linked worktree this run happens to be building in. The capture is what keeps every arm past the pick, the losing ones included, as a durable revert record distinct from the live comparison page.
72
+ 4. Resolve `<archive-dir>` as `.canon/picks/<slug>/` against the main worktree root, since shared session scratch resolves there rather than against a linked worktree this run happens to be building in. The capture is what keeps every arm past the pick, the losing ones included, as a durable revert record distinct from the live comparison page.
72
73
  5. Delete `<dest>` and every file inside it, when `<dest>` is the scratch path, now that every arm sits at the durable path above. A variant left behind there is a second design nobody maintains.
73
74
  6. Leave `<dest>` in place when it is a live track's `evidence/<slug>/`: `plan-groundwork`'s write scope treats evidence as durable rather than as scratch a session may delete, and the arms already sit at a durable path there.
74
75
  7. Report `<dest>` as still standing when the scratch-path delete is refused, naming the path for the operator to remove, rather than closing on a report the tree contradicts. The pick is applied either way, so the run has done its work and the folder is what outlives it.
@@ -0,0 +1,19 @@
1
+ # Live app arms
2
+
3
+ Read when the surface under decision is a running app rather than a static mockup: the operator's request names a route or URL of the project's own app, or the decision is about a surface a build command serves. Skip it for a decision with nothing running to lift from, which stays on Step 2's default inlined path.
4
+
5
+ ## Lift from the app
6
+
7
+ - Dump the rendered markup of the surface under decision from the built page, after it has loaded, into a file under `<dest>`. Strip scripts from the dump.
8
+ - Copy the built stylesheet and font files beside the page, at the path the dumped markup links them from, so a candidate page renders with the stylesheet the app ships. Every arm then differs from the shipped page only by what the arm names.
9
+ - Trim a large dump to the part the decision needs, and keep the wrapper classes intact so layout rules keyed to them still resolve.
10
+ - Size each frame to the content width the decision names rather than the window width, since a container query reads the frame.
11
+ - Write copy an arm introduces with `write-human`, and take every other word from the dump.
12
+
13
+ ## The page
14
+
15
+ - Generate the page with a short script, one per round, so a shared change is one edit and a rerun.
16
+ - Put a theme button on the page that flips the app's own theme switch on the root, rather than drawing each frame once per theme. Read `?arm=<id>&theme=<name>` to strip every other arm and the button for capture. Skip the button for an app that ships one theme.
17
+ - Print each frame's measurement under it from a script in the page, so the numbers the operator reads are the browser's.
18
+ - Write an index page linking one page per arm when an arm is a whole page or a route rather than a frame, with thumbnails copied beside it.
19
+ - Name anything the preview cannot reproduce, such as an asset whose colors follow the browser rather than the page's theme button, rather than fixing the page around it.
@@ -167,11 +167,11 @@ After a migration pass, add: `Converted .claude/DIAGRAMS.md into N entries. The
167
167
  If the user asks to export the diagrams (`export to svg`, `give me images`, `render to png`), run:
168
168
 
169
169
  ```bash
170
- mkdir -p .canon/review/diagrams && bunx -y @mermaid-js/mermaid-cli -i .canon/diagrams/<kind>.md -o .canon/review/diagrams/<kind>.png
170
+ mkdir -p .canon/tmp/render/diagrams && bunx -y @mermaid-js/mermaid-cli -i .canon/diagrams/<kind>.md -o .canon/tmp/render/diagrams/<kind>.png
171
171
  ```
172
172
 
173
173
  Export PNG by default. Swap the extension for `.svg` only when the user asks for vector, and never for the Step 5 verification path. The CLI writes one file per `mermaid` block, suffixing when an entry holds more than one. Export every entry when the user names no kind. Output line:
174
174
 
175
175
  ```plaintext
176
- 📝 Wrote N files to .canon/review/diagrams/
176
+ 📝 Wrote N files to .canon/tmp/render/diagrams/
177
177
  ```
@@ -40,7 +40,7 @@ The palette and type scale live in the CLI. Own the choices the source controls.
40
40
  Shell out to the CLI. It writes the deck and reports the path.
41
41
 
42
42
  ```bash
43
- canon slides render --source .claude/SLIDES.md --out .canon/review/slides
43
+ canon slides render --source .claude/SLIDES.md --out .canon/tmp/render/slides
44
44
  ```
45
45
 
46
46
  Pass `--variant light` or `--variant dark` to override the source variant for a one-off render. Pass `--open` to open the deck, and `--mirror <dir>` (or set `CANON_SLIDES_MIRROR`) to copy it into a synced folder.
@@ -58,7 +58,7 @@ Output up to four lines:
58
58
  ✅ Shipped
59
59
  <N facts routed to context entries>
60
60
  <N memories captured in .canon/memory/>
61
- <Memory proposal at .canon/review/memory/memory-review-<slug>.md>
61
+ <Memory proposal at .canon/memory/review/memory-review-<slug>.md>
62
62
  ```
63
63
 
64
64
  Omit the second line if nothing routed. Omit the third and fourth if `memory-capture` wrote no memory file this session, since an empty pen means no scoped review and no proposal.
@@ -68,7 +68,7 @@ The handoff is a file rather than a spoken result so the routed fact survives a
68
68
 
69
69
  ## Step 4: dedupe
70
70
 
71
- For each remaining candidate, grep `.canon/memory/` for an existing file on the same topic. If one exists, update it in place rather than create a new file. Read it first and write the whole file back, since the guard above rules out editing a line inside it.
71
+ For each remaining candidate, grep the top-level `*.md` files in `.canon/memory/` for an existing file on the same topic, never its `review/` or `archive/` subfolders, since a hit there is a receipt or a retired entry rather than a live one to update. If one exists, update it in place rather than create a new file. Read it first and write the whole file back, since the guard above rules out editing a line inside it.
72
72
 
73
73
  ## Step 5: write the residue
74
74
 
@@ -5,7 +5,7 @@ description: Reviews `.canon/memory/` and proposes per-entry actions (promote to
5
5
 
6
6
  # Memory review
7
7
 
8
- This skill drives the full memory review lifecycle in five phases. Pick the phase from what the user said and whether a review receipt already exists at `<main-root>/.canon/review/memory/memory-review-*.md`.
8
+ This skill drives the full memory review lifecycle in five phases. Pick the phase from what the user said and whether a review receipt already exists at `<main-root>/.canon/memory/review/memory-review-*.md`.
9
9
 
10
10
  What an entry looks like and why a retired one is moved rather than deleted are fixed by `${CLAUDE_SKILL_DIR}/../../standards/memory.md`. Read it before rewriting an entry, since a promotion rewrites the rule and a rewrite has to leave the entry conforming.
11
11
 
@@ -23,7 +23,7 @@ If the user re-pings the skill with no new phrase and a receipt exists, default
23
23
 
24
24
  - All `.canon/memory/` reads, edits, and archive moves resolve at the main worktree root, not the current worktree. Resolve that root the way `session-worktree` does.
25
25
  - If no `.canon/memory/` directory exists at the main worktree root, stop: `❌ No .canon/memory/ directory found.`
26
- - If `.canon/memory/` contains no `*.md` entries other than `index.md`, stop: `✅ No memory entries to review.`
26
+ - If `.canon/memory/` contains no top-level `*.md` entries other than `index.md`, stop: `✅ No memory entries to review.` The pen holds two subfolders now, `review/` and `archive/`, and neither is a memory entry, so this count and every entry read below stay at the top level and never recurse into either.
27
27
  - Cleanup is exempt from the two stops above. It works on receipts in `.canon/review/`, and a drained pen is the normal state once Apply has run, so a pen-shaped stop would strand the receipt it exists to delete.
28
28
  - Resolve the main root via `git worktree list --porcelain | grep -m 1 '^worktree ' | cut -d' ' -f2-`, falling back to `pwd`. All review and memory reads anchor here.
29
29
  - From a linked worktree the file-editing tools refuse every main-root path, so each write below goes out through `Bash` as a plain single command. The receipt and a memory entry are both short and this session has read them whole, so a rewrite replaces the file with a heredoc rather than editing a line inside it. Promotion targets are tracked files at `pwd` and keep taking `Edit`.
@@ -42,7 +42,7 @@ Propose is the ship-time entry point. The ship skills run it right after capture
42
42
  Read in parallel from the project root:
43
43
 
44
44
  - `.canon/memory/index.md`: the generated index
45
- - every other `*.md` file under `.canon/memory/`: individual entries with frontmatter (`title`, `description`, `category`)
45
+ - every other top-level `*.md` file in `.canon/memory/`, never its `review/` or `archive/` subfolders: individual entries with frontmatter (`title`, `description`, `category`)
46
46
 
47
47
  ### Step 2: read promotion targets
48
48
 
@@ -72,7 +72,7 @@ For each in-scope entry (see Scope), pick one action:
72
72
  - **Hand off to governance**: the rule is coding-standards class (typescript, testing, naming, error-handling, performance, logging, concurrency, planning), never a cross-domain behavior rule. Do not author the rule file inline. Never edit the synced `.claude/rules/` copies of toolkit rules, because `canon gov sync` overwrites them. Stop at handoff. This and **Promote to an always-loaded rule** never both claim one entry: class names the topic (coding-standards routes here), firing axis names the rest (applies-every-session routes to the rule promote).
73
73
  - In the toolkit repo, point the user at `internal-governance` and `${CLAUDE_SKILL_DIR}/../../standards/rule.md`, which own the source-of-truth rules under `governance/rules/`.
74
74
  - In a target project, point the user at the `create-rule` skill, which scaffolds a project-local rule under `.claude/rules/`.
75
- - **Retire**: the rule is stale, already absorbed into a durable surface, too vague to phrase as a rule, or a one-time incident narrative. Apply moves the file to `.canon/tmp/memory-archive/` rather than deleting it.
75
+ - **Retire**: the rule is stale, already absorbed into a durable surface, too vague to phrase as a rule, or a one-time incident narrative. Apply moves the file to `.canon/memory/archive/` rather than deleting it.
76
76
 
77
77
  Retire is an archive, not a deletion, which `${CLAUDE_SKILL_DIR}/../../standards/memory.md` states as the rule and this skill executes. The archive is worth less than a plan's, since a promoted entry survives in its destination and a stale one is discarded on purpose, which is why the move is cheap rather than free.
78
78
 
@@ -92,11 +92,11 @@ Rules that resist crisp one-line phrasing default to **Retire** over promote. Ne
92
92
 
93
93
  Derive `<slug>` per `${CLAUDE_SKILL_DIR}/../../standards/slug.md`. Fall back to `latest` on an empty result.
94
94
 
95
- Write the full proposal to `.canon/review/memory/memory-review-<slug>.md` at the main worktree root. Do not print it inline. Read `${CLAUDE_SKILL_DIR}/references/receipt-format.md` for the file structure, the item template, and how each action type varies the body. The four phases below rewrite items inside an existing receipt rather than authoring one, so none of them opens it.
95
+ Write the full proposal to `.canon/memory/review/memory-review-<slug>.md` at the main worktree root. Do not print it inline. Read `${CLAUDE_SKILL_DIR}/references/receipt-format.md` for the file structure, the item template, and how each action type varies the body. The four phases below rewrite items inside an existing receipt rather than authoring one, so none of them opens it.
96
96
 
97
97
  A phase changing items reads the receipt, applies every change for that phase, and writes the whole file back in one command. Batching is what keeps a per-item rewrite from costing a full read each time, and it is the only route from a linked worktree, where the guard above rules out editing a line in place.
98
98
 
99
- Tell the user `✅ Wrote proposal to .canon/review/memory/memory-review-<slug>.md`. Ask them to fill in `Decision:` per item, then re-ping with "discuss" for question rounds or "apply" to commit.
99
+ Tell the user `✅ Wrote proposal to .canon/memory/review/memory-review-<slug>.md`. Ask them to fill in `Decision:` per item, then re-ping with "discuss" for question rounds or "apply" to commit.
100
100
 
101
101
  Rewrite the review file in place whenever the proposal changes mid-review. The file stays the source of truth for the current decisions.
102
102
 
@@ -104,7 +104,7 @@ Rewrite the review file in place whenever the proposal changes mid-review. The f
104
104
 
105
105
  Trigger: user says "challenge the promotes", "challenge before apply", or asks for a high-bar pass. Run before Apply. No mutations to memory files or promotion targets. Review file only.
106
106
 
107
- 1. Read the latest `.canon/review/memory/memory-review-*.md` at the main root.
107
+ 1. Read the latest `.canon/memory/review/memory-review-*.md` at the main root.
108
108
  2. For each promote item, apply three tests:
109
109
  - **Absorbed**: grep the target surface for the rule's keywords. If already stated or implied, flip to retire.
110
110
  - **Delta**: if the rule is a nice-to-have next to existing bullets, flip to retire.
@@ -115,7 +115,7 @@ Trigger: user says "challenge the promotes", "challenge before apply", or asks f
115
115
 
116
116
  Trigger: user says "discuss", "respond to questions", or any `Decision:` value contains `?` or an unrecognized verb. No mutations to memory files or targets. Review file only. Multi-round.
117
117
 
118
- 1. Read the latest `.canon/review/memory/memory-review-*.md` at the main root.
118
+ 1. Read the latest `.canon/memory/review/memory-review-*.md` at the main root.
119
119
  2. For each item whose `Decision:` contains `?` or any unrecognized verb (anything other than `apply`, `skip`, `defer`):
120
120
  - Write a `Take:` line under `Decision:`, separated by exactly one blank line. If a `Take:` line already exists, overwrite it.
121
121
  - Format: pick + one-line reason. Max 2 sentences. Decision-help style. State the recommendation (`apply` / `skip` / `retire` / specific alternative) first, then the reason. Do not enumerate tradeoffs unless one changes the call.
@@ -157,7 +157,7 @@ Action by action type:
157
157
  - **Hand off**: do not edit governance. Archive the memory file only if the user confirmed the handoff explicitly. Otherwise leave it in place.
158
158
  - **Retire**: archive the memory file.
159
159
 
160
- Archiving means creating `.canon/tmp/memory-archive/` at the main worktree root and moving the file there under its original name, overwriting any file already at that name. Send the `mkdir -p` and the `mv` as two plain commands rather than joining them with `&&`, which is refused as compound from a linked worktree. Never delete a memory entry. Nothing recovers one from a gitignored folder.
160
+ Archiving means creating `.canon/memory/archive/` at the main worktree root and moving the file there under its original name, overwriting any file already at that name. Send the `mkdir -p` and the `mv` as two plain commands rather than joining them with `&&`, which is refused as compound from a linked worktree. Never delete a memory entry. Nothing recovers one from a gitignored folder.
161
161
 
162
162
  Do not hand-edit `.canon/memory/index.md`. Once every archive move is done, regenerate it instead:
163
163
 
@@ -189,11 +189,11 @@ End with: `✅ Applied: <nums> | ⏭ Skipped: <nums> | 📝 Pending: <nums>`. Om
189
189
 
190
190
  Trigger: user says "cleanup" or "delete the receipt" after Apply has run.
191
191
 
192
- Cleanup folds one receipt's skips and removes that receipt, and does nothing else. It is the fallback route now that Apply and `docs-fold` Step 10 each collect a resolved receipt on their own, so it reaches a file those two left behind rather than being the only collector. Apply is still the only phase that moves a memory entry out of the pen, and it does so per approved item into `.canon/tmp/memory-archive/`. A user asking to sweep stale memories wants Propose, which classifies entries and writes a decision slot per entry.
192
+ Cleanup folds one receipt's skips and removes that receipt, and does nothing else. It is the fallback route now that Apply and `docs-fold` Step 10 each collect a resolved receipt on their own, so it reaches a file those two left behind rather than being the only collector. Apply is still the only phase that moves a memory entry out of the pen, and it does so per approved item into `.canon/memory/archive/`. A user asking to sweep stale memories wants Propose, which classifies entries and writes a decision slot per entry.
193
193
 
194
- If no `.canon/review/memory/memory-review-*.md` exists at the main root, stop: `✅ No review receipt to clean up.` Every other refusal in this skill carries a message, and the phase reads a receipt before it does anything else.
194
+ If no `.canon/memory/review/memory-review-*.md` exists at the main root, stop: `✅ No review receipt to clean up.` Every other refusal in this skill carries a message, and the phase reads a receipt before it does anything else.
195
195
 
196
- 1. Read the latest `.canon/review/memory/memory-review-*.md` at the main root and confirm Apply has run against it. If any item is still 📝 pending, stop and name the pending numbers.
196
+ 1. Read the latest `.canon/memory/review/memory-review-*.md` at the main root and confirm Apply has run against it. If any item is still 📝 pending, stop and name the pending numbers.
197
197
  2. Collect it per the collection rule in `${CLAUDE_SKILL_DIR}/../../standards/memory.md`, folding each ⏭ skipped item before the file goes. The fold happens wherever a receipt is collected, so this phase runs the same rule the Apply sweep does.
198
198
  3. Delete that one file. Leave every other receipt beside it in place, because the pending test above covers the file it read and nothing has tested the rest.
199
199
  4. Leave every memory entry in the pen. A skip records the decline on the entry and keeps the file, and applied promotions, governance handoffs, and user-type memories each stay as the review left them.
@@ -206,7 +206,7 @@ Output one line per action taken in the most recent phase:
206
206
 
207
207
  - `✅ Promoted: .canon/memory/<memory-file> → <target>`
208
208
  - `✅ Handed off: .canon/memory/<memory-file> → governance`
209
- - `📦 Retired: .canon/memory/<memory-file> → .canon/tmp/memory-archive/`
209
+ - `📦 Retired: .canon/memory/<memory-file> → .canon/memory/archive/`
210
210
  - `🗑 Swept: .canon/review/<review-file>, folded <n> skips`
211
211
  - `⏭ Kept: .canon/review/<review-file>, <n> items pending`
212
212
 
@@ -5,7 +5,7 @@ description: The proposal file structure, its item template, and how each action
5
5
 
6
6
  # Memory review receipt format
7
7
 
8
- The shape Step 4 of the Propose phase writes to `.canon/review/memory/memory-review-<slug>.md`. Only Propose writes this file. Challenge, Discuss, and Apply rewrite items inside a receipt that already exists, and Cleanup deletes one, so none of the four needs this file.
8
+ The shape Step 4 of the Propose phase writes to `.canon/memory/review/memory-review-<slug>.md`. Only Propose writes this file. Challenge, Discuss, and Apply rewrite items inside a receipt that already exists, and Cleanup deletes one, so none of the four needs this file.
9
9
 
10
10
  ## Structure
11
11
 
@@ -114,7 +114,7 @@ If nothing is wrong, use: `✅ No findings.`
114
114
 
115
115
  Derive `<slug>` per `${CLAUDE_SKILL_DIR}/../../standards/slug.md`. Fall back to `latest` on an empty result.
116
116
 
117
- Write the full report directly to `.canon/review/branch/review-<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.
117
+ Write the full report directly to `.canon/review/branch-<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.
118
118
 
119
119
  From a linked worktree the file-editing tools refuse that path, so the report 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.
120
120
 
@@ -130,7 +130,7 @@ Output only the summary line and the file path. Do not repeat the full report in
130
130
 
131
131
  ```plaintext
132
132
  X critical, Y should-fix, Z minor across N files.
133
- 📝 Wrote .canon/review/branch/review-<slug>.md
133
+ 📝 Wrote .canon/review/branch-<slug>.md
134
134
  ```
135
135
 
136
- If no findings: `✅ No findings. Wrote .canon/review/branch/review-<slug>.md`
136
+ If no findings: `✅ No findings. Wrote .canon/review/branch-<slug>.md`
@@ -22,9 +22,10 @@ running and re-invoking it would restart the build.
22
22
 
23
23
  ## Where the session stands
24
24
 
25
- - Resolve `.canon/plans/`, `.canon/tasks/`, `.canon/review/`, and `.canon/memory/` at the main worktree root, never against the linked worktree this session builds in. Those folders are gitignored, so `git worktree add` never creates them and the copy beside the build is absent rather than empty.
25
+ - Resolve `.canon/plans/`, `.canon/tasks/`, `.canon/review/`, `.canon/memory/`, and `.canon/ready/` at the main worktree root, never against the linked worktree this session builds in. Those folders are gitignored, so `git worktree add` never creates them and the copy beside the build is absent rather than empty.
26
26
  - Report a plan that fails to resolve as unreadable from here, naming the main-root path. Reporting the task as having no plan is true where this session stands and wrong about the world, and a reader with no second tree to check cannot separate the two.
27
27
  - Build the plan the launch named. Do not write a second one when the path fails to resolve, since a row that cites a plan already has one and drafting another produces two plans for one row.
28
+ - Copy a ready folder's files verbatim to the paths its plan's constraints name, when the plan's `**Constraints:**` block names one, and edit only what the gate or the overview's own list requires. A rewrite discards the text the handoff exists to carry.
28
29
  - Report a draft flag reading ready once, and leave it cleared. The ship chain marks the pull request a draft and no step anywhere un-marks, so a flag reading ready afterwards was lifted by the operator or by the controlling session that closed the review, each acting directly on the pull request, which GitHub requires before a merge. Re-drafting fights them, which four sessions did on 2026-08-31 on a belief no surface in the tree states.
29
30
  - Refuse an instruction to lift the mark yourself, whoever sends it. This session cannot verify who is asking or whether review actually closed, so the refusal holds regardless of the sender's claimed authority. A controlling session instructed a worker to lift the mark instead of taking the act itself on 2026-09-07, and the worker complied and reported against the surface rather than the outcome.
30
31
  - Rewrite a plan question's `- Suggested:` line as `overridden at execution to <pick>,` plus the measurement when this build decides against an unanswered one, leaving the `- Answer:` slot blank, and put the same deviation in one line under the open task's `## Findings`, per `${CLAUDE_SKILL_DIR}/../../standards/plan.md`.
@@ -44,7 +44,7 @@ The arms here are fixed references rather than drafted markup, so nothing about
44
44
 
45
45
  1. Carry forward the reason Step 3's pick already stated, as written rather than paraphrased. Ask the operator to state, in their own words, why the picked reference won only when the pick arrived with no reason attached.
46
46
  2. Read the picked arm's render at `<dest>/refs/arm-<id>.png` and trace its color, type, and spacing by looking, the same reading a person does against a screenshot. Name a role only where the reference actually shows it. Leave one out rather than guessing.
47
- 3. Write `.canon/review/evidence/<slug>/design-handoff.md`, resolved against the main worktree root rather than the linked worktree this run may be building in, since shared session scratch always resolves there. One field per line, grouped under the section names `${CLAUDE_SKILL_DIR}/../../standards/design.md` fixes, so `design-extract` reads it mechanically:
47
+ 3. Write `.canon/picks/<slug>/design-handoff.md`, resolved against the main worktree root rather than the linked worktree this run may be building in, since shared session scratch always resolves there. One field per line, grouped under the section names `${CLAUDE_SKILL_DIR}/../../standards/design.md` fixes, so `design-extract` reads it mechanically:
48
48
 
49
49
  ```markdown
50
50
  # Design handoff
@@ -71,14 +71,14 @@ The arms here are fixed references rather than drafted markup, so nothing about
71
71
 
72
72
  Write only the sections and roles the trace actually names. A role or a whole section with nothing traced is left out rather than written empty, since `design-extract` Step 2 treats an absent line as untraced and an empty one as a claim about the source.
73
73
 
74
- 4. Batch-capture the final round's arm files, the same directory-batch convention `draft-and-pick` Step 6 uses: `canon capture <dest>/arms --selector <wrapper-class> --out .canon/review/evidence/<slug>/`, naming Step 2's chosen class, so every arm considered, not only the winner, survives past the pick as a revert record.
74
+ 4. Batch-capture the final round's arm files, the same directory-batch convention `draft-and-pick` Step 6 uses: `canon capture <dest>/arms --selector <wrapper-class> --out .canon/picks/<slug>/`, naming Step 2's chosen class, so every arm considered, not only the winner, survives past the pick as a revert record.
75
75
  5. Delete `<dest>` and everything in it, now that the handoff and the arms both sit at the durable path above. Report the path as still standing when the delete is refused, rather than closing on a report the tree contradicts.
76
76
 
77
77
  ## Response format
78
78
 
79
79
  ```plaintext
80
- 📝 Wrote .canon/review/evidence/<slug>/design-handoff.md
81
- 📝 Wrote .canon/review/evidence/<slug>/arm-<id>.png (and every other arm considered)
80
+ 📝 Wrote .canon/picks/<slug>/design-handoff.md
81
+ 📝 Wrote .canon/picks/<slug>/arm-<id>.png (and every other arm considered)
82
82
 
83
83
  Picked arm-<id>: <label>. Run /canon:design-extract to fill canon/DESIGN.md from the trace.
84
84
  ```
@@ -27,7 +27,7 @@ A walkthrough turns what the operator sees in a running app into findings and pi
27
27
  2. **Take the operator's list in their order.** Name each item as a finding with the walkthrough letter and a number, such as T1, and confirm the order once rather than per item.
28
28
  3. **Measure before drafting.** Read the component behind the finding and pull the numbers off the built page, per `${CLAUDE_SKILL_DIR}/references/measuring.md`. Write the finding into the walkthrough file with those numbers before any arm exists.
29
29
  4. **Route a finding with no visible choice.** A parse defect, a stale figure or a broken invariant gets recorded as a finding with no draft and goes into the batch as a proposed row, not as a pick.
30
- 5. **Draft three or four arms.** Follow `draft-and-pick` Steps 1 and 2 for the arms, with arm 0 the shipped state, one property varied and a cost on each. Build the page from the app's own rendered markup, per `${CLAUDE_SKILL_DIR}/references/candidate-pages.md`.
30
+ 5. **Draft three or four arms.** Follow `draft-and-pick` Steps 1 and 2 for the arms, with arm 0 the shipped state, one property varied and a cost on each. Take `draft-and-pick`'s live-app branch of Step 2 to build the page from the app's own rendered markup, per `${CLAUDE_SKILL_DIR}/references/candidate-pages.md`.
31
31
  6. **Look before handing anything over.** Capture every arm in every theme the app ships into `.canon/walkthroughs/<nn>-<slug>/evidence/<nn>-<slug>/`, with the finding's number as the prefix, open the captures, and fix what rendered wrong before the operator sees the page.
32
32
  7. **Hand the link, then ask.** Emit `http://localhost:<port>/<nn>-<slug>/candidates.html` in a message that ends the turn, confirmed with a `200`, carrying no question. Take any reply after that message as the operator having looked, an explicit "go" included, rather than holding for a stated confirmation, and only then put the choice through the structured question surface with the recommendation first.
33
33
  8. **Record the pick.** Write what won, what it beat and by which numbers, where the evidence is, and the build criteria, per `${CLAUDE_SKILL_DIR}/references/record.md`. Read every figure you quote back from the page or the data file first, and correct the record where the question quoted one wrong.
@@ -44,7 +44,7 @@ A walkthrough turns what the operator sees in a running app into findings and pi
44
44
 
45
45
  ## What this delegates
46
46
 
47
- - `draft-and-pick` owns the arm discipline and the structured question. This walkthrough departs from its Step 2 inlining and its Step 6 apply and delete, for the reasons `${CLAUDE_SKILL_DIR}/references/candidate-pages.md` states.
47
+ - `draft-and-pick` owns the arm discipline and the structured question. This walkthrough takes its live-app branch of Step 2 and departs from its Step 6 apply and delete, for the reasons `${CLAUDE_SKILL_DIR}/references/candidate-pages.md` states.
48
48
  - `write-human` carries the voice of every recorded passage and any copy an arm puts in front of a reader.
49
49
  - `plan-feature` and whoever dispatches builds turn a batch into plans and code.
50
50
  - `canon capture`, `canon serve` and `canon sessions list` own the render, the address and the roster.
@@ -2,25 +2,10 @@
2
2
 
3
3
  Read when drafting arms for a finding. Skip it for a finding with no visible choice.
4
4
 
5
- ## Build from the app
6
-
7
- - Dump the rendered markup of the surface under test from the built page, after it has loaded, into a JSON file in scratch. Strip scripts from the dump.
8
- - Copy the built stylesheet and font files under `.canon/tmp/`, at the path the dumped markup links them from, so a candidate page renders with the stylesheet the app ships. Every arm then differs from the shipped page only by what the arm names.
9
- - Trim a large dump to the part the finding needs, and keep the wrapper classes intact so layout rules keyed to them still resolve.
10
- - Size each frame to the content width the finding names rather than the window width, since a container query reads the frame.
11
- - Write copy an arm introduces with `write-human`, and take every other word from the dump.
12
-
13
- ## The page
14
-
15
- - Generate the page with a short script, one per round, so a shared change is one edit and a rerun.
16
- - Put a theme button on the page that flips the app's own theme switch on the root, rather than drawing each frame once per theme. Read `?arm=<id>&theme=<name>` to strip every other arm and the button for capture. Skip the button for an app that ships one theme.
17
- - Print each frame's measurement under it from a script in the page, so the numbers the operator reads are the browser's.
18
- - Write an index page linking one page per arm when an arm is a whole page or a route rather than a frame, with thumbnails copied beside it.
19
- - Name anything the preview cannot reproduce, such as an asset whose colors follow the browser rather than the page's theme button, rather than fixing the page around it.
5
+ Follow `${CLAUDE_SKILL_DIR}/../draft-and-pick/SKILL.md` Step 2's live-app branch for lifting the markup, copying the stylesheet, and building the page, which routes to its own `references/live-arms.md`. What follows is only where this walkthrough departs from that shared path.
20
6
 
21
7
  ## Where this departs from draft-and-pick
22
8
 
23
9
  - Capture into the walkthrough's own numbered evidence folder instead of the folder `draft-and-pick` Step 6 archives arms into, per `${CLAUDE_SKILL_DIR}/references/record.md`.
24
- - Link the app's built stylesheet instead of inlining every asset. Lifted markup needs the real stylesheet, and an inlined copy is the drift this avoids.
25
10
  - Keep `candidates.html` and never apply the winning arm. The walkthrough records and a build applies.
26
11
  - Leave `.canon/tmp/<nn>-<slug>/` in place until the picks are built, and never delete the round's evidence folder.