@erclx/canon 5.47.0 → 5.49.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 (67) hide show
  1. package/claude/.claude-plugin/plugin.json +1 -1
  2. package/claude/skills/auto-ship/SKILL.md +1 -1
  3. package/claude/skills/git-pr/references/closing-issues.md +2 -0
  4. package/claude/skills/plan-feature/SKILL.md +18 -15
  5. package/claude/skills/plan-feature/references/batches.md +5 -5
  6. package/claude/skills/plan-feature/references/plan.md +82 -33
  7. package/claude/skills/plan-groundwork/SKILL.md +8 -0
  8. package/claude/skills/plan-groundwork/references/groundwork.md +2 -1
  9. package/claude/skills/plan-intake/SKILL.md +8 -0
  10. package/claude/skills/plan-intake/references/intake.md +9 -1
  11. package/claude/skills/plan-ready/REQUIREMENT.md +3 -3
  12. package/claude/skills/plan-ready/SKILL.md +3 -3
  13. package/claude/skills/plan-ready/references/assembly.md +7 -7
  14. package/claude/skills/plan-ready/references/ready.md +8 -6
  15. package/claude/skills/review-ui/REQUIREMENT.md +2 -2
  16. package/claude/skills/review-ui/SKILL.md +7 -14
  17. package/claude/skills/review-ui/references/close-out.md +1 -1
  18. package/claude/skills/review-ui/references/drive-copy.md +38 -0
  19. package/claude/skills/review-ui/references/post.md +36 -3
  20. package/claude/skills/review-ui/references/tick.md +4 -1
  21. package/claude/skills/review-ui/references/verb-absent.md +18 -0
  22. package/claude/skills/role-orchestrator/SKILL.md +3 -2
  23. package/claude/skills/role-orchestrator/references/orchestrator-dispatch.md +1 -1
  24. package/claude/skills/role-orchestrator/references/orchestrator-hand-launch.md +60 -0
  25. package/claude/skills/role-orchestrator/references/orchestrator-launch.md +5 -0
  26. package/claude/skills/role-orchestrator/references/orchestrator-parked.md +1 -1
  27. package/claude/skills/role-orchestrator/references/orchestrator-poll.md +1 -1
  28. package/claude/skills/role-orchestrator/references/orchestrator-refill.md +4 -2
  29. package/claude/skills/role-orchestrator/references/orchestrator-reviewer-launch.md +1 -1
  30. package/claude/skills/role-planner/SKILL.md +1 -1
  31. package/claude/skills/role-reviewer/SKILL.md +1 -1
  32. package/claude/skills/role-worker/SKILL.md +4 -2
  33. package/claude/skills/session-compact/references/handoff-note.md +3 -1
  34. package/claude/skills/session-map/references/session.md +1 -1
  35. package/claude/skills/task-board/references/board.md +2 -2
  36. package/claude/skills/task-board/references/tasks.md +5 -3
  37. package/claude/skills/task-complete/SKILL.md +1 -0
  38. package/claude/skills/task-complete/references/archive.md +2 -1
  39. package/docs/agents/migrate.md +2 -2
  40. package/docs/agents/records.md +1 -1
  41. package/docs/target/migrations.md +4 -2
  42. package/docs/workflow/operating-model.md +2 -2
  43. package/docs/workflow/parallel-features.md +2 -2
  44. package/package.json +1 -1
  45. package/src/commands/claude.ts +4 -0
  46. package/src/commands/migrate.ts +5 -4
  47. package/src/commands/pr.ts +712 -58
  48. package/src/commands/records.ts +45 -8
  49. package/src/commands/tasks.ts +21 -1
  50. package/src/hooks/post-merge.ts +11 -0
  51. package/src/migrate/session-defaults.ts +20 -5
  52. package/src/pr/drive-copy.ts +218 -0
  53. package/src/pr/lift.ts +19 -0
  54. package/src/pr/local.ts +26 -0
  55. package/src/pr/merge.ts +175 -0
  56. package/src/pr/rest.ts +3 -0
  57. package/src/pr/review-scope.ts +40 -1
  58. package/src/pr/tick.ts +21 -1
  59. package/src/records/structure.ts +147 -0
  60. package/src/records/validate.ts +113 -12
  61. package/src/tasks/archive.ts +154 -8
  62. package/src/tasks/board.ts +68 -13
  63. package/src/tasks/closes.ts +9 -5
  64. package/src/tasks/validate.ts +43 -4
  65. package/tooling/base/configs/.github/workflows/pr-local-preview.yml +1 -1
  66. package/tooling/claude/reference.md +3 -1
  67. package/tooling/claude/seeds/.claude/settings.json +1 -1
@@ -22,8 +22,8 @@ The checklist is its only statement of intent, so it tests the feature the way a
22
22
 
23
23
  A pass stops rather than repeat a verdict that already covers the head.
24
24
 
25
- - The newest UI verdict is `## UI review closed` at the current head: stop, `The UI review already covers <short-sha>.`
26
- - An open verdict at the head stops the same way, unless a `## Review response` or `## Post-review findings` comment is newer than it or the launch names an address
25
+ - The newest UI verdict is `## UI review closed` at the current head and drove a box: stop, `The UI review already covers <short-sha>.`
26
+ - An open verdict at the head stops the same way, unless a `## Review response` or `## Post-review findings` comment is newer, the launch names an address, or it drove no box, as `post.md` defines
27
27
  - The hosted preview was not built from the head: stop and post nothing, naming `built`, `tip`, and `canon pr preview <number> --json` for the dispatcher
28
28
  - Post, then run `canon pr lift <number>` on a close. Never merge or ready the PR by hand, and edit the evidence comment only through `canon pr tick`.
29
29
  - A push after a close owes a re-drive only when it changed a painted path, since the lift carries the close across the rest.
@@ -36,15 +36,7 @@ Record `<pass>` once, as the instant this pass starts, with `date -u +%Y%m%dT%H%
36
36
 
37
37
  ### When the verb is absent
38
38
 
39
- Every read here runs on REST, since `gh pr` runs on GraphQL and a cloud session's proxy refuses it. A target whose CLI predates the verb gets no record back, so read the pull request directly:
40
-
41
- ```bash
42
- gh api "repos/{owner}/{repo}/pulls?head={owner}:$(git branch --show-current | jq -Rr @uri)&state=open" --jq '.[].number'
43
- gh api repos/{owner}/{repo}/pulls/<number> --jq .head.sha
44
- ```
45
-
46
- - With no number named, take the open pull requests on the current branch, and stop when that prints anything but one number
47
- - A named number skips that lookup, since this checkout's branch need not be the pull request's
39
+ A target whose CLI predates `canon pr head` gets no record back. Read `${CLAUDE_SKILL_DIR}/references/verb-absent.md` for the REST reads that stand in for it.
48
40
 
49
41
  ### Read the newest verdict and reply
50
42
 
@@ -96,9 +88,9 @@ When the hosted rung answers, read `${CLAUDE_SKILL_DIR}/references/hosted-previe
96
88
 
97
89
  ### Unverified and unanswered addresses
98
90
 
99
- The check covers the hosted address only. The local rung and a launch-named address have no deploy run to read, so say in the comment they were driven unverified.
91
+ The check covers the hosted address only. The local rung and a launch-named address have no deploy run to read, so the post says they were driven unverified and names no loopback address, per `${CLAUDE_SKILL_DIR}/references/post.md`.
100
92
 
101
- An address that exists and does not answer differs from no address. When every rung fails to answer, skip the drive, record each box as not driven with the addresses tried and what each returned, and go to Step 7.
93
+ An address that exists and does not answer differs from no address. When every rung fails to answer, skip the drive, record each box as not driven with the addresses tried and what each returned, and go to Step 7. No box was driven, so Step 7 posts it open.
102
94
 
103
95
  ## Step 4: open the browser
104
96
 
@@ -110,6 +102,7 @@ ${CLAUDE_SKILL_DIR}/scripts/pw.sh -s=<project>-<number> open <url>
110
102
 
111
103
  - Pass `--config=<path>` on `open` only when the launch names a CLI config path, which is how a machine's GPU recipe reaches the pass. Render in software otherwise.
112
104
  - Read the WebGL renderer once with an `eval` through the debug renderer extension and carry it into the comment, since a canvas page can paint differently in software
105
+ - Before `open`, rebuild the drive copy and record the worktree's state per `${CLAUDE_SKILL_DIR}/references/drive-copy.md`
113
106
 
114
107
  ## Step 5: drive each box
115
108
 
@@ -147,7 +140,7 @@ A console error or an overflow is a finding. A probe result is a reading to conf
147
140
 
148
141
  ## Step 7: post
149
142
 
150
- Read `${CLAUDE_SKILL_DIR}/references/post.md` for the heading rule, the body shape, the marker every body ends on, and the post command. Each box lands in the section its verdict names, and the `link` its Step 5 push returned goes as given into that box's own entry.
143
+ Run the worktree check in `${CLAUDE_SKILL_DIR}/references/drive-copy.md` first. Read `${CLAUDE_SKILL_DIR}/references/post.md` for the heading rule, the body shape, the marker every body ends on, and the post command. Each box lands in the section its verdict names, and the `link` its Step 5 push returned goes as given into that box's own entry.
151
144
 
152
145
  That file sends a pass closing under a prior `## UI review closed` at an older head on to `${CLAUDE_SKILL_DIR}/references/close-out.md`, which rewrites the standing close in place.
153
146
 
@@ -20,7 +20,7 @@ gh api --paginate 'repos/{owner}/{repo}/pulls/<number>/reviews?per_page=100' --j
20
20
 
21
21
  ## Write the replacement
22
22
 
23
- Write the full body for this pass to the file `post.md` names, with the heading, the count line, and the Passed table regenerated from what this pass drove. Patching only the marker would leave a count line and an address naming the old head.
23
+ Write the full body for this pass to the file `post.md` names, with the heading, the count line, and the Passed table regenerated from what this pass drove. Patching only the marker would leave a count line and an address naming the old head. A loopback address reads as a local preview here too, as on a first post.
24
24
 
25
25
  Add one line under the count line, reading the prior head off the standing verdict's marker and the commit count off the compare:
26
26
 
@@ -0,0 +1,38 @@
1
+ ---
2
+ title: Drive a throwaway copy
3
+ description: Steps 4 and 7 of review-ui, which rebuild the copy a preview saves into before the browser opens and check the worker's worktree for a tracked change before the post
4
+ ---
5
+
6
+ # Drive a throwaway copy
7
+
8
+ Steps 4 and 7 of `review-ui`. A preview that saves what the pass drives would otherwise write the worker's tracked files, and a drag would land in a committed fixture.
9
+
10
+ A project names the folders its preview writes in `canon/config/preview.json`. The worker starts its server reading a copy of them, and the pass rebuilds that copy at every head so the last pass's drags never reach this one.
11
+
12
+ ## Before the browser opens
13
+
14
+ Rebuild the copy and record the worktree's state:
15
+
16
+ ```bash
17
+ canon pr drive-copy <number> --baseline --json
18
+ ```
19
+
20
+ Branch on `reason` rather than on the exit code.
21
+
22
+ - `copied` means the address serves a throwaway copy rebuilt from the worker's worktree. Keep `copied` for the comment.
23
+ - `no-config` means the project declares no preview writes, so drive as usual. The check below still runs.
24
+ - `no-worktree` means no local worktree holds the branch, as for a cloud worker's. Drive, and say in the comment that the worktree check did not run.
25
+ - Any other refusal stops the pass with nothing posted, naming the `reason` and `message` for the dispatcher, since a broken `canon/config/preview.json` would send the drives into the real folders
26
+
27
+ ## Before the post
28
+
29
+ At the start of Step 7, with the browser closed since Step 6, read whether the drives changed anything git tracks in the worker's worktree:
30
+
31
+ ```bash
32
+ canon pr drive-copy <number> --check --json
33
+ ```
34
+
35
+ - `clean` continues with the post
36
+ - `changed` stops the pass. Step 7 posts it open with every path in `paths` named, and Step 8 ticks nothing, since the boxes ran against a tree the drives rewrote.
37
+ - Leave each changed path as it stands. The worktree is the worker's, so the pass reports a change and never reverts it.
38
+ - A refusal, `no-worktree` and `no-baseline` among them, means the check did not run. Say so in the comment rather than reading it as clean.
@@ -11,15 +11,25 @@ Step 7 of `review-ui`.
11
11
 
12
12
  The heading reports whether the branch owes anything, the way the code review's does.
13
13
 
14
- - `## UI review` when a box failed, the sweep found a console error or an overflow, or a box was not driven for a cause on the page, such as a target the snapshot does not hold.
14
+ - `## UI review` when a box failed, the sweep found a console error or an overflow, the worktree check read `changed`, a box was not driven for a cause on the page, or the pass drove no box at all.
15
15
  - `## UI review closed` otherwise.
16
16
 
17
- A needs-eyes box leaves the review closed, and so does a box not driven for a cause off the page, such as an address that did not answer or a `(local only)` box on a hosted preview.
17
+ A needs-eyes box leaves the review closed, and so does a box not driven for a cause off the page, such as an address that did not answer or a `(local only)` box on a hosted preview, as long as something else was driven.
18
18
 
19
19
  - Each is owed to the person who merges, and no commit can settle it, so opening the heading would hold the draft mark at every head
20
20
  - Name each such box in the count line's not-driven count and in its Not driven entry
21
21
  - Do not append the pull request number, which GitHub already renders
22
22
 
23
+ ### A pass that drove no box
24
+
25
+ A pass with 0 failed, 0 need your eyes, 0 passed, and any box not driven looked at nothing, so it has not covered the head. It takes `## UI review` whatever the cause, including a checklist of only `(local only)` boxes on a hosted preview.
26
+
27
+ - Put a line naming the cause directly under the count line, such as the addresses tried and what each returned, ahead of the address line, naming a loopback address as A loopback address says
28
+ - The cure is a re-drive on an address that answers, which Step 1 of `review-ui` allows past this verdict
29
+ - Message the controller with the cause and send the worker no `review-address`, since the verdict holds no box a fix worker could change
30
+ - `canon pr lift` refuses a close of this shape as `ui-undriven`, so a violation holds the draft mark
31
+ - A checklist with no box at all, which counts 0 not driven too, is an empty pass and takes the closed heading
32
+
23
33
  ## The body
24
34
 
25
35
  Write it to `.canon/tmp/pr/review-ui/body-<number>-<short-sha>.md` at the main worktree root, sent as a heredoc the way `session-worktree` states for a main-root write. Load the `write-human` skill for the prose and follow `${CLAUDE_SKILL_DIR}/../markdown-craft/references/markdown.md` for punctuation.
@@ -37,6 +47,10 @@ Driven at `<short-sha>` on <address>, rendered by <renderer>.
37
47
 
38
48
  ![box <n>](link)
39
49
 
50
+ ### Changed in the worktree
51
+
52
+ - `<path>`
53
+
40
54
  ### Needs your eyes
41
55
 
42
56
  **<n>. <box> (taste)**
@@ -80,10 +94,19 @@ The post takes the length limits alone, with a box's reason under 350 characters
80
94
 
81
95
  The body opens on its count line, in that order, so the operator reads what they owe before anything else. The second line carries the address, the head, and the renderer, and says the address was driven unverified when it came from the local rung or the launch.
82
96
 
83
- - Drop each section holding no box, along with its heading. Order is fixed: Failed, Needs your eyes, Not driven, then the folded blocks.
97
+ - Drop each section holding no box, along with its heading. The order is fixed as Failed, Changed in the worktree, Needs your eyes, Not driven, then the folded blocks.
84
98
  - A box takes exactly one section by its verdict, so a box that fails and also ends in `(taste)` appears once, under Failed
85
99
  - Quote page text in backticks as content, never as the pass's own words
86
100
 
101
+ ### A loopback address
102
+
103
+ A loopback address has `localhost`, `127.0.0.1`, `0.0.0.0`, or `[::1]` as its host, with any port. It never appears in the post, so the second line reads ``Driven at `<short-sha>` on a local preview, unverified, rendered by <renderer>.`` instead.
104
+
105
+ - The cause line of a pass that drove no box, and every Not driven entry, name a loopback address it tried as a local preview with its port, such as `a local preview on port 4211`
106
+ - A hosted address posts as written, since it outlives the session, and the close drops it from the evidence comment
107
+ - The evidence comment carries the local link while the pull request is open, for an operator on the same machine
108
+ - `canon pr local --remove` masks a loopback address left on a review's `Driven at` line when the pull request closes
109
+
87
110
  ### A failed box
88
111
 
89
112
  A box in a section opens on its number and the box as written, in bold, with the reading beneath it in words. A failed box that rests on a read has no image.
@@ -92,6 +115,14 @@ A box in a section opens on its number and the box as written, in bold, with the
92
115
  - That link names the frame's path on the frames branch, which stays put while other pull requests' frames are dropped and carries this pass's stamp
93
116
  - A later pass therefore never changes the image
94
117
 
118
+ ### The drive copy and the worktree check
119
+
120
+ The two `canon pr drive-copy` reads at the start of Steps 4 and 7 each leave a mark on the body, so the operator knows what the drives touched.
121
+
122
+ - When Step 4 read `copied`, add `Drove a throwaway copy of <copied paths>.` as its own line directly under the address line, naming each path in backticks
123
+ - When Step 7's check read `changed`, list every path from `paths` under Changed in the worktree, in backticks, with no reading beside it. The heading opens, and Step 8 ticks nothing.
124
+ - When either read refused, add `Worktree check did not run, <reason>.` on a line of its own under the address line, so a skipped check never reads as a clean one
125
+
95
126
  ### A needs-eyes box
96
127
 
97
128
  A needs-eyes box shows its dark and light shots in a two-cell table ahead of anything else it carries, since the operator decides from them without opening the app. A box whose evidence holds one theme still renders both cells.
@@ -126,6 +157,8 @@ Driven at `<short-sha>` on <address>, rendered by <renderer>.
126
157
  </details>
127
158
  ```
128
159
 
160
+ The count line is read by two verbs, `canon pr tick` for the passed count and `canon pr lift` for the driven test, so keep it exactly in the form `F failed · E need your eyes · P passed · N not driven`. A line that drifts reads as no counts, and both checks then stand down.
161
+
129
162
  The count line and the sections beneath it hold the same totals, and Step 10's printed line is the same four counts. A pass where every box needs eyes and nothing else is owed takes the closed heading.
130
163
 
131
164
  ## The marker
@@ -7,7 +7,7 @@ description: Step 8 of review-ui, which ticks each box that passed through canon
7
7
 
8
8
  Step 8 of `review-ui`. The verdict has posted, so the ticks and the verdict name the same `<head>`.
9
9
 
10
- Tick every box that took a `pass` verdict, whatever the heading, so a partly passed checklist shows its progress:
10
+ Tick every box that took a `pass` verdict at this head, whatever the heading, so a partly passed checklist shows its progress. A re-drive ticks all of them again, including a box whose verdict did not change, since a new head clears the ticks stamped at an older one.
11
11
 
12
12
  ```bash
13
13
  canon pr tick <number> --boxes <n,...> --head <head> --json
@@ -17,9 +17,12 @@ Number the boxes off the `boxes` field Step 2 kept. Leave a box that failed, nee
17
17
 
18
18
  The verb refuses a taste box and a head that is no longer the remote tip, writing nothing in either case. Branch on the record's `reason`, which reads `ticked` on success.
19
19
 
20
+ - `count-mismatch`: nothing was written. With `ticked` below `passed`, re-run once with every passed box. With it above, a box ticked earlier has failed, so report it on `Ticks:` for the operator.
20
21
  - `stale-head`: a push landed while this pass drove. Report it on the `Ticks:` line of Step 10 and never retry at the new tip, since the boxes were driven at the old one.
21
22
  - `body-refused`: the comment is ticked and the body is not. Retry the same call once, then report the partial result on the `Ticks:` line rather than claiming both.
22
23
  - Any other refusal: report the `reason` on the `Ticks:` line and tick nothing further.
23
24
  - A binary whose `canon pr` lacks `tick` predates the verb. Report that on the `Ticks:` line and tick nothing.
24
25
 
26
+ The record's `countCheck` reads `matched` when the verdict's passed count agreed with the ticks, and `unchecked` when the verdict did not cover the head or carried no count line. Report an `unchecked` on the `Ticks:` line.
27
+
25
28
  The same call also writes the one UI pass line in the body's `## Testing`, such as `UI pass, 17 of 17 boxes passed at <sha>, 1 taste box left to the operator`, so the operator sees the result without opening the evidence comment. Never edit that line by hand.
@@ -0,0 +1,18 @@
1
+ ---
2
+ title: Resolve the pull request without the verb
3
+ description: Step 1 of review-ui on a target whose CLI predates canon pr head, which reads the number and the head straight off the REST pulls endpoint
4
+ ---
5
+
6
+ # Resolve the pull request without the verb
7
+
8
+ Step 1 of `review-ui`, read when `canon pr head` returns no record.
9
+
10
+ Every read here runs on REST, since `gh pr` runs on GraphQL and a cloud session's proxy refuses it. A target whose CLI predates the verb gets no record back, so read the pull request directly:
11
+
12
+ ```bash
13
+ gh api "repos/{owner}/{repo}/pulls?head={owner}:$(git branch --show-current | jq -Rr @uri)&state=open" --jq '.[].number'
14
+ gh api repos/{owner}/{repo}/pulls/<number> --jq .head.sha
15
+ ```
16
+
17
+ - With no number named, take the open pull requests on the current branch, and stop when that prints anything but one number
18
+ - A named number skips that lookup, since this checkout's branch need not be the pull request's
@@ -38,10 +38,11 @@ No surface carries cross-version sequencing, so report none, since reasoning spa
38
38
 
39
39
  ## Runbooks on request
40
40
 
41
- A compaction is a moment this skill cannot detect, so the human asks for each side of it and this skill reads the matching runbook.
41
+ The human asks for each side of a compaction, and this skill reads the runbook.
42
42
 
43
43
  - On a request to write the handoff, follow `${CLAUDE_SKILL_DIR}/references/orchestrator-handoff.md`. It sends the generic half to `canon:session-map` and adds decisions taken under delegated authority.
44
44
  - That map follows `${CLAUDE_SKILL_DIR}/../session-map/references/session.md`. Write nothing to the handoff that the board, a task file, or a groundwork folder already carries.
45
+ - Hand launch: `${CLAUDE_SKILL_DIR}/references/orchestrator-hand-launch.md`
45
46
  - A lesson about how to work goes to the owning task's Findings, as a bold-labeled line per `${CLAUDE_SKILL_DIR}/../task-board/references/tasks.md`
46
47
  - On a request to resume after a compaction, read `${CLAUDE_SKILL_DIR}/references/orchestrator-resume.md`, which reads that file back with the board and the groundwork behind the live work
47
48
 
@@ -108,7 +109,7 @@ The handback runbook holds how the message is addressed and worded, what to do w
108
109
 
109
110
  ### Constraints from the tracks in flight
110
111
 
111
- A plan written here targets a tree several branches are changing, so it names each in-flight track's file set as a constraint, read from that track's Touches column. State for each set which of the two acts it forbids, per Constraints in `${CLAUDE_SKILL_DIR}/../plan-feature/references/plan.md`.
112
+ A plan written here targets a tree several branches are changing, so it names each in-flight track's file set as a constraint, read from the plan its row links. State for each set which of the two acts it forbids, per Constraints in `${CLAUDE_SKILL_DIR}/../plan-feature/references/plan.md`.
112
113
 
113
114
  - A bare path list leaves the worker guessing, and can end up forbidding the repair of a citation the change broke
114
115
  - A shared path forbids an act only where the conflict check in `orchestrator-dispatch.md` holds the pair. Otherwise it names what the second branch to merge rebases over.
@@ -125,7 +125,7 @@ No practitioner source serializes on a shared file. Each builds in parallel and
125
125
  Read `canon sessions list --json` for the branches in flight as well as the board, since a hand-launched track carries no row, and read the plan of any branch no row names.
126
126
 
127
127
  - `canon tasks validate` and `canon tasks plan-reach` report the paths two rows share, a candidate list for the five holds and the paths a dispatch names
128
- - A shared folder means a Touches cell claimed it bare, so narrow that cell rather than reading the folder as a sweep
128
+ - A shared folder means a plan declared it bare, so narrow that plan's list rather than reading the folder as a sweep
129
129
  - A declared set predicts rather than bounds, since `canon:context-fold`, `canon:docs-sync`, and the drift stages write past every plan
130
130
  - Such a crossing changes what the second branch rebases over, not whether a row holds, and `canon tasks plan-reach` at `canon:git-ship` step 5 names it
131
131
 
@@ -0,0 +1,60 @@
1
+ ---
2
+ title: Orchestrator hand launch
3
+ description: The one lean prompts file the orchestrator writes when the operator launches sessions by hand, with its path, overwrite rule, shape, and a filled example
4
+ ---
5
+
6
+ Run this when the operator launches sessions by hand rather than through `claude --bg`. The rules every launch shares stay in `orchestrator-launch.md`.
7
+
8
+ # Hand launch
9
+
10
+ When the operator launches sessions by hand, write every prompt to one file, `.canon/tmp/dispatch/prompts.md`, and overwrite it at each wave. It lists every row with a session not yet launched. A row launched from an older copy and again from a newer one would build twice, and the branch check in `orchestrator-dispatch.md` catches that.
11
+
12
+ The operator opens the file, reads one lead line, and pastes one fence per session. The shape is fixed:
13
+
14
+ - An H1, `# Dispatch prompts`, then one lead line carrying the measured head, the merge order, and the folder to open each session in
15
+ - An H2 per task as `## <label>: <title>`, an H3 per role as `### Worker` or `### Reviewer`, a `Model: <model>.` line, and a `text` fence
16
+ - In the fence, the command at position zero, then `Controller: <sessionId>`, then only context the plan does not carry, one line each
17
+
18
+ Keep the command at position zero per `### Position zero` in `orchestrator-launch.md`, and carry only what `### What the brief may carry` there allows. Leave out the answer-slot default and anything else the plan states.
19
+
20
+ The `Controller:` line replaces the background template's message clauses, which `role-worker` and `session-relay` already own. `auto-ship` Step 0 loads `role-worker`, so the fence needs nothing more.
21
+
22
+ - A reviewer launched by hand takes the `### Reviewer` H3 under its row's H2, with the sibling facts `orchestrator-reviewer-launch.md` lists
23
+ - Its `<number>` exists once the worker opened its pull request, so a later wave carries `### Reviewer` alone under the row, and the launched worker's H3 is gone
24
+
25
+ The first wave carries the worker. The wave after its pull request opens carries the reviewer alone.
26
+
27
+ ````markdown
28
+ # Dispatch prompts
29
+
30
+ Head `<head>`. Merge `<label-a>` first, then `<label-b>`. Open each session in the repository root.
31
+
32
+ ## <label-b>: <title>
33
+
34
+ ### Worker
35
+
36
+ Model: opus.
37
+
38
+ ```text
39
+ /canon:auto-ship .canon/plans/feature-<slug>.md
40
+ Controller: <sessionId>
41
+ <branch-a> edits the section of <file> this plan leaves alone. Rebase over it when told.
42
+ ```
43
+ ````
44
+
45
+ ````markdown
46
+ # Dispatch prompts
47
+
48
+ Head `<head>`. Merge `<label-a>` first, then `<label-b>`. Open each session in the repository root.
49
+
50
+ ## <label-b>: <title>
51
+
52
+ ### Reviewer
53
+
54
+ Model: opus.
55
+
56
+ ```text
57
+ Run /canon:role-reviewer, then /canon:review-pr <number>
58
+ Controller: <sessionId>
59
+ ```
60
+ ````
@@ -12,6 +12,7 @@ Run this once `orchestrator-dispatch.md` has cleared a row, or from its planning
12
12
  - [Dispatch to address a review](#dispatch-to-address-a-review)
13
13
  - [Dispatch to plan a row](#dispatch-to-plan-a-row)
14
14
  - [Dispatch a talk session](#dispatch-a-talk-session)
15
+ - [Hand launch](#hand-launch)
15
16
  - [Dispatch a reviewer](#dispatch-a-reviewer)
16
17
 
17
18
  ## Dispatch
@@ -156,6 +157,10 @@ Read the session's `sessionId` off the launch output, carry it in this session's
156
157
 
157
158
  The map exists only once the handoff writes it, so this session's own launches, read with the prior map, are what the first wind-down reads talk sessions from.
158
159
 
160
+ ## Hand launch
161
+
162
+ Read `${CLAUDE_SKILL_DIR}/references/orchestrator-hand-launch.md` when the operator launches sessions by hand. It states the single prompts file at `.canon/tmp/dispatch/prompts.md`, the lean shape of each fence, and a filled example, while the background templates above keep their full controller paragraph.
163
+
159
164
  ## Dispatch a reviewer
160
165
 
161
166
  Read `${CLAUDE_SKILL_DIR}/references/orchestrator-reviewer-launch.md` when `orchestrator-review-dispatch.md` sends a pull request to a dispatched reviewer, for the code, cloud, and UI reviewer shapes.
@@ -32,7 +32,7 @@ The blocker cell states what the row waits on, and each kind is tested different
32
32
 
33
33
  ### A hold behind a track in flight
34
34
 
35
- The validator tests the file the cell cites against the Touches column of every `## Run now` row. A track that merged since the row was parked is no longer in flight, whatever the sets still share.
35
+ The validator tests the file the cell cites against the files every `## Run now` row's plans declare. A track that merged since the row was parked is no longer in flight, whatever the sets still share.
36
36
 
37
37
  - Re-test the cell under the conflict check in `orchestrator-dispatch.md` too, since a row parked on a shared file alone holds on nothing and moves up
38
38
  - A cell naming the file in prose rather than backticks cites nothing, so rewrite the hold in the board's spelling and the next run picks it up
@@ -54,7 +54,7 @@ Poll GitHub for pull request movement by running `bun <POLL_SCRIPT>`, then act o
54
54
  - CONFLICT or STALE: send the session holding that branch the rebase handback in the canon:role-orchestrator skill's handback runbook, resolving it the way the handback rule below does. The branch owner rebases, not this session. The poll prints one of the two for a pull request, never both, so it earns one message. The canon pr lift verb refuses on either standing itself, since the green run tested a main that no longer exists, so nothing here lifts the mark.
55
55
  - OVERLAP: report the pair and the files, and settle their merge order now under the Parallelism rule of the canon:role-orchestrator skill. Dispatch nobody. The second to merge reads STALE or CONFLICT once the first lands, and the handback goes out then.
56
56
  - UNMATCHED: report it and stop. A comment posted under a heading outside the known set reaches nobody automatically, so a person decides whether to answer it by hand or the set needs a ninth heading.
57
- - UI-OPEN: report it and stop when the live UI reviewer holds the pull request, since that reviewer sends the canon:review-address dispatch itself. Otherwise dispatch it under the fallback rule below, the same as an open code pass.
57
+ - UI-OPEN: a zero-driven pass goes to the live UI reviewer to drive again, or a new one. Any other: report and stop if that reviewer holds it, since it dispatches canon:review-address, else use the fallback rule below.
58
58
  - UI-CLOSED: report it. When the pull request is still a draft and its code review is closed too, run `canon pr lift <number> --json` and report the reason it returns. Each reviewer runs the verb on its own close, so this run is the fallback for a lift neither reviewer's run made, and the verb reads every gate itself.
59
59
  - A pull request a cloud reviewer holds, on every run whatever the script printed for it: run `canon pr review-state <number> --json`. The script reports nothing when a code review posts on an unchanged head, so this read is the only one that sees a cloud pass land. An open pass newer than the last dispatch earns the dispatch rule below. A closed pass at the head on a pull request still a draft earns `canon pr lift <number> --json`, reporting the reason it returns, since a cloud reviewer can neither message nor lift.
60
60
  - UI-STALE: the UI verdict trails the head. Message the live UI reviewer to drive the new head, or launch one, and lift no mark on it.
@@ -21,11 +21,12 @@ The third trigger reaches a window the first two cannot. A session with three wo
21
21
  - A finding that changes a rule goes to the standard or rule that states it
22
22
  - One that changes another task goes to that task's Findings, and one that overturns a groundwork lean to that folder marked answered
23
23
  3. Archive what closed.
24
- - A task whose outcomes are all `[x]` and whose pull request merged is archived by the `post-merge` hook through `canon tasks archive`, plans included
24
+ - A task whose outcomes are all `[x]`, or all `[x]` beside `Operator check:` lines, and whose pull request merged is archived by the `post-merge` hook through `canon tasks archive`, plans included
25
25
  - Run `task-complete` to archive one the hook left in place
26
26
  - A task whose outcomes are standing policy never closes, so hand it to a worker to encode the policy where it is enforced, then cut the outcomes with the reason and archive once that branch merges
27
27
  - Encoding it from this session would write a tracked file, which `## Boundaries` in the skill body forbids
28
- - A merged task whose only open outcomes need the operator or another repository never archives, since `canon tasks archive` refuses `open-outcomes`. Strike each one on the task file as `- ~~<outcome>~~ <reason>`, with the reason on the same line, then archive. The task files are gitignored scratch, so this session may edit them.
28
+ - An outcome marked `- [ ] Operator check: <outcome>` never blocks the archive. The hook prints no record, so read the archived file's `Operator check:` lines into the report's `Operator checks:` line and leave them unticked.
29
+ - A merged task whose only open outcomes another repository owes, or that an operator owns and nobody marked, never archives, since `canon tasks archive` refuses `open-outcomes`. Strike each one on the task file as `- ~~<outcome>~~ <reason>`, with the reason on the same line, then archive. The task files are gitignored scratch, so this session may edit them.
29
30
  - Strike only an outcome the operator or another repository owes. An open outcome this repository owes stays on the board, and the task stays with it.
30
31
  - Send a struck outcome that another repository owes to that repository's orchestrator through `session-relay`, which resolves the address, and let the receiver file it with `task-board` on its own board. `task-board` here would file it on this board. Name it in the report for the operator when no such session is live.
31
32
  - List every struck outcome in the report's `Struck:` line, so the work is carried by a named owner rather than lost to the strike
@@ -45,6 +46,7 @@ The third trigger reaches a window the first two cannot. A session with three wo
45
46
  Findings placed: <finding> → <destination>
46
47
  Archived: <task>
47
48
  Struck: <outcome>, owed by <operator or repository>, <reason>
49
+ Operator checks: <outcome>, left unticked on <task>
48
50
  Promoted: <task>, touches <surfaces>, parallel with <task>, sharing <paths or none>
49
51
  Serialized: <task> behind <task>, held on <dependency, contract, relocation, sweep, or reason>
50
52
  Backlogged: <task>, because <what stopped being near-term>
@@ -9,7 +9,7 @@ Run this once `orchestrator-review-dispatch.md` has sent a pull request to a dis
9
9
 
10
10
  `review-pr` is a single pass rather than a role, so a launch naming it alone reaches no `role-reviewer` and owes no message. Reach the role first on this launch, the way the planning shape in `orchestrator-launch.md` reaches `role-planner`. `orchestrator-review-dispatch.md` decides whether a pull request takes this shape at all.
11
11
 
12
- No branch and no worktree are entered here. The reviewer reads the pull request at the head `review-pr` resolves and writes the comment and its body file alone.
12
+ No branch and no worktree are entered here. The reviewer reads the pull request at the head `review-pr` resolves and writes the comment and its body file alone. A reviewer the operator launches by hand takes the `### Reviewer` H3 that `orchestrator-hand-launch.md` states.
13
13
 
14
14
  ```bash
15
15
  claude --bg --model <model> -n "reviewer-<project>-<number>" "Run /canon:role-reviewer, then /canon:review-pr <number>. Your controller is the session whose sessionId is <dispatcher-id>. Resolve its current name from that id through canon sessions list --json, which carries sessionId per row, at the moment you send, and never resolve an addressee by name prefix. When the pass posts under ## Review, message the worker holding the branch to run review-address, carrying your own sessionId, and send it to the controller instead when no worker resolves. When it posts ## Review closed, run canon pr lift <number> --json and message the controller with the heading, the count line, and the reason the verb returned, unless that reason names the UI review as still open or missing. Message the controller again if you stop on a question."
@@ -39,7 +39,7 @@ Each item below is something a record needed and a launch string did not carry.
39
39
  - The task file, and its `## Findings` before deciding anything, since a row can carry its own disproof under a title still stating the original claim
40
40
  - The source files themselves, opened rather than summarized. Never a count quoted from the task file, which goes wrong or stale.
41
41
  - `CLAUDE.md` and the context entries the row touches, for the decision and the alternative it was taken against rather than for the decision alone
42
- - `.canon/tasks/priority.md` for the row's Touches column and its blocker. Read it for the shared-path lines and holds of the constraint block, never as a gate a plan must clear.
42
+ - `.canon/tasks/priority.md` for the row's blocker and the plan each running row links. Read those plans for the constraint block's shared paths and holds, never as a gate a plan must clear.
43
43
 
44
44
  ### Reads for a feature plan alone
45
45
 
@@ -56,7 +56,7 @@ Nobody watches this pass, so the messages below are owed and nothing else. The w
56
56
 
57
57
  ### The address-review dispatch
58
58
 
59
- Send it to the worker holding the branch as `review-pr` Step 5 returns an open `## Review`, or as `review-ui` reports an open `## UI review`.
59
+ Send it to the worker holding the branch as `review-pr` Step 5 returns an open `## Review`, or as `review-ui` reports an open `## UI review` that drove a box. A `## UI review` that drove no box goes to the controller with its cause instead, per `${CLAUDE_SKILL_DIR}/../review-ui/references/post.md`.
60
60
 
61
61
  - Carry the pull request number, the heading, that step's count line verbatim, and this session's own sessionId for the worker's reply
62
62
  - Resolve the worker with `canon sessions list --branch <branch> --json`, where `<branch>` is the pull request's head branch
@@ -50,6 +50,8 @@ A painted pull request needs a server in this worktree for `canon pr local` to f
50
50
  - Wait up to 60 seconds for the verb to read `ok`, then ship either way. A stack with no `dev` script gets no start, and `pr-evidence` reports `no-server`.
51
51
  - Never detach it with `nohup`, `setsid`, or `disown`, since the owning session is the stop. `canon worktrees reclaim` ends any listener left in a worktree it removes.
52
52
 
53
+ Run `canon pr drive-copy --json` before starting `dev`. On `copied`, start it with `env` set to `copyRoot`, so the operator's address serves the copy. On `no-config`, start it as it is. On a refusal, start nothing and send the controller the `reason`, since a broken config would send drives into tracked folders.
54
+
53
55
  A hand-run `git-ship` or `git-pr` starts no server, since only a worker has a lifetime to own one.
54
56
 
55
57
  ### Building against a design reference
@@ -86,7 +88,7 @@ The controlling session cannot watch this one build, so the messages below are o
86
88
 
87
89
  ### The pull request announcement
88
90
 
89
- Announce the pull request as the ship chain's pull request step returns, carrying the number, the branch, and the task it closes. That transition is the one moment only this session knows, and the controller's review poll no longer starts on a dispatch.
91
+ Announce the pull request as the ship chain's pull request step returns, carrying the number, the branch, the head sha, the CI state, the task it closes, and each departure from the plan. That transition is the one moment only this session knows, and the controller's review poll no longer starts on a dispatch.
90
92
 
91
93
  - Carry the reach in that message, being the paths this branch wrote that another live plan or `## Run now` row holds, and who holds each, which `canon tasks plan-reach` reports as `claimed`
92
94
  - Report each as a rebase the controller should order, never as a breach, since sharing a path is not a hold
@@ -123,7 +125,7 @@ A worker that improvised this read polled issue comments, never saw a UI close p
123
125
 
124
126
  ### Addressing
125
127
 
126
- Address the session the launch named, and the reviewer by its dispatch's sessionId, each as a `sessionId` rather than a name. `canon:session-relay` turns that id into an address and carries the send, falling back to a copyable block where no send tool exists.
128
+ Address the session the launch named, and the reviewer by its dispatch's sessionId, each as a `sessionId` rather than a name. `canon:session-relay` turns that id into an address and carries the send, falling back to a copyable block where no send tool exists. A `Controller: <sessionId>` line names the controller.
127
129
 
128
130
  Ask the operator when the launch named nobody and a person is there, putting candidate rows through the structured question surface. The halt is the cheaper error, since a message sent to the wrong session reports success and is lost.
129
131
 
@@ -39,7 +39,9 @@ Name what was not touched too. A session that changed no source says so, since a
39
39
 
40
40
  One bullet per decision, each naming what it beat. A decision with no rejected alternative reads as arbitrary and gets reopened by the next session that dislikes it.
41
41
 
42
- Where a decision rests on a measurement, give the number rather than the conclusion. `27 spacing values became 7` survives a reader disagreeing with it, where `the spacing was tidied` does not.
42
+ - Keep each bullet under 200 characters, and give a decision needing more an H3 of its own and a short paragraph
43
+ - The note holds to the six criteria under `### Structure` in `${CLAUDE_SKILL_DIR}/../plan-feature/references/plan.md`
44
+ - Where a decision rests on a measurement, give the number rather than the conclusion. `27 spacing values became 7` survives a reader disagreeing with it, where `the spacing was tidied` does not.
43
45
 
44
46
  ### `## What is open`
45
47
 
@@ -66,7 +66,7 @@ Three sections form the core, in this order, and every session fills all three.
66
66
  - `## Mistakes worth not repeating`: what went wrong and the rule it yields
67
67
  - `## Standing cautions`: commands that lie, tools that measure the wrong tree, and anything unbacked
68
68
 
69
- Add a section only for content that fits none of the three and would otherwise be lost.
69
+ Add a section only for content that fits none of the three and would otherwise be lost. Every section holds to the six criteria under `### Structure` in `${CLAUDE_SKILL_DIR}/../plan-feature/references/plan.md`.
70
70
 
71
71
  ## Writing one
72
72
 
@@ -91,9 +91,9 @@ A collision with running work blocks a task only where no merge settles it, bein
91
91
 
92
92
  ### The `Touches` cell
93
93
 
94
- A `Touches` cell is the first three paths of its plan's `**Files to touch:**` and a count of the rest, the union in line order for a sliced task. It states what the branch sets out to write, and a running branch outgrows it.
94
+ A `Touches` cell counts its plans' declared files and names the two fullest folders, as in ``12 files under `src/tasks/`, `claude/skills/` ``. The linked plan holds the file list, which the overlap checks read.
95
95
 
96
- - `canon tasks plan-reach <plan>` reads the current reach off the branch's diff
96
+ - `canon tasks plan-reach <plan>` reads the reach a running branch grew to
97
97
  - Change the plan's list to change the cell. A worker never edits this board.
98
98
 
99
99
  ### Cell width
@@ -83,7 +83,7 @@ Two headings, `## Outcomes` and `## Findings`. Outcomes are future and checkable
83
83
 
84
84
  - Add no third heading. Status stays inline on an outcome rather than becoming an "In progress" section.
85
85
  - Outcomes stay a checklist, since the board tools read them by their `- [ ]` line
86
- - Open each finding with a bold label naming its source and date, as in `- **planner, 2026-10-11:** <finding>`. Keep it to a few sentences, moving anything longer into the plan or groundwork folder.
86
+ - Open each finding with a bold label naming its source and date, as in `- **planner, 2026-10-11:** <finding>`. Past 200 characters it becomes a paragraph, and the plan holds anything longer.
87
87
 
88
88
  ### Sizing outcomes
89
89
 
@@ -198,7 +198,7 @@ Session history and ordering both have homes off the task file.
198
198
 
199
199
  ## Archiving
200
200
 
201
- Never delete a task file. A shipped task moves to `.canon/tasks/archive/` under its own name through `canon tasks archive`, and the live index regenerates without it. What the verb does and refuses on is at `canon tasks archive --help`, and a flat `.claude/task-archive/` names an older binary rather than a second archive.
201
+ Never delete a task file. A shipped task moves to `.canon/tasks/archive/` under its own name through `canon tasks archive`, and the live index regenerates without it. What the verb does and refuses on is at `canon tasks archive --help`.
202
202
 
203
203
  ### The plan and ready folder
204
204
 
@@ -209,4 +209,6 @@ Archiving a task archives its plan alongside it when the task is that plan's las
209
209
 
210
210
  ### Open outcomes
211
211
 
212
- A task with an open outcome stays on the board, and so does its plan. Close it, or cut an abandoned outcome by striking its body, as `- ~~<outcome>~~ <why>`, which reads as cut whatever its checkbox holds, so a task of cut outcomes still archives.
212
+ A task with an open outcome stays on the board with its plan. Close it, or cut an abandoned one by striking its body, as `- ~~<outcome>~~ <why>`, which reads as cut.
213
+
214
+ An operator-only check outside this repository takes `- [ ] Operator check: <outcome>`, written before the pull request opens. It closes unticked.
@@ -43,6 +43,7 @@ For each unchecked outcome, decide whether the diff shipped the behavior it name
43
43
 
44
44
  - Mark only outcomes already written on the board. Never infer a new task from the diff.
45
45
  - Match on the behavior an outcome describes, not on filenames or commit subjects. The path match above only narrowed which task files to open.
46
+ - Never tick an outcome marked `Operator check:`, since a diff cannot prove a check only the operator can run.
46
47
  - Leave an outcome `[ ]` when the diff is ambiguous. An unmarked shipped outcome costs one manual edit, while a wrongly marked one hides work that never happened.
47
48
  - Do not touch task files the diff does not relate to.
48
49
 
@@ -56,7 +56,8 @@ An empty `plans` means the task cited no live plan, or a sibling still holds eve
56
56
  Each reason has one resolution, and none of them is to archive around it.
57
57
 
58
58
  - `open-outcomes`: the named outcomes are unmarked or genuinely open. Run `task-complete` when the work shipped unmarked, and leave the task on the board when the outcome is real.
59
- - An outcome only the operator or another repository can close is the exception. The orchestrator's merge sweep strikes it with its reason and lists it in the report, per `${CLAUDE_SKILL_DIR}/../role-orchestrator/references/orchestrator-refill.md`, and the archive then runs. An outcome this repository owes is never struck for that.
59
+ - An outcome only the operator can check is marked `- [ ] Operator check: <outcome>` rather than struck, which the archive passes and the record lists under `operatorChecks`. The mark has to land before the pull request opens.
60
+ - Abandoned work, an outcome another repository owes, and an operator outcome nobody marked in time take the strike. The orchestrator's merge sweep strikes it with its reason and lists it in the report, per `${CLAUDE_SKILL_DIR}/../role-orchestrator/references/orchestrator-refill.md`, and the archive then runs. An outcome this repository owes is never struck for that.
60
61
  - `ambiguous`: two tasks name one pull request, the misfile `${CLAUDE_SKILL_DIR}/references/tasks.md` rules out. Resolve the citation by hand, since no sweep repairs it.
61
62
  - `earlier-slice`: the number is listed on the task but is not the last. Leave the task on the board, and its last slice's merge archives it.
62
63
 
@@ -18,13 +18,13 @@ kind: reference
18
18
  | `rule-layout` | A flat installed-rule layout onto the `canon/`-wrapped one |
19
19
  | `scratch-evidence` | A folder a durable record cites out of `.tmp/`, with its citations |
20
20
  | `record-layout` | Review receipts, memory archives, feedback, renders, picks, and evidence into their current folders |
21
- | `session-defaults` | The seeded session defaults into an existing `.claude/settings.json`: `Agent` and `Task` denied, auto memory off |
21
+ | `session-defaults` | The seeded session defaults into an existing `.claude/settings.json`: `Agent`, `Task`, and both merge commands denied, auto memory off |
22
22
 
23
23
  - `skill-names` takes no `--scope`, and skips the changelog, eval transcripts, and the pointer each renamed `draft-` skill leaves at its old name
24
24
  - `surface-roots` leaves `rules/`, `skills/`, `hooks/`, and `settings.json` where Claude Code reads them
25
25
  - `rule-layout` classifies each flat file against the stamp as clean, edited, or unclaimed. Clean and edited files move untouched, and an unclaimed name stays.
26
26
  - `record-layout` labels each evidence folder `(pick)` or `(evidence)` in the dry run
27
- - `session-defaults` adds a key only when absent. It never removes a deny entry or changes a set `autoMemoryEnabled`, and a missing settings file is nothing to do.
27
+ - `session-defaults` adds a key only when absent, merge entries included, and each older project runs it once. `--write` restores a removed `Agent` or `Task` and never removes a deny entry.
28
28
 
29
29
  ## Output
30
30
 
@@ -57,5 +57,5 @@ Branch on `reason` in the `--json` record, not the exit code.
57
57
  ## See also
58
58
 
59
59
  - `canon records ordinal <kind> <slug> --claim`: reserve the next intake or groundwork ordinal
60
- - `canon records validate <kind> --help`: where a record folder disagrees with its standard
60
+ - `canon records validate <kind> [record] --help`: where a record disagrees with its standard, plus a `structure` report that never sets the exit
61
61
  - `canon records stale --help`: when the requirements record was last reviewed
@@ -150,9 +150,9 @@ The wireframes record is retired, and nothing deletes what a project holds.
150
150
 
151
151
  The toolkit no longer seeds `canon/ARCHITECTURE.md`, and a held file and its `CLAUDE.md` import stay. Move a trap a session would hit into that domain's `## Gotchas`, then delete the file and its `@canon/ARCHITECTURE.md` line.
152
152
 
153
- ## Deny subagents and turn auto memory off, once
153
+ ## Deny subagents and merges, and turn auto memory off, once
154
154
 
155
- The seeded `.claude/settings.json` now denies the `Agent` and `Task` tools and sets `autoMemoryEnabled` to `false`. `canon claude sync` never rewrites a settings file you hold, so it warns while the file holds neither default. Removing the deny later to allow subagents draws no warning.
155
+ The seeded `.claude/settings.json` now denies the `Agent` and `Task` tools and both merge commands, and sets `autoMemoryEnabled` to `false`. `canon claude sync` never rewrites a settings file you hold, so it warns while the file holds no default or lacks a merge entry. Removing `Agent` and `Task` later draws no warning.
156
156
 
157
157
  ```bash
158
158
  canon migrate session-defaults --json
@@ -161,6 +161,8 @@ canon migrate session-defaults --write --json
161
161
 
162
162
  The verb only adds a key that is absent. A person who wants auto memory back sets it in their own `.claude/settings.local.json`.
163
163
 
164
+ The verb adds `Bash(canon pr merge:*)` and `Bash(gh pr merge:*)` so a session cannot merge. A project migrated before them runs `--write` once more, which also restores `Agent` and `Task` for a person who removed them to allow subagents, so remove them again after.
165
+
164
166
  ## Move the capture cases out of the harness, once
165
167
 
166
168
  A web project's `e2e/screenshot.ts` is a config, so sync overwrites it. It now loads `CASES` from a seeded `e2e/capture/cases.ts` that sync copies once and never overwrites. Cases edited in the old harness leave the working tree on the first sync and stay in git history.