@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.
- package/claude/.claude-plugin/plugin.json +1 -1
- package/claude/skills/auto-ship/SKILL.md +6 -6
- package/claude/skills/canon-feedback-file/SKILL.md +2 -2
- package/claude/skills/design-extract/SKILL.md +3 -3
- package/claude/skills/docs-fold/SKILL.md +3 -3
- package/claude/skills/draft-and-pick/REQUIREMENT.md +2 -1
- package/claude/skills/draft-and-pick/SKILL.md +4 -3
- package/claude/skills/draft-and-pick/references/live-arms.md +19 -0
- package/claude/skills/draft-diagram/SKILL.md +2 -2
- package/claude/skills/draft-slides/SKILL.md +1 -1
- package/claude/skills/git-ship/SKILL.md +1 -1
- package/claude/skills/memory-capture/SKILL.md +1 -1
- package/claude/skills/memory-review/SKILL.md +13 -13
- package/claude/skills/memory-review/references/receipt-format.md +1 -1
- package/claude/skills/review-branch/SKILL.md +3 -3
- package/claude/skills/role-worker/SKILL.md +2 -1
- package/claude/skills/sketch-design/SKILL.md +4 -4
- package/claude/skills/ux-walkthrough/SKILL.md +2 -2
- package/claude/skills/ux-walkthrough/references/candidate-pages.md +1 -16
- package/docs/agents/commands.md +100 -95
- package/docs/agents/design-board.md +7 -7
- package/docs/workflow/ai-workflow.md +3 -3
- package/docs/workflow/visual-design-workflow.md +1 -1
- package/governance/rules/claude/563-ready.md +11 -0
- package/governance/rules/core/045-memory.md +1 -1
- package/package.json +1 -1
- package/src/cli.ts +1 -1
- package/src/commands/design.ts +3 -3
- package/src/commands/feedback.ts +12 -12
- package/src/commands/migrate.ts +168 -3
- package/src/commands/slides.ts +2 -2
- package/src/design/board.ts +17 -10
- package/src/migrate/evidence-ordinal.ts +79 -0
- package/src/migrate/record-layout.ts +599 -0
- package/src/migrate/record-tree.ts +1 -1
- package/src/migrate/scratch-evidence.ts +57 -30
- package/src/record-root.ts +4 -0
- package/standards/index.md +1 -0
- package/standards/memory.md +1 -1
- package/standards/plan.md +2 -0
- package/standards/publish.md +1 -1
- package/standards/ready.md +105 -0
- package/standards/skill.md +1 -1
- package/tooling/claude/seeds/.claude/hooks/memory-index.sh +10 -0
|
@@ -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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
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
|
|
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
|
|
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
|
|
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
|
-
-
|
|
32
|
-
-
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
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
|
|
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
|
|
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
|
|
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/
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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/
|
|
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/
|
|
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
|
|
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
|
|
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/
|
|
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
|
|
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
|
|
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
|
|
133
|
+
📝 Wrote .canon/review/branch-<slug>.md
|
|
134
134
|
```
|
|
135
135
|
|
|
136
|
-
If no findings: `✅ No findings. Wrote .canon/review/branch
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
81
|
-
📝 Wrote .canon/
|
|
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.
|
|
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
|
|
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
|
-
|
|
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.
|