@erclx/canon 4.117.0 → 4.119.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/claude/.claude-plugin/plugin.json +1 -1
- package/claude/skills/canon-operator/SKILL.md +1 -1
- package/claude/skills/canon-rollout/SKILL.md +2 -2
- package/claude/skills/design-extract/SKILL.md +1 -1
- package/claude/skills/docs-fold/SKILL.md +2 -2
- package/claude/skills/draft-ready/REQUIREMENT.md +1 -1
- package/claude/skills/draft-ready/SKILL.md +1 -1
- package/claude/skills/draft-ready/references/assembly.md +8 -0
- package/claude/skills/draft-screencast/SKILL.md +1 -1
- package/claude/skills/git-pr/SKILL.md +5 -3
- package/claude/skills/memory-capture/SKILL.md +3 -3
- package/claude/skills/memory-review/SKILL.md +3 -3
- package/claude/skills/plan-feature/REQUIREMENT.md +1 -0
- package/claude/skills/plan-feature/SKILL.md +8 -1
- package/claude/skills/review-branch/SKILL.md +1 -1
- package/claude/skills/review-pr/REQUIREMENT.md +1 -0
- package/claude/skills/review-pr/SKILL.md +4 -2
- package/claude/skills/role-planner/SKILL.md +1 -1
- package/claude/skills/role-worker/REQUIREMENT.md +1 -1
- package/claude/skills/role-worker/SKILL.md +10 -41
- package/claude/skills/seed-sync/SKILL.md +1 -1
- package/claude/skills/session-compact/SKILL.md +1 -1
- package/claude/skills/session-map/SKILL.md +1 -1
- package/claude/skills/session-relay/REQUIREMENT.md +7 -1
- package/claude/skills/session-relay/SKILL.md +4 -7
- package/claude/skills/session-worktree/REQUIREMENT.md +5 -1
- package/claude/skills/session-worktree/SKILL.md +7 -1
- package/claude/skills/session-worktree/references/main-root-writes.md +24 -0
- package/claude/skills/target-check/references/domains.md +1 -1
- package/claude/skills/task-board/SKILL.md +4 -3
- package/claude/skills/teach-workspace/SKILL.md +4 -4
- package/claude/skills/ui-checklist/SKILL.md +1 -1
- package/claude/skills/ux-audit/SKILL.md +1 -1
- package/claude/skills/ux-measure/SKILL.md +1 -1
- package/claude/skills/ux-walkthrough/references/relay.md +1 -1
- package/docs/agents/commands.md +3 -3
- package/docs/agents/context-audit-checks.md +2 -28
- package/docs/agents/context-audit.md +1 -1
- package/docs/agents/install-and-sync.md +28 -17
- package/docs/agents/tasks.md +4 -4
- package/docs/target-projects.md +2 -2
- package/docs/workflow/ai-workflow.md +9 -9
- package/docs/workflow/operating-model.md +1 -1
- package/docs/workflow/visual-design-workflow.md +2 -2
- package/governance/renames.toml +13 -0
- package/governance/rules/claude/510-context.md +0 -12
- package/governance/rules/core/005-behavior.md +1 -2
- package/governance/rules/core/015-output.md +1 -3
- package/governance/rules/core/035-tasks.md +1 -3
- package/governance/rules/core/045-memory.md +0 -1
- package/governance/rules/core/055-scratch.md +2 -4
- package/governance/rules/core/070-planning.md +1 -4
- package/governance/rules/core/085-worktrees.md +2 -8
- package/governance/rules/core/087-git.md +2 -2
- package/governance/rules/core/090-code-comments.md +1 -1
- package/governance/rules/ui/460-design-taste.md +0 -15
- package/package.json +1 -1
- package/src/claude/cases/workflow.ts +10 -0
- package/src/commands/context.ts +11 -111
- package/src/commands/sync.ts +11 -3
- package/src/commands/tasks.ts +9 -8
- package/src/context/audit.ts +3 -145
- package/src/design/base.css +19 -19
- package/src/design/board.ts +18 -7
- package/src/design/neutral.ts +127 -0
- package/src/design/regen.ts +6 -4
- package/src/design/tokens.ts +5 -2
- package/src/gate/measures.ts +37 -0
- package/src/gate/stages.ts +13 -4
- package/src/gov/adapter.ts +59 -7
- package/src/gov/install.ts +13 -3
- package/src/gov/renames.ts +76 -0
- package/src/gov/stacks.ts +5 -1
- package/src/records/validate.ts +5 -1
- package/src/sync/check.ts +25 -4
- package/src/sync/engine.ts +154 -10
- package/src/sync/stamp.ts +44 -0
- package/src/tasks/archive.ts +28 -7
- package/src/tasks/record.ts +16 -9
- package/src/tasks/validate.ts +3 -1
- package/standards/plan.md +24 -1
- package/standards/tasks.md +5 -3
- package/governance/rules/core/091-channel.md +0 -13
- package/src/context/narration.ts +0 -99
|
@@ -27,7 +27,7 @@ Read seven fields off the report and carry each to `## Route`:
|
|
|
27
27
|
- `unmigrated`: a domain sitting at the root layout with nothing under `.claude/`. The most urgent finding, because that domain reports no drift of its own while being entirely behind
|
|
28
28
|
- `superseded`: a file a newer seed folder replaced. No command moves it, since the content is the project's own, so this routes to `canon:target-check` for the full per-domain reading rather than ending at the report
|
|
29
29
|
- `seeds`: entries are `matching`, `stale`, `drifted`, or `missing`. Anything but `matching` needs the seed handoff
|
|
30
|
-
- `domains[].entries`: per-file `stale`, `customized`, `stranded`, and `orphaned` as before
|
|
30
|
+
- `domains[].entries`: per-file `stale`, `customized`, `stranded`, and `orphaned` as before, plus `retired` for a rule the toolkit no longer ships, which the next sync deletes
|
|
31
31
|
- `reverse`: what the target holds that no live catalog claims. `unclaimed` lists folders at roots the toolkit stopped shipping, each with an `attribution` of `dropped`, `unattributed`, or `project`. Act on the first two and leave `project` alone, which history proved the project owns
|
|
32
32
|
- `historyUnavailable` on a domain, on `seeds`, or on `reverse`: nothing could be dated, so treat every difference as unverified and say so rather than reporting a file as untouched. It is set on `reverse` when the toolkit itself ships without history, which is the registry-install case, so the walk found nothing rather than finding a clean target
|
|
33
33
|
- `tooling`: read `measured` first. Every count under it is zero when it is false, which is an absence of measurement rather than a measured zero. Past that, `chain` names the stacks the install resolved, nearest first, and `counts.gitignore` counts the managed ignore entries the target is missing.
|
|
@@ -104,11 +104,11 @@ One session, one target, from the worktree entry to the merge of the branch it o
|
|
|
104
104
|
3. Check what this target holds. Invoke `canon:target-check`, which reports per domain what the target carries against what the toolkit ships and repairs nothing. It runs before any repair so the wave reads one stated set of domains per target rather than whatever each session decided to examine.
|
|
105
105
|
4. Diagnose and repair. Invoke `canon:canon-operator`, which reads `canon sync --check . --json` and routes each finding to the command or the skill that owns it. Do not restate that routing here and do not edit a managed file by hand.
|
|
106
106
|
5. Commit and open the pull request through `canon:git-commit` and `canon:git-pr`, handing each the fixed shape above rather than taking the title the generator derives from the diff.
|
|
107
|
-
6. Announce as the pull request opens, carrying its URL, its number, and the branch, to whoever dispatched this session
|
|
107
|
+
6. Announce as the pull request opens, carrying its URL, its number, and the branch, to whoever dispatched this session, sending it through `canon:session-relay`. That transition is the one moment only this session can observe.
|
|
108
108
|
7. Answer the review. Invoke `canon:review-address`, which pulls the findings and the CI state on this branch's open pull request, fixes each in the working tree, replies, and pushes. Answer every finding whatever its severity.
|
|
109
109
|
8. Stop there. Do not mark the pull request ready, do not merge, and do not declare the review closed. A narrow re-review posts `## Review closed`.
|
|
110
110
|
|
|
111
|
-
Send a block out
|
|
111
|
+
Send a block out through `canon:session-relay` before it becomes an interactive prompt, which states why the order matters.
|
|
112
112
|
|
|
113
113
|
Refuse an instruction this target's tree contradicts and carry the evidence with the refusal, naming the commands read and what complying would cost. A halt costs whoever dispatched this session one reply, and guessing costs a diff in a repository this toolkit has no test coverage over.
|
|
114
114
|
|
|
@@ -77,7 +77,7 @@ Anchor every proposal to a signal, never to a default. "Calm and dense" pins mut
|
|
|
77
77
|
- **Traced cells**: when Step 2 matched a `design-handoff.md` file, fill only the fields it actually states, no tag, the same traced-versus-proposed distinction the source path draws for a stylesheet value.
|
|
78
78
|
- The handoff carries hex and family and size, never Weight, Line height, or a color's Intent. Those cells, every field of a role the handoff never names, and Motion and Iconography regardless, still follow the proposal rules below, tag included.
|
|
79
79
|
- **Personality**: transcribe the `## Personality` paragraph from `canon/REQUIREMENTS.md` verbatim. This is the one section that is not a proposal. No tag.
|
|
80
|
-
- **Color**: one row per role. Rewrite the Intent cell in personality language, for example `
|
|
80
|
+
- **Color**: one row per role. Rewrite the Intent cell in personality language, for example `near-white page canvas` instead of the seed default `page canvas`. Propose hex values matching the personality. Dense and calm gives low saturation and high text contrast. Playful gives saturated accents. Every Intent and Value cell gets `? verify`.
|
|
81
81
|
- **Typography**: one row per role. Propose families fitting the platform, system UI for web, monospaced for CLI tools, serif for editorial, and a harmonious scale. Every cell gets `? verify`.
|
|
82
82
|
- **Spacing**: propose a base unit matching density intent. Dense gives a 4px base, roomy gives 8px. Keep the Multiplier column as the seed ships it, no tag. Only the Value column gets `? verify`.
|
|
83
83
|
- **Borders**: propose radius and width per role. Sharp and technical gives a small radius, soft gives a larger one. Every Radius and Width cell gets `? verify`.
|
|
@@ -100,7 +100,7 @@ For each doc with relevant changes, apply updates following these rules. Read a
|
|
|
100
100
|
- Do not touch task files this session did not change.
|
|
101
101
|
- Never hand-edit `.canon/tasks/index.md`. A hook regenerates it.
|
|
102
102
|
|
|
103
|
-
The verb resolves the board at the main worktree root in-process, which is the route
|
|
103
|
+
The verb resolves the board at the main worktree root in-process, which is the route `session-worktree` states for an edit inside an existing main-root file.
|
|
104
104
|
|
|
105
105
|
Read `ok` and `reason` out of that record rather than the exit. An operator's shell profile may wrap `canon` in a function that runs the binary and then a second command and takes the second status, which flattens every non-zero exit to zero. A refusal arriving as success leaves the outcome unmarked while the chain moves on, so the board reports shipped work as open and the next session re-plans it.
|
|
106
106
|
|
|
@@ -216,7 +216,7 @@ Report a block left unfolded rather than dropping it:
|
|
|
216
216
|
|
|
217
217
|
Sweep the review and memory receipts this session consumed. Resolve all paths at the main worktree root, not the current worktree, the way `session-worktree` does.
|
|
218
218
|
|
|
219
|
-
Every delete below is a
|
|
219
|
+
Every delete below is a plain `rm`, one per call, routed the way `session-worktree` states.
|
|
220
220
|
|
|
221
221
|
Plans are not swept here. A plan is settled by the merge rather than by an outcome this run marked, and `canon tasks archive` moves it with the task the `post-merge` hook archives. Sweeping it from this step read a closure Step 3 had written moments earlier and moved a plan the branch was still building from.
|
|
222
222
|
|
|
@@ -28,7 +28,7 @@ Without this skill, a session holding finished files that hands them to a worker
|
|
|
28
28
|
- Copy each finished file whole to its destination path inside the folder, and carry nothing else into it.
|
|
29
29
|
- Write the plan and the task through `canon tasks plan-link`, `canon records validate plans`, and `canon markdown audit` rather than by restating what those verbs check.
|
|
30
30
|
- Place the task's row by the three branches `task-board` Step 4 states, so a solo project never ends with a task file on no surface.
|
|
31
|
-
- Route a write at the main root from a linked worktree through `Bash`,
|
|
31
|
+
- Route a write at the main root from a linked worktree through `Bash`, the way `session-worktree` routes it.
|
|
32
32
|
- Name the archive move in the closing report, since the skill writes a folder that stays live until someone moves it.
|
|
33
33
|
|
|
34
34
|
## Must not
|
|
@@ -53,7 +53,7 @@ install -D -m 0644 <source> <main-root>/.canon/ready/<nn>-<slug>/<destination pa
|
|
|
53
53
|
|
|
54
54
|
- Copy whole and edit nothing. A change wanted now is made in the source file first and copied after.
|
|
55
55
|
- Carry no notes, alternates, or drafts into the folder. Anything else belongs in the plan or the pull request body.
|
|
56
|
-
- Write each of these at the main root
|
|
56
|
+
- Write each of these at the main root, routed the way `session-worktree` states. Create a whole new file with a heredoc.
|
|
57
57
|
|
|
58
58
|
## Step 5: write the thin plan
|
|
59
59
|
|
|
@@ -47,10 +47,18 @@ destinations:
|
|
|
47
47
|
|
|
48
48
|
- `<path/to/file>`: copy from the ready folder, <one clause on what it changes>
|
|
49
49
|
|
|
50
|
+
**Verification:**
|
|
51
|
+
|
|
52
|
+
- <the command that proves the copy landed, or "None identified.">
|
|
53
|
+
|
|
50
54
|
**Risks:**
|
|
51
55
|
|
|
52
56
|
- <what could go wrong, or "None identified.">
|
|
53
57
|
|
|
58
|
+
**Review focus:**
|
|
59
|
+
|
|
60
|
+
- <an input the copied files must handle, or "None identified.">
|
|
61
|
+
|
|
54
62
|
**Questions:**
|
|
55
63
|
|
|
56
64
|
None identified.
|
|
@@ -43,7 +43,7 @@ Build a 2-to-4-word kebab-case slug from the topic and discovery answers. Exampl
|
|
|
43
43
|
|
|
44
44
|
Create `.canon/tmp/screencast/<slug>.md` at the main worktree root. Create the directory if it does not exist. The file is gitignored.
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
The draft is a main-root write, so it goes out as a heredoc, routed the way `session-worktree` states.
|
|
47
47
|
|
|
48
48
|
Write all eight sections. Pre-seed every section with concrete content so the draft is shippable as-is. The user edits down rather than fills blanks.
|
|
49
49
|
|
|
@@ -219,7 +219,7 @@ gh pr comment <number> --body-file <main-root>/.canon/tmp/handoff/ui-checklist/<
|
|
|
219
219
|
|
|
220
220
|
Run the cleanup below only once the call that carried the checklist reports success, whichever of the two steps that was. On a failure, stop and leave the file in place: a retry needs the checklist to still be there, and deleting it on a failed post loses the only copy with nothing landed on the pull request.
|
|
221
221
|
|
|
222
|
-
|
|
222
|
+
The cleanup is a main-root delete, so it goes out as a plain `rm` and then a plain `rmdir`, the file and then the folder, routed the way `session-worktree` states:
|
|
223
223
|
|
|
224
224
|
```bash
|
|
225
225
|
rm <main-root>/.canon/tmp/handoff/ui-checklist/<slug>.md
|
|
@@ -266,9 +266,11 @@ canon tasks pull-request <number> --plan feature-<slug> --json
|
|
|
266
266
|
|
|
267
267
|
The slug is a guess at which plan this branch carries rather than a fact about the task, which is why the verb re-checks it against the board and refuses instead of writing on a near miss. A branch whose slug names no plan file falls to the silent skip below, the same as one whose plan no task cites.
|
|
268
268
|
|
|
269
|
-
The verb resolves the board at the main worktree root in-process, adds `Pull request: #NNN` under the `Plan:`, `Groundwork:`, `Intake:`, or `Issue:` lines the task already carries, and corrects the number in place when the line exists. This is the route because the write is an edit inside an existing file, which
|
|
269
|
+
The verb resolves the board at the main worktree root in-process, adds `Pull request: #NNN` under the `Plan:`, `Groundwork:`, `Intake:`, or `Issue:` lines the task already carries, and corrects the number in place when the line exists. This is the route because the write is an edit inside an existing main-root file, which `session-worktree` routes through a verb. That root is the one `session-worktree` resolves on entry.
|
|
270
270
|
|
|
271
|
-
|
|
271
|
+
The correction reaches only a line that does not read as a list of `#NNN` entries. A line that does takes the new number appended rather than replaced, reported as `appended`, so a task shipped in slices keeps every pull request.
|
|
272
|
+
|
|
273
|
+
Skip this silently when the record is `ok: false` and `reason` is `no-board`, `no-match`, or `ambiguous`. Those are the three cases a guessed write would compound: no board, no task naming the plan, or more than one. One pull request names one task, and a wrong match archives the wrong task unattended once the branch merges. Report any other refusal rather than swallowing it.
|
|
272
274
|
|
|
273
275
|
The number is what lets the merge close the task. Every merge on `main` is a squash carrying it in the subject, so the number survives where a branch name does not, and `post-merge` reads it back to call `canon tasks archive`. Writing it here rather than at worktree time is what makes it a pull request number rather than a branch the squash discards.
|
|
274
276
|
|
|
@@ -14,7 +14,7 @@ The filename and its type prefix, the frontmatter, the body shape each type carr
|
|
|
14
14
|
## Guards
|
|
15
15
|
|
|
16
16
|
- All `.canon/memory/` reads and writes resolve at the main worktree root, not the current worktree. Resolve that root the way `session-worktree` does.
|
|
17
|
-
-
|
|
17
|
+
- Every path below sits at the main root, so each write in this skill goes out as a heredoc, routed the way `session-worktree` states. A memory entry holds one fact and this session has read it, so an update rewrites the whole file with a heredoc rather than editing a line inside it.
|
|
18
18
|
- If `.canon/memory/` does not exist at the main worktree root, create it, along with an `index.md` carrying `title` and `subtitle` frontmatter. `canon claude init` seeds both, and a project predating that seed has neither. Regeneration errors without the index, so the first write into a bare folder would report a frontmatter failure against a file that is fine.
|
|
19
19
|
- If the session produced no user corrections, confirmations, or context disclosures worth persisting, stop: `✅ Nothing worth capturing.`
|
|
20
20
|
- Routing edits a tracked file, so it runs only where the caller commits. When the session is in the main worktree, or the caller states it does not commit, skip Step 3 and write every candidate as a memory file. `role-orchestrator` is the caller this covers.
|
|
@@ -44,7 +44,7 @@ For each project candidate, match its subject against `canon/context/index.md`.
|
|
|
44
44
|
|
|
45
45
|
Fail closed. A project candidate matching no entry stays a memory file, and so does one matching two entries where neither is clearly the owner. The residue is what the folder is for, and a fact filed under the wrong entry is worse than one in memory because a context entry is a surface sessions trust.
|
|
46
46
|
|
|
47
|
-
Do not edit a context entry here. `docs-fold` owns those edits and folds the routed facts in on its own pass, or two skills write one file at the same step. Write each routed fact to `.canon/tmp/handoff/memory-routing/<slug>.md` at the main worktree root instead, appending when the file exists. Name the heading with the entry's own path from `canon/context/index.md`, flat or the nested `index.md`, since that heading is what tells `docs-fold`'s routed-facts fold which file to open. An append is a whole-file operation
|
|
47
|
+
Do not edit a context entry here. `docs-fold` owns those edits and folds the routed facts in on its own pass, or two skills write one file at the same step. Write each routed fact to `.canon/tmp/handoff/memory-routing/<slug>.md` at the main worktree root instead, appending when the file exists. Name the heading with the entry's own path from `canon/context/index.md`, flat or the nested `index.md`, since that heading is what tells `docs-fold`'s routed-facts fold which file to open. An append is a whole-file operation, so send it as a heredoc:
|
|
48
48
|
|
|
49
49
|
A flat domain takes:
|
|
50
50
|
|
|
@@ -78,7 +78,7 @@ Two of its rules are the ones a capture pass gets wrong under time pressure. Sta
|
|
|
78
78
|
|
|
79
79
|
Do not edit the index. `.canon/memory/index.md` is generated from sibling frontmatter by a `PostToolUse` hook, the same way the task board's index is, so a hand-appended row is drift the next regeneration discards.
|
|
80
80
|
|
|
81
|
-
|
|
81
|
+
A shell write skips that hook, as `session-worktree` states. Regenerate the index once after the last write when the entries went out through `Bash`:
|
|
82
82
|
|
|
83
83
|
```bash
|
|
84
84
|
canon indexes regen --no-stage --root <main-root> <main-root>/.canon/memory/index.md
|
|
@@ -26,7 +26,7 @@ If the user re-pings the skill with no new phrase and a receipt exists, default
|
|
|
26
26
|
- If `.canon/memory/` contains no top-level `*.md` entries other than `index.md`, stop: `✅ No memory entries to review.` The pen holds two subfolders now, `review/` and `archive/`, and neither is a memory entry, so this count and every entry read below stay at the top level and never recurse into either.
|
|
27
27
|
- Cleanup is exempt from the two stops above. It works on receipts in `.canon/review/`, and a drained pen is the normal state once Apply has run, so a pen-shaped stop would strand the receipt it exists to delete.
|
|
28
28
|
- Resolve the main root via `git worktree list --porcelain | grep -m 1 '^worktree ' | cut -d' ' -f2-`, falling back to `pwd`. All review and memory reads anchor here.
|
|
29
|
-
-
|
|
29
|
+
- Every main-root write below goes out as a heredoc, routed the way `session-worktree` states. The receipt and a memory entry are both short and this session has read them whole, so a rewrite replaces the file with a heredoc rather than editing a line inside it. Promotion targets are tracked files at `pwd` and keep taking `Edit`.
|
|
30
30
|
|
|
31
31
|
## Propose phase
|
|
32
32
|
|
|
@@ -156,7 +156,7 @@ Action by action type:
|
|
|
156
156
|
- **Hand off**: do not edit governance. Archive the memory file only if the user confirmed the handoff explicitly. Otherwise leave it in place.
|
|
157
157
|
- **Retire**: archive the memory file.
|
|
158
158
|
|
|
159
|
-
Archiving means creating `.canon/memory/archive/` at the main worktree root and moving the file there under its original name, overwriting any file already at that name. Send the `mkdir -p` and
|
|
159
|
+
Archiving means creating `.canon/memory/archive/` at the main worktree root and moving the file there under its original name, overwriting any file already at that name. Send the `mkdir -p` and a plain `mv`, routed the way `session-worktree` states for a main-root move. Never delete a memory entry. Nothing recovers one from a gitignored folder.
|
|
160
160
|
|
|
161
161
|
Do not hand-edit `.canon/memory/index.md`. Once every archive move is done, regenerate it instead:
|
|
162
162
|
|
|
@@ -164,7 +164,7 @@ Do not hand-edit `.canon/memory/index.md`. Once every archive move is done, rege
|
|
|
164
164
|
canon indexes regen --no-stage --root <main-root> <main-root>/.canon/memory/index.md
|
|
165
165
|
```
|
|
166
166
|
|
|
167
|
-
|
|
167
|
+
An archive move is a shell `mv`, which skips the index hook the way `session-worktree` states. Without this call the index keeps a row per archived entry and drifts exactly the way the hand-appended one did. Run it once after the last move rather than per item.
|
|
168
168
|
|
|
169
169
|
Apply promotion edits one at a time via `Edit`. Claude Code's tool permission dialog is the confirmation gate per edit. Never rewrite a whole promotion target.
|
|
170
170
|
|
|
@@ -14,6 +14,7 @@ Without this skill, implementation starts before anyone knows what it touches. A
|
|
|
14
14
|
- Read the project's own Claude setup before scanning source, so the plan inherits decisions already made instead of reopening them
|
|
15
15
|
- Name every file the work touches with the reason it is touched
|
|
16
16
|
- Place each new path against the layout guidance with a one-clause reason, loading that guidance only when the plan creates a file or folder, since the planner decides placement and the worker copies whatever path it is given
|
|
17
|
+
- Name how each outcome is proven and which input or state would break the change, so the executing session has a check to run and the reviewer has a place to look
|
|
17
18
|
- Surface each unresolved ambiguity as a numbered question carrying a suggested answer and an empty answer slot, so the plan is decision-ready in one pass
|
|
18
19
|
- State which act a constraint forbids when it names a surface to leave alone, since conforming that surface and retargeting a pointer into it are different acts and only one is out of scope
|
|
19
20
|
- Scale the output to the work. A two-file change with nothing to decide should not produce a plan file.
|
|
@@ -46,6 +46,7 @@ What this skill adds on top of the standard:
|
|
|
46
46
|
- Apply senior judgment to every `- Suggested:` line. Pick the best option and state it in one line with its reason or main tradeoff. No padding, no alternatives unless they change the pick.
|
|
47
47
|
- Suggest a real default when best practice, the codebase, or prior context points to one.
|
|
48
48
|
- Load the `canon:codebase-layout` skill before writing the `**Files to touch:**` entries when any of them names a file or folder that does not exist yet, and give each new path its placement reason in its entry. Skip the load when every entry edits an existing file. Report it rather than proceeding silently when the skill does not resolve.
|
|
49
|
+
- Write `**Verification:**` as one bullet per outcome naming the test or command that proves it, and `**Review focus:**` as the inputs or states that would break the change. You understood the risk before any diff existed, and these two sections carry it to the executing session and to the reviewer.
|
|
49
50
|
- Prefer `None identified.` over low-signal fillers. A small feature should produce a short plan, not a padded one.
|
|
50
51
|
- When three or more questions remain, keep chat output to the file pointer plus a short summary. Inline chat is fine when two or fewer remain.
|
|
51
52
|
|
|
@@ -76,8 +77,14 @@ Output the plan to chat. Do not write a plan file. The markers match the standar
|
|
|
76
77
|
**Files to touch:**
|
|
77
78
|
|
|
78
79
|
- `path/to/file`: reason
|
|
80
|
+
|
|
81
|
+
**Verification:**
|
|
82
|
+
|
|
83
|
+
- <outcome>: `<test or command that proves it>`
|
|
79
84
|
```
|
|
80
85
|
|
|
86
|
+
Small mode carries no `**Review focus:**`, since it already requires Risks to come out `None identified.` and a change with no risk leaves the reviewer no breaking input to name.
|
|
87
|
+
|
|
81
88
|
If real questions exist, include a numbered `**Questions:**` section below, each with a `- Suggested:` line and an `- Answer:` slot:
|
|
82
89
|
|
|
83
90
|
```markdown
|
|
@@ -94,7 +101,7 @@ Omit empty sections. Do not print `None identified.` in chat.
|
|
|
94
101
|
|
|
95
102
|
Derive a 2-to-4-word kebab-case slug from the feature description. Write the full plan to `.canon/plans/feature-<slug>.md` at the main worktree root, not the current worktree. Resolve that root the way `session-worktree` does. Create the directory if it does not exist.
|
|
96
103
|
|
|
97
|
-
|
|
104
|
+
The plan is a main-root write, from a linked worktree and from a background session sitting at the main root with none entered alike, so it goes out as a heredoc, routed the way `session-worktree` states.
|
|
98
105
|
|
|
99
106
|
The file follows the template in `${CLAUDE_SKILL_DIR}/../../standards/plan.md`. Copy the shape from there rather than from this body, so one edit to the standard moves every plan.
|
|
100
107
|
|
|
@@ -116,7 +116,7 @@ Derive `<slug>` per `${CLAUDE_SKILL_DIR}/../../standards/slug.md`. Fall back to
|
|
|
116
116
|
|
|
117
117
|
Write the full report directly to `.canon/review/branch-<slug>.md` at the main worktree root, not the current worktree. Resolve that root the way `session-worktree` does. Create the directory if it does not exist. Always overwrite.
|
|
118
118
|
|
|
119
|
-
|
|
119
|
+
The report is a main-root write, so it goes out as a heredoc, routed the way `session-worktree` states.
|
|
120
120
|
|
|
121
121
|
If there are no findings, write `✅ No findings.` to the file with a timestamp.
|
|
122
122
|
|
|
@@ -28,6 +28,7 @@ Scoping a later pass off GitHub's review stamp skipped real work. On 2026-09-07
|
|
|
28
28
|
- Key the body file on the pull request number and the head commit, and on the response it answers once the head repeats, so no two passes overwrite each other
|
|
29
29
|
- Scan the comment for banned characters and internal phase labels before posting, since a finding phrased against a phase label reaches a reader with no task board
|
|
30
30
|
- Answer a `## For the reviewer` bullet in the body, bounded to the section itself rather than the Summary or the Technical Context around it, so the independent vantage stays clear of the author's framing
|
|
31
|
+
- Confirm each `**Review focus:**` item the plan names on a first pass, and turn one the pass cannot confirm into a finding, since the planning session named the breaking inputs before the diff existed and no other reader holds that list
|
|
31
32
|
|
|
32
33
|
## Must not
|
|
33
34
|
|
|
@@ -47,7 +47,7 @@ Read these in parallel from the project root, skipping any that do not exist:
|
|
|
47
47
|
- `canon/REQUIREMENTS.md`: feature scope and non-goals
|
|
48
48
|
- `canon/ARCHITECTURE.md`: technical design decisions
|
|
49
49
|
- `.canon/tasks/priority.md`: where this feature sits on the board and what each neighboring row waits on. Resolve this one at the main worktree root the way `session-worktree` does, since the board is gitignored and a linked worktree holds no copy of it
|
|
50
|
-
- `.canon/plans/feature-<slug>.md` for the branch, when present: the intent the PR should satisfy
|
|
50
|
+
- `.canon/plans/feature-<slug>.md` for the branch, when present: the intent the PR should satisfy, and its `**Review focus:**` section as the inputs this pass must confirm the diff handles
|
|
51
51
|
|
|
52
52
|
Coding standards from `.claude/rules/` are auto-loaded by Claude Code.
|
|
53
53
|
|
|
@@ -157,6 +157,8 @@ Read `## For the reviewer` the same way, bounded to the bullets under that headi
|
|
|
157
157
|
|
|
158
158
|
Answer each bullet in the body, on the same terms as a Testing question: no severity, no count. A request nobody can answer stays owed under the heading and dispatch Step 4 states, keeping the thread open exactly as an unanswered Testing box does. One the pass does answer carries no further weight, since the answer is discharged in the same comment that carries it.
|
|
159
159
|
|
|
160
|
+
On a first pass, confirm each `**Review focus:**` item the plan names against the diff, since the planning session named the inputs that would break the change before any code existed and no other reader holds that list. Report the items in a `**Review focus**` block after the `**For the reviewer**` block, one bullet per item naming what confirmed it, such as a test, a guard, or a branch in the code. The block carries no severity and enters no count. An item the pass cannot confirm becomes a `should-fix` finding under the file that should have handled it, so a reader can tell an item checked from one skipped. A plan whose section reads `None identified.`, or a branch with no plan, takes no block. The section binds the first pass only: a later pass checks whether the finding an unconfirmed item became has landed, like any other prior finding, and never re-raises a confirmed item against a delta that did not touch it.
|
|
161
|
+
|
|
160
162
|
Apply the high-signal filter: flag only what will cause incorrect behavior, break a documented rule, or mislead a downstream feature. If uncertain, do not flag.
|
|
161
163
|
|
|
162
164
|
A later pass applies the same axes to the delta, and adds one check the first pass cannot make: did each prior finding land, and did the fix regress anything it touched. Findings of its own are normal findings, stated at the same severity and counted the same way. That count is one of the two things Step 4 reads to pick the heading, so a pass raising a finding of its own is not a close-out at any severity.
|
|
@@ -167,7 +169,7 @@ Use severity: `critical` (blocks merge), `should-fix` (fix before merge), `minor
|
|
|
167
169
|
|
|
168
170
|
## Step 4: post to the PR
|
|
169
171
|
|
|
170
|
-
Write the comment to `.canon/tmp/pr/review/body-<number>-<short-sha>.md` at the main worktree root, not the current worktree, which the rest of this step calls `<body-file>`. Resolve that root
|
|
172
|
+
Write the comment to `.canon/tmp/pr/review/body-<number>-<short-sha>.md` at the main worktree root, not the current worktree, which the rest of this step calls `<body-file>`. Resolve that root and send the write as a heredoc, both the way `session-worktree` states. The PR number stops two sessions reviewing different pull requests from overwriting each other between the write and the post, and the head commit stops a second pass overwriting the first one's body.
|
|
171
173
|
|
|
172
174
|
Derive both segments from Step 1. Never pick a suffix by hand, and never reuse a name the folder already holds.
|
|
173
175
|
|
|
@@ -30,7 +30,7 @@ produces.
|
|
|
30
30
|
- Write only into the folder the running skill names: `plan-feature` at `.canon/plans/`, `plan-groundwork` at `.canon/groundwork/<nn>-<slug>/`, and `plan-intake` at `.canon/intake/<nn>-<slug>/`. Each skill's own `## Write scope` carries its exceptions, which is why they are not listed here. A change to one scope then edits one body.
|
|
31
31
|
- Resolve every one of those folders, and `.canon/tasks/` and `.canon/review/` beside them, at the main worktree root. They are gitignored, so a copy beside a linked worktree is absent rather than empty and reads as a folder nobody has written yet.
|
|
32
32
|
- Never enter a worktree, never create a branch, and never write a tracked file. A thinking session that builds has stopped being one, and the row loses the independent read the worker's own session was going to bring to it.
|
|
33
|
-
- This session holds no worktree, so send each record out as a
|
|
33
|
+
- This session holds no worktree, so send each record out as a heredoc, the main-root route `session-worktree` states. That route skips the write-matched hooks, which are no-ops on a record file.
|
|
34
34
|
- Work the row the launch named. Report a second row met while reading rather than taking it on, since which rows run is the controller's call.
|
|
35
35
|
|
|
36
36
|
## What to read before deciding
|
|
@@ -28,7 +28,7 @@ The draft mark fails from both ends. On 2026-08-31 four sessions re-drafted a pu
|
|
|
28
28
|
- State the shared board as read-only for a building session and name what it does instead when a row is owed, since a worker cannot pick a free label without reading every task file and every archive entry
|
|
29
29
|
- Owe an announcement the moment the pull request opens, carrying the number, the branch, and the task, since that transition is the one interval only the worker can observe
|
|
30
30
|
- Owe a message before a block becomes an interactive prompt, since a session already waiting on input never reaches the tool round an inbound message drains at
|
|
31
|
-
-
|
|
31
|
+
- Defer the addressee resolution to `session-relay` and keep only the operator ask and the last-rung inference, which discriminates here because a worker holds a feature branch and a controller does not, and which falls back to the roster and says so, since an operator's own launch names nobody
|
|
32
32
|
- Keep refusing a dispatcher a first-class move carrying its evidence, since the halts measured so far were correct and the cost of each fell where it belonged
|
|
33
33
|
- State that a held body may be older than the branch under it, since a plugin skill loads from the marketplace cache rather than from the working tree
|
|
34
34
|
- Point at `session-worktree`, `auto-ship`, and `review-address` for the steps each already owns
|
|
@@ -44,24 +44,15 @@ and nothing else.
|
|
|
44
44
|
- 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 because of it.
|
|
45
45
|
- Carry the reach in that same message: 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`. The gate cleared this branch against a prediction it has since outgrown, so the controller holds a disjointness reading that stopped being true hours ago and nothing else tells it. Say the reach was unread rather than clear when the installed binary carries no such subcommand, and leave the undeclared list to the pull request.
|
|
46
46
|
- Announce when an address-review pass finishes, as `review-address` Step 8 returns, carrying what was addressed and the PR's new CI state. That transition is the other moment only this session knows, and it is what tells the controller to re-review rather than leaving it to poll for an answer nothing marks as landed.
|
|
47
|
-
- Send a block out as a message before it becomes an interactive prompt.
|
|
47
|
+
- Send a block out as a message before it becomes an interactive prompt.
|
|
48
48
|
- Send nothing on progress. A worker reporting progress rebuilds, on this side of the channel, the poll the announcement retired on the other.
|
|
49
49
|
|
|
50
|
-
Address the session the launch named
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
Check that name against the agent listing before sending it. A name is not
|
|
57
|
-
unique, and the roster carries no field that separates two live sessions holding
|
|
58
|
-
one, so the resolution can end on a string that reaches the wrong session. Send
|
|
59
|
-
the name bare where the listing shows one row under it. Where it shows more than
|
|
60
|
-
one, complete the address with the `[ref]` that listing prints beside each row
|
|
61
|
-
rather than sending to the name alone, which lands on whichever row the channel
|
|
62
|
-
resolves first. Two sessions differing only by a trailing ` (3)` is the shape
|
|
63
|
-
this meets in practice, and one of them being a controller is what makes the
|
|
64
|
-
wrong pick silent.
|
|
50
|
+
Address the session the launch named, which it names as a `sessionId` rather
|
|
51
|
+
than a name. `canon:session-relay` turns that id into an address and carries the
|
|
52
|
+
send, so invoke it rather than resolving a name here. It reads the roster at the
|
|
53
|
+
moment of sending, checks the result against the agent listing, and falls back
|
|
54
|
+
to a copyable block where this session holds no tool to send through. The
|
|
55
|
+
message owed stays in its own bullet above.
|
|
65
56
|
|
|
66
57
|
Ask the operator when the launch named nobody and a person is there to answer.
|
|
67
58
|
Put the candidate rows to them through the structured question surface, so they
|
|
@@ -76,31 +67,9 @@ looks.
|
|
|
76
67
|
Infer only where no operator is present. Read `canon sessions list --json` and
|
|
77
68
|
take the sessions holding no feature branch as the candidates, since a
|
|
78
69
|
controlling session holds none. Say the addressee was inferred so the reader can
|
|
79
|
-
correct it.
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
somewhere else.
|
|
83
|
-
|
|
84
|
-
Report a resolution that returns nothing rather than falling back to a guess.
|
|
85
|
-
The roster and the send channel enumerate different populations in both
|
|
86
|
-
directions, measured at one moment: a live background session sat on the roster
|
|
87
|
-
that the agent listing did not carry, and nine sessions were addressable there
|
|
88
|
-
with no roster row at all. Those nine were driving through Remote Control, which
|
|
89
|
-
writes no local process record, so a controller working from a phone is exactly
|
|
90
|
-
the case this read answers nothing for.
|
|
91
|
-
|
|
92
|
-
Send through `canon:session-relay`. It holds the mechanical half of the send,
|
|
93
|
-
turning the `sessionId` the launch named into an address at the moment of
|
|
94
|
-
sending, checking the result against the agent listing, and falling back to a
|
|
95
|
-
copyable block where this session holds no tool to send through. The message
|
|
96
|
-
owed stays in its own bullet above.
|
|
97
|
-
|
|
98
|
-
The rungs above restate the resolution the relay also carries. What is a
|
|
99
|
-
worker's own is the last of them, the inference over sessions holding no feature
|
|
100
|
-
branch, which discriminates here because a worker holds one and a controller
|
|
101
|
-
does not. The rest is duplicated deliberately, so this body still reads whole
|
|
102
|
-
for a session that reaches it with the relay unresolved, which is the ordinary
|
|
103
|
-
case in a target that installed governance without the plugin.
|
|
70
|
+
correct it. This rung stays here rather than in the relay because it differs
|
|
71
|
+
between roles, and it discriminates for a worker because a worker holds a
|
|
72
|
+
feature branch and a controller does not.
|
|
104
73
|
|
|
105
74
|
## Refusing is part of the job
|
|
106
75
|
|
|
@@ -70,7 +70,7 @@ Derive `<slug>` per `${CLAUDE_SKILL_DIR}/../../standards/slug.md`. Fall back to
|
|
|
70
70
|
|
|
71
71
|
Write the full proposal to `.canon/review/seed-audit-<slug>.md` at the main worktree root. Do not print the proposal inline.
|
|
72
72
|
|
|
73
|
-
|
|
73
|
+
The proposal is a main-root write, so it goes out as a heredoc, routed the way `session-worktree` states.
|
|
74
74
|
|
|
75
75
|
Structure: a summary block at the top, a legend, a scope table, then one H2 per numbered item. Number items across all files so the user can reference them by number. Fuse the status, action, and target into each H2. Every item starts as 📝 pending.
|
|
76
76
|
|
|
@@ -13,7 +13,7 @@ Write only what a compaction destroys. Everything a later session can read from
|
|
|
13
13
|
|
|
14
14
|
- If `git rev-parse --git-dir` does not resolve, the note still writes. The filename comes from the work rather than from the branch, so nothing here needs a repository.
|
|
15
15
|
- Decline where the session holds no reasoning a reader could not get faster from git or from a record already written. Say so in one line and write nothing. A padded note is worse than an absent one, because a reader who finds a note trusts it.
|
|
16
|
-
- Resolve `.canon/` at the main worktree root
|
|
16
|
+
- Resolve `.canon/` at the main worktree root and send the write out as a heredoc, both the way `session-worktree` states.
|
|
17
17
|
|
|
18
18
|
## Step 1: capture memory
|
|
19
19
|
|
|
@@ -47,7 +47,7 @@ Record what the verb names under `## Standing cautions`. A refusal is the bounda
|
|
|
47
47
|
|
|
48
48
|
Follow items 4 through 6. Write only what a compaction destroys and no other artifact already carries, and cite a commit, a task, or a file and line for every claim.
|
|
49
49
|
|
|
50
|
-
The file sits at the main worktree root
|
|
50
|
+
The file sits at the main worktree root and is written whole every time, so send it out as a heredoc, routed the way `session-worktree` states.
|
|
51
51
|
|
|
52
52
|
## Step 4: extend it only where a role is held
|
|
53
53
|
|
|
@@ -39,6 +39,12 @@ role and a send tool was refused too, which left the resolution ladder
|
|
|
39
39
|
duplicated in both role bodies for the ordinary case. Both guards came off
|
|
40
40
|
together, since the mechanics are the same whichever route carries the text.
|
|
41
41
|
|
|
42
|
+
No governance rule carries the addressing or the reason for the order, so this
|
|
43
|
+
body is the only surface stating either for a session holding neither role. A
|
|
44
|
+
project that installs governance without the plugin therefore gets no surface
|
|
45
|
+
telling a roleless session to send before it prompts, a cost the operator
|
|
46
|
+
accepted over a rule loading into every session of every governed target.
|
|
47
|
+
|
|
42
48
|
## Must
|
|
43
49
|
|
|
44
50
|
- Fire for any session sending to another session, with or without a role and with or without a message-sending tool
|
|
@@ -46,7 +52,7 @@ together, since the mechanics are the same whichever route carries the text.
|
|
|
46
52
|
- Resolve the addressee from a `sessionId` or a branch at the moment of sending, never by a name prefix
|
|
47
53
|
- Check the resolved name against the agent listing, sending it bare under a single row and completing it with the `[ref]` under more than one
|
|
48
54
|
- Send through a message-sending tool where one exists, and compose the copyable block where none does or where the listing carries no row to address
|
|
49
|
-
- State block
|
|
55
|
+
- State why a block goes out before a prompt as the only surface carrying that reason, since no rule carries it and a caller restating the reason drifts from this body with nothing comparing them, while each caller still states that the message is owed
|
|
50
56
|
- Carry the message body verbatim from whatever names it
|
|
51
57
|
- Open the composed text with a header naming the sender, the addressee, and what the message is
|
|
52
58
|
- State the header as a default a session may write around, rather than a fixed vocabulary
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: session-relay
|
|
3
|
-
description: Relays a message to another session, turning the sessionId the caller named into an address at the moment of sending and composing a copyable block where no send tool exists. Use when asked to "relay this", "message the controller", "send this over to the session that dispatched me", or "tell the other session", with or without a role. Do NOT use to decide what the message says, and do NOT use to assert what a session may write or is on the hook for, which is `role-worker` or `role-planner`.
|
|
3
|
+
description: Relays a message to another session, turning the sessionId the caller named into an address at the moment of sending and composing a copyable block where no send tool exists. Use when asked to "relay this", "message the controller", "send this over to the session that dispatched me", or "tell the other session", with or without a role, and when a session stuck on a question owes the session that dispatched it a message before it stops to ask. Do NOT use to decide what the message says, and do NOT use to assert what a session may write or is on the hook for, which is `role-worker` or `role-planner`.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Session relay
|
|
@@ -14,7 +14,9 @@ own `## The channel` section where the session holds a role.
|
|
|
14
14
|
|
|
15
15
|
It fires for a session holding a role and for one holding none. A roleless
|
|
16
16
|
session reaches this body directly and finds everything it owes stated here,
|
|
17
|
-
rather than reading a ladder written for a role it does not have.
|
|
17
|
+
rather than reading a ladder written for a role it does not have. This body
|
|
18
|
+
alone holds the send mechanics and the reason a block goes out before a prompt.
|
|
19
|
+
A calling role or dispatch states only that the message is owed.
|
|
18
20
|
|
|
19
21
|
## Step 1: name the sender
|
|
20
22
|
|
|
@@ -78,11 +80,6 @@ session already waiting on input never reaches the tool round that drains an
|
|
|
78
80
|
inbound message, so an answer relayed afterwards arrives under the open question
|
|
79
81
|
and changes nothing. This holds on both routes.
|
|
80
82
|
|
|
81
|
-
The shipped channel rule states the same thing for a session holding neither
|
|
82
|
-
role, so the restatement here is for the target that installed the plugin and
|
|
83
|
-
not governance, where that rule never arrives. A session that does load it reads
|
|
84
|
-
the rule and this body in agreement rather than one of them alone.
|
|
85
|
-
|
|
86
83
|
Carry the message body verbatim from whatever names it. This skill composes and
|
|
87
84
|
never drafts, so a pull request announcement, an address-review announcement, or
|
|
88
85
|
a blocked question is exactly the text the calling bullet or the dispatch
|
|
@@ -19,6 +19,8 @@ A submodule checkout is the state the entry path reads wrong while reporting not
|
|
|
19
19
|
|
|
20
20
|
A stack that derives its ports from the working directory has the same shape. The number is correct and invisible, and `role-orchestrator` sends a reader here to read it rather than assign one, so the entry that knows the working directory is the surface that owes it.
|
|
21
21
|
|
|
22
|
+
A session writing to the main root meets a refusal from inside a linked worktree, and from a background session that entered none. The refusal points at a worktree copy that reports success and that no later session reads, and every skill body writing there carried its own copy of the route around it, which had begun to disagree. The skill that resolves the main root is the one surface every one of those bodies can name, so it owes the routing once.
|
|
23
|
+
|
|
22
24
|
## Must
|
|
23
25
|
|
|
24
26
|
- Derive the name from the plan matched to the current branch, falling through the ordered sources rather than picking
|
|
@@ -33,6 +35,7 @@ A stack that derives its ports from the working directory has the same shape. Th
|
|
|
33
35
|
- Report the same way when the project declares no package manifest, since silence there reads as a passing check
|
|
34
36
|
- Report the port offset this worktree derives, and say so when the project installs no derivation
|
|
35
37
|
- Name `git-worktree` where the description declines a list, cleanup, or rotation request, matching the pointer that skill already carries back
|
|
38
|
+
- State the route each kind of main-root write takes, being a heredoc for a whole-file create, a `canon` verb for a change inside an existing file, and a plain `rm` or `mv` for a delete or a move, along with the index cost a shell write carries
|
|
36
39
|
|
|
37
40
|
## Must not
|
|
38
41
|
|
|
@@ -42,6 +45,7 @@ A stack that derives its ports from the working directory has the same shape. Th
|
|
|
42
45
|
- Delete or overwrite a branch or a worktree directory that already carries the target name
|
|
43
46
|
- Rename when the worktree was entered by path, since that branch already has its own identity
|
|
44
47
|
- Invoke the exit path, which is the user's call
|
|
48
|
+
- Enter a worktree or run a guard for a session that loaded the skill to route a main-root write
|
|
45
49
|
|
|
46
50
|
## Guards
|
|
47
51
|
|
|
@@ -55,4 +59,4 @@ A stack that derives its ports from the working directory has the same shape. Th
|
|
|
55
59
|
|
|
56
60
|
- Listing, cleaning up, or rotating worktrees, which `git-worktree` owns and the description names, since this file routes no session
|
|
57
61
|
- Leaving a worktree, which the user decides
|
|
58
|
-
- What runs inside the worktree once entered, which the caller drives
|
|
62
|
+
- What runs inside the worktree once entered, which the caller drives, apart from the route a main-root write takes
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: session-worktree
|
|
3
|
-
description: Enters a Claude Code worktree at `.claude/worktrees/<name>/` with a name derived from the active plan or branch. Use when asked to "enter a worktree", "start a worktree", "work in a worktree", or at the plan-to-execute boundary after `/plan-feature`. Do NOT use to list, clean up, or rotate worktrees (use `git-worktree`).
|
|
3
|
+
description: Enters a Claude Code worktree at `.claude/worktrees/<name>/` with a name derived from the active plan or branch. Use when asked to "enter a worktree", "start a worktree", "work in a worktree", or at the plan-to-execute boundary after `/plan-feature`. Also use when an `Edit` or `Write` to a main-root file such as a plan, a task, or a memory entry was refused for session isolation. Do NOT use to list, clean up, or rotate worktrees (use `git-worktree`).
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Session worktree
|
|
7
7
|
|
|
8
8
|
Wrap the `EnterWorktree` entry path with name derivation so the user does not pick a name by hand.
|
|
9
9
|
|
|
10
|
+
The Guards and Steps gate entry alone. A session loading this skill for a main-root write reads `## Main-root writes`, enters nothing, and runs no guard, which is what keeps a session already inside a linked worktree off the first guard's stop.
|
|
11
|
+
|
|
10
12
|
## Guards
|
|
11
13
|
|
|
12
14
|
- If `git rev-parse --git-dir` and `git rev-parse --git-common-dir` differ, the session is already inside a linked worktree. Stop: `❌ Already in a worktree. Run ExitWorktree first.`
|
|
@@ -156,3 +158,7 @@ The helper refuses a folder left behind after its worktree was removed, which St
|
|
|
156
158
|
The offset is what `role-orchestrator` sends a reader here to read rather than assign, and what an operator overrides through `WORKTREE_PORT_OFFSET` when two worktrees derive the same value. Deriving it correctly and printing it nowhere leaves both instructions naming a number no surface emits.
|
|
157
159
|
|
|
158
160
|
Do not invoke `ExitWorktree` from this skill. Exit is the user's call.
|
|
161
|
+
|
|
162
|
+
## Main-root writes
|
|
163
|
+
|
|
164
|
+
Route a main-root write by what it does to the file: a whole-file create goes out as a heredoc, a change inside an existing file goes through a `canon` verb, and a delete or a move runs as a plain `rm` or `mv`. Read `${CLAUDE_SKILL_DIR}/references/main-root-writes.md` for which tools the refusal covers, the mechanics of each route, and the index cost a shell write carries.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Main-root write routing
|
|
3
|
+
description: Which tools the isolation refusal covers, the route each kind of main-root write takes, the fallback when a heredoc is refused, and the index cost a shell write carries
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Shared session scratch, being `.canon/plans/`, `.canon/review/`, `.canon/memory/`, and `.canon/tasks/`, lives at the main worktree root. Resolve that root with the first `worktree` entry of `git worktree list --porcelain`, falling back to `pwd` outside a git repository.
|
|
7
|
+
|
|
8
|
+
## The refusal
|
|
9
|
+
|
|
10
|
+
- The refusal is tool-scoped rather than path-scoped. `Edit` and `Write` are refused for every main-root path, `Read` resolves there normally, and `Bash` writes there.
|
|
11
|
+
- A background session that entered no worktree at all meets the identical refusal writing to the main root, since the guard gates on isolation rather than on sitting inside a linked worktree.
|
|
12
|
+
- The refusal names session isolation and points at a worktree copy. That copy is a second gitignored file no later session reads, so never take the redirect. The redirected write reports success, which is how a file gets lost with nothing saying so.
|
|
13
|
+
|
|
14
|
+
## Route by what the write does to the file
|
|
15
|
+
|
|
16
|
+
- A whole-file create goes out as one plain `Bash` command carrying a heredoc. Send `mkdir -p` for a missing folder as its own command first, since a `&&` compound is refused for complexity.
|
|
17
|
+
- When the heredoc itself is refused, which can happen on a body quoting shell syntax, a session inside a linked worktree can `Write` the file there and copy it out with a two-argument `cp` to the main-root path. The copy carries no syntax to inspect.
|
|
18
|
+
- A background session that entered no worktree has nothing to `Write` into, so it sends a short file as one `printf '%s\n'` command carrying each line as an argument. When the file is too long for that, it reports the refusal rather than taking the redirect.
|
|
19
|
+
- A change inside a file that already exists goes through a `canon` verb that resolves the main root in-process, such as `canon tasks outcome` or `canon tasks pull-request`. Where no verb covers the edit, read the whole file and write it back whole through the heredoc route. Never reach for a stream editor, which rewrites the line it anchored to and exits zero on a non-match.
|
|
20
|
+
- A delete or a move runs as one plain `rm` or `mv` per call rather than chained.
|
|
21
|
+
|
|
22
|
+
## The index cost
|
|
23
|
+
|
|
24
|
+
A shell write skips every `PostToolUse` hook, since those match `Write|Edit|MultiEdit` and never fire on `Bash`. That costs nothing on `.canon/plans/` and `.canon/review/`, which no hook indexes, and costs the generated `index.md` on `.canon/tasks/` and `.canon/memory/`. Regenerate positionally after a shell write there, by an explicit `canon indexes regen` call, unless the verb that made the write already calls it, as `canon tasks archive` does.
|
|
@@ -39,7 +39,7 @@ Routes by finding. `unmigrated` routes to a relocation the user runs, since no c
|
|
|
39
39
|
|
|
40
40
|
Read `domains` off the report and take every entry it carries rather than naming governance here. Each entry carries `stamped`, per-state `counts`, and `entries` with a `state` and a `rel` path.
|
|
41
41
|
|
|
42
|
-
The states are `matching`, `stale`, `customized`, `drifted`, `orphaned`, `stranded`, and `missing`.
|
|
42
|
+
The states are `matching`, `stale`, `customized`, `drifted`, `orphaned`, `retired`, `stranded`, and `missing`. A `retired` rule is one the toolkit no longer ships, and the next sync deletes it.
|
|
43
43
|
|
|
44
44
|
- Current: every count but `matching` reads zero.
|
|
45
45
|
- Behind: any other count is non-zero. Report the counts and name the paths behind `stale` and `missing`, which a sync repairs, separately from `customized` and `drifted`, which the project wrote and a sync would overwrite.
|