@erclx/canon 4.121.0 → 4.122.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/claude/.claude-plugin/plugin.json +1 -1
- package/claude/skills/auto-ship/SKILL.md +1 -1
- package/claude/skills/backlog-triage/REQUIREMENT.md +47 -0
- package/claude/skills/backlog-triage/SKILL.md +139 -0
- package/claude/skills/canon-rollout/SKILL.md +6 -6
- package/claude/skills/context-fold/REQUIREMENT.md +75 -0
- package/claude/skills/context-fold/SKILL.md +162 -0
- package/claude/skills/{docs-fold → context-fold}/references/anchor-sweep.md +1 -1
- package/claude/skills/{docs-fold → context-fold}/references/classify.md +4 -2
- package/claude/skills/context-fold/references/context-refresh.md +48 -0
- package/claude/skills/context-fold/references/promoted-pages.md +29 -0
- package/claude/skills/context-fold/references/receipt-sweep.md +43 -0
- package/claude/skills/context-fold/references/unusable-baseline.md +25 -0
- package/claude/skills/{docs-fold → context-fold}/references/wireframe-sweep.md +1 -1
- package/claude/skills/docs-fold/REQUIREMENT.md +8 -58
- package/claude/skills/docs-fold/SKILL.md +3 -278
- package/claude/skills/docs-sync/REQUIREMENT.md +1 -1
- package/claude/skills/docs-sync/SKILL.md +1 -1
- package/claude/skills/draft-context/REQUIREMENT.md +2 -2
- package/claude/skills/draft-context/SKILL.md +3 -3
- package/claude/skills/draft-docs/REQUIREMENT.md +1 -1
- package/claude/skills/draft-wireframes/REQUIREMENT.md +1 -1
- package/claude/skills/draft-wireframes/SKILL.md +2 -2
- package/claude/skills/git-pr/SKILL.md +8 -146
- package/claude/skills/git-pr/references/evidence.md +114 -0
- package/claude/skills/git-pr/references/labels.md +20 -0
- package/claude/skills/git-pr/references/task-number.md +26 -0
- package/claude/skills/git-ship/SKILL.md +1 -1
- package/claude/skills/memory-capture/REQUIREMENT.md +2 -2
- package/claude/skills/memory-capture/SKILL.md +5 -5
- package/claude/skills/memory-review/REQUIREMENT.md +1 -1
- package/claude/skills/memory-review/SKILL.md +5 -101
- package/claude/skills/memory-review/references/later-phases.md +108 -0
- package/claude/skills/plan-feature/REQUIREMENT.md +1 -1
- package/claude/skills/review-address/REQUIREMENT.md +1 -1
- package/claude/skills/review-address/SKILL.md +1 -1
- package/claude/skills/review-branch/SKILL.md +1 -1
- package/claude/skills/role-orchestrator/references/orchestrator-dispatch.md +1 -1
- package/claude/skills/role-orchestrator/references/orchestrator-parked.md +2 -0
- package/claude/skills/role-orchestrator/references/orchestrator-refill.md +2 -2
- package/claude/skills/session-resume/REQUIREMENT.md +1 -1
- package/claude/skills/session-worktree/SKILL.md +4 -10
- package/claude/skills/task-board/REQUIREMENT.md +1 -1
- package/claude/skills/task-board/SKILL.md +6 -80
- package/claude/skills/task-board/references/archive.md +54 -0
- package/claude/skills/task-board/references/decline.md +40 -0
- package/claude/skills/teach-workspace/SKILL.md +8 -105
- package/claude/skills/teach-workspace/references/lesson-craft.md +51 -1
- package/claude/skills/teach-workspace/references/promotion.md +41 -0
- package/docs/agents/architecture-record.md +26 -0
- package/docs/agents/commands.md +87 -154
- package/docs/agents/context-audit-checks.md +2 -20
- package/docs/agents/context-audit.md +1 -1
- package/docs/agents/context-classify.md +1 -1
- package/docs/agents/drift-surfaces.md +192 -0
- package/docs/agents/index.md +12 -4
- package/docs/agents/install-and-sync.md +2 -181
- package/docs/agents/markdown-audit-weight.md +73 -0
- package/docs/agents/markdown-audit.md +3 -90
- package/docs/agents/migrate.md +34 -0
- package/docs/agents/records-stale.md +62 -0
- package/docs/agents/records.md +5 -1
- package/docs/agents/sandbox.md +1 -1
- package/docs/agents/tasks-archive.md +81 -0
- package/docs/agents/tasks-plans.md +147 -0
- package/docs/agents/tasks-validate.md +131 -0
- package/docs/agents/tasks.md +6 -333
- package/docs/target-projects.md +3 -3
- package/docs/workflow/ai-workflow.md +32 -27
- package/governance/rules/core/045-memory.md +1 -1
- package/package.json +1 -1
- package/src/claude/cases/setup.ts +1 -1
- package/src/claude/cases/workflow.ts +22 -1
- package/src/commands/records.ts +146 -0
- package/src/commands/sandbox.ts +6 -4
- package/src/context/classify/extract.ts +1 -1
- package/src/context/classify/ollama.ts +1 -1
- package/src/context/classify/run.ts +1 -1
- package/src/gate/measures.ts +1 -1
- package/src/migrate/skill-names.ts +15 -2
- package/src/records/stale.ts +243 -0
- package/src/sandbox/expect.ts +1 -1
- package/src/tasks/archive.ts +28 -4
- package/src/tasks/record.ts +1 -1
- package/src/tasks/validate.ts +36 -3
- package/standards/memory.md +13 -1
- package/standards/tasks.md +1 -1
- package/tooling/astro/reference.md +1 -1
- package/tooling/base/configs/.husky/post-merge +1 -1
- package/tooling/claude/reference.md +1 -1
- package/tooling/go/reference.md +1 -1
- package/tooling/nextjs/reference.md +1 -1
- package/tooling/php/reference.md +1 -1
- package/tooling/python/reference.md +1 -1
- package/tooling/vite-react/reference.md +1 -1
- package/tooling/web/reference.md +1 -1
|
@@ -58,7 +58,7 @@ Read in parallel from the project root. Skip any file or folder that does not ex
|
|
|
58
58
|
|
|
59
59
|
`.canon/memory/` is a holding pen. Default every entry to promote or retire on review. Skip is the rare exception, reserved for active task overlap or user-type memories with no in-repo target.
|
|
60
60
|
|
|
61
|
-
`memory-capture` routes a project fact naming a domain with a context entry to that entry, so a pen filled since routing shipped is mostly feedback: rules about how to work, which no context entry owns. Propose against what the pen holds rather than expecting the older mix. An entry carried from before routing may still name a domain that has a context entry, and that entry's action is **Promote to a context entry**, which hands it to `
|
|
61
|
+
`memory-capture` routes a project fact naming a domain with a context entry to that entry, so a pen filled since routing shipped is mostly feedback: rules about how to work, which no context entry owns. Propose against what the pen holds rather than expecting the older mix. An entry carried from before routing may still name a domain that has a context entry, and that entry's action is **Promote to a context entry**, which hands it to `context-fold` the same way capture does rather than editing the entry here.
|
|
62
62
|
|
|
63
63
|
For each in-scope entry (see Scope), pick one action:
|
|
64
64
|
|
|
@@ -67,7 +67,7 @@ For each in-scope entry (see Scope), pick one action:
|
|
|
67
67
|
- In a target project, append the rule to an existing file under `.claude/rules/project/` with `Edit`, since a project rule is project-owned and sync never overwrites it, or hand off to the `create-rule` skill when no existing file fits.
|
|
68
68
|
- **Promote to a skill body**: the rule fires only when editing a specific path-scoped domain. Name the target skill.
|
|
69
69
|
- **Promote to a standards file**: the rule is an authoring reference that belongs in the project's own standards folder as `<domain>.md`.
|
|
70
|
-
- **Promote to a context entry**: the entry states a fact about a domain carrying an entry in `canon/context/index.md`. Append it to `.canon/tmp/handoff/memory-routing/<slug>.md` at the main worktree root, in the format `memory-capture` writes, and tell the user to run `/
|
|
70
|
+
- **Promote to a context entry**: the entry states a fact about a domain carrying an entry in `canon/context/index.md`. Append it to `.canon/tmp/handoff/memory-routing/<slug>.md` at the main worktree root, in the format `memory-capture` writes, and tell the user to run `/context-fold` from a branch. Do not edit the context entry here. A project-identity or command fact takes this action when a context entry owns the subject, such as a development entry for commands, and **Retire** otherwise, naming a hand edit to `CLAUDE.md` as the reason. Memory review does not write the root file itself.
|
|
71
71
|
- **Hand off to governance**: the rule is coding-standards class (typescript, testing, naming, error-handling, performance, logging, concurrency, planning), never a cross-domain behavior rule. Do not author the rule file inline. Never edit the synced `.claude/rules/` copies of toolkit rules, because `canon gov sync` overwrites them. Stop at handoff. This and **Promote to an always-loaded rule** never both claim one entry: class names the topic (coding-standards routes here), firing axis names the rest (applies-every-session routes to the rule promote).
|
|
72
72
|
- In the toolkit repo, point the user at `internal-governance` and `${CLAUDE_SKILL_DIR}/../../standards/rule.md`, which own the source-of-truth rules under `governance/rules/`.
|
|
73
73
|
- In a target project, point the user at the `create-rule` skill, which scaffolds a project-local rule under `.claude/rules/`.
|
|
@@ -91,7 +91,7 @@ Rules that resist crisp one-line phrasing default to **Retire** over promote. Ne
|
|
|
91
91
|
|
|
92
92
|
Derive `<slug>` per `${CLAUDE_SKILL_DIR}/../../standards/slug.md`. Fall back to `latest` on an empty result.
|
|
93
93
|
|
|
94
|
-
Write the full proposal to `.canon/memory/review/memory-review-<slug>.md` at the main worktree root. Do not print it inline. Read `${CLAUDE_SKILL_DIR}/references/receipt-format.md` for the file structure, the item template, and how each action type varies the body. The four phases
|
|
94
|
+
Write the full proposal to `.canon/memory/review/memory-review-<slug>.md` at the main worktree root. Do not print it inline. Read `${CLAUDE_SKILL_DIR}/references/receipt-format.md` for the file structure, the item template, and how each action type varies the body. The four later phases rewrite items inside an existing receipt rather than authoring one, so none of them opens it.
|
|
95
95
|
|
|
96
96
|
A phase changing items reads the receipt, applies every change for that phase, and writes the whole file back in one command. Batching is what keeps a per-item rewrite from costing a full read each time, and it is the only route from a linked worktree, where the guard above rules out editing a line in place.
|
|
97
97
|
|
|
@@ -99,105 +99,9 @@ Tell the user `✅ Wrote proposal to .canon/memory/review/memory-review-<slug>.m
|
|
|
99
99
|
|
|
100
100
|
Rewrite the review file in place whenever the proposal changes mid-review. The file stays the source of truth for the current decisions.
|
|
101
101
|
|
|
102
|
-
## Challenge
|
|
102
|
+
## Challenge, Discuss, Apply, and Cleanup phases
|
|
103
103
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
1. Read the latest `.canon/memory/review/memory-review-*.md` at the main root.
|
|
107
|
-
2. For each promote item, apply three tests:
|
|
108
|
-
- **Absorbed**: grep the target surface for the rule's keywords. If already stated or implied, flip to retire.
|
|
109
|
-
- **Delta**: if the rule is a nice-to-have next to existing bullets, flip to retire.
|
|
110
|
-
- **Generality**: if the rule fires only on one literal trigger phrase, rewrite broader or flip to retire.
|
|
111
|
-
3. Rewrite the review file in place with the updated actions and a one-line reason under each flip.
|
|
112
|
-
|
|
113
|
-
## Discuss phase
|
|
114
|
-
|
|
115
|
-
Trigger: user says "discuss", "respond to questions", or any `Decision:` value contains `?` or an unrecognized verb. No mutations to memory files or targets. Review file only. Multi-round.
|
|
116
|
-
|
|
117
|
-
1. Read the latest `.canon/memory/review/memory-review-*.md` at the main root.
|
|
118
|
-
2. For each item whose `Decision:` contains `?` or any unrecognized verb (anything other than `apply`, `skip`, `defer`):
|
|
119
|
-
- Write a `Take:` line under `Decision:`, separated by exactly one blank line. If a `Take:` line already exists, overwrite it.
|
|
120
|
-
- Format: pick + one-line reason. Max 2 sentences. Decision-help style. State the recommendation (`apply` / `skip` / `retire` / specific alternative) first, then the reason. Do not enumerate tradeoffs unless one changes the call.
|
|
121
|
-
- Leave the H2 emoji as 📝 pending.
|
|
122
|
-
3. Skip items whose `Decision:` is `apply`, `skip`, `defer`, or empty.
|
|
123
|
-
4. End with: `💬 Discussed: <nums> | ⏩ Skipped (committed or empty): <nums>`. Remind the user to refine `Decision:` lines and re-ping with "discuss" for another round, or "apply" when ready to commit.
|
|
124
|
-
|
|
125
|
-
Do not act on any item. Do not archive memory files. Do not edit promotion targets. Discuss only.
|
|
126
|
-
|
|
127
|
-
## Apply phase
|
|
128
|
-
|
|
129
|
-
Trigger: user says "apply", "commit", "ship the review", or re-pings with no question items remaining. Mutates tracked promotion targets and moves memory files into the archive.
|
|
130
|
-
|
|
131
|
-
Before applying any item, check the worktree state:
|
|
132
|
-
|
|
133
|
-
```bash
|
|
134
|
-
[ "$(git rev-parse --git-dir 2>/dev/null)" = "$(git rev-parse --git-common-dir 2>/dev/null)" ] && echo "MAIN" || echo "LINKED"
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
If the result is `MAIN`, stop and tell the user: `❌ Apply phase mutates tracked files. Run /session-worktree first.` Discuss and Challenge phases only touch `.canon/review/` scratch and run from anywhere.
|
|
138
|
-
|
|
139
|
-
Before applying a promote to an always-loaded rule in the toolkit repo, load `internal-governance`, which owns `internal/rules/core/` and `governance/rules/core/` and is the only route that may author into either. In a target project, hand off to `create-rule` with no load, since `internal-governance` is a toolkit-internal skill under `.claude/skills/` that a target project never has. An `Edit` appending to an existing file under `.claude/rules/project/` needs no load either.
|
|
140
|
-
|
|
141
|
-
Promotions are a separate concern from any feature in flight. Keep the promoted edits on their own commit. Do not fold an always-loaded-rule or skill-body change into a feature's commits, because a feature reviewer should not have to vet a change to how the agent operates.
|
|
142
|
-
|
|
143
|
-
For each item, parse the `Decision:` line:
|
|
144
|
-
|
|
145
|
-
- `apply` (or affirmative): run the proposed action, flip emoji to ✅.
|
|
146
|
-
- `skip`: leave the memory in place, flip emoji to ⏭.
|
|
147
|
-
- `defer` or empty: leave 📝 pending, take no action.
|
|
148
|
-
- Contains `?` or unrecognized verb: leave 📝 pending, take no action. Do not respond. Discussion is the Discuss phase's job.
|
|
149
|
-
|
|
150
|
-
Free-form text after the verb is a reason. Capture it in the receipt but do not let it change the action. When committing an item, strip any empty `Take:` line so the receipt stays clean. `Take:` lines with content stay as discussion history.
|
|
151
|
-
|
|
152
|
-
Action by action type:
|
|
153
|
-
|
|
154
|
-
- **Promote**: use `Edit` to insert the rewritten rule into the target surface, then archive the memory file. A promote to an always-loaded rule in the toolkit repo never reaches this line: it stops as a handoff to `internal-governance`, the same as **Hand off** below, and archives only on the user's explicit confirmation.
|
|
155
|
-
- **Promote to a context entry**: append the fact to `.canon/tmp/handoff/memory-routing/<slug>.md` at the main worktree root, then archive the memory file. `docs-fold` folds it in on its next run from a branch, which is what keeps one skill writing context entries.
|
|
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
|
-
- **Retire**: archive the memory file.
|
|
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 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
|
-
|
|
161
|
-
Do not hand-edit `.canon/memory/index.md`. Once every archive move is done, regenerate it instead:
|
|
162
|
-
|
|
163
|
-
```bash
|
|
164
|
-
canon indexes regen --no-stage --root <main-root> <main-root>/.canon/memory/index.md
|
|
165
|
-
```
|
|
166
|
-
|
|
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
|
-
|
|
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
|
-
|
|
171
|
-
This governs the tracked surfaces a promote lands in, which sit at `pwd` and take `Edit` from anywhere. The receipt and the memory entries are main-root scratch and follow the guard instead.
|
|
172
|
-
|
|
173
|
-
As each item resolves, update its status in the review file: flip the H2 emoji from 📝 to ✅ for applied, ⏭ for skipped, 📦 for retired, or 🤝 for handed off. Refresh the summary block counts at the top. Do not delete the file here. The sweep below decides whether it goes.
|
|
174
|
-
|
|
175
|
-
**Chat shortcut:** the user replies with `all`, `none`, a comma-separated list of numbers, or `skip <nums>`. Write the matching verb into the `Decision:` slot of every item the reply names, `apply` for `all` or a bare list and `skip` for a `skip` reply, then run the parse above against the file. A reply of `none` writes nothing. A slot the reply does not name keeps its own value, so the receipt stays the source of truth and an empty slot still means take no action.
|
|
176
|
-
|
|
177
|
-
### Sweep the receipt
|
|
178
|
-
|
|
179
|
-
Count the items still pending once the parse above has run. An item is pending when its H2 carries 📝, or when its H2 carries no status emoji and its `Decision:` slot holds nothing the parse above would act on or skip, since a receipt written by hand or by an older binary may lack the marker. Apply leaves one pending on `defer`, on empty, and on any unrecognized verb, so a receipt reaching this point may still be holding decisions.
|
|
180
|
-
|
|
181
|
-
Leave the receipt in place when any remain. When none do, collect it per the collection rule in `${CLAUDE_SKILL_DIR}/../../standards/memory.md`, which owns what a fold writes and which entry types take one.
|
|
182
|
-
|
|
183
|
-
`docs-fold` Step 9 sweeps the same folder on the same rule once per shipped branch, and either may reach a receipt first. Whichever does, the other finds no file and moves on.
|
|
184
|
-
|
|
185
|
-
End with: `✅ Applied: <nums> | ⏭ Skipped: <nums> | 📝 Pending: <nums>`. Omit empty buckets. If anything is pending, remind the user they can refine `Decision:` lines and re-ping, run "discuss" for question items, or commit a skip with `skip <nums>` in chat.
|
|
186
|
-
|
|
187
|
-
## Cleanup phase
|
|
188
|
-
|
|
189
|
-
Trigger: user says "cleanup" or "delete the receipt" after Apply has run.
|
|
190
|
-
|
|
191
|
-
Cleanup folds one receipt's skips and removes that receipt, and does nothing else. It is the fallback route now that Apply and `docs-fold` Step 9 each collect a resolved receipt on their own, so it reaches a file those two left behind rather than being the only collector. Apply is still the only phase that moves a memory entry out of the pen, and it does so per approved item into `.canon/memory/archive/`. A user asking to sweep stale memories wants Propose, which classifies entries and writes a decision slot per entry.
|
|
192
|
-
|
|
193
|
-
If no `.canon/memory/review/memory-review-*.md` exists at the main root, stop: `✅ No review receipt to clean up.` Every other refusal in this skill carries a message, and the phase reads a receipt before it does anything else.
|
|
194
|
-
|
|
195
|
-
1. Read the latest `.canon/memory/review/memory-review-*.md` at the main root and confirm Apply has run against it. If any item is still pending, by the test the Apply sweep states, stop and name the pending numbers.
|
|
196
|
-
2. Collect it per the collection rule in `${CLAUDE_SKILL_DIR}/../../standards/memory.md`, folding each ⏭ skipped item before the file goes. The fold happens wherever a receipt is collected, so this phase runs the same rule the Apply sweep does.
|
|
197
|
-
3. Delete that one file. Leave every other receipt beside it in place, because the pending test above covers the file it read and nothing has tested the rest.
|
|
198
|
-
4. Leave every memory entry in the pen. A skip records the decline on the entry and keeps the file, and applied promotions, governance handoffs, and user-type memories each stay as the review left them.
|
|
199
|
-
|
|
200
|
-
Do not promote or archive a memory entry. The skip fold is the one rewrite this phase makes, and it records a decline on an entry that stays in the pen.
|
|
104
|
+
Each later phase runs on its own invocation against a receipt Propose already wrote, picked by the table above. Read `${CLAUDE_SKILL_DIR}/references/later-phases.md` on reaching any of them, for the phase's trigger, what it may mutate, its procedure, and the line it ends on. Challenge and Discuss rewrite the review file only, Apply stops on the main worktree, and Cleanup removes one receipt.
|
|
201
105
|
|
|
202
106
|
## After completion
|
|
203
107
|
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Memory review later phases
|
|
3
|
+
description: The Challenge, Discuss, Apply, and Cleanup phases of memory-review, each run on its own invocation against a receipt the Propose phase already wrote
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Memory review later phases
|
|
7
|
+
|
|
8
|
+
The phases of `memory-review` after Propose. The session reads this file when the phase table in the skill picks Challenge, Discuss, Apply, or Cleanup, and reads only the section for that phase. The skill's Guards still hold for every phase here.
|
|
9
|
+
|
|
10
|
+
## Challenge phase
|
|
11
|
+
|
|
12
|
+
Trigger: user says "challenge the promotes", "challenge before apply", or asks for a high-bar pass. Run before Apply. No mutations to memory files or promotion targets. Review file only.
|
|
13
|
+
|
|
14
|
+
1. Read the latest `.canon/memory/review/memory-review-*.md` at the main root.
|
|
15
|
+
2. For each promote item, apply three tests:
|
|
16
|
+
- **Absorbed**: grep the target surface for the rule's keywords. If already stated or implied, flip to retire.
|
|
17
|
+
- **Delta**: if the rule is a nice-to-have next to existing bullets, flip to retire.
|
|
18
|
+
- **Generality**: if the rule fires only on one literal trigger phrase, rewrite broader or flip to retire.
|
|
19
|
+
3. Rewrite the review file in place with the updated actions and a one-line reason under each flip.
|
|
20
|
+
|
|
21
|
+
## Discuss phase
|
|
22
|
+
|
|
23
|
+
Trigger: user says "discuss", "respond to questions", or any `Decision:` value contains `?` or an unrecognized verb. No mutations to memory files or targets. Review file only. Multi-round.
|
|
24
|
+
|
|
25
|
+
1. Read the latest `.canon/memory/review/memory-review-*.md` at the main root.
|
|
26
|
+
2. For each item whose `Decision:` contains `?` or any unrecognized verb (anything other than `apply`, `skip`, `defer`):
|
|
27
|
+
- Write a `Take:` line under `Decision:`, separated by exactly one blank line. If a `Take:` line already exists, overwrite it.
|
|
28
|
+
- Format: pick + one-line reason. Max 2 sentences. Decision-help style. State the recommendation (`apply` / `skip` / `retire` / specific alternative) first, then the reason. Do not enumerate tradeoffs unless one changes the call.
|
|
29
|
+
- Leave the H2 emoji as 📝 pending.
|
|
30
|
+
3. Skip items whose `Decision:` is `apply`, `skip`, `defer`, or empty.
|
|
31
|
+
4. End with: `💬 Discussed: <nums> | ⏩ Skipped (committed or empty): <nums>`. Remind the user to refine `Decision:` lines and re-ping with "discuss" for another round, or "apply" when ready to commit.
|
|
32
|
+
|
|
33
|
+
Do not act on any item. Do not archive memory files. Do not edit promotion targets. Discuss only.
|
|
34
|
+
|
|
35
|
+
## Apply phase
|
|
36
|
+
|
|
37
|
+
Trigger: user says "apply", "commit", "ship the review", or re-pings with no question items remaining. Mutates tracked promotion targets and moves memory files into the archive.
|
|
38
|
+
|
|
39
|
+
Before applying any item, check the worktree state:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
[ "$(git rev-parse --git-dir 2>/dev/null)" = "$(git rev-parse --git-common-dir 2>/dev/null)" ] && echo "MAIN" || echo "LINKED"
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
If the result is `MAIN`, stop and tell the user: `❌ Apply phase mutates tracked files. Run /session-worktree first.` Discuss and Challenge phases only touch `.canon/review/` scratch and run from anywhere.
|
|
46
|
+
|
|
47
|
+
Before applying a promote to an always-loaded rule in the toolkit repo, load `internal-governance`, which owns `internal/rules/core/` and `governance/rules/core/` and is the only route that may author into either. In a target project, hand off to `create-rule` with no load, since `internal-governance` is a toolkit-internal skill under `.claude/skills/` that a target project never has. An `Edit` appending to an existing file under `.claude/rules/project/` needs no load either.
|
|
48
|
+
|
|
49
|
+
Promotions are a separate concern from any feature in flight. Keep the promoted edits on their own commit. Do not fold an always-loaded-rule or skill-body change into a feature's commits, because a feature reviewer should not have to vet a change to how the agent operates.
|
|
50
|
+
|
|
51
|
+
For each item, parse the `Decision:` line:
|
|
52
|
+
|
|
53
|
+
- `apply` (or affirmative): run the proposed action, flip emoji to ✅.
|
|
54
|
+
- `skip`: leave the memory in place, flip emoji to ⏭.
|
|
55
|
+
- `defer` or empty: leave 📝 pending, take no action.
|
|
56
|
+
- Contains `?` or unrecognized verb: leave 📝 pending, take no action. Do not respond. Discussion is the Discuss phase's job.
|
|
57
|
+
|
|
58
|
+
Free-form text after the verb is a reason. Capture it in the receipt but do not let it change the action. When committing an item, strip any empty `Take:` line so the receipt stays clean. `Take:` lines with content stay as discussion history.
|
|
59
|
+
|
|
60
|
+
Action by action type:
|
|
61
|
+
|
|
62
|
+
- **Promote**: use `Edit` to insert the rewritten rule into the target surface, then archive the memory file. A promote to an always-loaded rule in the toolkit repo never reaches this line: it stops as a handoff to `internal-governance`, the same as **Hand off** below, and archives only on the user's explicit confirmation.
|
|
63
|
+
- **Promote to a context entry**: append the fact to `.canon/tmp/handoff/memory-routing/<slug>.md` at the main worktree root, then archive the memory file. `context-fold` folds it in on its next run from a branch, which is what keeps one skill writing context entries.
|
|
64
|
+
- **Hand off**: do not edit governance. Archive the memory file only if the user confirmed the handoff explicitly. Otherwise leave it in place.
|
|
65
|
+
- **Retire**: archive the memory file.
|
|
66
|
+
|
|
67
|
+
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.
|
|
68
|
+
|
|
69
|
+
Do not hand-edit `.canon/memory/index.md`. Once every archive move is done, regenerate it instead:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
canon indexes regen --no-stage --root <main-root> <main-root>/.canon/memory/index.md
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
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.
|
|
76
|
+
|
|
77
|
+
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.
|
|
78
|
+
|
|
79
|
+
This governs the tracked surfaces a promote lands in, which sit at `pwd` and take `Edit` from anywhere. The receipt and the memory entries are main-root scratch and follow the skill's heredoc guard instead.
|
|
80
|
+
|
|
81
|
+
As each item resolves, update its status in the review file: flip the H2 emoji from 📝 to ✅ for applied, ⏭ for skipped, 📦 for retired, or 🤝 for handed off. Refresh the summary block counts at the top. Do not delete the file here. The sweep below decides whether it goes.
|
|
82
|
+
|
|
83
|
+
**Chat shortcut:** the user replies with `all`, `none`, a comma-separated list of numbers, or `skip <nums>`. Write the matching verb into the `Decision:` slot of every item the reply names, `apply` for `all` or a bare list and `skip` for a `skip` reply, then run the parse above against the file. A reply of `none` writes nothing. A slot the reply does not name keeps its own value, so the receipt stays the source of truth and an empty slot still means take no action.
|
|
84
|
+
|
|
85
|
+
### Sweep the receipt
|
|
86
|
+
|
|
87
|
+
Count the items still pending once the parse above has run. An item is pending when its H2 carries 📝, or when its H2 carries no status emoji and its `Decision:` slot holds nothing the parse above would act on or skip, since a receipt written by hand or by an older binary may lack the marker. Apply leaves one pending on `defer`, on empty, and on any unrecognized verb, so a receipt reaching this point may still be holding decisions.
|
|
88
|
+
|
|
89
|
+
Leave the receipt in place when any remain. When none do, collect it per the collection rule in `${CLAUDE_SKILL_DIR}/../../standards/memory.md`, which owns what a fold writes and which entry types take one.
|
|
90
|
+
|
|
91
|
+
`context-fold` Step 9 sweeps the same folder on the same rule once per shipped branch, and either may reach a receipt first. Whichever does, the other finds no file and moves on.
|
|
92
|
+
|
|
93
|
+
End with: `✅ Applied: <nums> | ⏭ Skipped: <nums> | 📝 Pending: <nums>`. Omit empty buckets. If anything is pending, remind the user they can refine `Decision:` lines and re-ping, run "discuss" for question items, or commit a skip with `skip <nums>` in chat.
|
|
94
|
+
|
|
95
|
+
## Cleanup phase
|
|
96
|
+
|
|
97
|
+
Trigger: user says "cleanup" or "delete the receipt" after Apply has run.
|
|
98
|
+
|
|
99
|
+
Cleanup folds one receipt's skips and removes that receipt, and does nothing else. It is the fallback route now that Apply and `context-fold` Step 9 each collect a resolved receipt on their own, so it reaches a file those two left behind rather than being the only collector. Apply is still the only phase that moves a memory entry out of the pen, and it does so per approved item into `.canon/memory/archive/`. A user asking to sweep stale memories wants Propose, which classifies entries and writes a decision slot per entry.
|
|
100
|
+
|
|
101
|
+
If no `.canon/memory/review/memory-review-*.md` exists at the main root, stop: `✅ No review receipt to clean up.` Every other refusal in this skill carries a message, and the phase reads a receipt before it does anything else.
|
|
102
|
+
|
|
103
|
+
1. Read the latest `.canon/memory/review/memory-review-*.md` at the main root and confirm Apply has run against it. If any item is still pending, by the test the Apply sweep states, stop and name the pending numbers.
|
|
104
|
+
2. Collect it per the collection rule in `${CLAUDE_SKILL_DIR}/../../standards/memory.md`, folding each ⏭ skipped item before the file goes. The fold happens wherever a receipt is collected, so this phase runs the same rule the Apply sweep does.
|
|
105
|
+
3. Delete that one file. Leave every other receipt beside it in place, because the pending test above covers the file it read and nothing has tested the rest.
|
|
106
|
+
4. Leave every memory entry in the pen. A skip records the decline on the entry and keeps the file, and applied promotions, governance handoffs, and user-type memories each stay as the review left them.
|
|
107
|
+
|
|
108
|
+
Do not promote or archive a memory entry. The skip fold is the one rewrite this phase makes, and it records a decline on an entry that stays in the pen.
|
|
@@ -35,4 +35,4 @@ Without this skill, implementation starts before anyone knows what it touches. A
|
|
|
35
35
|
|
|
36
36
|
- Executing the plan, which is the ship pipeline
|
|
37
37
|
- Task-board state, which `task-board` owns. A plan links to its task and does not create one.
|
|
38
|
-
- Reconciling the planning docs after the work lands, which `
|
|
38
|
+
- Reconciling the planning docs after the work lands, which `context-fold` owns
|
|
@@ -52,6 +52,6 @@ A declined finding fails on a third axis, which is where its reason ends up. A w
|
|
|
52
52
|
|
|
53
53
|
- Writing the review, which `review-pr` owns. The split is by side of the channel: that one posts findings from an independent session and this one is the worker's return leg.
|
|
54
54
|
- Staging, committing, and pushing the follow-up, which `git-followup` owns under this skill's direction
|
|
55
|
-
- Refreshing the `.claude/` docs the fixes made stale, which `
|
|
55
|
+
- Refreshing the `.claude/` docs the fixes made stale, which `context-fold` owns
|
|
56
56
|
- Re-reviewing its own fixes, which hands back to the orchestrator
|
|
57
57
|
- Re-reading a rewritten branch, which `review-pr` absorbs by testing whether the prior reviewed commit still reaches the head and paying for a full pass when it does not
|
|
@@ -46,7 +46,7 @@ Do not push a red follow-up.
|
|
|
46
46
|
|
|
47
47
|
## Step 4: refresh stale docs
|
|
48
48
|
|
|
49
|
-
The fixes may have changed or added behavior that `.claude/` context entries, docs, or wireframes describe. Refresh them with the `
|
|
49
|
+
The fixes may have changed or added behavior that `.claude/` context entries, docs, or wireframes describe. Refresh them with the `context-fold` skill, which maps the changed files to the entries that reference them and rewrites the stale sections. Do not reimplement that mapping here. When a fix adds a new capability with no existing entry, `context-fold` flags it rather than creating one.
|
|
50
50
|
|
|
51
51
|
## Step 5: rebase a stale branch
|
|
52
52
|
|
|
@@ -121,7 +121,7 @@ If there are no findings, write `✅ No findings.` to the file with a timestamp.
|
|
|
121
121
|
|
|
122
122
|
The `.canon/review/` directory is gitignored. Do not stage or commit the file.
|
|
123
123
|
|
|
124
|
-
The report is disposable. It outlives the ship chain that reads it, and `
|
|
124
|
+
The report is disposable. It outlives the ship chain that reads it, and `context-fold` sweeps it once the branch it names is gone, because the durable record of what a review found is the comment `review-pr` posts on the pull request. A review run on a branch that never opens one leaves nothing behind once that branch is gone, so fold anything worth keeping into the pull request body or a task finding while the report is still on disk.
|
|
125
125
|
|
|
126
126
|
### Chat output
|
|
127
127
|
|
|
@@ -70,7 +70,7 @@ Take the comparison at the file path rather than at a folder above it. `canon ta
|
|
|
70
70
|
|
|
71
71
|
The finding names which row contributed the containing path, and a bare-folder cell reports as a claim of its own beside the findings. Read that output as a candidate list, settle each pair by file, and narrow the cell that over-claimed rather than discounting the collision it caused.
|
|
72
72
|
|
|
73
|
-
A declared set is what a branch sets out to write rather than a bound on it, so this gate clears against a prediction and the branch outgrows it hours later. A track can cross the set it cleared against and still merge clean, which is a gate reporting disjoint while a real overlap stood. Two classes account for nearly all of the crossing. The ship chain's own steps write past every plan, since `canon:
|
|
73
|
+
A declared set is what a branch sets out to write rather than a bound on it, so this gate clears against a prediction and the branch outgrows it hours later. A track can cross the set it cleared against and still merge clean, which is a gate reporting disjoint while a real overlap stood. Two classes account for nearly all of the crossing. The ship chain's own steps write past every plan, since `canon:context-fold` refreshes whichever context entry a change reaches and `canon:docs-sync` reaches the public docs, and neither surface is one a planner can name before the change exists. The drift stages `bun run check` regenerates and asserts are the second, together with the test and sandbox siblings a source change drags in. Nothing here prevents either, because the files at issue are written long after this gate clears. What reads the other end is `canon tasks plan-reach`, which `canon:git-ship` runs at step 5 against the branch's own diff, so a crossing this gate could not see is named before the pull request opens rather than after it merges.
|
|
74
74
|
|
|
75
75
|
Disjointness is necessary and not sufficient, so hold a candidate whose sets do not touch when a stated reason serializes it, and write the reason on the hold. One row creating a skill and another auditing that catalog and counting it write nothing in common, and dispatching both still leaves the audit counting a denominator that moves underneath it. Nothing verifies that a reason was written, so the rule holds only while the dispatcher applies it.
|
|
76
76
|
|
|
@@ -41,6 +41,8 @@ Clearing a row answers yes to that question. It is not a count of how long the r
|
|
|
41
41
|
|
|
42
42
|
A row this test clears moves out of `backlog.md` and onto the bottom of `## Needs a plan`, carrying a `Waiting on` cell that states what changed and ends with the word `last`. `canon tasks validate`'s ordering check reads `last` as the ordinal bottom placement already claims, and a cell stating only what changed matches neither that check's ordinal reading nor its rank reading, which raises the finding this pass would then have written against its own row. The next refill sweep's promotion step still orders the row against the rest of that heading the way it orders every other row there, per step 5 under `## Refilling the ready queue` in `role-orchestrator`.
|
|
43
43
|
|
|
44
|
+
This pass only clears a row upward. Declining or archiving a backlog row is `backlog-triage`, which files a verdict for every row and applies the ones the operator approved.
|
|
45
|
+
|
|
44
46
|
## Two ways a re-test goes wrong
|
|
45
47
|
|
|
46
48
|
Both return a confident wrong answer rather than an error, which is why each gets a step of its own.
|
|
@@ -14,7 +14,7 @@ It counts unclaimed plans against workers rather than reading the reserve in ste
|
|
|
14
14
|
1. Run `gh pr list --state open` and `git log --oneline -8`. Report any pull request whose review has not been posted and stop for that one first.
|
|
15
15
|
2. For each pull request merged since the last sweep, place every finding it produced. Route a finding that changes a rule to the standard or rule that states it, one that changes another task to that task's Findings, and one that overturns a groundwork lean to that folder marked answered. Never leave a finding in a pull request thread alone.
|
|
16
16
|
3. Archive what closed.
|
|
17
|
-
- A task whose outcomes are all `[x]` runs `
|
|
17
|
+
- A task whose outcomes are all `[x]` runs `context-fold` for the plan sweep, then `task-board` to archive
|
|
18
18
|
- A task whose outcomes describe standing policy rather than a deliverable never closes on its own, so hand it to a worker to encode the policy where it is enforced, then cut the outcomes with the reason recorded and archive once that branch merges. Encoding it from this session would write a tracked file, which `## Boundaries` in the skill body forbids.
|
|
19
19
|
4. Read `.canon/tasks/priority.md` and count entries under its `## Run now` heading that carry a written plan. Keep one in reserve beyond what is running.
|
|
20
20
|
5. Promote from the top of `## Needs a plan`, which is where the last sweep recorded what to plan next. Depart from that order when something has changed under it and say what changed, since a position nobody honors is the ordering going stale on the surface built to hold it. What sets the order in the first place is whether a task establishes functionality rather than how old it is, so prefer a task that adds or proves a mechanism over one that trims, tidies, or audits an existing surface.
|
|
@@ -53,4 +53,4 @@ Promoting, demoting, and archiving a row all write `.canon/tasks/priority.md`, a
|
|
|
53
53
|
- Re-resolve every Plan pointer after anything archives a plan
|
|
54
54
|
- Read the file back after writing it, since the row that lands is the row a worker acts on
|
|
55
55
|
|
|
56
|
-
A Plan pointer goes stale from a branch this board never sees. `
|
|
56
|
+
A Plan pointer goes stale from a branch this board never sees. `context-fold` moves a plan to `.canon/plans/archive/` and rewrites the citation in the task file alone, so a row for a task still on the board keeps pointing into `.canon/plans/` at a file that has moved. Workers running the ship chain on their own branches archive plans this board still cites, and the board reads as correct until a pointer is followed.
|
|
@@ -45,5 +45,5 @@ A resume is a read, and a session that treats it as a cleanup pass offers to arc
|
|
|
45
45
|
- Writing a handoff, which happens at the close of a session rather than at its start. This skill names the standard that governs one and follows it no further.
|
|
46
46
|
- The sections a role adds over the core handoff, which belong to that role's own surface
|
|
47
47
|
- Archiving a shipped task out of the folder: `task-board`
|
|
48
|
-
- Archiving a plan and marking an outcome, which `
|
|
48
|
+
- Archiving a plan and marking an outcome, which `context-fold` does when the work ships
|
|
49
49
|
- Implementing the item it recommends, which is the next request rather than part of this one
|
|
@@ -47,21 +47,17 @@ Try each source in order. Stop at the first match.
|
|
|
47
47
|
4b. **Session context.** When on `main` or `master` with no matching plan, read the current conversation to infer a kebab slug from the topic being discussed. Propose it: `Infer: <slug>. Confirm or rename?` Do not enter the worktree until the user confirms or provides a corrected name.
|
|
48
48
|
5. **Ask.** None of the above applies. Ask the user for a name. Do not invent one.
|
|
49
49
|
|
|
50
|
-
Tier 0 sits ahead of the inference because every tier below it answers from state the caller cannot set
|
|
50
|
+
Tier 0 sits ahead of the inference because every tier below it answers from state the caller cannot set. A dispatched worker starts on `main` beside several plans, so without it the run lands on tier 3 and asks somebody who is not there.
|
|
51
51
|
|
|
52
52
|
Validate the result: letters, digits, dots, underscores, dashes only, max 64 chars (`/` separators are also allowed). If the derived name violates the rule, sanitize by replacing invalid chars with `-` and truncating. Show the sanitized name in the preview before invoking.
|
|
53
53
|
|
|
54
54
|
Resolve `<type>` here as well, since Step 3 previews it and Step 5 renames onto it, drawing the value from the type vocabulary in `${CLAUDE_SKILL_DIR}/../../standards/branch.md`. A type the caller spelled in tier 0 wins outright and no reading overrides it. A name that came from a plan, through tier 1 or tier 2, takes its type from `canon tasks plan-branch <plan> --json`, read off the record's `type` field. Every other case takes `feat`, which covers a name from a branch, a bare name from the user, and a plan the verb could not answer for.
|
|
55
55
|
|
|
56
|
-
The verb is the reading rather than this body, because a type read off a plan's
|
|
57
|
-
|
|
58
|
-
The caller's type still wins over the verb's, because tier 0 is the one source that knows something no file states. The ordinary caller is `auto-ship` Step 0, which ran the verb itself and is handing over the answer it got, so nothing is overridden in that case either.
|
|
56
|
+
The verb is the reading rather than this body, because a type read off a plan's sections is a judgment that two sessions reading one plan can grade differently, and the verb answers the same for both. The caller's type still wins over the verb's, because tier 0 is the one source that knows something no file states.
|
|
59
57
|
|
|
60
58
|
Branch on the record rather than on the exit code, which a shell function wrapping `canon` can flatten to zero. Take `feat` and say the verb did not answer where it refuses, where the record carries no `type` key, or where the installed binary carries no `plan-branch` subcommand.
|
|
61
59
|
|
|
62
|
-
A wrong type is
|
|
63
|
-
|
|
64
|
-
`git-branch` does not correct it, which three surfaces used to say it did. Its second guard reads `If branch name already follows conventions, stop`, and `${CLAUDE_SKILL_DIR}/../../standards/branch.md` makes the type vocabulary an axis without making the choice within that vocabulary one, so `feat/` over a fix conforms and the guard fires ahead of the Analysis line that would have re-derived the type.
|
|
60
|
+
A wrong type is cosmetic, since `git-stage` and `git-pr` read their types off the diff rather than the branch name. Nothing corrects it later either: `git-branch` stops on any name that already conforms, and `feat/` over a fix conforms.
|
|
65
61
|
|
|
66
62
|
Then test both names the entry is about to claim. Neither read needs a worktree, and a stop after Step 4 leaves one built with the session sitting inside it, so both belong here rather than beside the rename:
|
|
67
63
|
|
|
@@ -74,7 +70,7 @@ The two tests catch different collisions. The branch test misses the one `${CLAU
|
|
|
74
70
|
|
|
75
71
|
The branch test fires on the tier 1 and tier 4 sources whenever the branch the session started on is already conventional, since a name derived from that branch resolves back onto it. Stopping is the answer there. The concern already has a branch, git refuses a second under the same name, and the bare-name rename this replaces only carried the collision forward to the `git-branch` step. It fires on tier 0 as well, where a caller handed a name something already holds.
|
|
76
72
|
|
|
77
|
-
It reads both ref spaces rather than the local head alone,
|
|
73
|
+
It reads both ref spaces rather than the local head alone, the way `checkClaim` does, so a name this skill clears and a branch a dispatcher cleared are one answer, and a branch pushed from elsewhere is caught before the first push rather than at it.
|
|
78
74
|
|
|
79
75
|
## Step 3: preview
|
|
80
76
|
|
|
@@ -153,8 +149,6 @@ Then report the port this worktree derives, on a second line:
|
|
|
153
149
|
|
|
154
150
|
Branch on the exit rather than on the output, since the helper prints nothing to stdout when it refuses and reading that as a number reports an offset of zero, which is the main checkout's.
|
|
155
151
|
|
|
156
|
-
The helper refuses a folder left behind after its worktree was removed, which Step 4 cannot land on, since it registers whatever it creates. The branch is here so a refusal is never read back as an offset of zero, which is the main checkout's port and the collision the helper exists to prevent.
|
|
157
|
-
|
|
158
152
|
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.
|
|
159
153
|
|
|
160
154
|
Do not invoke `ExitWorktree` from this skill. Exit is the user's call.
|
|
@@ -42,6 +42,6 @@ Placing a row without checking for another writer collides the same way. Two ses
|
|
|
42
42
|
|
|
43
43
|
## Out of scope
|
|
44
44
|
|
|
45
|
-
- Editing the contents of a task that already exists, which `
|
|
45
|
+
- Editing the contents of a task that already exists, which `context-fold` owns along with marking outcomes and sweeping plans
|
|
46
46
|
- Deciding what the task should argue. This owns the file's existence and its shape, not its content.
|
|
47
47
|
- Relocating a plan, which one skill owns so two do not relocate it differently
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: task-board
|
|
3
|
-
description: Creates a task file in `.canon/tasks/` with the filename, phase label, and frontmatter the standard requires, and archives a shipped one out of the folder. Use when asked to "add a task", "create a task", "queue this", "put this on the board", "archive that task", or "close out a shipped task". Do NOT use to mark an outcome `[x]`. That is `
|
|
3
|
+
description: Creates a task file in `.canon/tasks/` with the filename, phase label, and frontmatter the standard requires, and archives a shipped one out of the folder. Use when asked to "add a task", "create a task", "queue this", "put this on the board", "archive that task", or "close out a shipped task". Do NOT use to mark an outcome `[x]`. That is `context-fold`.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Task board
|
|
7
7
|
|
|
8
|
-
Owns the two operations that bring a task file into existence and take it out of the folder. `
|
|
8
|
+
Owns the two operations that bring a task file into existence and take it out of the folder. `context-fold` edits the contents of a task that already exists, marking outcomes `[x]`. Do not mark outcomes here, and do not move a plan by hand: the archive carries it.
|
|
9
9
|
|
|
10
10
|
Read `${CLAUDE_SKILL_DIR}/../../standards/tasks.md` before writing any file. It holds the filename convention, the frontmatter contract, and the file format. Do not work them from memory.
|
|
11
11
|
|
|
12
12
|
## Guards
|
|
13
13
|
|
|
14
14
|
- Resolve the board at the main worktree root, not `pwd`. Run `git worktree list --porcelain | grep -m 1 '^worktree ' | cut -d' ' -f2-`, falling back to `pwd` outside a git repo. Every read and write below resolves against that root. The board is gitignored scratch shared across worktrees, so a linked worktree writing to its own `pwd` creates a second board nothing else reads.
|
|
15
|
-
- A new task file is a main-root write, so it goes out as a heredoc. Archiving already runs through `canon tasks archive`, which resolves the root in-process. Marking an outcome shipped is `
|
|
15
|
+
- A new task file is a main-root write, so it goes out as a heredoc. Archiving already runs through `canon tasks archive`, which resolves the root in-process. Marking an outcome shipped is `context-fold` and runs through `canon tasks outcome`. Resolve that root and route the write the way `session-worktree` states.
|
|
16
16
|
- If `.canon/tasks/` does not exist at that root, stop: `❌ No .canon/tasks/ board. Run canon claude init to set it up.`
|
|
17
17
|
- Route on the request rather than on a flag. Creating names work that does not exist yet, archiving names a task file already shipped, and declining names one decided against. If the request fits none of the three, stop: `❌ Ambiguous. Say whether to create a task, archive one, or decline one.`
|
|
18
18
|
- Never hand-edit `.canon/tasks/index.md`. A hook regenerates it from sibling frontmatter after a write. Do not run the regen command directly, except after a shell write from a linked worktree: the hook matches `Write|Edit|MultiEdit` and nothing fires on `Bash`, so that one case regenerates explicitly with `canon indexes regen --no-stage --root <main-root> <main-root>/.canon/tasks/index.md`.
|
|
@@ -84,85 +84,11 @@ Say the origins were read even when nothing comes back, which is the ordinary re
|
|
|
84
84
|
|
|
85
85
|
## Archive
|
|
86
86
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
Do not move the file, edit `priority.md`, or regenerate the index by hand. `canon tasks archive` owns all three as one unit and the hook calls the same command, so a hand-rolled move here drifts from the unattended path.
|
|
90
|
-
|
|
91
|
-
### Step 1: confirm the work reached main
|
|
92
|
-
|
|
93
|
-
`docs-fold` marks outcomes on the branch as step 1 of the ship chain, so an all-`[x]` task routinely describes a pull request that is still open. The command gates on the outcomes and cannot tell those two apart, which is what puts this check here:
|
|
94
|
-
|
|
95
|
-
```bash
|
|
96
|
-
git fetch origin main --quiet && git log origin/main --oneline -20
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
Match the shipped outcomes against that log, widening to `gh pr list --state merged --limit 20` when a remote is configured and the log does not settle it. When the work is not on `main`, name the task and stop: `❌ Work not on main. Archiving now loses the task if the pull request is abandoned.`
|
|
100
|
-
|
|
101
|
-
The board is gitignored, so an archived task has no history behind it and nothing restores one archived early. Skip this check when the task carries a `Pull request:` line and the last number it lists is merged, since the number already proves what the log is being read for.
|
|
102
|
-
|
|
103
|
-
### Step 2: run the archive
|
|
104
|
-
|
|
105
|
-
Pass the task's filename stem, or the pull request number when the request names one:
|
|
106
|
-
|
|
107
|
-
```bash
|
|
108
|
-
canon tasks archive <stem> --json
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
The command refuses rather than reports, and the refusal reaches this skill through the record rather than through the exit. Branch on `ok`, then on `reason`. 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 masks every non-zero exit rather than only an absent verb. The binary exits 1 for an unknown subcommand and 1 for an ordinary refusal alike, so the record is the only signal that survives the wrapper.
|
|
112
|
-
|
|
113
|
-
On success the record carries `from`, `to`, `priorityRowRemoved`, and `indexRegenerated`, which is what moved, what row it cleared, and whether the index changed. It also carries `plan` when the task was the last live citation of a live plan, holding the `from` and `to` of the plan moved alongside it. A `plan` of `null` means the task cited no live plan, or that a sibling still holds it.
|
|
114
|
-
|
|
115
|
-
### Step 3: route on a refusal
|
|
116
|
-
|
|
117
|
-
Each reason has one resolution and none of them is to archive around it:
|
|
118
|
-
|
|
119
|
-
- `open-outcomes`: the named outcomes are unmarked or genuinely open. Run `docs-fold` when the work shipped and nothing marked it. Leave the task on the board when the outcome is real. When the work is being abandoned, cut it by striking the body, `- ~~<outcome>~~ <why>`, whatever the checkbox holds, so the board records what was dropped rather than meeting this refusal a second time.
|
|
120
|
-
- `ambiguous`: two tasks name one pull request, which is the misfile `${CLAUDE_SKILL_DIR}/../../standards/tasks.md` rules out. Resolve the citation by hand, since no sweep repairs it.
|
|
121
|
-
- `earlier-slice`: the number is listed on the task but is not the last, so a later slice is still to merge. Leave the task on the board. Its last slice's merge archives it.
|
|
122
|
-
- `no-match`: the stem or number names nothing on the board. Check the name against the listed stems.
|
|
123
|
-
- `bad-input`: the command line was wrong rather than the board. Read the message, fix the arguments, and run it again. Nothing on the board needs repair, which is what separates this from the two above.
|
|
124
|
-
|
|
125
|
-
Do not move a plan by hand from this skill. The command carries the plan with the task when no other live task cites it, and retargets the archived task's `Plan:` line at the new path. A second mover drifts into relocating the same file differently.
|
|
126
|
-
|
|
127
|
-
Leave `TASK-ARCHIVE.md` alone when it is present in the archive folder. It records the single-file era in the shape that era used, and splitting it would fabricate per-task files nobody wrote.
|
|
128
|
-
|
|
129
|
-
### Step 4: clear prose naming the task
|
|
130
|
-
|
|
131
|
-
The command drops the task's row from `.canon/tasks/priority.md` and leaves prose alone. Remove any sentence that still names the archived task or counts the rows that changed, since a stale count reads as board state.
|
|
87
|
+
Read `${CLAUDE_SKILL_DIR}/references/archive.md` when the request names a shipped task to archive. It carries the check that the work reached `main`, the `canon tasks archive` call, the route for each refusal, and the prose to clear afterwards. Never move the file, edit `priority.md`, or regenerate the index by hand, since the command owns all three.
|
|
132
88
|
|
|
133
89
|
## Decline
|
|
134
90
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
Do not move the file, edit `priority.md` or `backlog.md`, or regenerate the index by hand. `canon tasks decline` owns all three as one unit.
|
|
138
|
-
|
|
139
|
-
### Step 1: gather the reason
|
|
140
|
-
|
|
141
|
-
Ask for the reason when the request does not carry one, and stop rather than guessing: `❌ No reason. Say why the task is being declined.` The command takes it as `--reason <text>` and refuses without it, so gathering it here saves a round trip through that refusal.
|
|
142
|
-
|
|
143
|
-
### Step 2: run the decline
|
|
144
|
-
|
|
145
|
-
Pass the task's filename stem:
|
|
146
|
-
|
|
147
|
-
```bash
|
|
148
|
-
canon tasks decline <stem> --reason "<text>" [--by <name>] --json
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
The command refuses rather than reports, and the refusal reaches this skill through the record rather than through the exit, the same wrapper hazard `canon tasks archive` carries. Branch on `ok`, then on `reason`.
|
|
152
|
-
|
|
153
|
-
On success the record carries `from`, `to`, `priorityRowRemoved`, `backlogRowRemoved`, and `indexRegenerated`, where `backlogRowRemoved` is decline's own field since a task can be declined straight off `backlog.md` and archive never checks that file. It also carries `plan` when the task was the last live citation of a live plan, holding the `from` and `to` of the plan moved alongside it, the same shape `canon tasks archive` uses for its own `plan` field.
|
|
154
|
-
|
|
155
|
-
### Step 3: route on a refusal
|
|
156
|
-
|
|
157
|
-
- `no-match`: the stem does not name exactly one task. Either none matches, or exactly one starts with it and the full name is needed. Check the name against the listed stems.
|
|
158
|
-
- `ambiguous`: the stem is a prefix more than one task starts with, unlike archive's own `ambiguous`, which fires on a shared pull request. Decline takes no pull-request selector, so this is the only route to it. Pass the full stem.
|
|
159
|
-
- `bad-input`: the command line was wrong rather than the board. Read the message, fix the arguments, and run it again. Nothing on the board needs repair, which is what separates this from the two above.
|
|
160
|
-
|
|
161
|
-
Do not move a plan by hand from this skill. The command carries the plan with the task when no other live task cites it, and retargets the declined task's `Plan:` line at the new path. A second mover drifts into relocating the same file differently.
|
|
162
|
-
|
|
163
|
-
### Step 4: clear prose naming the task
|
|
164
|
-
|
|
165
|
-
The command drops the task's row from `.canon/tasks/priority.md` or `.canon/tasks/backlog.md` and leaves prose alone. Remove any sentence that still names the declined task or counts the rows that changed, since a stale count reads as board state.
|
|
91
|
+
Read `${CLAUDE_SKILL_DIR}/references/decline.md` when the request names a task decided against. It carries gathering the reason, the `canon tasks decline` call, the route for each refusal, and the prose to clear afterwards. Never move the file, edit `priority.md` or `backlog.md`, or regenerate the index by hand, since the command owns all three.
|
|
166
92
|
|
|
167
93
|
## Output
|
|
168
94
|
|
|
@@ -198,4 +124,4 @@ Archive, reporting the paths the command returned:
|
|
|
198
124
|
<ordering and index disposition in one line>
|
|
199
125
|
```
|
|
200
126
|
|
|
201
|
-
A refusal reports the reason and the resolution
|
|
127
|
+
A refusal reports the reason and the resolution the mode's reference routes it to under its Step 3, on one line each.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Archive a shipped task
|
|
3
|
+
description: How task-board confirms a task's work reached main, runs canon tasks archive, routes each refusal, and clears prose naming the archived task
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Archive a shipped task
|
|
7
|
+
|
|
8
|
+
The Archive mode of `task-board`. The session reads this file when the request names a task file already shipped.
|
|
9
|
+
|
|
10
|
+
The `post-merge` git hook archives the task a merge closed, so a request arriving here is usually one the hook could not resolve on its own. Run the steps below against whatever the hook left in place.
|
|
11
|
+
|
|
12
|
+
Do not move the file, edit `priority.md`, or regenerate the index by hand. `canon tasks archive` owns all three as one unit and the hook calls the same command, so a hand-rolled move here drifts from the unattended path.
|
|
13
|
+
|
|
14
|
+
## Step 1: confirm the work reached main
|
|
15
|
+
|
|
16
|
+
`context-fold` marks outcomes on the branch as step 1 of the ship chain, so an all-`[x]` task routinely describes a pull request that is still open. The command gates on the outcomes and cannot tell those two apart, which is what puts this check here:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
git fetch origin main --quiet && git log origin/main --oneline -20
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Match the shipped outcomes against that log, widening to `gh pr list --state merged --limit 20` when a remote is configured and the log does not settle it. When the work is not on `main`, name the task and stop: `❌ Work not on main. Archiving now loses the task if the pull request is abandoned.`
|
|
23
|
+
|
|
24
|
+
The board is gitignored, so an archived task has no history behind it and nothing restores one archived early. Skip this check when the task carries a `Pull request:` line and the last number it lists is merged, since the number already proves what the log is being read for.
|
|
25
|
+
|
|
26
|
+
## Step 2: run the archive
|
|
27
|
+
|
|
28
|
+
Pass the task's filename stem, or the pull request number when the request names one:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
canon tasks archive <stem> --json
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
The command refuses rather than reports, and the refusal reaches this skill through the record rather than through the exit. Branch on `ok`, then on `reason`. 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 masks every non-zero exit rather than only an absent verb. The binary exits 1 for an unknown subcommand and 1 for an ordinary refusal alike, so the record is the only signal that survives the wrapper.
|
|
35
|
+
|
|
36
|
+
On success the record carries `from`, `to`, `priorityRowRemoved`, and `indexRegenerated`, which is what moved, what row it cleared, and whether the index changed. It also carries `plan` when the task was the last live citation of a live plan, holding the `from` and `to` of the plan moved alongside it. A `plan` of `null` means the task cited no live plan, or that a sibling still holds it.
|
|
37
|
+
|
|
38
|
+
## Step 3: route on a refusal
|
|
39
|
+
|
|
40
|
+
Each reason has one resolution and none of them is to archive around it:
|
|
41
|
+
|
|
42
|
+
- `open-outcomes`: the named outcomes are unmarked or genuinely open. Run `context-fold` when the work shipped and nothing marked it. Leave the task on the board when the outcome is real. When the work is being abandoned, cut it by striking the body, `- ~~<outcome>~~ <why>`, whatever the checkbox holds, so the board records what was dropped rather than meeting this refusal a second time.
|
|
43
|
+
- `ambiguous`: two tasks name one pull request, which is the misfile `${CLAUDE_SKILL_DIR}/../../standards/tasks.md` rules out. Resolve the citation by hand, since no sweep repairs it.
|
|
44
|
+
- `earlier-slice`: the number is listed on the task but is not the last, so a later slice is still to merge. Leave the task on the board. Its last slice's merge archives it.
|
|
45
|
+
- `no-match`: the stem or number names nothing on the board. Check the name against the listed stems.
|
|
46
|
+
- `bad-input`: the command line was wrong rather than the board. Read the message, fix the arguments, and run it again. Nothing on the board needs repair, which is what separates this from the two above.
|
|
47
|
+
|
|
48
|
+
Do not move a plan by hand from this skill. The command carries the plan with the task when no other live task cites it, and retargets the archived task's `Plan:` line at the new path. A second mover drifts into relocating the same file differently.
|
|
49
|
+
|
|
50
|
+
Leave `TASK-ARCHIVE.md` alone when it is present in the archive folder. It records the single-file era in the shape that era used, and splitting it would fabricate per-task files nobody wrote.
|
|
51
|
+
|
|
52
|
+
## Step 4: clear prose naming the task
|
|
53
|
+
|
|
54
|
+
The command drops the task's row from `.canon/tasks/priority.md` and leaves prose alone. Remove any sentence that still names the archived task or counts the rows that changed, since a stale count reads as board state.
|