@erclx/canon 4.122.0 → 4.124.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 +7 -8
- package/claude/skills/auto-ship/references/tier-failures.md +7 -4
- package/claude/skills/backlog-triage/SKILL.md +1 -1
- package/claude/skills/codebase-layout/REQUIREMENT.md +1 -1
- package/claude/skills/codebase-layout/SKILL.md +1 -1
- package/claude/skills/create-rule/SKILL.md +5 -2
- package/claude/skills/design-taste/SKILL.md +1 -1
- package/claude/skills/draft-ready/REQUIREMENT.md +1 -1
- package/claude/skills/draft-ready/SKILL.md +1 -1
- package/claude/skills/git-ship/SKILL.md +4 -3
- package/claude/skills/memory-capture/SKILL.md +14 -4
- package/claude/skills/memory-review/REQUIREMENT.md +4 -2
- package/claude/skills/memory-review/SKILL.md +18 -7
- package/claude/skills/memory-review/references/later-phases.md +7 -4
- package/claude/skills/memory-review/references/receipt-format.md +19 -3
- package/claude/skills/role-orchestrator/SKILL.md +2 -2
- package/claude/skills/role-orchestrator/references/orchestrator-parked.md +2 -2
- package/claude/skills/session-resume/SKILL.md +4 -3
- package/claude/skills/task-board/SKILL.md +1 -1
- package/claude/skills/task-board/references/archive.md +1 -1
- package/claude/skills/task-board/references/decline.md +1 -1
- package/claude/skills/test-first/REQUIREMENT.md +1 -1
- package/docs/agents/counts.md +3 -3
- package/docs/agents/drift-surfaces.md +2 -2
- package/docs/agents/rule-citations.md +4 -4
- package/docs/agents/tasks-archive.md +3 -3
- package/docs/agents/tasks-plans.md +5 -3
- package/docs/agents/tasks-validate.md +1 -1
- package/docs/agents/tasks.md +1 -1
- package/docs/agents/test-order.md +1 -1
- package/docs/index.md +3 -0
- package/docs/target-migrations.md +93 -0
- package/docs/target-projects.md +4 -216
- package/docs/target-scenarios.md +56 -0
- package/docs/target-sync.md +93 -0
- package/docs/workflow/ai-workflow.md +4 -203
- package/docs/workflow/index.md +2 -0
- package/docs/workflow/operating-model.md +18 -47
- package/docs/workflow/parallel-features.md +77 -0
- package/docs/workflow/skill-map.md +148 -0
- package/governance/renames.toml +34 -0
- package/governance/rules/{claude/555-tasks.md → canon/655-tasks.md} +2 -1
- package/governance/rules/{claude/560-diagrams.md → canon/660-diagrams.md} +1 -1
- package/governance/rules/{claude/562-session.md → canon/662-session.md} +1 -1
- package/governance/rules/code/000-code.md +21 -0
- package/governance/rules/lib/300-testing-ts.md +0 -4
- package/governance/rules/lib/330-testing-py.md +0 -4
- package/governance/rules/{claude/500-prose.md → writing/800-prose.md} +1 -1
- package/governance/rules/{claude/501-markdown.md → writing/801-markdown.md} +1 -1
- package/governance/rules/{claude/502-mermaid.md → writing/802-mermaid.md} +1 -1
- package/governance/stacks/base.toml +7 -6
- package/governance/stacks/node.toml +1 -1
- package/governance/stacks/python.toml +1 -1
- package/package.json +1 -1
- package/scripts/core/install-check.sh +3 -5
- package/src/claude/routing.ts +1 -1
- package/src/commands/gov.ts +1 -1
- package/src/commands/tasks.ts +39 -29
- package/src/gate/measures.ts +1 -6
- package/src/gate/stages.ts +1 -0
- package/src/gov/citations.ts +1 -1
- package/src/gov/list.ts +1 -1
- package/src/gov/restated.ts +2 -2
- package/src/init/steps.ts +1 -1
- package/src/labels/spelling.ts +1 -1
- package/src/records/prune.ts +1 -1
- package/src/shipped/references.ts +1 -1
- package/src/tasks/archive.ts +212 -105
- package/src/tasks/reach.ts +1 -1
- package/src/tasks/record.ts +59 -16
- package/src/tasks/validate.ts +1 -1
- package/standards/board.md +136 -0
- package/standards/commit.md +5 -0
- package/standards/groundwork.md +25 -36
- package/standards/index.md +2 -1
- package/standards/plan.md +20 -34
- package/standards/readme.md +8 -77
- package/standards/requirements.md +2 -2
- package/standards/rule.md +4 -6
- package/standards/tasks.md +18 -125
- package/standards/versioning.md +1 -1
- package/tooling/base/configs/commitlint.config.js +27 -1
- package/tooling/base/reference.md +2 -2
- package/tooling/claude/seeds/.claude/hooks/path-form.sh +1 -1
- package/tooling/claude/seeds/.claude/hooks/scratch-guard.sh +1 -1
- package/tooling/web/reference.md +1 -1
- package/governance/rules/core/000-constitution.md +0 -30
- package/governance/rules/core/020-concurrency.md +0 -22
- package/governance/rules/core/030-error-handling.md +0 -31
- package/governance/rules/core/040-performance.md +0 -20
- package/governance/rules/core/050-logging.md +0 -20
- package/governance/rules/core/060-naming.md +0 -19
- package/governance/rules/snippets/600-at-references.md +0 -9
- /package/governance/rules/{core/025-indexes.md → canon/601-indexes.md} +0 -0
- /package/governance/rules/{core/035-tasks.md → canon/602-tasks.md} +0 -0
- /package/governance/rules/{core/045-memory.md → canon/603-memory.md} +0 -0
- /package/governance/rules/{core/055-scratch.md → canon/604-scratch.md} +0 -0
- /package/governance/rules/{core/085-worktrees.md → canon/605-worktrees.md} +0 -0
- /package/governance/rules/{core/087-git.md → canon/606-git.md} +0 -0
- /package/governance/rules/{claude/510-context.md → canon/610-context.md} +0 -0
- /package/governance/rules/{claude/511-indexes.md → canon/611-indexes.md} +0 -0
- /package/governance/rules/{claude/520-wireframes.md → canon/620-wireframes.md} +0 -0
- /package/governance/rules/{claude/530-requirements.md → canon/630-requirements.md} +0 -0
- /package/governance/rules/{claude/540-architecture.md → canon/640-architecture.md} +0 -0
- /package/governance/rules/{claude/545-decisions.md → canon/645-decisions.md} +0 -0
- /package/governance/rules/{claude/550-design.md → canon/650-design.md} +0 -0
- /package/governance/rules/{claude/556-groundwork.md → canon/656-groundwork.md} +0 -0
- /package/governance/rules/{claude/557-intake.md → canon/657-intake.md} +0 -0
- /package/governance/rules/{claude/558-plan.md → canon/658-plan.md} +0 -0
- /package/governance/rules/{claude/559-memory.md → canon/659-memory.md} +0 -0
- /package/governance/rules/{claude/561-teach.md → canon/661-teach.md} +0 -0
- /package/governance/rules/{claude/563-ready.md → canon/663-ready.md} +0 -0
- /package/governance/rules/{core/005-behavior.md → claude/565-behavior.md} +0 -0
- /package/governance/rules/{core/015-output.md → claude/566-output.md} +0 -0
- /package/governance/rules/{core/070-planning.md → claude/567-planning.md} +0 -0
- /package/governance/rules/{core → code}/010-testing.md +0 -0
- /package/governance/rules/{ci → tooling}/700-ci-workflow.md +0 -0
- /package/governance/rules/{core/065-spelling.md → tooling/765-spelling.md} +0 -0
- /package/governance/rules/{core/075-dependencies.md → tooling/775-dependencies.md} +0 -0
- /package/governance/rules/{core/080-config-comments.md → tooling/780-config-comments.md} +0 -0
- /package/governance/rules/{core/090-code-comments.md → tooling/790-code-comments.md} +0 -0
- /package/governance/rules/{claude/580-readme.md → writing/880-readme.md} +0 -0
- /package/governance/rules/{claude/591-standard-authoring.md → writing/891-standard-authoring.md} +0 -0
|
@@ -47,7 +47,7 @@ When the invocation argument is a plan path or a bare slug, name the worktree fr
|
|
|
47
47
|
|
|
48
48
|
Resolve `<plan>` in this order, stopping at the first match:
|
|
49
49
|
|
|
50
|
-
1. **Caller-supplied task.** The invocation carried a path under `.canon/tasks/`. If it does not resolve to a file, stop: `❌ No task at <path>. Path was supplied, not derived, so check it and re-run.` Read that task's first `Plan:` line and take what it names as `<plan>`, per `${CLAUDE_SKILL_DIR}/../../standards/tasks.md`, reading `${CLAUDE_SKILL_DIR}/references/tier-failures.md` first for how the pointer resolves and the
|
|
50
|
+
1. **Caller-supplied task.** The invocation carried a path under `.canon/tasks/`. If it does not resolve to a file, stop: `❌ No task at <path>. Path was supplied, not derived, so check it and re-run.` Read that task's first `Plan:` line and take what it names as `<plan>`, per `${CLAUDE_SKILL_DIR}/../../standards/tasks.md`, reading `${CLAUDE_SKILL_DIR}/references/tier-failures.md` first for how the pointer resolves and the four stops it can take.
|
|
51
51
|
2. **Caller-supplied plan.** The invocation carried something else. Accept it as a plan path or a bare slug, in the same position `session-worktree` tier 0 accepts its name. A bare slug resolves to `.canon/plans/feature-<slug>.md`, and a path is taken as given from the main worktree root. If it does not resolve to a file, stop: `❌ No plan at <path>. Path was supplied, not derived, so check it and re-run.`
|
|
52
52
|
3. **Derived.** `.canon/plans/feature-<slug>.md`, from the `<slug>` the Guards derived. If it does not exist, stop: `❌ No approved plan at .canon/plans/feature-<slug>.md, where <slug> was derived from the current branch, <branch>. The invocation carried no argument, so pass a plan or a task path, or run /plan-feature first.`
|
|
53
53
|
|
|
@@ -55,7 +55,7 @@ Only a path reaches tier 1, and a bare slug is read as a plan's throughout, sinc
|
|
|
55
55
|
|
|
56
56
|
### When a tier fails
|
|
57
57
|
|
|
58
|
-
Tier 1 stops
|
|
58
|
+
Tier 1 stops on a `Plan:` line linking several plans, on a task carrying none, and on a pointer into a plans archive or to no file. `${CLAUDE_SKILL_DIR}/references/tier-failures.md` carries the stop each one takes and the order the archive and existence tests run in.
|
|
59
59
|
|
|
60
60
|
Test the shape of whatever `<plan>` resolved to before reading it as one, after all three tiers, since a file resolving under any tier can still be the wrong document.
|
|
61
61
|
|
|
@@ -99,8 +99,6 @@ If the diff touches UI files (JSX, TSX, Vue, Svelte, HTML, or CSS under `src/`),
|
|
|
99
99
|
|
|
100
100
|
If `ui-checklist` produces a checklist, stop: `❌ UI requires visual verification. Checklist at .canon/tmp/handoff/ui-checklist/<slug>.md, which reaches the pull request once /git-ship runs. Verify manually, then run /git-ship.`
|
|
101
101
|
|
|
102
|
-
The stop is the only thing that makes the operator look before `git-ship`.
|
|
103
|
-
|
|
104
102
|
If there is nothing to verify visually and nothing shipping untested, continue.
|
|
105
103
|
|
|
106
104
|
## Step 6: review
|
|
@@ -137,7 +135,7 @@ Read origin as causation rather than authorship, so staleness this run induced i
|
|
|
137
135
|
|
|
138
136
|
Bound the repair at one pass, the way Step 3 bounds verify. When that re-read shows the finding still standing, stop: `❌ A self-introduced finding survived one fix pass. See .canon/review/branch-<slug>.md. Fix and run /git-ship.`
|
|
139
137
|
|
|
140
|
-
This chain owns the receipt's lifetime
|
|
138
|
+
This chain owns the receipt's lifetime. The `context-fold` sweep under Step 8 reaches only reports whose branch is gone, so it collects this one a branch later.
|
|
141
139
|
|
|
142
140
|
## Step 8: ship
|
|
143
141
|
|
|
@@ -145,22 +143,23 @@ Invoke `canon:git-ship`. That body owns the sequence, being the verify gate, mem
|
|
|
145
143
|
|
|
146
144
|
One thing this chain adds. Mark the pull request as a draft as soon as `git-ship`'s pull request step returns, ahead of its CI watch, naming the number that step returned rather than one resolved by branch. Read `${CLAUDE_SKILL_DIR}/references/draft-mark.md` on reaching that point for the one command that proves the target, marks it, and reads the flag back. A `false` read stops the chain, and never re-issue the mark on it.
|
|
147
145
|
|
|
148
|
-
`git-ship` verifies again at its own gate,
|
|
146
|
+
`git-ship` verifies again at its own gate, repeating Step 3 on a clean run. Keep that repeat, since a resumed run enters at that gate.
|
|
149
147
|
|
|
150
148
|
## Output
|
|
151
149
|
|
|
152
|
-
Respond with up to
|
|
150
|
+
Respond with up to five lines:
|
|
153
151
|
|
|
154
152
|
```plaintext
|
|
155
153
|
✅ Autoshipped (<state>): <PR url>
|
|
156
154
|
<N minor findings kept in .canon/review/branch-<slug>.md>
|
|
157
155
|
<N facts routed to context entries>
|
|
158
156
|
<N memories captured in .canon/memory/>
|
|
157
|
+
<the review line memory-capture returned>
|
|
159
158
|
```
|
|
160
159
|
|
|
161
160
|
`<state>` is whatever the Step 8 read returned, being `draft` or `ready, unsupervised`, rather than the state the undo asked for.
|
|
162
161
|
|
|
163
|
-
Omit the second line if there were no minor findings, and the third if nothing routed. Omit the fourth if `memory-capture` wrote no memory file this session.
|
|
162
|
+
Omit the second line if there were no minor findings, and the third if nothing routed. Omit the fourth if `memory-capture` wrote no memory file this session, and the fifth if it returned no review line. Pass that line through verbatim, since a dispatched worker's controller relays it to the operator.
|
|
164
163
|
|
|
165
164
|
This block replaces the one `git-ship` closes on rather than following it, since emitting both reports one run twice and buries the state under a `✅ Shipped` that does not name it.
|
|
166
165
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Tier 1 task reads
|
|
3
|
-
description: How auto-ship Step 1 resolves a caller-supplied task's Plan line to a plan, and the
|
|
3
|
+
description: How auto-ship Step 1 resolves a caller-supplied task's Plan line to a plan, and the four stops it takes when that line links several plans or its pointer is missing, archived, or resolves to no file
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Reading a task's plan pointer
|
|
@@ -9,14 +9,17 @@ Step 1 of `auto-ship`, tier 1. The session reads this file when the invocation c
|
|
|
9
9
|
|
|
10
10
|
## Reading the pointer
|
|
11
11
|
|
|
12
|
-
One plan per task is what makes the tier 1 read unambiguous, so it takes the first `Plan:` line and never scans for a second. A caller who means the task holds its path already, having read it off the board, which is why a bare slug never reaches this tier.
|
|
12
|
+
One plan per task is what makes the tier 1 read unambiguous, so it takes the first `Plan:` line outside a fenced sample and never scans for a second line or reads past a second link on that one. A caller who means the task holds its path already, having read it off the board, which is why a bare slug never reaches this tier.
|
|
13
13
|
|
|
14
|
-
Read the target out of the link's parentheses, and take the rest of the line when the line carries no link, since an older task writes the target as a plain path with nothing around it.
|
|
14
|
+
Read the target out of the link's parentheses, and take the rest of the line when the line carries no link, since an older task writes the target as a plain path with nothing around it. A bare line counts its leading run of tokens carrying `/` or ending in `.md` as targets and stops at the first word that is neither, so trailing prose after one path still names a single plan.
|
|
15
|
+
|
|
16
|
+
Resolve a relative target against the directory holding the task file rather than against `.canon/tasks/`, and take a project-root target from the root. The archived task is what makes that base matter, since the standard points its line at `../../plans/archive/feature-<slug>.md` once the task sits a folder deeper, and reading that from `.canon/tasks/` lands on a repository-root `plans/archive/` that never exists.
|
|
15
17
|
|
|
16
18
|
## When a tier fails
|
|
17
19
|
|
|
18
|
-
Tier 1 stops on
|
|
20
|
+
Tier 1 stops on four failures, and each names a different repair:
|
|
19
21
|
|
|
22
|
+
- The line links more than one plan. Stop: `❌ <path> links <N> plans on its Plan: line (<every target>), so the task does not say which one this run builds. Pass one plan path directly.` Test this ahead of the three below, since taking the first link runs whichever plan leads the line and reports success.
|
|
20
23
|
- No `Plan:` line at all. Stop: `❌ <path> carries no Plan: line, so nothing there names a plan to run. Write the plan and point the task at it, or pass the plan path directly.` A row still awaiting a plan is the ordinary case, so the message names the missing pointer rather than the missing plan sections a reader would then go hunting for.
|
|
21
24
|
- The pointer resolves into a plans archive. Stop: `❌ <path> points at an archived plan, which describes work that already shipped. Reopen the task against a live plan, or pass that plan directly.` Test the resolved path rather than the task's outcomes or its `Pull request:` line, since a stale board gets its ticks wrong and the standard fixes where a shipped pointer lands.
|
|
22
25
|
- The pointer resolves to no file. Stop: `❌ <path> points at <target>, which does not exist. The citation is stale, so repoint the task or pass the plan path directly.`
|
|
@@ -7,7 +7,7 @@ description: Files a measured verdict for every backlog row into an intake folde
|
|
|
7
7
|
|
|
8
8
|
A backlog only grows while nothing can decline a row. This pass reads every row against the current tree, files one verdict per row for the operator, and later applies what they approved.
|
|
9
9
|
|
|
10
|
-
The record is an ordinary intake folder at `.canon/intake/<nn>-backlog-triage/`. Read `${CLAUDE_SKILL_DIR}/../../standards/intake.md` before writing any file in it, since it holds the item format, the frontmatter, the index shape, and the answer contract this skill is bound by. Read `${CLAUDE_SKILL_DIR}/../../standards/tasks.md` before applying, since
|
|
10
|
+
The record is an ordinary intake folder at `.canon/intake/<nn>-backlog-triage/`. Read `${CLAUDE_SKILL_DIR}/../../standards/intake.md` before writing any file in it, since it holds the item format, the frontmatter, the index shape, and the answer contract this skill is bound by. Read `${CLAUDE_SKILL_DIR}/../../standards/board.md` and `${CLAUDE_SKILL_DIR}/../../standards/tasks.md` before applying, since the first holds the backlog and the ordering file and the second holds the `Declined:` line.
|
|
11
11
|
|
|
12
12
|
## Guards
|
|
13
13
|
|
|
@@ -30,7 +30,7 @@ Sharpening the rules does not reach the decision. Both were loaded and neither w
|
|
|
30
30
|
- Carry a hard file-count threshold. A command folder holding sixty files of one role reads fine flat, and a number would fail it.
|
|
31
31
|
- Restate the layer rule, the layer table, or the final filter `test-craft` owns
|
|
32
32
|
- Mandate one layout across projects, such as a `features/` tree, over the project's own strategy
|
|
33
|
-
- Restate the
|
|
33
|
+
- Restate the pointer in `000-code`, which loads in code stacks only. The rule points here and this body carries the depth.
|
|
34
34
|
|
|
35
35
|
## Guards
|
|
36
36
|
|
|
@@ -53,5 +53,5 @@ Read `${CLAUDE_SKILL_DIR}/references/adopted.md` only when extending this guidan
|
|
|
53
53
|
|
|
54
54
|
- Which layer a test belongs at: `test-craft`. This skill decides where the test file sits once its layer is chosen.
|
|
55
55
|
- Where a new path gets written into a plan, and the plan's shape: `plan-feature` and the plan standard
|
|
56
|
-
- The
|
|
56
|
+
- The pointer here that every session of a code stack loads: `000-code`
|
|
57
57
|
- Runner, suffix, and top-level test folder conventions per language: `300-testing-ts`, `330-testing-py`, `335-testing-go`, and `336-testing-php`
|
|
@@ -23,12 +23,15 @@ Resolve both from the request, and ask only for what is missing. Attach a propos
|
|
|
23
23
|
|
|
24
24
|
Pick the subdir from the topic. It sits under `.claude/rules/project/` and names the rule's domain:
|
|
25
25
|
|
|
26
|
-
- `
|
|
26
|
+
- `code/`: code placement, errors, naming, testing.
|
|
27
27
|
- `lang/`: one programming language.
|
|
28
28
|
- `framework/`: one framework.
|
|
29
29
|
- `lib/`: one library or tool.
|
|
30
30
|
- `ui/`: UI copy, accessibility, forms.
|
|
31
|
-
- `claude/`: `.claude/` authoring surfaces.
|
|
31
|
+
- `claude/`: session conduct and `.claude/` authoring surfaces.
|
|
32
|
+
- `canon/`: the toolkit workflow and its record folders.
|
|
33
|
+
- `tooling/`: dev setup, such as CI workflows, dependencies, and config.
|
|
34
|
+
- `writing/`: prose and document shape.
|
|
32
35
|
|
|
33
36
|
## Step 3: pick a free number
|
|
34
37
|
|
|
@@ -44,7 +44,7 @@ Two worked examples:
|
|
|
44
44
|
|
|
45
45
|
The read fixes the kind, which decides which rules apply, and names the layer, which decides what may vary. A round that cannot state its read has not decided what it is doing.
|
|
46
46
|
|
|
47
|
-
Put the read to the operator through the structured question surface where it genuinely forks, per `
|
|
47
|
+
Put the read to the operator through the structured question surface where it genuinely forks, per `565-behavior`. Where context settles it, declare and proceed rather than asking.
|
|
48
48
|
|
|
49
49
|
## The layers, and the order they settle
|
|
50
50
|
|
|
@@ -50,4 +50,4 @@ Without this skill, a session holding finished files that hands them to a worker
|
|
|
50
50
|
- `role-worker` copies the folder into a worktree and ships it. This stops once the three artifacts exist.
|
|
51
51
|
- `task-board` creates a task file for a row with no ready folder. This writes the row it needs beside the folder and calls the same verbs.
|
|
52
52
|
- `git-ship` ships a branch, and a ready folder never reaches one.
|
|
53
|
-
- `standards/ready.md` owns the folder's shape and lifecycle, and this skill owns the procedure that produces it, the way `write-human` and `
|
|
53
|
+
- `standards/ready.md` owns the folder's shape and lifecycle, and this skill owns the procedure that produces it, the way `write-human` and `800-prose` split.
|
|
@@ -75,7 +75,7 @@ canon tasks plan-link <task-stem> .canon/plans/feature-<slug>.md --json
|
|
|
75
75
|
|
|
76
76
|
Branch on the record rather than on the exit. The `Ready:` line orients a worker reading the task, and `canon tasks archive` reads it to move the folder on ship.
|
|
77
77
|
|
|
78
|
-
A task file with no row is a dropped task, so place the row in the same pass. The plan exists, so the row takes `## Run now` when `canon tasks plan-reach` reports nothing claimed and `## Up next` otherwise, with the held path in its `Waiting on` cell, per the tests in `${CLAUDE_SKILL_DIR}/../../standards/
|
|
78
|
+
A task file with no row is a dropped task, so place the row in the same pass. The plan exists, so the row takes `## Run now` when `canon tasks plan-reach` reports nothing claimed and `## Up next` otherwise, with the held path in its `Waiting on` cell, per the tests in `${CLAUDE_SKILL_DIR}/../../standards/board.md`. Check the roster the way `canon:task-board` Step 4 does, reading `canon sessions list --self --json` for this session and `canon sessions list --json` for a row from the same repository, under another `sessionId`, whose `name` starts with `orchestrator-`. Treat a refused read as a roster read that failed.
|
|
79
79
|
|
|
80
80
|
- **Orchestrator found.** Write neither file. Message that session with the row's title, the plan link, and the group with its reason, so it places the row itself rather than two sessions writing the board at once.
|
|
81
81
|
- **Not found, and this session's name starts with `worker-` or `planner-`.** Write neither file, since both role bodies ban a board write with no exception. Report the row and its group in Step 8.
|
|
@@ -49,14 +49,15 @@ Capture leads the sequence because a routed fact lands in a context entry, which
|
|
|
49
49
|
|
|
50
50
|
## After completion
|
|
51
51
|
|
|
52
|
-
Output up to
|
|
52
|
+
Output up to four lines:
|
|
53
53
|
|
|
54
54
|
```plaintext
|
|
55
55
|
✅ Shipped
|
|
56
56
|
<N facts routed to context entries>
|
|
57
57
|
<N memories captured in .canon/memory/>
|
|
58
|
+
<the review line memory-capture returned>
|
|
58
59
|
```
|
|
59
60
|
|
|
60
|
-
Omit the second line if nothing routed
|
|
61
|
+
Omit the second line if nothing routed, the third if `memory-capture` wrote no memory file this session, and the fourth if `memory-capture` returned no review line. Pass that line through verbatim rather than restating it.
|
|
61
62
|
|
|
62
|
-
Emit nothing here when a wrapping caller states it closes on its own block. `auto-ship` is that caller and its block carries these same
|
|
63
|
+
Emit nothing here when a wrapping caller states it closes on its own block. `auto-ship` is that caller and its block carries these same three trailing lines below a first line naming the draft state, so emitting both reports one run twice. A caller that states no such thing gets this block, which is every direct invocation.
|
|
@@ -16,7 +16,7 @@ The filename and its type prefix, the frontmatter, the body shape each type carr
|
|
|
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
|
-
- If the session produced no user corrections, confirmations, or context disclosures worth persisting, stop: `✅ Nothing worth capturing
|
|
19
|
+
- If the session produced no user corrections, confirmations, or context disclosures worth persisting, run Step 6 and stop: `✅ Nothing worth capturing.`, followed by the review line when Step 6 counted one batch due.
|
|
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.
|
|
21
21
|
|
|
22
22
|
## Step 1: read context
|
|
@@ -68,7 +68,7 @@ The handoff is a file rather than a spoken result so the routed fact survives a
|
|
|
68
68
|
|
|
69
69
|
## Step 4: dedupe
|
|
70
70
|
|
|
71
|
-
For each remaining candidate, grep the top-level `*.md` files in `.canon/memory/` for an existing file on the same topic, never its `review/` or `archive/` subfolders, since a hit there is a receipt or a retired entry rather than a live one to update. If one exists, update it in place rather than create a new file. Read it first and write the whole file back, since the guard above rules out editing a line inside it.
|
|
71
|
+
For each remaining candidate, grep the top-level `*.md` files in `.canon/memory/` for an existing file on the same topic, never its `review/` or `archive/` subfolders, since a hit there is a receipt or a retired entry rather than a live one to update. If one exists, update it in place rather than create a new file. Read it first and write the whole file back, since the guard above rules out editing a line inside it. Carry a `reviewed` field through the rewrite untouched, since dropping it sends a kept entry back to the front of the review queue.
|
|
72
72
|
|
|
73
73
|
## Step 5: write the residue
|
|
74
74
|
|
|
@@ -86,6 +86,14 @@ canon indexes regen --no-stage --root <main-root> <main-root>/.canon/memory/inde
|
|
|
86
86
|
|
|
87
87
|
Run `canon records validate memory` when the writes are done and fix what it names. It reads the whole pen rather than this session's writes, so treat a finding on a carried entry as one to fix in place rather than as a reason to stop.
|
|
88
88
|
|
|
89
|
+
## Step 6: count what review owes
|
|
90
|
+
|
|
91
|
+
Run `canon records stale memory --json` and count the entries whose `due` is true, and among them the ones carrying a non-empty `unresolved` list. Branch on the record rather than on the exit, which a shell function wrapping `canon` can flatten to zero. When the count reaches 25, one `memory-review` batch, the Output below adds the review line. Below that, add nothing.
|
|
92
|
+
|
|
93
|
+
Stay silent when the record refuses or the installed binary carries no `records stale` subcommand. This step reports and never stops the capture.
|
|
94
|
+
|
|
95
|
+
The line fires on a count rather than on every run. An unconditional prompt after each ship was tried and removed, since a review per ship costs more than it drains, and a hook would reach every session including workers that cannot act on it.
|
|
96
|
+
|
|
89
97
|
## Output
|
|
90
98
|
|
|
91
99
|
Respond with one line per fact routed, written, or updated:
|
|
@@ -100,6 +108,8 @@ When anything routed, add a line naming the handoff so the caller knows a `conte
|
|
|
100
108
|
|
|
101
109
|
Omit that line when the caller runs `context-fold` itself later in its own chain.
|
|
102
110
|
|
|
103
|
-
|
|
111
|
+
When Step 6 counted at least one batch due, add the review line last:
|
|
112
|
+
|
|
113
|
+
`→ <n> memory entries due for review, <m> citing a moved path. Run /canon:memory-review.`
|
|
104
114
|
|
|
105
|
-
`✅ Nothing worth capturing
|
|
115
|
+
If nothing was captured, output `✅ Nothing worth capturing.`, followed by the review line when Step 6 counted one batch due.
|
|
@@ -9,11 +9,13 @@ description: What memory review is for, the gaps it closes, and why every action
|
|
|
9
9
|
|
|
10
10
|
Without this skill, the memory folder grows and never drains. Entries pile up restating rules a durable surface already carries, nothing decides which memory has earned a place in one, and a rule that does get promoted arrives verbatim in a file whose voice it does not match. The folder then reads as a second source of truth that no surface points at.
|
|
11
11
|
|
|
12
|
-
A pen
|
|
12
|
+
A pen too large to review whole is the same gap wearing a different shape. Routing at capture takes the domain facts and whatever the ownership test leaves stays, in whatever mix of types that is, so the folder reaches a size no single pass can read: every entry plus every promotion target runs to hundreds of thousands of tokens before one entry is classified. A review that cannot run drains nothing however often someone asks for it, so the pass takes a bounded batch in the order the stale verb reports and reads targets per entry. An entry leaving the pen is archived rather than deleted, because a folder git does not hold gives a wrong bulk call no undo.
|
|
13
13
|
|
|
14
14
|
## Must
|
|
15
15
|
|
|
16
|
-
- Treat the folder as a holding pen, so every entry in scope leaves it as a promotion, a handoff, or an archive
|
|
16
|
+
- Treat the folder as a holding pen, so every entry in scope leaves it as a promotion, a handoff, or an archive, or stays only as a kept entry stamped with the date it was reviewed
|
|
17
|
+
- Take one bounded batch per pass in the order `canon records stale memory` reports, and stop rather than falling back to a full sweep when that verb is absent
|
|
18
|
+
- Stamp `reviewed` on every entry a pass keeps or skips, so the next batch moves on to entries nobody has read
|
|
17
19
|
- Archive an entry out of the pen rather than deleting it, since nothing recovers a file from a gitignored folder
|
|
18
20
|
- Hand a fact a context entry owns to `context-fold` through the routing file, rather than editing the entry here
|
|
19
21
|
- Verify the rule is not already stated or implied in the target before proposing a promotion, by reading the target rather than trusting the memory's claim about it
|
|
@@ -34,18 +34,23 @@ Propose is the entry point for a standalone run. The ship skills stop at capture
|
|
|
34
34
|
|
|
35
35
|
### Scope
|
|
36
36
|
|
|
37
|
-
- **
|
|
37
|
+
- **Batch:** run `canon records stale memory --json` and take the first 25 entries whose `due` is true, in the order the record lists them. When fewer than 25 are due, take all of them and say so. Never pad a batch with an entry that is not due.
|
|
38
|
+
- **Named set:** when the user names entries, a list, or a slug, that set is the scope and overrides the verb's order. Propose nothing outside it.
|
|
39
|
+
|
|
40
|
+
A whole pen does not fit one pass. Every entry plus every promotion target reads as several hundred thousand tokens on a grown project, so a full sweep fails before it classifies anything. The batch is bounded by the receipt the operator approves, which stays short enough for one pass at 25 items.
|
|
41
|
+
|
|
42
|
+
Branch on the record rather than on the exit, which a shell function wrapping `canon` can flatten to zero. When the installed binary carries no `records stale` subcommand, or the record comes back with `ok: false`, stop: `❌ canon records stale is missing or refused. Update the canon CLI, since a review without it falls back to a full sweep that cannot run.` Never fall back to reading the whole pen.
|
|
38
43
|
|
|
39
44
|
### Step 1: read the memory folder
|
|
40
45
|
|
|
41
46
|
Read in parallel from the project root:
|
|
42
47
|
|
|
43
|
-
- `.canon/memory/index.md`: the generated index
|
|
44
|
-
-
|
|
48
|
+
- `.canon/memory/index.md`: the generated index, which is what lets a batch entry find a duplicate outside the batch
|
|
49
|
+
- each entry in the batch, by name, never its `review/` or `archive/` subfolders: individual entries with frontmatter (`title`, `description`, `category`, and `reviewed` when a past pass kept it)
|
|
45
50
|
|
|
46
|
-
### Step 2:
|
|
51
|
+
### Step 2: search promotion targets per entry
|
|
47
52
|
|
|
48
|
-
|
|
53
|
+
Do not read every target up front. For each entry in the batch, grep the target set below for the entry's subject, taking two or three keywords from its title and rule, and read the files that hit. Read `canon/context/index.md` once for the **Promote to a context entry** route. Skip any file or folder that does not exist.
|
|
49
54
|
|
|
50
55
|
- `CLAUDE.md`: project behavior rules and Content ownership section, still a read target for the absorbed-already check even though it takes no new promotion
|
|
51
56
|
- every `SKILL.md` under `.claude/skills/`: domain-scoped internal skill bodies
|
|
@@ -54,16 +59,20 @@ Read in parallel from the project root. Skip any file or folder that does not ex
|
|
|
54
59
|
- every `*.md` under `governance/rules/` in the toolkit repo, or `.claude/rules/` in a target project: coding-standards rules
|
|
55
60
|
- every `*.md` under `internal/rules/` in the toolkit repo, or `.claude/rules/project/` in a target project: always-loaded rules a promote lands in
|
|
56
61
|
|
|
62
|
+
A target the grep missed turns a promote into a retire, and only the operator's pass catches that. Name the targets each item searched in its receipt entry so the miss is visible there.
|
|
63
|
+
|
|
57
64
|
### Step 3: classify each entry
|
|
58
65
|
|
|
59
|
-
`.canon/memory/` is a holding pen. Default every entry to promote or retire on review.
|
|
66
|
+
`.canon/memory/` is a holding pen. Default every entry to promote or retire on review. Keep is the exception, reserved for an entry still true that no surface owns, such as active task overlap or a user-type memory with no in-repo target.
|
|
67
|
+
|
|
68
|
+
An entry's `unresolved` list in the stale record names paths it cites that the tree no longer holds. Weigh it as evidence for **Retire**, or for a rewrite when the rule survives the move, and never read it as the verdict alone. A rule can outlive the file it happened to name.
|
|
60
69
|
|
|
61
70
|
`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
71
|
|
|
63
72
|
For each in-scope entry (see Scope), pick one action:
|
|
64
73
|
|
|
65
74
|
- **Promote to an always-loaded rule**: the rule is cross-domain behavior or a design principle applied across the whole project, passing `592-claude-md.md`'s test (applies every session regardless of what is being edited). Do not author a toolkit rule file inline.
|
|
66
|
-
- In the toolkit repo, hand off to `internal-governance` and `${CLAUDE_SKILL_DIR}/../../standards/rule.md`, which own `internal/rules
|
|
75
|
+
- In the toolkit repo, hand off to `internal-governance` and `${CLAUDE_SKILL_DIR}/../../standards/rule.md`, which own `internal/rules/` (this repo only, never ships) and the audience group under `governance/rules/` the rule serves (ships to every target that group reaches).
|
|
67
76
|
- 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
77
|
- **Promote to a skill body**: the rule fires only when editing a specific path-scoped domain. Name the target skill.
|
|
69
78
|
- **Promote to a standards file**: the rule is an authoring reference that belongs in the project's own standards folder as `<domain>.md`.
|
|
@@ -72,6 +81,7 @@ For each in-scope entry (see Scope), pick one action:
|
|
|
72
81
|
- 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
82
|
- In a target project, point the user at the `create-rule` skill, which scaffolds a project-local rule under `.claude/rules/`.
|
|
74
83
|
- **Retire**: the rule is stale, already absorbed into a durable surface, too vague to phrase as a rule, or a one-time incident narrative. Apply moves the file to `.canon/memory/archive/` rather than deleting it.
|
|
84
|
+
- **Keep**: the rule is still true and no durable surface owns it. The entry stays in the pen, and Apply stamps `reviewed` so the verb does not queue it again until the window lapses.
|
|
75
85
|
|
|
76
86
|
Retire is an archive, not a deletion, which `${CLAUDE_SKILL_DIR}/../../standards/memory.md` states as the rule and this skill executes. The archive is worth less than a plan's, since a promoted entry survives in its destination and a stale one is discarded on purpose, which is why the move is cheap rather than free.
|
|
77
87
|
|
|
@@ -111,6 +121,7 @@ Output one line per action taken in the most recent phase:
|
|
|
111
121
|
- `✅ Handed off: .canon/memory/<memory-file> → governance`
|
|
112
122
|
- `📦 Retired: .canon/memory/<memory-file> → .canon/memory/archive/`
|
|
113
123
|
- `🗑 Swept: .canon/review/<review-file>, folded <n> skips`
|
|
124
|
+
- `📌 Kept: .canon/memory/<memory-file>, reviewed <date>`
|
|
114
125
|
- `⏭ Kept: .canon/review/<review-file>, <n> items pending`
|
|
115
126
|
|
|
116
127
|
If the user accepted nothing, output: `✅ No changes applied.`
|
|
@@ -44,14 +44,14 @@ Before applying any item, check the worktree state:
|
|
|
44
44
|
|
|
45
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
46
|
|
|
47
|
-
Before applying a promote to an always-loaded rule in the toolkit repo, load `internal-governance`, which owns `internal/rules
|
|
47
|
+
Before applying a promote to an always-loaded rule in the toolkit repo, load `internal-governance`, which owns `internal/rules/` and `governance/rules/` 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
48
|
|
|
49
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
50
|
|
|
51
51
|
For each item, parse the `Decision:` line:
|
|
52
52
|
|
|
53
53
|
- `apply` (or affirmative): run the proposed action, flip emoji to ✅.
|
|
54
|
-
- `skip`: leave the memory in place, flip emoji to ⏭.
|
|
54
|
+
- `skip`: leave the memory in place, stamp it reviewed as below, flip emoji to ⏭.
|
|
55
55
|
- `defer` or empty: leave 📝 pending, take no action.
|
|
56
56
|
- Contains `?` or unrecognized verb: leave 📝 pending, take no action. Do not respond. Discussion is the Discuss phase's job.
|
|
57
57
|
|
|
@@ -63,10 +63,13 @@ Action by action type:
|
|
|
63
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
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
65
|
- **Retire**: archive the memory file.
|
|
66
|
+
- **Keep**: stamp the memory file reviewed as below, and flip the emoji to 📌.
|
|
67
|
+
|
|
68
|
+
Stamping means writing `reviewed: <today>` as a `YYYY-MM-DD` date into the entry's frontmatter, replacing any earlier value, and changing nothing else in the file. The entry is main-root scratch, so the stamp goes out as the same whole-file heredoc rewrite the Guards state. Stamp only an entry that stays in the pen, being a keep or a skip. A promote or a retire takes no stamp, since the entry leaves for the archive. The stamp is what takes a kept entry off the front of `canon records stale memory`'s queue, so an entry kept without one returns in the next batch.
|
|
66
69
|
|
|
67
70
|
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
71
|
|
|
69
|
-
Do not hand-edit `.canon/memory/index.md`. Once every archive move is done, regenerate it instead:
|
|
72
|
+
Do not hand-edit `.canon/memory/index.md`. Once every archive move and stamp is done, regenerate it instead:
|
|
70
73
|
|
|
71
74
|
```bash
|
|
72
75
|
canon indexes regen --no-stage --root <main-root> <main-root>/.canon/memory/index.md
|
|
@@ -78,7 +81,7 @@ Apply promotion edits one at a time via `Edit`. Claude Code's tool permission di
|
|
|
78
81
|
|
|
79
82
|
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
83
|
|
|
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.
|
|
84
|
+
As each item resolves, update its status in the review file: flip the H2 emoji from 📝 to ✅ for applied, ⏭ for skipped, 📦 for retired, 📌 for kept, 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
85
|
|
|
83
86
|
**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
87
|
|
|
@@ -16,9 +16,11 @@ Do not include a `Take:` slot in the template. Discuss inserts one directly unde
|
|
|
16
16
|
````plaintext
|
|
17
17
|
# Memory review: <slug>
|
|
18
18
|
|
|
19
|
+
**Batch:** <n> of <due> due entries, in `canon records stale memory` order. <due minus n> stay due after this batch.
|
|
20
|
+
|
|
19
21
|
**Pending:** <all numbers>
|
|
20
22
|
|
|
21
|
-
Legend: ✅ applied · ⏭ skipped · 📦 retired · 🤝 handed off · 📝 pending
|
|
23
|
+
Legend: ✅ applied · ⏭ skipped · 📦 retired · 📌 kept · 🤝 handed off · 📝 pending
|
|
22
24
|
|
|
23
25
|
How to respond: fill in `Decision:` per item (`apply`, `skip`, `defer`, or a question with `?`), then re-ping the skill. Say "discuss" for question rounds, "apply" to commit. Chat shortcut: `all`, `none`, or a list of numbers.
|
|
24
26
|
|
|
@@ -28,6 +30,8 @@ How to respond: fill in `Decision:` per item (`apply`, `skip`, `defer`, or a que
|
|
|
28
30
|
|
|
29
31
|
Why: <one-line pulled from the memory's Why>
|
|
30
32
|
|
|
33
|
+
Searched: <the targets the grep hit and read>
|
|
34
|
+
|
|
31
35
|
```diff
|
|
32
36
|
+ <rewritten rule text>
|
|
33
37
|
```
|
|
@@ -38,11 +42,23 @@ Decision:
|
|
|
38
42
|
|
|
39
43
|
`<memory-file>`
|
|
40
44
|
|
|
41
|
-
Reason: <one-line reason>
|
|
45
|
+
Reason: <one-line reason, naming any unresolved path the stale record listed>
|
|
46
|
+
|
|
47
|
+
Searched: <the targets the grep hit and read>
|
|
48
|
+
|
|
49
|
+
Decision:
|
|
50
|
+
|
|
51
|
+
## 3. 📝 Keep
|
|
52
|
+
|
|
53
|
+
`<memory-file>`
|
|
54
|
+
|
|
55
|
+
Reason: <one-line reason no surface owns the rule>
|
|
56
|
+
|
|
57
|
+
Searched: <the targets the grep hit and read>
|
|
42
58
|
|
|
43
59
|
Decision:
|
|
44
60
|
````
|
|
45
61
|
|
|
46
62
|
## Variation by action
|
|
47
63
|
|
|
48
|
-
For Hand off items, the body is a pointer to the governance target instead of a rewritten rule: `internal-governance` and `${CLAUDE_SKILL_DIR}/../../standards/rule.md` in the toolkit repo, or the `create-rule` skill in a target project. For a Promote to an always-loaded rule item, the H2 target names the rule file path the rule lands in, `<target>` in the template above, being an existing path under `internal/rules
|
|
64
|
+
For Hand off items, the body is a pointer to the governance target instead of a rewritten rule: `internal-governance` and `${CLAUDE_SKILL_DIR}/../../standards/rule.md` in the toolkit repo, or the `create-rule` skill in a target project. For a Promote to an always-loaded rule item, the H2 target names the rule file path the rule lands in, `<target>` in the template above, being an existing path under `internal/rules/` or `governance/rules/` in the toolkit repo, or under `.claude/rules/project/` in a target project, or the `create-rule` pointer when no existing file fits. For Retire and Keep items, skip the rewrite block. A batch holding fewer than 25 entries says so in the `**Batch:**` line, and a scope the user named replaces that line with `**Batch:** named by the user, <n> entries`. Every item gets a `Decision:` slot regardless of action. `Take:` is added only when a question response is needed.
|
|
@@ -35,7 +35,7 @@ Then output the state of play so the human knows what to launch, review, and mer
|
|
|
35
35
|
|
|
36
36
|
`priority.md` is the ordering source. `index.md` sorts by filename and says nothing about order, so read the sequence from the first and never infer it from the second. When `priority.md` is absent, report the queue and say the order is unrecorded.
|
|
37
37
|
|
|
38
|
-
Row position under `## Needs a plan` is what gets planned next, top first, per `${CLAUDE_SKILL_DIR}/../../standards/
|
|
38
|
+
Row position under `## Needs a plan` is what gets planned next, top first, per `${CLAUDE_SKILL_DIR}/../../standards/board.md`. `backlog.md` carries what nobody is scheduling and is explicitly unordered, so read it for what exists and never as a queue. Report a backlog count rather than its rows, since listing them puts the length back in front of the reader the cut took it away from. This read reports how many rows exist and nothing about whether each still belongs there. `references/orchestrator-parked.md` is what re-tests a backlog row's currency, on its own trigger below.
|
|
39
39
|
|
|
40
40
|
No surface carries cross-version sequencing, so report none. A row's `Waiting on` cell states why that row sits where it does, and reasoning spanning several rows reaches this session only through whoever remembers it. Say nothing about an active version, since nothing in the tree states one and a version asserted from the board is the unsourced claim this omission exists against.
|
|
41
41
|
|
|
@@ -85,7 +85,7 @@ The tracked-file boundary collides with `CLAUDE.md`, which says to handle a smal
|
|
|
85
85
|
|
|
86
86
|
Record a change identified while orchestrating against the task that owns it, fold one no task owns into the next task touching the same surface, and file a task only when no such task exists or is expected. Run `review-branch` when the boundary is crossed anyway, since a branch-diff pass is not independent and is the only check a self-authored change can get.
|
|
87
87
|
|
|
88
|
-
Filing a row states the defect and the surface it was seen on, and stops there. The extent and the cause belong to whoever plans it, so a row names neither a count of how far the defect reaches nor the mechanism behind it. Say in a plain sentence in the task file that the count was not taken, where the row's shape invites one, rather than in a marker of any prescribed form. The board's own cell has no room for it, since `${CLAUDE_SKILL_DIR}/../../standards/
|
|
88
|
+
Filing a row states the defect and the surface it was seen on, and stops there. The extent and the cause belong to whoever plans it, so a row names neither a count of how far the defect reaches nor the mechanism behind it. Say in a plain sentence in the task file that the count was not taken, where the row's shape invites one, rather than in a marker of any prescribed form. The board's own cell has no room for it, since `${CLAUDE_SKILL_DIR}/../../standards/board.md` caps a `Waiting on` cell at two clauses.
|
|
89
89
|
|
|
90
90
|
A finding placed into another task's `## Findings` is filing under a second name and takes the same rule. An unverified cause costs more than an unverified count, since a count fails loudly at the first re-measurement while a mechanism nobody opened the module to check sends real work in the wrong direction.
|
|
91
91
|
|
|
@@ -17,7 +17,7 @@ The sweep's own question stays distinct from this one. It asks which parked row
|
|
|
17
17
|
|
|
18
18
|
Every row under `## Up next` and `## Needs a plan` in `.canon/tasks/priority.md`. A `## Run now` row carries no blocker by definition, so the pass skips it. On the idle trigger, also every row in `.canon/tasks/backlog.md` when the file exists, per the trigger split above. Resolve the board, the backlog, and each task file at the main worktree root, the way `session-worktree` does.
|
|
19
19
|
|
|
20
|
-
Take the board rows in board order and finish one before opening the next. Clearing a row changes what the next row collides with, so a pass that measures every row first and writes afterwards writes against a board it has already invalidated. On the idle trigger, walk the backlog after the board, in the file's own filename order, since `${CLAUDE_SKILL_DIR}/../../standards/
|
|
20
|
+
Take the board rows in board order and finish one before opening the next. Clearing a row changes what the next row collides with, so a pass that measures every row first and writes afterwards writes against a board it has already invalidated. On the idle trigger, walk the backlog after the board, in the file's own filename order, since `${CLAUDE_SKILL_DIR}/../../standards/board.md` fixes that file as unordered and nothing about a row's position there means anything to preserve mid-pass.
|
|
21
21
|
|
|
22
22
|
## Re-testing a row
|
|
23
23
|
|
|
@@ -35,7 +35,7 @@ Write the result into the row. A re-test reported in chat is lost at the next co
|
|
|
35
35
|
|
|
36
36
|
## Re-testing a backlog row
|
|
37
37
|
|
|
38
|
-
A backlog row carries no blocker cell, since `${CLAUDE_SKILL_DIR}/../../standards/
|
|
38
|
+
A backlog row carries no blocker cell, since `${CLAUDE_SKILL_DIR}/../../standards/board.md` fixes `backlog.md` as a flat list of links with no state of its own. The five kinds above test what a blocker names, and a backlog row names none, so this pass asks the board-or-backlog question the standard already states instead: has the work in front of the row landed, or has the world changed under it. Read the answer from the task file's own `## Findings` and its origin line (`Plan:`, `Groundwork:`, `Intake:`, or `Issue:`), which name what the row was filed against and whether the fact behind it still holds.
|
|
39
39
|
|
|
40
40
|
Clearing a row answers yes to that question. It is not a count of how long the row has waited: `## Two results that are not a re-test` below refuses age as evidence for a board row, and it refuses it here on the same ground, since a row untouched for weeks is not more clearable than one added yesterday.
|
|
41
41
|
|
|
@@ -14,13 +14,14 @@ Read these in parallel, skipping any that do not exist:
|
|
|
14
14
|
- the newest `.canon/compact/*.md`, then the newest `.canon/tasks/session-*.md`: the handoff a previous session wrote before a compaction. The first is the note `session-compact` writes, and the second is the board-side map per `${CLAUDE_SKILL_DIR}/../../standards/session.md`, which stays readable. Whichever exists leads the report rather than the reads, and both lead it when both exist.
|
|
15
15
|
- `.canon/tasks/index.md`: the folder catalog. Read this before any individual task file, and take the task list from it by dropping the `index`, `priority`, `backlog`, and `session-` rows, which are siblings rather than tasks.
|
|
16
16
|
- `.canon/plans/*.md`: execution detail for in-progress tasks
|
|
17
|
-
- `.canon/memory/index.md` and any memory files relevant to the top backlog item
|
|
18
17
|
|
|
19
18
|
Then read only the task files the summary needs, typically the top one. Do not read the whole folder.
|
|
20
19
|
|
|
20
|
+
Once the top task is known, grep `.canon/memory/index.md` for two or three terms from its title and read at most three of the entries whose rows match. Never read the index whole, since a grown pen's index runs to hundreds of rows and the report shows three at most. With no top task, or no row matching, read no memory entry and say nothing about it.
|
|
21
|
+
|
|
21
22
|
Most projects carry no handoff. Say nothing about its absence, since a line reporting it every run trains a reader to skip the line on the run where a handoff exists.
|
|
22
23
|
|
|
23
|
-
If
|
|
24
|
+
If the handoff, task, and plan surfaces are all absent or empty, stop: `✅ No tracked work found. Start a new task.`
|
|
24
25
|
|
|
25
26
|
## Step 2: summarize
|
|
26
27
|
|
|
@@ -32,7 +33,7 @@ Output these sections, omitting the first when no handoff was found:
|
|
|
32
33
|
|
|
33
34
|
**Active plans:** one line per file in `.canon/plans/`, linking each to its task file in `.canon/tasks/`. Say "None" if empty.
|
|
34
35
|
|
|
35
|
-
**Relevant context:**
|
|
36
|
+
**Relevant context:** the memory entries Step 1 matched to the top backlog item, three at most. Skip if none matched.
|
|
36
37
|
|
|
37
38
|
## Step 3: recommend
|
|
38
39
|
|
|
@@ -47,7 +47,7 @@ Write it immediately. Claude Code's tool permission dialog is the confirmation g
|
|
|
47
47
|
|
|
48
48
|
A task file with no row is a dropped task, so name the surface it lands on in the same pass that creates it. A task that would plausibly be planned within the next few waves takes a row under `## Needs a plan` in `.canon/tasks/priority.md`, positioned by where it sits against the rows already there, with the reason for that position in its `Waiting on` cell. Anything else takes a line in `.canon/tasks/backlog.md`, which is unordered and where in the file it goes means nothing.
|
|
49
49
|
|
|
50
|
-
The test and both file shapes are in `${CLAUDE_SKILL_DIR}/../../standards/
|
|
50
|
+
The test and both file shapes are in `${CLAUDE_SKILL_DIR}/../../standards/board.md`.
|
|
51
51
|
|
|
52
52
|
Check the roster for a live orchestrator before writing either file. Read `canon sessions list --self --json` for this session's own `sessionId` and `name`, then read `canon sessions list --json` and match a row whose `repository` matches this session's own, whose `sessionId` differs from it, and whose `name` starts with `orchestrator-`. That is the convention every hand-launched controller on this machine currently uses, and it excludes every `worker-` and `planner-` session cleanly. Treat a refusal from either call the same as a roster read that failed.
|
|
53
53
|
|
|
@@ -33,7 +33,7 @@ canon tasks archive <stem> --json
|
|
|
33
33
|
|
|
34
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
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 `
|
|
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 `plans`, one `from` and `to` for each live plan the task was the last live citation of, in the order its `Plan:` line links them. An empty `plans` means the task cited no live plan, or that a sibling still holds every one it cited.
|
|
37
37
|
|
|
38
38
|
## Step 3: route on a refusal
|
|
39
39
|
|
|
@@ -25,7 +25,7 @@ canon tasks decline <stem> --reason "<text>" [--by <name>] --json
|
|
|
25
25
|
|
|
26
26
|
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`.
|
|
27
27
|
|
|
28
|
-
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 `
|
|
28
|
+
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 `plans`, one `from` and `to` for each live plan the task was the last live citation of, empty when nothing moved, the same shape `canon tasks archive` uses for its own `plans` field.
|
|
29
29
|
|
|
30
30
|
## Step 3: route on a refusal
|
|
31
31
|
|
|
@@ -32,5 +32,5 @@ Without this skill, a session implementing a planned change writes the test afte
|
|
|
32
32
|
|
|
33
33
|
- Choosing the layer a test belongs at and judging whether it is a good test: `canon:test-craft`, loaded at step 1 rather than restated here
|
|
34
34
|
- Finding the cause of an unexplained failure: `canon:systematic-debugging`
|
|
35
|
-
- Confirming visual output after a change lands: `
|
|
35
|
+
- Confirming visual output after a change lands: `567-planning.md` states the order and `ui-checklist` writes the list to confirm against
|
|
36
36
|
- The mechanical audit of whether an implementation reached history ahead of its test: `canon gov test-order`, invoked from `auto-ship`
|
package/docs/agents/counts.md
CHANGED
|
@@ -37,7 +37,7 @@ The set is closed rather than derived, so widening it is a deliberate change to
|
|
|
37
37
|
|
|
38
38
|
A sentence has to carry an assertion verb (`loads`, `ships`, `carries`, `holds`, `counts`, `totals`, `documents`, `declares`, `installs`, `lists`, `contains`, `comprises`, `authors`), the quantifier `all`, or an article (`the`, `a`, `an`) immediately ahead of the number, which is immediately ahead of the catalog noun, with one optional qualifying word between the number and the noun (`sixty-one shipped skills`). The number reads either as digits or as a spelled-out cardinal through ninety-nine, since this corpus states a catalog size in words as often as in digits.
|
|
39
39
|
|
|
40
|
-
Nothing stands between the trigger and the number, which is the rule an author writing a new count has to know. It separates `the toolkit authors
|
|
40
|
+
Nothing stands between the trigger and the number, which is the rule an author writing a new count has to know. It separates `the toolkit authors 74 rules` and `took all 74 rules`, both read, from `a domain of 55 skills` and `denominator of sixty-one shipped skills`, neither of them read. A figure meant as a past state takes a date in the same sentence instead, which reads the sentence past whatever its shape.
|
|
41
41
|
|
|
42
42
|
## How the trigger set grew
|
|
43
43
|
|
|
@@ -45,7 +45,7 @@ The verb gate is not the first design tried. A bare number next to a catalog nou
|
|
|
45
45
|
|
|
46
46
|
The article half was added after a first review of the shipped design found a live miss: the development domain's gating-stages entry stated a stale audit total while the tree held 20, and the verb gate never reached it, since that sentence puts its verb after the noun rather than ahead of the number. Widening the trigger set to admit an article ahead of the number closed that gap.
|
|
47
47
|
|
|
48
|
-
The quantifier `all` and the verb `authors` joined on the same evidence, two more live misses failing only the trigger test. Allowing words to stand between the trigger and the number was the other candidate, measured and declined: at widths of one, two, and three it reached 77, 104, and 132 sentences against a baseline of 65, missed `took all
|
|
48
|
+
The quantifier `all` and the verb `authors` joined on the same evidence, two more live misses failing only the trigger test. Allowing words to stand between the trigger and the number was the other candidate, measured and declined: at widths of one, two, and three it reached 77, 104, and 132 sentences against a baseline of 65, missed `took all 74 rules` at every width, and reached `the toolkit authors 74 rules` only at a width admitting the indirect-noun shape below. The two words reach both at 75 sentences and no false positive.
|
|
49
49
|
|
|
50
50
|
## The plausibility filter
|
|
51
51
|
|
|
@@ -59,7 +59,7 @@ The article gate is looser than the verb list and carries a real cost. Re-runnin
|
|
|
59
59
|
|
|
60
60
|
A delta phrased as a transition (`from fourteen to fifteen`), a fraction (`thirteen of sixteen`), and a total reached through an indirect noun (`denominator of sixty-one shipped skills`) are all catalog-size claims this corpus carries, and none matches the trigger shape this reads. Each stays a known gap. The false-positive rate that gated closing them has a measurement behind it now, and what it showed is that the widening these three need is the one that costs a false positive rather than the one that does not.
|
|
61
61
|
|
|
62
|
-
A second figure in a sentence whose first figure already matched is a fourth gap and a structural one, since one match is taken per catalog per sentence. `authors
|
|
62
|
+
A second figure in a sentence whose first figure already matched is a fourth gap and a structural one, since one match is taken per catalog per sentence. `authors 74 rules under governance/rules/ and consumes 62 into .claude/rules/` is read for its 74 alone, which is correct here because the two figures name different populations, and a sentence stating one catalog twice would go unread the same way.
|
|
63
63
|
|
|
64
64
|
A calendar date (`2026-08-21`) or a backticked commit reference in the same sentence reads the whole sentence past, since that is how this corpus already marks a figure as a historical record rather than a live claim. `canon/ARCHITECTURE.md` and the context entries carry a figure this way deliberately, and every one of them stays correct forever.
|
|
65
65
|
|