@erclx/canon 4.84.0 → 4.86.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/docs-fold/SKILL.md +1 -1
- package/claude/skills/draft-and-pick/REQUIREMENT.md +2 -1
- package/claude/skills/draft-and-pick/SKILL.md +3 -2
- package/claude/skills/draft-and-pick/references/live-arms.md +19 -0
- package/claude/skills/git-ship/SKILL.md +2 -2
- package/claude/skills/memory-capture/SKILL.md +1 -1
- package/claude/skills/memory-review/REQUIREMENT.md +1 -1
- package/claude/skills/memory-review/SKILL.md +25 -22
- package/claude/skills/memory-review/references/receipt-format.md +2 -2
- package/claude/skills/role-worker/SKILL.md +2 -1
- package/claude/skills/ux-walkthrough/SKILL.md +2 -2
- package/claude/skills/ux-walkthrough/references/candidate-pages.md +1 -16
- package/docs/agents/commands.md +4 -1
- package/docs/agents/records.md +6 -6
- package/docs/workflow/ai-workflow.md +2 -2
- package/governance/rules/claude/563-ready.md +11 -0
- package/governance/rules/core/045-memory.md +1 -1
- package/package.json +1 -1
- package/src/commands/migrate.ts +142 -0
- package/src/commands/records.ts +12 -6
- package/src/design/tokens.ts +7 -4
- package/src/migrate/record-layout.ts +346 -0
- package/src/migrate/record-tree.ts +1 -1
- package/src/migrate/scratch-evidence.ts +3 -3
- package/src/record-root.ts +2 -0
- package/src/records/backup.ts +132 -37
- package/src/records/size.ts +16 -12
- package/standards/index.md +1 -0
- package/standards/memory.md +1 -1
- package/standards/plan.md +2 -0
- package/standards/ready.md +105 -0
- package/standards/skill.md +1 -1
- package/tooling/claude/seeds/.claude/hooks/memory-index.sh +10 -0
|
@@ -212,7 +212,7 @@ Respond with up to five lines:
|
|
|
212
212
|
<N minor findings kept in .canon/review/branch/review-<slug>.md>
|
|
213
213
|
<N facts routed to context entries>
|
|
214
214
|
<N memories captured in .canon/memory/>
|
|
215
|
-
<Memory proposal at .canon/review/memory
|
|
215
|
+
<Memory proposal at .canon/memory/review/memory-review-<slug>.md>
|
|
216
216
|
```
|
|
217
217
|
|
|
218
218
|
`<state>` is whatever the Step 8 read returned, being `draft` or `ready, unsupervised`, rather than the state the undo asked for. Writing the word `draft` there unconditionally is what this line used to do, and it named a state no step had read.
|
|
@@ -228,7 +228,7 @@ Sweep the branch reports this session never opened. List `.canon/review/branch/r
|
|
|
228
228
|
|
|
229
229
|
What that removes is a local-only review on a branch deleted before it opened a pull request. `review-branch` says so where a reader meets the report, and the sweep runs anyway rather than keeping every report against the one case, since nothing else ever clears them.
|
|
230
230
|
|
|
231
|
-
Memory receipts sweep board-wide rather than by slug. Scan every `.canon/review/memory
|
|
231
|
+
Memory receipts sweep board-wide rather than by slug. Scan every `.canon/memory/review/memory-review-*.md`, not only the one matching this slug. `memory-review` writes its receipt after this skill has run in every ship chain, so a sweep keyed on the current slug looks for a file that does not exist yet, and no later branch looks for it either because a slug is unique per feature. Scanning the folder is what makes the sweep fire at all.
|
|
232
232
|
|
|
233
233
|
For each receipt, count the H2 items still marked 📝 pending:
|
|
234
234
|
|
|
@@ -19,11 +19,12 @@ Without this skill, a session facing a decision nobody can settle from a diff:
|
|
|
19
19
|
- Reads a driver record as a verdict and drops an arm on it. `canon drive` reports findings and never gates, so a run filtering the arms on a probe reading has made a claim the probe catalog has not earned.
|
|
20
20
|
- Reads a color without compositing its alpha, samples a round control at the corner of its bounding box, or confirms a panel's dimensions while it sits above the viewport. Each reads as a passing measurement about something no reader sees.
|
|
21
21
|
- Meets a machine with no browser binary and reports on the arms anyway, since nothing in the default flow separates a render that failed from one that was never attempted.
|
|
22
|
+
- Hand-writes a mockup of a surface a running app already serves, which drifts from what ships by a few pixels and a few words the moment the app's own markup or stylesheet moves on.
|
|
22
23
|
|
|
23
24
|
## Must
|
|
24
25
|
|
|
25
26
|
- Produce three to five arms with the shipping state among them, each carrying an id, a label, and what the arm costs.
|
|
26
|
-
- Author the whole candidate set as one self-contained page and render it once, so the comparison arrives as one image.
|
|
27
|
+
- Author the whole candidate set as one self-contained page and render it once, so the comparison arrives as one image, except where the surface under decision is a running app: there the page links a copy of the built stylesheet rather than inlining it, per `references/live-arms.md`.
|
|
27
28
|
- Vary one property across the arms, so the answer names a difference.
|
|
28
29
|
- Render before reporting on any arm, and report a missing browser binary as a refusal naming the repair rather than describing an arm nobody has seen.
|
|
29
30
|
- Take the pick through the structured question surface, with the recommendation ranked first and marked, and every option carrying its cost.
|
|
@@ -28,8 +28,9 @@ Write every arm side by side on one self-contained HTML page at `<dest>/candidat
|
|
|
28
28
|
- One page for the pick, never a set of separate images handed to the operator to compare from memory. The comparison they judge is `candidates.html`, which Step 3 renders and Step 4 asks about. The per-arm files exist only for Step 6's archival capture, once the pick is made, and only the last pass through this step is what Step 6 finds there.
|
|
29
29
|
- Wrap each arm's markup in the same class on both files, chosen once per run and reused everywhere, so one selector addresses an arm on the combined page and on its own standalone file alike.
|
|
30
30
|
- Label each arm on the page with its id and its cost, so the render carries what the question will ask about.
|
|
31
|
-
-
|
|
32
|
-
-
|
|
31
|
+
- Take the live-app branch instead when the surface under decision is a running app: lift the rendered markup and link a copy of the built stylesheet rather than inlining, per `${CLAUDE_SKILL_DIR}/references/live-arms.md`.
|
|
32
|
+
- On the default path, inline every style, script, and asset the page needs. The render reads the file off disk, so a page reaching for a build step or a network font renders without it and the arms differ by something nobody chose.
|
|
33
|
+
- On the default path, declare a font stack the machine resolves, such as `system-ui` behind a generic fallback. The render refuses a page that would rewrap against a substitute rather than shipping a false comparison, so a page naming no font at all is refused on whatever the default resolves to.
|
|
33
34
|
- Vary one property across the arms. A page whose arms differ in three ways answers no question, since the pick cannot say which difference decided it.
|
|
34
35
|
|
|
35
36
|
## Step 3: render and hand off
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Live app arms
|
|
2
|
+
|
|
3
|
+
Read when the surface under decision is a running app rather than a static mockup: the operator's request names a route or URL of the project's own app, or the decision is about a surface a build command serves. Skip it for a decision with nothing running to lift from, which stays on Step 2's default inlined path.
|
|
4
|
+
|
|
5
|
+
## Lift from the app
|
|
6
|
+
|
|
7
|
+
- Dump the rendered markup of the surface under decision from the built page, after it has loaded, into a file under `<dest>`. Strip scripts from the dump.
|
|
8
|
+
- Copy the built stylesheet and font files beside the page, at the path the dumped markup links them from, so a candidate page renders with the stylesheet the app ships. Every arm then differs from the shipped page only by what the arm names.
|
|
9
|
+
- Trim a large dump to the part the decision needs, and keep the wrapper classes intact so layout rules keyed to them still resolve.
|
|
10
|
+
- Size each frame to the content width the decision names rather than the window width, since a container query reads the frame.
|
|
11
|
+
- Write copy an arm introduces with `write-human`, and take every other word from the dump.
|
|
12
|
+
|
|
13
|
+
## The page
|
|
14
|
+
|
|
15
|
+
- Generate the page with a short script, one per round, so a shared change is one edit and a rerun.
|
|
16
|
+
- Put a theme button on the page that flips the app's own theme switch on the root, rather than drawing each frame once per theme. Read `?arm=<id>&theme=<name>` to strip every other arm and the button for capture. Skip the button for an app that ships one theme.
|
|
17
|
+
- Print each frame's measurement under it from a script in the page, so the numbers the operator reads are the browser's.
|
|
18
|
+
- Write an index page linking one page per arm when an arm is a whole page or a route rather than a frame, with thumbnails copied beside it.
|
|
19
|
+
- Name anything the preview cannot reproduce, such as an asset whose colors follow the browser rather than the page's theme button, rather than fixing the page around it.
|
|
@@ -48,7 +48,7 @@ An installed binary carrying no `plan-reach` subcommand reports the reach unread
|
|
|
48
48
|
|
|
49
49
|
Capture leads the sequence because a routed fact lands in a context entry, which is a tracked file. Running it after the pull request opens leaves that edit off the branch entirely, so the fact reaches nothing. Memory files are gitignored either way, which is what hid the ordering while capture wrote only those.
|
|
50
50
|
|
|
51
|
-
Stop at the Propose phase. Do not run Apply. Promoting an entry to
|
|
51
|
+
Stop at the Propose phase. Do not run Apply. Promoting an entry to an always-loaded rule or a skill body ships as its own change, separate from this feature.
|
|
52
52
|
|
|
53
53
|
## After completion
|
|
54
54
|
|
|
@@ -58,7 +58,7 @@ Output up to four lines:
|
|
|
58
58
|
✅ Shipped
|
|
59
59
|
<N facts routed to context entries>
|
|
60
60
|
<N memories captured in .canon/memory/>
|
|
61
|
-
<Memory proposal at .canon/review/memory
|
|
61
|
+
<Memory proposal at .canon/memory/review/memory-review-<slug>.md>
|
|
62
62
|
```
|
|
63
63
|
|
|
64
64
|
Omit the second line if nothing routed. Omit the third and fourth if `memory-capture` wrote no memory file this session, since an empty pen means no scoped review and no proposal.
|
|
@@ -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 `.canon/memory/` for an existing file on the same topic. 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.
|
|
72
72
|
|
|
73
73
|
## Step 5: write the residue
|
|
74
74
|
|
|
@@ -29,7 +29,7 @@ A pen the caller cannot face is the same gap wearing a different shape. Routing
|
|
|
29
29
|
## Must not
|
|
30
30
|
|
|
31
31
|
- Apply anything the user has not approved by item
|
|
32
|
-
- Author a
|
|
32
|
+
- Author a toolkit rule inline. A toolkit rule under `internal/rules/` or `governance/rules/` has an owner and a scaffolding path, `internal-governance`, and a rule written here bypasses it. A project rule under `.claude/rules/project/` is project-owned and takes an `Edit` appending to an existing file, or a handoff to `create-rule` when none fits.
|
|
33
33
|
- Mutate tracked files from the main worktree
|
|
34
34
|
- Answer a question raised in a decision slot while applying. Discussion and application are separate passes so an approval is never inferred from a reply.
|
|
35
35
|
- Delete a memory entry at all. Every exit from the pen is a move into the archive.
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: memory-review
|
|
3
|
-
description: Reviews `.canon/memory/` and proposes per-entry actions (promote to
|
|
3
|
+
description: Reviews `.canon/memory/` and proposes per-entry actions (promote to an always-loaded rule, move into a skill body, route to a context entry, hand off to governance, or retire as stale). Also runs the discuss, challenge, apply, and cleanup phases on an existing review file. Use when asked to "review memory", "discuss memory questions", "challenge the promotes", "apply memory decisions", "cleanup memory review", "promote memory", or "consolidate memories". Do NOT auto-apply. Output a grouped proposal and wait for block-by-block approval.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Memory review
|
|
7
7
|
|
|
8
|
-
This skill drives the full memory review lifecycle in five phases. Pick the phase from what the user said and whether a review receipt already exists at `<main-root>/.canon/review/memory
|
|
8
|
+
This skill drives the full memory review lifecycle in five phases. Pick the phase from what the user said and whether a review receipt already exists at `<main-root>/.canon/memory/review/memory-review-*.md`.
|
|
9
9
|
|
|
10
10
|
What an entry looks like and why a retired one is moved rather than deleted are fixed by `${CLAUDE_SKILL_DIR}/../../standards/memory.md`. Read it before rewriting an entry, since a promotion rewrites the rule and a rewrite has to leave the entry conforming.
|
|
11
11
|
|
|
@@ -23,7 +23,7 @@ If the user re-pings the skill with no new phrase and a receipt exists, default
|
|
|
23
23
|
|
|
24
24
|
- All `.canon/memory/` reads, edits, and archive moves resolve at the main worktree root, not the current worktree. Resolve that root the way `session-worktree` does.
|
|
25
25
|
- If no `.canon/memory/` directory exists at the main worktree root, stop: `❌ No .canon/memory/ directory found.`
|
|
26
|
-
- If `.canon/memory/` contains no `*.md` entries other than `index.md`, stop: `✅ No memory entries to review.`
|
|
26
|
+
- If `.canon/memory/` contains no top-level `*.md` entries other than `index.md`, stop: `✅ No memory entries to review.` The pen holds two subfolders now, `review/` and `archive/`, and neither is a memory entry, so this count and every entry read below stay at the top level and never recurse into either.
|
|
27
27
|
- Cleanup is exempt from the two stops above. It works on receipts in `.canon/review/`, and a drained pen is the normal state once Apply has run, so a pen-shaped stop would strand the receipt it exists to delete.
|
|
28
28
|
- Resolve the main root via `git worktree list --porcelain | grep -m 1 '^worktree ' | cut -d' ' -f2-`, falling back to `pwd`. All review and memory reads anchor here.
|
|
29
29
|
- From a linked worktree the file-editing tools refuse every main-root path, so each write below goes out through `Bash` as a plain single command. The receipt and a memory entry are both short and this session has read them whole, so a rewrite replaces the file with a heredoc rather than editing a line inside it. Promotion targets are tracked files at `pwd` and keep taking `Edit`.
|
|
@@ -42,17 +42,18 @@ Propose is the ship-time entry point. The ship skills run it right after capture
|
|
|
42
42
|
Read in parallel from the project root:
|
|
43
43
|
|
|
44
44
|
- `.canon/memory/index.md`: the generated index
|
|
45
|
-
- every other `*.md` file
|
|
45
|
+
- every other top-level `*.md` file in `.canon/memory/`, never its `review/` or `archive/` subfolders: individual entries with frontmatter (`title`, `description`, `category`)
|
|
46
46
|
|
|
47
47
|
### Step 2: read promotion targets
|
|
48
48
|
|
|
49
49
|
Read in parallel from the project root. Skip any file or folder that does not exist.
|
|
50
50
|
|
|
51
|
-
- `CLAUDE.md`: project behavior rules and Content ownership section
|
|
51
|
+
- `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
|
|
52
52
|
- every `SKILL.md` under `.claude/skills/`: domain-scoped internal skill bodies
|
|
53
53
|
- every `SKILL.md` under `claude/skills/`: plugin skill bodies
|
|
54
54
|
- every `*.md` under `${CLAUDE_SKILL_DIR}/../../standards/`: authoring references
|
|
55
55
|
- every `*.md` under `governance/rules/` in the toolkit repo, or `.claude/rules/` in a target project: coding-standards rules
|
|
56
|
+
- 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
57
|
|
|
57
58
|
### Step 3: classify each entry
|
|
58
59
|
|
|
@@ -62,14 +63,16 @@ Read in parallel from the project root. Skip any file or folder that does not ex
|
|
|
62
63
|
|
|
63
64
|
For each in-scope entry (see Scope), pick one action:
|
|
64
65
|
|
|
65
|
-
- **Promote to
|
|
66
|
+
- **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.
|
|
67
|
+
- In the toolkit repo, hand off to `internal-governance` and `${CLAUDE_SKILL_DIR}/../../standards/rule.md`, which own `internal/rules/core/` (this repo only, never ships) and `governance/rules/core/` (ships to every target).
|
|
68
|
+
- 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.
|
|
66
69
|
- **Promote to a skill body**: the rule fires only when editing a specific path-scoped domain. Name the target skill.
|
|
67
70
|
- **Promote to a standards file**: the rule is an authoring reference that belongs in the project's own standards folder as `<domain>.md`.
|
|
68
|
-
- **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/memory-routing/<slug>.md` at the main worktree root, in the format `memory-capture` writes, and tell the user to run `/docs-fold` from a branch. Do not edit the context entry here.
|
|
69
|
-
- **Hand off to governance**: the rule is coding-standards class (typescript, testing, naming, error-handling, performance, logging, concurrency, planning). 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.
|
|
71
|
+
- **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/memory-routing/<slug>.md` at the main worktree root, in the format `memory-capture` writes, and tell the user to run `/docs-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.
|
|
72
|
+
- **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).
|
|
70
73
|
- 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/`.
|
|
71
74
|
- In a target project, point the user at the `create-rule` skill, which scaffolds a project-local rule under `.claude/rules/`.
|
|
72
|
-
- **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/
|
|
75
|
+
- **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.
|
|
73
76
|
|
|
74
77
|
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.
|
|
75
78
|
|
|
@@ -83,17 +86,17 @@ The check covers implication, not only keyword match. If an adjacent bullet in t
|
|
|
83
86
|
|
|
84
87
|
#### Crispness check
|
|
85
88
|
|
|
86
|
-
Rules that resist crisp one-line phrasing default to **Retire** over promote. Never promote a memory unchanged. Rewrite to match the destination surface's tone. Use
|
|
89
|
+
Rules that resist crisp one-line phrasing default to **Retire** over promote. Never promote a memory unchanged. Rewrite to match the destination surface's tone. Use single-directive rule-bullet phrasing for an always-loaded rule and imperative phrasing for skill bodies.
|
|
87
90
|
|
|
88
91
|
### Step 4: write the proposal to the review file
|
|
89
92
|
|
|
90
93
|
Derive `<slug>` per `${CLAUDE_SKILL_DIR}/../../standards/slug.md`. Fall back to `latest` on an empty result.
|
|
91
94
|
|
|
92
|
-
Write the full proposal to `.canon/review/memory
|
|
95
|
+
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 below rewrite items inside an existing receipt rather than authoring one, so none of them opens it.
|
|
93
96
|
|
|
94
97
|
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.
|
|
95
98
|
|
|
96
|
-
Tell the user `✅ Wrote proposal to .canon/review/memory
|
|
99
|
+
Tell the user `✅ Wrote proposal to .canon/memory/review/memory-review-<slug>.md`. Ask them to fill in `Decision:` per item, then re-ping with "discuss" for question rounds or "apply" to commit.
|
|
97
100
|
|
|
98
101
|
Rewrite the review file in place whenever the proposal changes mid-review. The file stays the source of truth for the current decisions.
|
|
99
102
|
|
|
@@ -101,7 +104,7 @@ Rewrite the review file in place whenever the proposal changes mid-review. The f
|
|
|
101
104
|
|
|
102
105
|
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.
|
|
103
106
|
|
|
104
|
-
1. Read the latest `.canon/review/memory
|
|
107
|
+
1. Read the latest `.canon/memory/review/memory-review-*.md` at the main root.
|
|
105
108
|
2. For each promote item, apply three tests:
|
|
106
109
|
- **Absorbed**: grep the target surface for the rule's keywords. If already stated or implied, flip to retire.
|
|
107
110
|
- **Delta**: if the rule is a nice-to-have next to existing bullets, flip to retire.
|
|
@@ -112,7 +115,7 @@ Trigger: user says "challenge the promotes", "challenge before apply", or asks f
|
|
|
112
115
|
|
|
113
116
|
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.
|
|
114
117
|
|
|
115
|
-
1. Read the latest `.canon/review/memory
|
|
118
|
+
1. Read the latest `.canon/memory/review/memory-review-*.md` at the main root.
|
|
116
119
|
2. For each item whose `Decision:` contains `?` or any unrecognized verb (anything other than `apply`, `skip`, `defer`):
|
|
117
120
|
- Write a `Take:` line under `Decision:`, separated by exactly one blank line. If a `Take:` line already exists, overwrite it.
|
|
118
121
|
- 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.
|
|
@@ -134,9 +137,9 @@ Before applying any item, check the worktree state:
|
|
|
134
137
|
|
|
135
138
|
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.
|
|
136
139
|
|
|
137
|
-
Before applying a promote to
|
|
140
|
+
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.
|
|
138
141
|
|
|
139
|
-
Promotions are a separate concern from any feature in flight. Keep the promoted edits on their own commit. Do not fold
|
|
142
|
+
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.
|
|
140
143
|
|
|
141
144
|
For each item, parse the `Decision:` line:
|
|
142
145
|
|
|
@@ -149,12 +152,12 @@ Free-form text after the verb is a reason. Capture it in the receipt but do not
|
|
|
149
152
|
|
|
150
153
|
Action by action type:
|
|
151
154
|
|
|
152
|
-
- **Promote**: use `Edit` to insert the rewritten rule into the target surface, then archive the memory file.
|
|
155
|
+
- **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.
|
|
153
156
|
- **Promote to a context entry**: append the fact to `.canon/tmp/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.
|
|
154
157
|
- **Hand off**: do not edit governance. Archive the memory file only if the user confirmed the handoff explicitly. Otherwise leave it in place.
|
|
155
158
|
- **Retire**: archive the memory file.
|
|
156
159
|
|
|
157
|
-
Archiving means creating `.canon/
|
|
160
|
+
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 the `mv` as two plain commands rather than joining them with `&&`, which is refused as compound from a linked worktree. Never delete a memory entry. Nothing recovers one from a gitignored folder.
|
|
158
161
|
|
|
159
162
|
Do not hand-edit `.canon/memory/index.md`. Once every archive move is done, regenerate it instead:
|
|
160
163
|
|
|
@@ -186,11 +189,11 @@ End with: `✅ Applied: <nums> | ⏭ Skipped: <nums> | 📝 Pending: <nums>`. Om
|
|
|
186
189
|
|
|
187
190
|
Trigger: user says "cleanup" or "delete the receipt" after Apply has run.
|
|
188
191
|
|
|
189
|
-
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 10 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/
|
|
192
|
+
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 10 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.
|
|
190
193
|
|
|
191
|
-
If no `.canon/review/memory
|
|
194
|
+
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.
|
|
192
195
|
|
|
193
|
-
1. Read the latest `.canon/review/memory
|
|
196
|
+
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, stop and name the pending numbers.
|
|
194
197
|
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.
|
|
195
198
|
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.
|
|
196
199
|
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.
|
|
@@ -203,7 +206,7 @@ Output one line per action taken in the most recent phase:
|
|
|
203
206
|
|
|
204
207
|
- `✅ Promoted: .canon/memory/<memory-file> → <target>`
|
|
205
208
|
- `✅ Handed off: .canon/memory/<memory-file> → governance`
|
|
206
|
-
- `📦 Retired: .canon/memory/<memory-file> → .canon/
|
|
209
|
+
- `📦 Retired: .canon/memory/<memory-file> → .canon/memory/archive/`
|
|
207
210
|
- `🗑 Swept: .canon/review/<review-file>, folded <n> skips`
|
|
208
211
|
- `⏭ Kept: .canon/review/<review-file>, <n> items pending`
|
|
209
212
|
|
|
@@ -5,7 +5,7 @@ description: The proposal file structure, its item template, and how each action
|
|
|
5
5
|
|
|
6
6
|
# Memory review receipt format
|
|
7
7
|
|
|
8
|
-
The shape Step 4 of the Propose phase writes to `.canon/review/memory
|
|
8
|
+
The shape Step 4 of the Propose phase writes to `.canon/memory/review/memory-review-<slug>.md`. Only Propose writes this file. Challenge, Discuss, and Apply rewrite items inside a receipt that already exists, and Cleanup deletes one, so none of the four needs this file.
|
|
9
9
|
|
|
10
10
|
## Structure
|
|
11
11
|
|
|
@@ -45,4 +45,4 @@ Decision:
|
|
|
45
45
|
|
|
46
46
|
## Variation by action
|
|
47
47
|
|
|
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 Retire items, skip the rewrite block. Every item gets a `Decision:` slot regardless of action. `Take:` is added only when a question response is needed.
|
|
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/core/` or `governance/rules/core/` 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 items, skip the rewrite block. Every item gets a `Decision:` slot regardless of action. `Take:` is added only when a question response is needed.
|
|
@@ -22,9 +22,10 @@ running and re-invoking it would restart the build.
|
|
|
22
22
|
|
|
23
23
|
## Where the session stands
|
|
24
24
|
|
|
25
|
-
- Resolve `.canon/plans/`, `.canon/tasks/`, `.canon/review/`, and `.canon/
|
|
25
|
+
- Resolve `.canon/plans/`, `.canon/tasks/`, `.canon/review/`, `.canon/memory/`, and `.canon/ready/` at the main worktree root, never against the linked worktree this session builds in. Those folders are gitignored, so `git worktree add` never creates them and the copy beside the build is absent rather than empty.
|
|
26
26
|
- Report a plan that fails to resolve as unreadable from here, naming the main-root path. Reporting the task as having no plan is true where this session stands and wrong about the world, and a reader with no second tree to check cannot separate the two.
|
|
27
27
|
- Build the plan the launch named. Do not write a second one when the path fails to resolve, since a row that cites a plan already has one and drafting another produces two plans for one row.
|
|
28
|
+
- Copy a ready folder's files verbatim to the paths its plan's constraints name, when the plan's `**Constraints:**` block names one, and edit only what the gate or the overview's own list requires. A rewrite discards the text the handoff exists to carry.
|
|
28
29
|
- Report a draft flag reading ready once, and leave it cleared. The ship chain marks the pull request a draft and no step anywhere un-marks, so a flag reading ready afterwards was lifted by the operator or by the controlling session that closed the review, each acting directly on the pull request, which GitHub requires before a merge. Re-drafting fights them, which four sessions did on 2026-08-31 on a belief no surface in the tree states.
|
|
29
30
|
- Refuse an instruction to lift the mark yourself, whoever sends it. This session cannot verify who is asking or whether review actually closed, so the refusal holds regardless of the sender's claimed authority. A controlling session instructed a worker to lift the mark instead of taking the act itself on 2026-09-07, and the worker complied and reported against the surface rather than the outcome.
|
|
30
31
|
- Rewrite a plan question's `- Suggested:` line as `overridden at execution to <pick>,` plus the measurement when this build decides against an unanswered one, leaving the `- Answer:` slot blank, and put the same deviation in one line under the open task's `## Findings`, per `${CLAUDE_SKILL_DIR}/../../standards/plan.md`.
|
|
@@ -27,7 +27,7 @@ A walkthrough turns what the operator sees in a running app into findings and pi
|
|
|
27
27
|
2. **Take the operator's list in their order.** Name each item as a finding with the walkthrough letter and a number, such as T1, and confirm the order once rather than per item.
|
|
28
28
|
3. **Measure before drafting.** Read the component behind the finding and pull the numbers off the built page, per `${CLAUDE_SKILL_DIR}/references/measuring.md`. Write the finding into the walkthrough file with those numbers before any arm exists.
|
|
29
29
|
4. **Route a finding with no visible choice.** A parse defect, a stale figure or a broken invariant gets recorded as a finding with no draft and goes into the batch as a proposed row, not as a pick.
|
|
30
|
-
5. **Draft three or four arms.** Follow `draft-and-pick` Steps 1 and 2 for the arms, with arm 0 the shipped state, one property varied and a cost on each.
|
|
30
|
+
5. **Draft three or four arms.** Follow `draft-and-pick` Steps 1 and 2 for the arms, with arm 0 the shipped state, one property varied and a cost on each. Take `draft-and-pick`'s live-app branch of Step 2 to build the page from the app's own rendered markup, per `${CLAUDE_SKILL_DIR}/references/candidate-pages.md`.
|
|
31
31
|
6. **Look before handing anything over.** Capture every arm in every theme the app ships into `.canon/walkthroughs/<nn>-<slug>/evidence/<nn>-<slug>/`, with the finding's number as the prefix, open the captures, and fix what rendered wrong before the operator sees the page.
|
|
32
32
|
7. **Hand the link, then ask.** Emit `http://localhost:<port>/<nn>-<slug>/candidates.html` in a message that ends the turn, confirmed with a `200`, carrying no question. Take any reply after that message as the operator having looked, an explicit "go" included, rather than holding for a stated confirmation, and only then put the choice through the structured question surface with the recommendation first.
|
|
33
33
|
8. **Record the pick.** Write what won, what it beat and by which numbers, where the evidence is, and the build criteria, per `${CLAUDE_SKILL_DIR}/references/record.md`. Read every figure you quote back from the page or the data file first, and correct the record where the question quoted one wrong.
|
|
@@ -44,7 +44,7 @@ A walkthrough turns what the operator sees in a running app into findings and pi
|
|
|
44
44
|
|
|
45
45
|
## What this delegates
|
|
46
46
|
|
|
47
|
-
- `draft-and-pick` owns the arm discipline and the structured question. This walkthrough
|
|
47
|
+
- `draft-and-pick` owns the arm discipline and the structured question. This walkthrough takes its live-app branch of Step 2 and departs from its Step 6 apply and delete, for the reasons `${CLAUDE_SKILL_DIR}/references/candidate-pages.md` states.
|
|
48
48
|
- `write-human` carries the voice of every recorded passage and any copy an arm puts in front of a reader.
|
|
49
49
|
- `plan-feature` and whoever dispatches builds turn a batch into plans and code.
|
|
50
50
|
- `canon capture`, `canon serve` and `canon sessions list` own the render, the address and the roster.
|
|
@@ -2,25 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
Read when drafting arms for a finding. Skip it for a finding with no visible choice.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
- Dump the rendered markup of the surface under test from the built page, after it has loaded, into a JSON file in scratch. Strip scripts from the dump.
|
|
8
|
-
- Copy the built stylesheet and font files under `.canon/tmp/`, at the path the dumped markup links them from, so a candidate page renders with the stylesheet the app ships. Every arm then differs from the shipped page only by what the arm names.
|
|
9
|
-
- Trim a large dump to the part the finding needs, and keep the wrapper classes intact so layout rules keyed to them still resolve.
|
|
10
|
-
- Size each frame to the content width the finding names rather than the window width, since a container query reads the frame.
|
|
11
|
-
- Write copy an arm introduces with `write-human`, and take every other word from the dump.
|
|
12
|
-
|
|
13
|
-
## The page
|
|
14
|
-
|
|
15
|
-
- Generate the page with a short script, one per round, so a shared change is one edit and a rerun.
|
|
16
|
-
- Put a theme button on the page that flips the app's own theme switch on the root, rather than drawing each frame once per theme. Read `?arm=<id>&theme=<name>` to strip every other arm and the button for capture. Skip the button for an app that ships one theme.
|
|
17
|
-
- Print each frame's measurement under it from a script in the page, so the numbers the operator reads are the browser's.
|
|
18
|
-
- Write an index page linking one page per arm when an arm is a whole page or a route rather than a frame, with thumbnails copied beside it.
|
|
19
|
-
- Name anything the preview cannot reproduce, such as an asset whose colors follow the browser rather than the page's theme button, rather than fixing the page around it.
|
|
5
|
+
Follow `${CLAUDE_SKILL_DIR}/../draft-and-pick/SKILL.md` Step 2's live-app branch for lifting the markup, copying the stylesheet, and building the page, which routes to its own `references/live-arms.md`. What follows is only where this walkthrough departs from that shared path.
|
|
20
6
|
|
|
21
7
|
## Where this departs from draft-and-pick
|
|
22
8
|
|
|
23
9
|
- Capture into the walkthrough's own numbered evidence folder instead of the folder `draft-and-pick` Step 6 archives arms into, per `${CLAUDE_SKILL_DIR}/references/record.md`.
|
|
24
|
-
- Link the app's built stylesheet instead of inlining every asset. Lifted markup needs the real stylesheet, and an inlined copy is the drift this avoids.
|
|
25
10
|
- Keep `candidates.html` and never apply the winning arm. The walkthrough records and a build applies.
|
|
26
11
|
- Leave `.canon/tmp/<nn>-<slug>/` in place until the picks are built, and never delete the round's evidence folder.
|
package/docs/agents/commands.md
CHANGED
|
@@ -53,7 +53,7 @@ Full help: `canon <command> --help`. Behavior notes for the install and sync ver
|
|
|
53
53
|
| `canon records migrate` | Rewrite the records a validate finding names a recoverable transform for (`--write`, `--json`) |
|
|
54
54
|
| `canon records ordinal` | Report or claim the next ordinal `intake` and `groundwork` share, creating the folder atomically (`--claim`, `--json`) |
|
|
55
55
|
| `canon records size` | Report what each record folder holds and how much of it is recent, heaviest first (`--json`) |
|
|
56
|
-
| `canon records push` | Commit
|
|
56
|
+
| `canon records push` | Commit every record folder less the exclusion set and push it to a private records remote (`--json`) |
|
|
57
57
|
| `canon records pull` | Fetch the records remote and write it back, refusing rather than discarding unpushed records (`--json`) |
|
|
58
58
|
| `canon migrate rename` | Rewrite every unprotected `aitk` token to `canon` and move the paths that carry the name, reporting the plan without `--write` (`--scope`, `--json`) |
|
|
59
59
|
| `canon migrate skill-names` | Move the prefixed skill folders onto their two-word names and rewrite every citation, reporting the plan without `--write` (`--root`, `--json`) |
|
|
@@ -62,6 +62,7 @@ Full help: `canon <command> --help`. Behavior notes for the install and sync ver
|
|
|
62
62
|
| `canon migrate record-tree` | Repoint the old-root citations inside the records themselves, scoped to the live folders and reporting every line without `--write` (`--root`, `--json`) |
|
|
63
63
|
| `canon migrate rule-layout` | Move a target's installed rules from the flat `.claude/rules/<subdir>/` layout to `.claude/rules/canon/<subdir>/`, reporting the plan without `--write` (`--root`, `--json`) |
|
|
64
64
|
| `canon migrate scratch-evidence` | Move a folder under `.tmp/` that a durable record cites as evidence to `.canon/review/evidence/`, repointing every citation live or archived, reporting the plan without `--write` (`--root`, `--json`) |
|
|
65
|
+
| `canon migrate record-layout` | Fold review receipts from `.canon/review/memory/` and the retired-entry archive from `.canon/tmp/memory-archive/` under the memory pen itself, repointing every citation live or archived, reporting the plan without `--write` (`--root`, `--json`) |
|
|
65
66
|
| `canon sessions list` | Resolve live sessions to the worktree and branch each holds, filtered by `--branch` (`--json`) |
|
|
66
67
|
| `canon worktrees list` | Report which worktrees are reclaimable, keyed on the pull request having merged, with every refusal and the removal route named (`--json`) |
|
|
67
68
|
| `canon worktrees reclaim` | Remove every reclaimable worktree and the branch behind it, reporting without acting under `--dry-run` (`--json`) |
|
|
@@ -187,6 +188,8 @@ Every citation in scope is reported with its file, its line number, and the line
|
|
|
187
188
|
|
|
188
189
|
A destination that already holds the same bytes marks the flat file a duplicate, which `--write` deletes rather than moves. One holding different bytes is a real collision: neither file is touched, it is reported by name, and every other planned move still applies independently. Run this before `canon gov install` or `canon gov sync` against a target still on the flat layout, since neither bootstrap verb detects or clears it on its own.
|
|
189
190
|
|
|
191
|
+
`migrate record-layout` folds two record folders under the memory pen: review receipts move from `.canon/review/memory/` to `.canon/memory/review/`, and retired entries move from `.canon/tmp/memory-archive/` to `.canon/memory/archive/`, backed for the first time since `memory/` is a folder `canon records push` carries and `tmp/` is not. Each move is refused independently when its destination already exists, and the citation repoint sweeps every folder `canon records push` carries, archives included, since an archived receipt still cites the row it retired. The same `canon-keep-record-root` marker and second-run idempotence check apply. A receipt sitting at the flat `review/` root, from before `.canon/review/memory/` existed, matches neither mapped move and is reported by name rather than moved.
|
|
192
|
+
|
|
190
193
|
## Version skew
|
|
191
194
|
|
|
192
195
|
`canon sync --check` and `canon claude skills drift` are the two moments a target
|
package/docs/agents/records.md
CHANGED
|
@@ -126,7 +126,7 @@ Exit codes: `0` reported the next ordinal, or `--claim` created the folder. `1`
|
|
|
126
126
|
|
|
127
127
|
## Size
|
|
128
128
|
|
|
129
|
-
`canon records size` reports what each record folder holds and how much of it is recent. It reads the
|
|
129
|
+
`canon records size` reports what each record folder holds and how much of it is recent. It reads the same backed folders push carries, resolved the same way, plus the scratch folder, and it gates nothing.
|
|
130
130
|
|
|
131
131
|
```bash
|
|
132
132
|
canon records size
|
|
@@ -138,7 +138,7 @@ canon records size --json
|
|
|
138
138
|
| `--json` | Add a machine-readable record on stdout |
|
|
139
139
|
| `--root <path>` | Project root, defaulting to the main worktree |
|
|
140
140
|
|
|
141
|
-
The table carries one row per folder that exists, heaviest first, with the file count, the bytes, a count for each growth window, and the dates of the least and most recently written file. Those dates render in the machine's local time, which is the calendar day whoever wrote the file was living in, and the reading is per-machine already. Folders that do not exist are named on one line below it rather than printed as rows of zeros.
|
|
141
|
+
The table carries one row per folder that exists, heaviest first, with the file count, the bytes, a count for each growth window, and the dates of the least and most recently written file. Those dates render in the machine's local time, which is the calendar day whoever wrote the file was living in, and the reading is per-machine already. Folders that do not exist are named on one line below it rather than printed as rows of zeros. At the legacy `.claude` root, the record a `--json` call emits carries every folder in the fixed list either way, each with a `present` flag, so a caller reading the record gets a stable set of keys and can tell an absent folder from one the reading skipped. At a `.canon` root, the folder set is read off the directory itself rather than off a fixed list, so an absent folder is not listed at all: nothing enumerates a name nobody has created yet.
|
|
142
142
|
|
|
143
143
|
Ordering by weight is what makes the reading worth taking. A folder listed alphabetically hides behind its neighbors, and the row a reader came for is the one that grew.
|
|
144
144
|
|
|
@@ -150,7 +150,7 @@ The scratch folder is read here and skipped by a backup, because deletable witho
|
|
|
150
150
|
|
|
151
151
|
The window counts read `mtime`, so what they report is a file written inside the window rather than one created there. An entry edited long after it landed reads as recent, which overstates growth and never understates it, and these folders are append-mostly so the two readings agree on nearly every file. The one reading that is wrong rather than early is a machine restored by `canon records pull`, which resets the work tree hard and re-dates every file it writes, so a window taken there counts the restore. Nothing on the filesystem separates the two, since a restored file is new by every stamp it carries.
|
|
152
152
|
|
|
153
|
-
Exit codes: `0` the reading completed, `1` refused. The one refusal is `no-folder`, raised when the project holds neither record root. A project holding a root and no records is empty rather than absent
|
|
153
|
+
Exit codes: `0` the reading completed, `1` refused. The one refusal is `no-folder`, raised when the project holds neither record root. A project holding a root and no records is empty rather than absent: at the legacy `.claude` root each folder's own `present` flag says which ones it carries, and at a `.canon` root the folder list itself is already the answer, since nothing absent is named.
|
|
154
154
|
|
|
155
155
|
## Push and pull
|
|
156
156
|
|
|
@@ -162,9 +162,9 @@ canon records push --json
|
|
|
162
162
|
canon records pull
|
|
163
163
|
```
|
|
164
164
|
|
|
165
|
-
|
|
165
|
+
At the `.canon` root, the backed folders are every top-level directory less three: `tmp`, which is deletable without loss, `ordinal-locks`, whose entries are transient per claim and would race the claim they guard, and `.records.git`, which is the history the rest are pushed into. Nothing bounds the set from outside, since the claude manifest ships one `.canon/` root entry and names no folder, so a record folder added later enters the payload on its own rather than waiting on a name written here. A push names each folder in scope that the records index has never tracked before, so a folder that picked up a name by mistake, such as a misrouted scratch write, is visible in the report rather than entering the payload silently. The legacy `.claude` root keeps a fixed allowlist instead, since that root also holds tracked `skills/`, `rules/`, and `hooks/` a push must never carry, and an exclusion set there would stage all three. Each name is a top-level record folder and every archive sits inside the one it archives, so the set stays at one entry per surface however many archives appear, and it deliberately does not match the six record kinds `validate` hardcodes.
|
|
166
166
|
|
|
167
|
-
Records are gitignored by design, so the history lives in a second git directory at `.records.git` inside the record root, with that root as its work tree. Both resolve off the root together rather than folder by folder, since a history opened at one root beside a work tree at the other would stage the deletion of every folder a move relocated. Every path stays where it is, which is what a separate checkout could not do. The verbs stage the
|
|
167
|
+
Records are gitignored by design, so the history lives in a second git directory at `.records.git` inside the record root, with that root as its work tree. Both resolve off the root together rather than folder by folder, since a history opened at one root beside a work tree at the other would stage the deletion of every folder a move relocated. Every path stays where it is, which is what a separate checkout could not do. The verbs stage the backed folders by explicit pathspec with `--force`, so nothing outside them can enter the index however the ignore rules read, and the project working tree and its index are never touched. Each pathspec is a bare folder name and git reads it against the current directory rather than against the work tree the same call names, so the invocation carries `-C` at the work tree beside the other two flags. That is what lets either verb run from a linked worktree under `.claude/worktrees/`, which sits inside the records work tree and would otherwise prefix every name with its own path.
|
|
168
168
|
|
|
169
169
|
### Setup
|
|
170
170
|
|
|
@@ -196,7 +196,7 @@ Point it at a private repository, and at one that is not a remote of the project
|
|
|
196
196
|
|
|
197
197
|
`split-roots` runs ahead of every gate below it and fires on a half-migrated tree, which is what a `canon migrate records` run that failed partway leaves. `recordRoot` answers for the whole tree on the first root that exists, so a folder left at the old root is absent from the work tree while the records index still names it, and an unguarded `add -A` would stage its deletion and drop it from the remote on the next push. Finish the move, or put the stranded folders back beside the others.
|
|
198
198
|
|
|
199
|
-
The two `pull` refusals exist because the directions are not symmetric. A push only adds, while a pull onto a machine holding work that never left it would discard that work. Resolve either by running `push` first, or by moving the local folders aside. A machine holding
|
|
199
|
+
The two `pull` refusals exist because the directions are not symmetric. A push only adds, while a pull onto a machine holding work that never left it would discard that work. Resolve either by running `push` first, or by moving the local folders aside. A machine holding no backed folders has nothing to lose, so a restore onto a fresh checkout runs straight through.
|
|
200
200
|
|
|
201
201
|
### When it runs
|
|
202
202
|
|
|
@@ -105,7 +105,7 @@ An execution that picks other than the suggestion rewrites the `- Suggested:` li
|
|
|
105
105
|
|
|
106
106
|
`canon records validate plans` reports where a plan and that standard disagree: a filename that is not `feature-<slug>.md`, a missing required section, a files-to-touch entry naming no file, and a question carrying a suggestion with no answer slot. The same verb takes `groundwork`, `intake`, `memory`, and `teach`, which are governed the same way and were unreachable for the same reason. Nothing fires it automatically, because all five folders are gitignored and every check the repository runs reads changed files from git. It reports and never writes, since the folders are per-machine scratch with no history to recover a wrong repair from.
|
|
107
107
|
|
|
108
|
-
`canon records push` carries these folders off the disk they live on, and `canon records pull` brings them back.
|
|
108
|
+
`canon records push` carries these folders off the disk they live on, and `canon records pull` brings them back. Every top-level entry under `.canon/` is backed except `tmp`, `ordinal-locks`, and `.records.git`, so a folder added later enters the payload on its own rather than waiting on a name written into a list. Push names each folder it carries the first time it sees it, which is what keeps a stray folder visible instead of silently entering the payload. The history lives in a second git directory at `.canon/.records.git` with `.canon/` as its work tree, so every path a task file cites stays where it is.
|
|
109
109
|
|
|
110
110
|
A person points it at a private repository once and both verbs refuse until they have, and `push` refuses when that origin is also a remote of the project, since the payload is the memory pen and the groundwork trails. `.husky/post-merge` runs the push after its archive loop, on every merge rather than only on one that closed a task. See [records](../agents/records.md) for the refusal table.
|
|
111
111
|
|
|
@@ -166,7 +166,7 @@ Capture leads rather than trails because a routed fact edits a tracked file, whi
|
|
|
166
166
|
|
|
167
167
|
If capture wrote at least one memory file, `memory-review` then proposes a decision-ready fix scoped to those entries while context is fresh, otherwise it is skipped. It stops at Propose. Review the receipt and run Apply yourself, on its own commit separate from the feature.
|
|
168
168
|
|
|
169
|
-
Run `memory-review` standalone to curate the whole pen. An entry it retires moves to `.canon/
|
|
169
|
+
Run `memory-review` standalone to curate the whole pen. An entry it retires moves to `.canon/memory/archive/` rather than being deleted, since a bulk pass has no undo.
|
|
170
170
|
|
|
171
171
|
The receipt is collected once every item on it has been decided, and it survives untouched while any item is still pending. Whichever runs first takes it: Apply collects the receipt it has resolved, and `docs-fold` scans the folder on every shipped branch for one an earlier session left behind. Before the file goes, each declined item is folded into the entry it was about, since a promotion survives in its target and in git while a decline is recorded nowhere else. `canon standards memory` states what a fold writes and which entry types take one.
|
|
172
172
|
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Route .canon/ready/ edits to the ready standard for the folder layout, the overview frontmatter, and the thin-plan contract
|
|
3
|
+
paths:
|
|
4
|
+
- '.canon/ready/**'
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Ready standards
|
|
8
|
+
|
|
9
|
+
## Authority
|
|
10
|
+
|
|
11
|
+
- Follow the ready standard for the folder layout, ordinal naming, the overview frontmatter, the mirrored tree, and the thin-plan contract. It is the single source. Read it with `canon standards ready`.
|
|
@@ -8,5 +8,5 @@ description: Keep memory writes scoped to .canon/memory/ and out of context-owne
|
|
|
8
8
|
|
|
9
9
|
- Write all memory files to `.canon/memory/`, not `~/.claude/projects/`
|
|
10
10
|
- A fact about a domain goes to that domain's `canon/context/` entry, not to memory. `canon:memory-capture` routes it there and `canon:docs-fold` folds it in. Memory keeps only what no context entry owns. Report it rather than proceeding silently when either skill does not resolve. Both ship with the plugin and this rule ships with the CLI, so a project that installed governance alone does not have them.
|
|
11
|
-
- Never delete a memory entry. Retire one by moving it to `.canon/
|
|
11
|
+
- Never delete a memory entry. Retire one by moving it to `.canon/memory/archive/`, which `canon records push` backs. A bulk retire runs through the shell, where no file edit fires a path-scoped rule.
|
|
12
12
|
- Follow the memory standard for the filename and type prefix, the frontmatter, the body shape each type carries, and the lifecycle. Read it with `canon standards memory`. Check every entry in the pen against that standard and fix what breaks it, since nothing keeps the folder conforming on its own.
|