@erclx/canon 5.7.0 → 5.9.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 (77) hide show
  1. package/README.md +4 -2
  2. package/claude/.claude-plugin/plugin.json +2 -2
  3. package/claude/skills/auto-ship/SKILL.md +2 -0
  4. package/claude/skills/draft-and-pick/REQUIREMENT.md +2 -1
  5. package/claude/skills/draft-and-pick/SKILL.md +9 -6
  6. package/claude/skills/git-followup/SKILL.md +1 -1
  7. package/claude/skills/git-pr/references/evidence.md +1 -1
  8. package/claude/skills/git-ship/REQUIREMENT.md +3 -2
  9. package/claude/skills/git-ship/SKILL.md +25 -2
  10. package/claude/skills/review-address/SKILL.md +6 -4
  11. package/claude/skills/review-craft/REQUIREMENT.md +8 -2
  12. package/claude/skills/review-craft/SKILL.md +63 -7
  13. package/claude/skills/review-craft/references/adopted.md +49 -0
  14. package/docs/agents/commands.md +2 -0
  15. package/docs/agents/hooks.md +56 -0
  16. package/docs/agents/index.md +1 -0
  17. package/docs/agents/install-and-sync.md +1 -1
  18. package/docs/agents/markdown-audit.md +1 -1
  19. package/docs/agents/pr-evidence.md +33 -17
  20. package/docs/agents/records-push.md +1 -1
  21. package/docs/agents/records-validate.md +1 -1
  22. package/docs/agents/scripting.md +6 -0
  23. package/docs/agents/tasks-archive.md +4 -2
  24. package/docs/agents/tasks.md +1 -1
  25. package/docs/agents/worktrees.md +2 -2
  26. package/docs/target/scenarios.md +2 -2
  27. package/package.json +2 -2
  28. package/src/claude/skills-audit.ts +1 -0
  29. package/src/cli.ts +2 -0
  30. package/src/commands/claude.ts +1 -1
  31. package/src/commands/docs.ts +51 -11
  32. package/src/commands/hooks.ts +67 -0
  33. package/src/commands/pr.ts +146 -76
  34. package/src/commands/standards.ts +33 -2
  35. package/src/commands/tasks.ts +45 -0
  36. package/src/commands/tooling.ts +3 -3
  37. package/src/commands/upgrade.ts +3 -2
  38. package/src/commands/worktrees.ts +4 -3
  39. package/src/docs/list.ts +103 -0
  40. package/src/docs/read.ts +63 -19
  41. package/src/gov/stacks.ts +1 -1
  42. package/src/help.ts +2 -0
  43. package/src/hooks/post-merge.ts +331 -0
  44. package/src/pr/evidence.ts +21 -0
  45. package/src/records/validate.ts +1 -38
  46. package/src/standards/list.ts +33 -0
  47. package/src/standards/read.ts +13 -0
  48. package/src/standards/scope.ts +56 -0
  49. package/src/sync/check.ts +38 -4
  50. package/src/tasks/archive.ts +168 -3
  51. package/src/tooling/inject.ts +4 -3
  52. package/src/tooling/manifest.ts +62 -8
  53. package/src/tooling/scan.ts +4 -3
  54. package/src/tooling/stamp.ts +11 -2
  55. package/src/tooling/subfolder.ts +7 -3
  56. package/tooling/astro/reference.md +1 -1
  57. package/tooling/base/configs/scripts/verify.json +3 -0
  58. package/tooling/base/configs/scripts/verify.sh +1 -110
  59. package/tooling/base/configs/scripts/verify.ts +378 -0
  60. package/tooling/base/manifest.toml +1 -0
  61. package/tooling/base/reference.md +5 -3
  62. package/tooling/go/configs/scripts/verify.json +10 -0
  63. package/tooling/go/reference.md +5 -4
  64. package/tooling/php/configs/scripts/verify.json +7 -0
  65. package/tooling/php/reference.md +5 -4
  66. package/tooling/python/configs/scripts/verify.json +4 -0
  67. package/tooling/python/reference.md +3 -3
  68. package/tooling/web/configs/scripts/verify.json +3 -0
  69. package/tooling/web/reference.md +3 -3
  70. package/scripts/docs/list.sh +0 -184
  71. package/scripts/lib/frontmatter.sh +0 -30
  72. package/scripts/standards/list.sh +0 -115
  73. package/src/commands/pass-through.ts +0 -39
  74. package/tooling/go/configs/scripts/verify.sh +0 -142
  75. package/tooling/php/configs/scripts/verify.sh +0 -147
  76. package/tooling/python/configs/scripts/verify.sh +0 -141
  77. package/tooling/web/configs/scripts/verify.sh +0 -153
package/README.md CHANGED
@@ -11,7 +11,7 @@
11
11
  [![CI status](https://img.shields.io/github/actions/workflow/status/erclx/canon/verify.yml?branch=main)](https://github.com/erclx/canon/actions/workflows/verify.yml)
12
12
  [![License MIT](https://img.shields.io/npm/l/@erclx/canon)](LICENSE)
13
13
 
14
- canon is a CLI and Claude Code plugin that stops your AI conventions drifting apart across repositories. It keeps one authoritative copy and installs it into each project on demand.
14
+ canon is a CLI and Claude Code plugin that runs your agent's work from plan to merge, holds it to the practices that make code worth keeping, and installs the same setup in every repository.
15
15
 
16
16
  **[See it run at canon.erclx.dev](https://canon.erclx.dev)**
17
17
 
@@ -21,7 +21,9 @@ That page is one real session the toolkit ran on itself, and every count on it i
21
21
 
22
22
  ## Why
23
23
 
24
- If you work across more than one repository and your AI setup has started to drift between them, this is for you. Every AI coding setup accumulates the same assets. Prompts to reuse, rules agents should follow, slash commands, skills, seed docs, sync scripts. Once you have enough projects, your copies drift and your agents stop getting consistent signals.
24
+ If an agent writes code for you in more than one repository, this is for you. canon runs that work from plan to merge. A planner writes the plan, a worker builds it on its own branch, and a separate session reviews the pull request. It holds the work to a practice, with rules that load when a matching path is edited and checks that fail when a rule is ignored. Both run on one setup, installed the same way in every repository you keep.
25
+
26
+ That shared setup is what the rest of this page describes, and it is the part that drifts without a source. Every AI coding setup accumulates the same assets. Prompts to reuse, rules agents should follow, slash commands, skills, seed docs, sync scripts. Once you have enough projects, your copies drift and your agents stop getting consistent signals.
25
27
 
26
28
  Three design choices shape the toolkit.
27
29
 
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "canon",
3
- "description": "Automated governance, versioning, and discovery tools for Claude Code.",
4
- "version": "5.7.0",
3
+ "description": "Runs your agent's work and keeps its code good, on one setup for every repo.",
4
+ "version": "5.9.0",
5
5
  "author": {
6
6
  "name": "Eric Le",
7
7
  "url": "https://github.com/erclx"
@@ -143,6 +143,8 @@ Invoke `canon:git-ship`. That body owns the sequence, being the verify gate, mem
143
143
 
144
144
  One thing this chain adds. Mark the pull request as a draft as soon as `git-ship`'s pull request step returns, ahead of its CI watch, naming the number that step returned rather than one resolved by branch. Read `${CLAUDE_SKILL_DIR}/references/draft-mark.md` on reaching that point for the one command that proves the target, marks it, and reads the flag back. A `false` read stops the chain, and never re-issue the mark on it.
145
145
 
146
+ Emit the Output block on the wake after `git-ship`'s background CI watch exits on `passing`, not when the turn ends on its watch line.
147
+
146
148
  `git-ship` verifies again at its own gate, repeating Step 3 on a clean run. Keep that repeat, since a resumed run enters at that gate.
147
149
 
148
150
  ## Output
@@ -29,6 +29,7 @@ Without this skill, a session facing a decision nobody can settle from a diff:
29
29
  - Judges a lower layer through a finished higher one, so an operator asked about composition looks at the palette instead and answers about that.
30
30
  - Hands over the combined page alone for a decision about layout, where every arm sits in a column while the media queries answer to the whole window, so no arm is ever seen at its own viewport and a fault that appears only narrower survives the pick.
31
31
  - Rebuilds a navigation harness by hand on a run with several rounds, since each round writes its own folder and nothing reaches all of them from one address. Two design tracks hand-wrote the same page picker and theme toggle.
32
+ - Puts the pick question with no address in its output, after capturing the page and reading the image back. The operator then has to ask for a served page before they can look, so the question goes unanswered or gets answered blind.
32
33
  - Sets the theme on an arm that persists its own and reads it back on load, so the control reports one theme while the arm renders the other and the set is compared across two.
33
34
 
34
35
  ## Must
@@ -49,7 +50,7 @@ Without this skill, a session facing a decision nobody can settle from a diff:
49
50
  - Apply the winning arm in one change.
50
51
  - Capture every arm from the final round as an image before deleting the run's scratch folder, rather than discarding the losing arms with it.
51
52
  - Resolve the archival capture's destination against the main worktree root, never against a linked worktree the run happens to be building in.
52
- - Serve the candidates live where the decision is one the operator has to drive, since a still cannot answer how a gesture feels or how a pace reads.
53
+ - Serve the candidates on every run, whatever the decision's layer, and emit the local link ahead of the first pick question, so the operator can open the page the question is about and a still is never the only address.
53
54
 
54
55
  ## Must not
55
56
 
@@ -45,17 +45,19 @@ Write every arm side by side on one self-contained HTML page at `<dest>/candidat
45
45
 
46
46
  ## Step 3: render and hand off
47
47
 
48
- Render the page, then look at what came back:
48
+ Serve the page first, then render it and look at what came back. Every run serves, whatever the decision's layer, since a pick asked about a page the operator cannot open is a question nobody can answer.
49
49
 
50
50
  ```bash
51
+ canon serve <dest> --entry candidates.html --json
51
52
  canon capture <dest>/candidates.html --selector <element>
52
53
  ```
53
54
 
55
+ - Start `canon serve` in the background and read the link off its record, never assuming a port, since the printed link opens `index.html` without `--entry` and `<dest>` holds no such file. Keep each server up through the loop and note its process, since Step 5 re-enters this step and Step 6 stops them all. Serving needs no browser, so the link exists the moment the page is written.
56
+ - Where Step 2 wrote a frame, hand over the frame's link instead, served from the parent folder as Step 2 says, and let no earlier round's `<dest>`-only link stand as the address a later round cites.
54
57
  - `--selector` has no default and the command refuses without it. Name the element wrapping the arms rather than `body`, which crops to whatever the page's own margins leave.
55
- - `canon capture` and `canon drive` both need a browser binary the toolkit does not install. When either refuses for that reason, report the refusal and name `bunx playwright install chromium` as the repair, then stop rather than describing an arm nobody has seen.
56
- - Serve the page instead of capturing it when the operator has to drive the decision, such as a hover response, a scroll-linked position, or a pace. Start `canon serve <dest> --entry candidates.html` in the background and read the link off its record, since the printed link opens `index.html` without that flag and `<dest>` holds no such file. A still answers how a thing looks and answers none of those.
58
+ - `canon capture` and `canon drive` both need a browser binary the toolkit does not install. When either refuses for that reason, report the refusal and name `bunx playwright install chromium` as the repair, stop every server Step 3 started, then stop rather than describing an arm nobody has seen.
57
59
  - Write the render inside the record that cites it wherever one exists, by pointing `--out` at `<dest>/renders/` rather than at a session scratch path. A pick taken from an image the record does not hold is a judgment nobody but this session can check, and the archival capture in Step 6 covers the final round alone.
58
- - Hand over the address rather than a description. Emit the PNG path on its own line, and the link beside it where the page is served.
60
+ - Hand over the address rather than a description. Emit the link first on its own line, then the PNG path on its own line. A still answers how a thing looks and answers none of a hover response, a scroll-linked position, or a pace, which the served page does.
59
61
  - Never report a visual result you have not looked at. A claim about appearance with no render behind it is a guess.
60
62
  - Look to judge rather than to confirm. Reading the image back to check it rendered satisfies the rule above and still hands over weak work, so name the weakest thing on the page in a sentence. Where that sentence would embarrass the work, fix it and hand over the second version. Say the remaining weakness out loud either way, so the operator is not hunting for what you already know.
61
63
 
@@ -63,6 +65,7 @@ canon capture <dest>/candidates.html --selector <element>
63
65
 
64
66
  Put the choice to the operator through the structured question surface, since a call the operator's preference decides always routes through it rather than through prose.
65
67
 
68
+ - Emit the link in the response text ahead of the question call, and name it again in the question's own text, since some surfaces render the question card alone. A question that goes out with no address is one the operator cannot answer by looking.
66
69
  - One option per arm, labeled with the arm's id and carrying its cost as the description.
67
70
  - Rank the recommendation first and mark it `(Recommended)`.
68
71
  - Author the real arms only. The surface appends its own escapes for a free-text answer and for reopening the question, so writing either as an option ships a duplicate the tool rejects.
@@ -82,8 +85,8 @@ Put the choice to the operator through the structured question surface, since a
82
85
  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.
83
86
  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.
84
87
  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.
85
- 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.
86
- 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.
88
+ 5. Stop every background server Step 3 started, one per round where the loop re-entered it, then 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, and a server left running would serve a folder that no longer exists.
89
+ 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. Stop every server there too.
87
90
  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.
88
91
  8. Report every surface that changed, each on its own line, name the arm that won by its id and its cost, and report the archival path from Step 3 where it ran.
89
92
 
@@ -32,7 +32,7 @@ A missing tracking ref is no longer a guard. An open pull request proves the bra
32
32
  5. Post the evidence comparison, on every invocation including `reply-owned`, since this comment is not the reply step 8 owns. Run `canon pr evidence <number> --json`, resolving `<number>` from `gh pr view --json number`, and read `reason` on the record rather than the exit code.
33
33
  - `no-evidence`: nothing changed under an `evidence/` segment this push. Say nothing and move on.
34
34
  - `ok`: write `body` to `.canon/tmp/pr/evidence/body-<number>.md` at the main worktree root (resolved the way `session-worktree` does), then post the comment with `gh pr comment <number> --body-file <main-root>/.canon/tmp/pr/evidence/body-<number>.md` when the record carries no `commentId`, or edit the existing one in place with `gh api -X PATCH repos/{owner}/{repo}/issues/comments/<commentId> -F body=@<main-root>/.canon/tmp/pr/evidence/body-<number>.md` when it does. Clean up the tmp file only after the call reports success.
35
- - Any other reason is one of the mirrored git refusals (`gh-missing`, `gh-failed`, `no-base`, `unreadable-tree`, `unreadable-changes`). Report it and continue without stopping the chain.
35
+ - Any other reason is one of the mirrored git refusals (`gh-missing`, `gh-failed`, `no-base`, `unreadable-changes`, `would-empty`). Report it and continue without stopping the chain.
36
36
  6. Check for existing review comments: `gh api 'repos/{owner}/{repo}/pulls/<number>/comments' --jq 'length'`, resolving `<number>` from `gh pr view --json number`.
37
37
  7. Sync the body and title on every invocation, before the routing below decides on the reply.
38
38
  - Run `gh pr view --json url,title,body` and update the body with `gh pr edit --body` when the new commit changes scope, and the title with `gh pr edit --title` when the scope shifted enough to make it inaccurate.
@@ -64,7 +64,7 @@ gh api -X PATCH repos/{owner}/{repo}/issues/comments/<commentId> -F body=@<main-
64
64
 
65
65
  Delete the handoff file once that call reports success, per the cleanup below, since the checklist now lives on the pull request. Clean up the tmp body file the same way.
66
66
 
67
- Any other `reason` is one of the mirrored git refusals (`gh-missing`, `gh-failed`, `no-base`, `unreadable-tree`, `unreadable-changes`). Report it and move on without stopping the chain: a branch that carries no evidence images most of the time should not fail here on a transient git or `gh` read. Fall through to the checklist step, which posts the checklist alone rather than losing it to a transient read.
67
+ Any other `reason` is one of the mirrored git refusals (`gh-missing`, `gh-failed`, `no-base`, `unreadable-changes`, `would-empty`). Report it and move on without stopping the chain: a branch that carries no evidence images most of the time should not fail here on a transient git or `gh` read. Fall through to the checklist step, which posts the checklist alone rather than losing it to a transient read.
68
68
 
69
69
  ## Post the UI checklist alone
70
70
 
@@ -20,7 +20,7 @@ The sequence also reaches the remote on work nothing re-checked. This skill is t
20
20
  - Emit no text between steps. The sequence is the unit and prose inside it reopens settled decisions.
21
21
  - Name the one point a wrapping caller may act at, so a chain built on this one is not left to pick a gap of its own
22
22
  - Name the condition under which the closing block is not emitted, since a caller that closes on its own block leaves two instructions about the last line and nothing deciding between them
23
- - Watch continuous integration to a terminal state, and stop on a failure naming the check
23
+ - Watch continuous integration to a terminal state in the background, so the session stays reachable while CI runs, and stop on a failure naming the check
24
24
  - Stop memory work at the Propose phase
25
25
 
26
26
  ## Must not
@@ -30,11 +30,12 @@ The sequence also reaches the remote on work nothing re-checked. This skill is t
30
30
  - Run the memory Apply phase. Promoting an entry changes how the agent operates and ships as its own change.
31
31
  - Attempt a fix for a failing verify. The user is already making one, which is what brought the run back here.
32
32
  - Implement or review. This chain starts from work already believed done.
33
+ - Report the chain done before the CI watch exits. A turn ending on the watch line leaves a pull request still waiting on CI, and a `✅ Shipped` there claims a result nothing has read.
33
34
 
34
35
  ## Guards
35
36
 
36
37
  - A failing verify stops the run before the sync skills write, so the tree is left as the user left it
37
- - A failing check stops the sequence. This is the one place text is allowed between steps.
38
+ - A failing check stops the sequence. A stop report and the line announcing the background watch are the two places text is allowed between steps.
38
39
 
39
40
  ## Out of scope
40
41
 
@@ -7,7 +7,7 @@ description: Runs the full post-feature workflow by syncing docs, staging commit
7
7
 
8
8
  Run the full post-feature workflow by invoking each skill in sequence using the Skill tool. After each skill returns, invoke the next step immediately in the same response.
9
9
 
10
- Do not output any text between steps and do not wait for user input. Tool permission dialogs are the only interrupts allowed. The final output is `✅ Shipped`, unless a wrapping caller states it closes on its own block, which `auto-ship` does.
10
+ Do not output any text between steps and do not wait for user input. Tool permission dialogs are the only interrupts allowed. The final output is `✅ Shipped`, emitted on the wake after the step 9 watch exits on `passing` rather than when the turn ends on the watch line, unless a wrapping caller states it closes on its own block, which `auto-ship` does.
11
11
 
12
12
  ## Verify
13
13
 
@@ -31,10 +31,33 @@ Run `git diff --cached --name-only 2>/dev/null` to check for staged files. If ou
31
31
  6. Invoke `canon:git-stage` to group staged changes and commit by concern
32
32
  7. Invoke `canon:git-branch` to rename branch to match conventional format
33
33
  8. Invoke `canon:git-pr` to push branch and open pull request
34
- 9. After the PR opens, watch CI. Poll `canon pr checks <number> --json` until the record's `state` leaves `pending` or the record carries `conflicted: true`, branching on those fields rather than on the exit, and fall back to `gh pr checks <number>` when no record comes back at all, which is a target whose CLI predates the verb. On `passing`, continue. On `failing`, stop the sequence and report the failing check with its URL. On `conflicted`, stop the sequence and report that the branch conflicts with its base, since no run will start for it and polling on never ends. A rebase is the repair. Do not auto-fix. This step may output on failure, the one exception to the no-text-between-steps rule.
34
+ 9. After the PR opens, watch CI in the background, so the session stays reachable while CI runs. Read `### Watching CI` below for the commands and the wake.
35
35
 
36
36
  A caller wrapping this sequence may act between step 8 and step 9, which is the one gap the order leaves open, since the pull request exists there and nothing has read its checks yet. `auto-ship` marks the pull request draft in it. Nothing else may go there, and a caller that needs a step anywhere else in the sequence is asking for a change to this body rather than for a place to stand.
37
37
 
38
+ ### Watching CI
39
+
40
+ Run `canon pr checks <number> --json` once in the foreground. When no record comes back at all, the target's CLI predates the verb, and the watch command is `gh pr checks <number> --watch`. The loop below would never exit on such a target, since an empty read never satisfies its test.
41
+
42
+ Otherwise start this loop through the Bash tool with `run_in_background` and a 60-minute timeout:
43
+
44
+ ```bash
45
+ until canon pr checks <number> --json | jq -e '.state != "pending" or .conflicted == true' >/dev/null; do sleep 30; done; canon pr checks <number> --json
46
+ ```
47
+
48
+ Emit `⏳ Watching CI on #<number> in the background` and end the turn. Print nothing more while the watch runs. The session wakes when the command exits, and the wake resumes this step rather than restarting the sequence at step 1. A wake that lands while the session is inside another skill, such as a `review-address` pass a message started during the watch, goes to whichever step is waiting on CI.
49
+
50
+ On the wake, branch on the final record's fields rather than on the exit:
51
+
52
+ - `state: passing`: continue to After completion.
53
+ - `state: failing`: stop the sequence and report the failing check with its URL.
54
+ - `conflicted: true`: stop the sequence and report that the branch conflicts with its base, since no run will start for it. A rebase is the repair.
55
+ - A `reason` and no `state`: the read was refused, such as `no-remote-branch` for a branch deleted on the remote. Stop and report that `reason`. A missing `state` is never a pass.
56
+ - The command hit its timeout and printed no final record: report CI unsettled after 60 minutes, and emit no `✅ Shipped`.
57
+ - The `gh pr checks --watch` fallback ran, which prints a check table rather than a record. Only a printed table carrying at least one check, every one passing, continues to After completion. Any failing check stops the sequence naming it with its URL. Empty or errored output stops the sequence and reports the message, since `no checks reported on the '<branch>' branch` is what a conflicted branch prints, and that fallback has no `conflicted` field to separate it from lag.
58
+
59
+ Do not auto-fix any of these. The watch line and a stop report from any branch above are the two exceptions to the no-text-between-steps rule.
60
+
38
61
  ### Why the reach reads at step 5
39
62
 
40
63
  The branch is whole there and nowhere earlier. Steps 2 and 3 write past whatever the plan declared, so a reading taken ahead of them misses the chain's own additions, and no pull request exists until step 8 to carry the answer anywhere.
@@ -170,10 +170,12 @@ echo "${comment_url##*issuecomment-}" > .canon/tmp/pr/reply/reply-<number>.id
170
170
 
171
171
  ## Step 7: confirm resolution
172
172
 
173
- After the follow-up push, watch CI on the PR. Poll
174
- `canon pr checks <number> --json` until the record's `state` leaves `pending`
175
- or it carries `conflicted: true`, then read it. On `conflicted`, stop and report
176
- that a rebase is the repair rather than polling on. When every finding is addressed and the state is `passing`, append
173
+ After the push, read Watching CI in `${CLAUDE_SKILL_DIR}/../git-ship/SKILL.md`
174
+ without invoking that skill, start its background watch, end the turn on its
175
+ line, and run the rest of this step and Step 8 on the wake. Reuse a watch
176
+ already running on this PR, since it reads the new tip. On the wake, stop on `conflicted` naming a rebase, on a `reason` naming it,
177
+ and on a timeout reporting CI unsettled. When every finding is addressed and
178
+ the state is `passing`, append
177
179
  the closing confirmation to the reply file Step 6 already posted, so the thread
178
180
  carries one terminal state rather than a second comment under no heading:
179
181
 
@@ -13,10 +13,16 @@ The miss is measured. On a seeded branch that deleted a dirty-tree guard while t
13
13
 
14
14
  Rendered output is the larger hole. `git-pr` posts an `## Evidence` comment through `canon pr evidence`, carrying base and head screenshots and a checklist a reviewer ticks. The pull request review named that heading only in its heading set, and no step opened an image. On a seeded pull request whose narrow head screenshot shows the navigation running off the edge while a ticked box claims it collapses, the review filed the finding off the stylesheet diff and said it had not rendered the page. On a styling change with no screenshot at all, on a project whose trunk keeps them, it did not mention the absence.
15
15
 
16
+ The axes also said nothing about a change that passes by lowering the bar it has to clear, such as a test skipped, a threshold moved, or a path excluded from a checker, nothing about performance, and one sentence about design with no procedure behind it. A refactor that only moved complexity read as a design gain, and a removal could call code dead without reading why it was added. The body carried no excuses, red flags, or closing checklist, so a session about to stop at the hunk met no answer first.
17
+
16
18
  ## Must
17
19
 
18
20
  - Open with the one fact the change's safety rests on, read on a ladder of asserted, pointed at, walked through, tested, and reproduced
19
- - State the axes in reading order: design and scope, correctness and edge cases, what breaks outside the diff, tests, security, rendered output, developer experience and operations, and executable prose
21
+ - State the axes in reading order: design and scope, correctness and edge cases, what breaks outside the diff, tests, guard the bar, performance, security, rendered output, developer experience and operations, and executable prose
22
+ - Carry the design review as an ordered procedure in the body, stack-neutral, plus the scope checks for a change carrying two concerns, complexity moved rather than reduced, and a removal that has not read why the code existed
23
+ - Name a lowered bar as a finding unless the diff states why, and accept a suppression whose stated reason holds
24
+ - Ask a claimed speedup for repeated measurements on both sides, and read a result inside the noise as an argument to revert
25
+ - Close with the practice skill's excuses, red flags, and closing checklist, and record every external source in `references/adopted.md`
20
26
  - Require every consumer of a changed contract to be listed and checked, and every doc the diff touches to be read whole for a claim the change made false
21
27
  - State a design finding as a concrete cost, so it survives the procedure's filter against subjective suggestions
22
28
  - Carry the evidence bar: confirm against the file at the reviewed head, quote a cited rule, name the breaking input, and drop what a gate owns or what rests on unread state
@@ -24,7 +30,7 @@ Rendered output is the larger hole. `git-pr` posts an `## Evidence` comment thro
24
30
  - Open the evidence images on a rendered change through `git show` at the row's own sha, never through the embedded address, within a stated read budget
25
31
  - Test each ticked checklist box against an opened image, and name a ticked box no image covers as untested
26
32
  - Flag a rendered change that carries no screenshot, as a finding where the trunk already keeps them and as a question elsewhere
27
- - Read the posted comment rather than running `canon pr evidence`, which compares the local checkout's diff and names the wrong change from a reviewing session not on the branch
33
+ - Read the posted comment rather than running `canon pr evidence`, which renders a new body from the pull request's files and can differ from the comment already posted
28
34
 
29
35
  ## Must not
30
36
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: review-craft
3
- description: Carries what a code review looks for and how much evidence a finding needs, from design and scope through breakage outside the diff, developer experience, executable prose, stale docs, security classes, and rendered output checked against the screenshots a pull request carries. Use when reviewing a change, when a review procedure loads it for its axes, or when asked "what should a review look for", "what does a good review check", "how sure do I need to be before flagging this", or "did the review look at the screenshots". Do NOT use to run a review, post it, or grade its findings, which is `review-branch` for local work and `review-pr` for a pull request, and do NOT use for a deliberate full security audit, which is the built-in `security-review`.
3
+ description: Carries what a code review looks for and how much evidence a finding needs, from design and scope through breakage outside the diff, a test or check the change weakens to pass, performance, developer experience, executable prose, stale docs, security classes, and rendered output checked against the screenshots a pull request carries. Use when reviewing a change, when a review procedure loads it for its axes, or when asked "what should a review look for", "what does a good review check", "how sure do I need to be before flagging this", or "did the review look at the screenshots". Do NOT use to run a review, post it, or grade its findings, which is `review-branch` for local work and `review-pr` for a pull request, and do NOT use for a deliberate full security audit, which is the built-in `security-review`.
4
4
  ---
5
5
 
6
6
  # Review craft
@@ -23,16 +23,43 @@ A risky claim resting on assertion alone is where the review spends its reading.
23
23
 
24
24
  ## Read the axes in this order
25
25
 
26
- An axis whose condition the diff meets is not optional. When axis 5 or 6 names a reference and its condition holds, read that reference before moving to the next axis, however clear the diff looks without it.
26
+ An axis whose condition the diff meets is not optional. When the security or the rendered output axis names a reference and its condition holds, read that reference before moving to the next axis, however clear the diff looks without it.
27
27
 
28
- 1. **Design and scope.** Does the change do one thing, is it more complex than the problem needs, and does it build what nobody asked for? State a design finding as a concrete cost, such as a second path nobody calls, a layer with one caller, or a flag no caller passes, never as a preference.
28
+ 1. **Design and scope.** Does the change do one thing, is it more complex than the problem needs, and does it build what nobody asked for? State a design finding as a concrete cost, such as a second path nobody calls, a layer with one caller, or a flag no caller passes, never as a preference. Walk it in the order `Walk the design` below gives.
29
29
  2. **Correctness and edge cases.** The empty input, the boundary value, the refused call, the second run, the concurrent run, and the error path a caller actually meets.
30
30
  3. **What breaks outside the diff.** List every consumer of a changed contract, whether a function signature, a file format, a flag, an output shape, or a heading another tool matches, and check the change against each one. Then list each behavior the diff removes or changes, such as a guard, a refusal, a default, or an output, and search every doc the diff touches, in full rather than at the hunk, for a sentence still promising the old behavior. File that sentence as a finding against the doc, quoting it and naming its section, since the doc is what goes wrong for the next reader.
31
31
  4. **Tests.** Hand each test the change adds or edits to `canon:test-craft` and its final filter. Report it rather than proceeding silently when that skill does not resolve.
32
- 5. **Security.** Read `${CLAUDE_SKILL_DIR}/references/security.md` when the diff runs a command, writes a file, handles input from outside the process, touches a secret, adds a dependency, or changes a default a consumer installs.
33
- 6. **Rendered output.** Read `${CLAUDE_SKILL_DIR}/references/ui.md` when the diff touches a file that paints, such as markup, a stylesheet, a component, a template, or a design token, or when the pull request carries an evidence comment. A finding read off a stylesheet diff says what the author changed, and only the screenshot says what a user sees, so the reference opens the images and checks whether any exist.
34
- 7. **Developer experience and operations.** Ports, hooks, scripts, config, and scaffold defaults a consumer installs. A new required step nobody documented, a default that fails on a clean machine, or a hook that slows every commit is a finding even when the code is correct.
35
- 8. **Executable prose.** A skill body, a rule, or a prompt is instructions a model runs. Read it the way you read code: a step that races another, a precondition it never states, a branch with no exit, and two instructions that contradict each other are bugs.
32
+ 5. **Guard the bar.** A change can pass by lowering its own bar: a threshold moved, a test skipped, deleted, or emptied of assertions, an inline suppression, a path dropped from a lint or type run, a stub that throws or an empty catch where behavior was promised, or a new config exception. Each is a finding unless the diff says why, and a suppression whose stated reason holds is the author's call.
33
+ 6. **Performance.** A query or a remote call inside a loop, a read with no bound on its size, and a list endpoint with no pagination. A claimed speedup needs a before and an after measured the same way and repeated past run-to-run noise. One run on each side is an anecdote, and a result inside the noise argues for reverting the added complexity.
34
+
35
+ ### Axes a condition opens
36
+
37
+ Read each of these when the diff reaches what it names.
38
+
39
+ 7. **Security.** Read `${CLAUDE_SKILL_DIR}/references/security.md` when the diff runs a command, writes a file, handles input from outside the process, touches a secret, adds a dependency, or changes a default a consumer installs.
40
+ 8. **Rendered output.** Read `${CLAUDE_SKILL_DIR}/references/ui.md` when the diff touches a file that paints, such as markup, a stylesheet, a component, a template, or a design token, or when the pull request carries an evidence comment. A finding read off a stylesheet diff says what the author changed, and only the screenshot says what a user sees, so the reference opens the images and checks whether any exist.
41
+ 9. **Developer experience and operations.** Ports, hooks, scripts, config, and scaffold defaults a consumer installs. A new required step nobody documented, a default that fails on a clean machine, or a hook that slows every commit is a finding even when the code is correct.
42
+ 10. **Executable prose.** A skill body, a rule, or a prompt is instructions a model runs. Read it the way you read code: a step that races another, a precondition it never states, a branch with no exit, and two instructions that contradict each other are bugs.
43
+
44
+ ### Walk the design
45
+
46
+ Walk the design axis in this order, and skip a step the change gives nothing to read:
47
+
48
+ 1. Name the next change this code is likely to need, and count the files and units it would touch. A count that grows with each new case is the cost to report.
49
+ 2. State what each new unit hides from its callers. A unit that passes its arguments straight through to another hides nothing and is a layer with no work.
50
+ 3. Find each rule or constant the change states, and check that it lives in one place. The same rule in two places drifts the first time one copy changes.
51
+ 4. Look for a parameter that switches what a function does, a chain of calls reaching through one object into another, and a read or write of global state. Each ties a caller to internals it should not know.
52
+ 5. Ask each changed file for its one reason to change. A file that two unrelated requests would both edit carries two concerns.
53
+ 6. List what the code reads without being handed it, such as the clock, the environment, the filesystem, or a random source. A hidden input is what makes the code hard to test and to reuse.
54
+ 7. Match each pattern or abstraction the change introduces to a problem the code has today. One built for a case nobody has asked for is speculative.
55
+ 8. Check that the rules of the domain sit apart from the code that moves data in and out, so a change of transport or storage leaves them untouched.
56
+ 9. Read names, unexplained literal numbers, errors caught and dropped, and side effects a function's name does not declare.
57
+
58
+ Three scope checks follow the walk:
59
+
60
+ - When a change carries two concerns that could land as two changes, name the split. Size is no finding on its own, since one concern can run long.
61
+ - On a refactor, count the concepts a reader must hold before and after. Complexity moved into a new file or function is moved, not reduced, so report it as such rather than as a design gain.
62
+ - Before calling removed code dead, state why it existed. Read `git blame` and the commit that added it, since a guard nobody remembers is often still guarding something.
36
63
 
37
64
  ## Hold every finding to the evidence bar
38
65
 
@@ -42,6 +69,35 @@ An axis whose condition the diff meets is not optional. When axis 5 or 6 names a
42
69
  - Drop what a linter, a type checker, or a gate in the project already owns. The gate reports it with more certainty than a review can.
43
70
  - Drop a finding resting on state you did not read. Say what you would need to read instead.
44
71
 
72
+ ## Excuses and rebuttals
73
+
74
+ | Excuse | Rebuttal |
75
+ | ----------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
76
+ | The tests pass, so the change works | Read what the diff did to the tests first. A test skipped, deleted, or stripped of its assertions passes by proving nothing. |
77
+ | The hunk reads clean, so the review is done | The hunk is where the author looked. A consumer, a doc a section away, and the commit that added a removed guard are not in it. |
78
+ | The checker passes on the branch | Read the checker's config and the inline suppressions in the diff. A path excluded from the run passes by not being read. |
79
+ | It was split into smaller functions, so it is simpler | Count the concepts a reader holds before and after. Moved complexity reads as simpler only to the person who moved it. |
80
+ | Nothing calls it, so deleting it is safe | Read why it was added. Code nobody calls today can still be guarding a path nobody exercised in the change. |
81
+ | The description says it is faster | A claimed speedup with no measurement, or one run each side, is asserted. Ask for runs that beat the noise. |
82
+ | The change only touches styles, so the screenshots can wait | A stylesheet diff says what changed and only the image says what a user sees. Open them, or say none exist. |
83
+
84
+ ## Red flags
85
+
86
+ - You are about to call the change clean having read only the lines it changed.
87
+ - A threshold, an exclude list, or a skip marker changed and you have not found the sentence explaining it.
88
+ - You are approving a refactor because it has more, smaller pieces.
89
+ - You are calling code dead without having read the commit that added it.
90
+ - A performance claim rests on a number you cannot trace to a repeated measurement.
91
+ - An axis condition held and you moved past it without reading the reference it names.
92
+
93
+ ## Before handing over
94
+
95
+ - Every axis whose condition the diff meets has a finding or a stated reason it found none.
96
+ - Every changed threshold, skip, suppression, and exclusion in the diff is either a finding or paired with the reason the diff gives.
97
+ - Every removal the review accepted names why the removed code existed.
98
+ - Every design finding states a concrete cost, and every refactor finding says whether complexity was reduced or moved.
99
+ - Every finding was confirmed against the file at the reviewed head and names the input or state that breaks.
100
+
45
101
  ## What this delegates
46
102
 
47
103
  - Which files a pass reads, the high-signal filter, the severity ladder, and where findings go: `review-branch` for local work and `review-pr` for a pull request
@@ -0,0 +1,49 @@
1
+ ---
2
+ title: Adopted and declined
3
+ description: Which external review patterns this skill adopted, which it declined, and why, so a later session extends the position instead of re-deriving it
4
+ ---
5
+
6
+ # Adopted and declined
7
+
8
+ External sources were read and filtered rather than imported. This file is the record. A later session extending the skill adds to it rather than re-arguing an item already settled here.
9
+
10
+ ## Adopted
11
+
12
+ ### Design and scope
13
+
14
+ **The design procedure.** The nine ordered steps under the design axis draw on four sources, each restated without a language, a framework, or a transport so the walk holds on any stack.
15
+
16
+ - Ousterhout's deep modules, information hiding, and pass-through methods ([A Philosophy of Software Design](https://web.stanford.edu/~ouster/cgi-bin/book.php)): the step asking what each unit hides and flagging a unit that passes its arguments straight through.
17
+ - Parnas's criterion that a module boundary hides a decision likely to change ([On the Criteria To Be Used in Decomposing Systems into Modules](https://dl.acm.org/doi/10.1145/361598.361623)): the opening step naming the next likely change and counting what it touches.
18
+ - Beck's design rules as Fowler records them, especially no duplication and fewest elements ([BeckDesignRules](https://martinfowler.com/bliki/BeckDesignRules.html)): the one-place step and the step matching each pattern to a problem the code has today.
19
+ - Google's reviewer guide on design, complexity, and over-engineering ([What to look for in a code review](https://google.github.io/eng-practices/review/reviewer/looking-for.html)): the frame for the whole walk, and the reason a speculative abstraction is a finding.
20
+
21
+ The procedure stays in the body rather than a reference, since every review reads the design axis and a reference would cost a read on every run.
22
+
23
+ **Change sizing as a split.** Google's [small CLs](https://google.github.io/eng-practices/review/developer/small-cls.html) asks for one self-contained change. Adopted as the scope check that names a split when two concerns could land as two changes. From `addyosmani/agent-skills@2686b620`, `skills/code-review-and-quality/SKILL.md`, the same check.
24
+
25
+ **Relocate versus reduce.** From the same `code-review-and-quality` skill: a refactor counts the concepts a reader must hold before and after. Adopted as the scope check that reports moved complexity as moved.
26
+
27
+ **Chesterton's Fence.** From `addyosmani/agent-skills@2686b620`, `skills/code-simplification/SKILL.md`: read why code exists before removing it. Adopted as the scope check that reads `git blame` and the commit that added a removed path before calling it dead.
28
+
29
+ ### Guard the bar
30
+
31
+ From `addyosmani/agent-skills@2686b620`, `skills/constraint-driven-development/SKILL.md`: a change must not pass by weakening the constraint it has to meet. Adopted as its own axis after tests, listing the moved threshold, the skipped or hollowed test, the inline suppression, the excluded path, the throwing stub, the empty catch, and the new config exception. The clause accepting a suppression whose stated reason holds is this skill's own, since a legitimate suppression with its reason beside it would otherwise report noise the procedures' filter then drops.
32
+
33
+ ### Performance
34
+
35
+ From `addyosmani/agent-skills@2686b620`, `skills/code-review-and-quality/SKILL.md` for the axis itself, a call inside a loop and an unbounded fetch, and `skills/performance-optimization/SKILL.md` for keep or revert: measure before and after the same way, and a neutral result argues for removing the added complexity. The repeated-run requirement against noise is stated here so one run on each side reads as an anecdote.
36
+
37
+ ### Closing sections
38
+
39
+ The excuses, red flags, and closing checklist follow the practice skill shape every practice skill in this toolkit carries, taken from `addyosmani/agent-skills@2686b620`, [`docs/skill-anatomy.md`](https://github.com/addyosmani/agent-skills/blob/2686b620fc1fed2e8f60c704839c766b8594c6b6/docs/skill-anatomy.md). Each excuse row rebuts a reason a review stops at the hunk, such as passing tests against a test the diff skipped, rather than an objection nobody raised.
40
+
41
+ ## Declined
42
+
43
+ **Google's approval standard.** "Approve a change once it definitely improves the overall code health" is a grading rule. Grading and posting belong to the procedures that load this skill, which each own a severity ladder, so the standard stays out of the body.
44
+
45
+ **A fixed line count for sizing.** Google's small-CL page sets no hard limit, and one concern regularly runs past a hundred lines here. A number would fire on nearly every branch, so the split is stated by concern instead.
46
+
47
+ **Named structural remedies as a catalog.** A list of refactorings to propose reads as a menu a session fills in. A design finding states the cost, and the remedy is the author's.
48
+
49
+ **The web and database tables from `performance-optimization`.** They name a stack, and the axis stays stack-neutral until a target asks for a per-stack reference.
@@ -40,6 +40,7 @@ One row per top-level command, in the order `canon --help` prints them. A domain
40
40
  | `canon records <verb>` | Validate, size, prune, and back up the session records |
41
41
  | `canon sessions <verb>` | Resolve live sessions to worktree and branch, and move one between machines |
42
42
  | `canon worktrees <verb>` | Report and remove worktrees whose pull request merged |
43
+ | `canon hooks <verb>` | Run the steps a git hook drives |
43
44
  | `canon autoship <verb>` | Decide whether a changed set needs the review pass |
44
45
  | `canon pr <verb>` | Read a pull request's diff, head, checks, and review, and post its evidence |
45
46
  | `canon feedback` | Write toolkit feedback from stdin, or open an issue with `--github` |
@@ -100,6 +101,7 @@ Each domain exposes a consistent shape where applicable: `list`, `install`, `syn
100
101
  - `records`, in `records.md`: `validate`, `migrate`, `ordinal`, `size`, `stale`, `prune-tmp`, `push`, `pull`
101
102
  - `sessions`, in `sessions.md`: `list`, `export`, `import`
102
103
  - `worktrees`, in `worktrees.md`: `list`, `reclaim`
104
+ - `hooks`, in `hooks.md`: `post-merge`
103
105
  - `autoship`, in `review-classification.md`: `classify`
104
106
  - `pr`, in `pr-reads.md`: `key-changes`, `head`, `checks`, `review-state`, `evidence`, `preview`, `local`
105
107
  - `audits`, in `audits.md`: `run`, `list`
@@ -0,0 +1,56 @@
1
+ ---
2
+ title: Hooks
3
+ description: Running the post-merge steps through one verb, the order and the child call behind each, the root and working directory each step reads, the skip switches, and the line each record maps to
4
+ ---
5
+
6
+ # Hooks
7
+
8
+ `canon hooks post-merge` runs the steps a git `post-merge` hook drives, so the hook itself stays a guard plus one call. It reads which pull requests the merge brought in, runs each step as a child `canon` call with `--json`, and prints one line per outcome worth reporting.
9
+
10
+ ```bash
11
+ canon hooks post-merge
12
+ canon hooks post-merge --root "$root"
13
+ ```
14
+
15
+ | Option | Behavior |
16
+ | --------------- | ---------------------------------------------------------------------------------------------------- |
17
+ | `--root <path>` | Main worktree root holding the board and the records, resolved from `git worktree list` when omitted |
18
+
19
+ Exit codes: `0` on every path, since a hook failing aborts nothing useful. Lines go to stderr, and stdout stays empty. An ordinary merge prints nothing.
20
+
21
+ ## The steps
22
+
23
+ The steps run in this order, and the verb's `--help` lists the child calls from the same table it runs them from.
24
+
25
+ | Step | Child call | Runs from |
26
+ | ------------------------ | ------------------------------------------------------------- | ---------------- |
27
+ | Archive the merged task | `canon tasks archive --pull-request <n> --root <root> --json` | the caller's cwd |
28
+ | Push the records | `canon records push --root <root> --json` | the caller's cwd |
29
+ | Reclaim merged worktrees | `canon worktrees reclaim --json` | the caller's cwd |
30
+ | Reinstall the CLI | `canon upgrade --json`, under `CANON_NON_INTERACTIVE=1` | the caller's cwd |
31
+ | Update the plugin cache | `canon claude plugin-update --json` | the caller's cwd |
32
+
33
+ The archive runs once per pull request number, read as the trailing `(#NNN)` on every subject in `ORIG_HEAD..HEAD`, or on the tip alone when the merge left no `ORIG_HEAD`.
34
+
35
+ The reclaim takes no `--root`. It refuses the worktree its own working directory names, so a root would let a pull inside a linked worktree remove the worktree it stands in. The archive and the push take the root because the board and the records live at the main worktree root.
36
+
37
+ Each step is a separate process rather than an in-process call, so the plugin update runs the binary the upgrade just installed. Every child, and every `git` read, runs with the repository variables a hook exports stripped, since `GIT_DIR` beats `-C`.
38
+
39
+ ## Skip switches
40
+
41
+ | Variable | Skips |
42
+ | ---------------------------- | ----------------------- |
43
+ | `CANON_SKIP_RECLAIM=1` | the worktree reclaim |
44
+ | `CANON_SKIP_UPGRADE=1` | the CLI reinstall |
45
+ | `CANON_SKIP_PLUGIN_UPDATE=1` | the plugin cache update |
46
+
47
+ Any non-empty value skips the step, and each switch skips its own step only.
48
+
49
+ ## What prints
50
+
51
+ Each line is decided from the child's parsed record. A child producing no parseable record is an older binary carrying no such subcommand, and that step stays quiet.
52
+
53
+ - Archive: the archived task and its number, plus a `Links not repointed in:` line naming the files in a non-empty `relinkFailed`, or the refusal's `message` with a pointer to the task board. A record carrying no `relinkFailed` reads as empty. `no-match` and `no-board` stay quiet.
54
+ - Records push: the count of changed paths when above zero, or the refusal reason. `no-repository` stays quiet.
55
+ - Reclaim: the removal count and the failure count, both read from the fields whatever the exit, or an unreadable reason. `gh-missing` stays quiet.
56
+ - Upgrade and plugin update: the record's `message` on any state but `current`, or on a failure. The plugin update stays quiet on `no-claude` and `no-plugin`.
@@ -24,6 +24,7 @@ CLI catalog and invocation rules for agents, split by command domain. Start with
24
24
  - [Drift surfaces](drift-surfaces.md): The six sections canon sync --check reports beside the per-domain scan, being seeds, superseded artifacts, unmigrated domains, new rules and skills, and the reverse walk, with the managed-target gate and what counts toward the exit code
25
25
  - [Driver](driver.md): Walking a page through named interactions, the probe catalog and the false finding each one carries, why viewport heights are never defaulted, and what each refusal reports
26
26
  - [Merge gate](gate.md): Running the gate this repository verifies a branch with, what the stage table holds and what stays a script, how the changed set scopes three stages, and why a stage that cannot read its input reports rather than passing
27
+ - [Hooks](hooks.md): Running the post-merge steps through one verb, the order and the child call behind each, the root and working directory each step reads, the skip switches, and the line each record maps to
27
28
  - [Indexes](indexes.md): Flags, exit codes, and JSON shape for canon indexes regen and canon indexes list, plus when regen auto-stages what it rewrote
28
29
  - [Install and sync](install-and-sync.md): What each install and sync verb writes, refuses, or leaves alone, and how drift is attributed in a target project
29
30
  - [Intake](intake.md): Reading intake folder counts and items, the three read states an item can be in, landing a batch of selections in one cluster, the refusal reasons, and why a call is scoped to one file
@@ -74,7 +74,7 @@ There is no `canon standards sync` and no `canon standards install`. The corpus
74
74
  installs into no project, so the domain has nothing in a target to reconcile.
75
75
  `canon standards <name>` prints one, resolving `standards/` at the working root
76
76
  and then the corpus inside the package, and `canon standards list --json` carries
77
- the catalog.
77
+ the catalog, each entry labeled by the root it was read from.
78
78
 
79
79
  ## Tooling diff and sync
80
80
 
@@ -87,7 +87,7 @@ A hit the closed set could not separate from correct prose was the case with no
87
87
 
88
88
  ### Where the rules are enforced
89
89
 
90
- Five surfaces apply the ban set and four of them go through this verb. `.claude/hooks/standards-audit.sh` runs it against a single file after each markdown edit, the seed copy a project installs does the same, the `Markdown bans` stage in `canon gate run` runs it across the whole corpus before this repository's own push, and the same-named stage in every stack's `scripts/verify.sh` runs it across a scaffolded project's tracked markdown before its own push. Each hook parsed its own copy of the word bans in awk before that, which left a British spelling passing at edit time and failing the push with nothing in between explaining the difference.
90
+ Five surfaces apply the ban set and four of them go through this verb. `.claude/hooks/standards-audit.sh` runs it against a single file after each markdown edit, the seed copy a project installs does the same, the `Markdown bans` stage in `canon gate run` runs it across the whole corpus before this repository's own push, and the same-named stage in the one verify runner every stack shares, `scripts/verify.ts`, runs it across a scaffolded project's tracked markdown before its own push. Each hook parsed its own copy of the word bans in awk before that, which left a British spelling passing at edit time and failing the push with nothing in between explaining the difference.
91
91
 
92
92
  The seed copy moved onto the verb when the sets became data, since its awk had nothing left to parse. It resolves one runner where the toolkit copy resolves two, looking for no checkout source, and a machine carrying no `canon` gets a report naming the binary to install rather than a silent pass. `scripts/core/check-seed-independence.sh` scopes its walk to markdown and leaves the seed hooks outside it, which its own comment records as deliberate.
93
93