@erclx/canon 4.85.0 → 4.87.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 +6 -6
- package/claude/skills/canon-feedback-file/SKILL.md +2 -2
- package/claude/skills/design-extract/SKILL.md +3 -3
- package/claude/skills/docs-fold/SKILL.md +3 -3
- package/claude/skills/draft-and-pick/REQUIREMENT.md +2 -1
- package/claude/skills/draft-and-pick/SKILL.md +4 -3
- package/claude/skills/draft-and-pick/references/live-arms.md +19 -0
- package/claude/skills/draft-diagram/SKILL.md +2 -2
- package/claude/skills/draft-slides/SKILL.md +1 -1
- package/claude/skills/git-ship/SKILL.md +1 -1
- package/claude/skills/memory-capture/SKILL.md +1 -1
- package/claude/skills/memory-review/SKILL.md +13 -13
- package/claude/skills/memory-review/references/receipt-format.md +1 -1
- package/claude/skills/review-branch/SKILL.md +3 -3
- package/claude/skills/role-worker/SKILL.md +2 -1
- package/claude/skills/sketch-design/SKILL.md +4 -4
- 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 +100 -95
- package/docs/agents/design-board.md +7 -7
- package/docs/workflow/ai-workflow.md +3 -3
- package/docs/workflow/visual-design-workflow.md +1 -1
- 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/cli.ts +1 -1
- package/src/commands/design.ts +3 -3
- package/src/commands/feedback.ts +12 -12
- package/src/commands/migrate.ts +168 -3
- package/src/commands/slides.ts +2 -2
- package/src/design/board.ts +17 -10
- package/src/migrate/evidence-ordinal.ts +79 -0
- package/src/migrate/record-layout.ts +599 -0
- package/src/migrate/record-tree.ts +1 -1
- package/src/migrate/scratch-evidence.ts +57 -30
- package/src/record-root.ts +4 -0
- package/standards/index.md +1 -0
- package/standards/memory.md +1 -1
- package/standards/plan.md +2 -0
- package/standards/publish.md +1 -1
- package/standards/ready.md +105 -0
- package/standards/skill.md +1 -1
- package/tooling/claude/seeds/.claude/hooks/memory-index.sh +10 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The promotion of nine cited measurement folders out of `.canon/tmp/` into
|
|
3
|
-
* `.canon/
|
|
3
|
+
* `.canon/evidence/<nn>-<folder>/`, which `canon records push` already backs.
|
|
4
4
|
*
|
|
5
5
|
* The scratch root is the one record root a disk loss takes with it, and a
|
|
6
6
|
* durable record naming a folder under it as its evidence is a citation into
|
|
@@ -26,6 +26,13 @@
|
|
|
26
26
|
import { existsSync } from 'node:fs'
|
|
27
27
|
import { mkdir, readFile, rename, writeFile } from 'node:fs/promises'
|
|
28
28
|
import { dirname, join } from 'node:path'
|
|
29
|
+
import {
|
|
30
|
+
byFirstAppearance,
|
|
31
|
+
folderNames,
|
|
32
|
+
nextOrdinal,
|
|
33
|
+
numberedName,
|
|
34
|
+
slugOf,
|
|
35
|
+
} from '@/migrate/evidence-ordinal'
|
|
29
36
|
import { presentFolders } from '@/records/backup'
|
|
30
37
|
import { recordDir, SCRATCH } from '@/record-root'
|
|
31
38
|
|
|
@@ -59,16 +66,14 @@ export const PROMOTED_FOLDERS: readonly string[] = [
|
|
|
59
66
|
'target-survey',
|
|
60
67
|
]
|
|
61
68
|
|
|
62
|
-
const EVIDENCE_ROOT = ['review', 'evidence'] as const
|
|
63
|
-
|
|
64
69
|
/** Where a promoted folder sits before the move. */
|
|
65
70
|
export function sourcePath(root: string, folder: string): string {
|
|
66
71
|
return recordDir(root, SCRATCH, folder)
|
|
67
72
|
}
|
|
68
73
|
|
|
69
|
-
/**
|
|
70
|
-
|
|
71
|
-
return recordDir(root,
|
|
74
|
+
/** The folder a promoted one lands inside, under whichever root carries it. */
|
|
75
|
+
function evidenceDir(root: string): string {
|
|
76
|
+
return recordDir(root, 'evidence')
|
|
72
77
|
}
|
|
73
78
|
|
|
74
79
|
function escape(value: string): string {
|
|
@@ -100,14 +105,14 @@ function citationPattern(folder: string): RegExp {
|
|
|
100
105
|
|
|
101
106
|
interface Rewrite {
|
|
102
107
|
readonly pattern: RegExp
|
|
103
|
-
readonly
|
|
108
|
+
readonly name: string
|
|
104
109
|
}
|
|
105
110
|
|
|
106
|
-
/** One rewrite per folder,
|
|
107
|
-
function buildRewrites(
|
|
108
|
-
return
|
|
111
|
+
/** One rewrite per folder, from its scratch name to its numbered one. */
|
|
112
|
+
function buildRewrites(names: ReadonlyMap<string, string>): readonly Rewrite[] {
|
|
113
|
+
return [...names].map(([folder, name]) => ({
|
|
109
114
|
pattern: citationPattern(folder),
|
|
110
|
-
|
|
115
|
+
name,
|
|
111
116
|
}))
|
|
112
117
|
}
|
|
113
118
|
|
|
@@ -131,8 +136,8 @@ function isKept(lines: readonly string[], index: number): boolean {
|
|
|
131
136
|
|
|
132
137
|
function rewriteLine(line: string, rewrites: readonly Rewrite[]): string {
|
|
133
138
|
return rewrites.reduce(
|
|
134
|
-
(current, { pattern,
|
|
135
|
-
current.replace(pattern, `.canon/
|
|
139
|
+
(current, { pattern, name }) =>
|
|
140
|
+
current.replace(pattern, `.canon/evidence/${name}`),
|
|
136
141
|
line,
|
|
137
142
|
)
|
|
138
143
|
}
|
|
@@ -144,7 +149,7 @@ interface RewriteOutcome {
|
|
|
144
149
|
|
|
145
150
|
/**
|
|
146
151
|
* Rewrites every unmarked citation of a folder `rewrites` covers into its
|
|
147
|
-
* destination under `.canon/
|
|
152
|
+
* destination under `.canon/evidence/`, absolute regardless of how the
|
|
148
153
|
* source citation was spelled, counting each as it goes. A file naming no
|
|
149
154
|
* such folder returns byte-identical with a count of zero, and a marked line
|
|
150
155
|
* is returned unchanged and uncounted.
|
|
@@ -232,30 +237,55 @@ export interface ScratchEvidencePlan {
|
|
|
232
237
|
}
|
|
233
238
|
|
|
234
239
|
/**
|
|
235
|
-
* Every promoted folder found on disk, with its destination,
|
|
236
|
-
*
|
|
240
|
+
* Every promoted folder found on disk, with its numbered destination, and the
|
|
241
|
+
* name each promoted folder's citations rewrite to.
|
|
242
|
+
*
|
|
243
|
+
* Folders on disk take ordinals in order of first appearance, continuing past
|
|
244
|
+
* the highest ordinal `evidence/` already holds. One whose slug `evidence/`
|
|
245
|
+
* already carries refuses rather than taking a second number, and its
|
|
246
|
+
* citations stay as they are. One already moved is not on disk under scratch,
|
|
247
|
+
* so its citations rewrite to the numbered name it landed at.
|
|
237
248
|
*/
|
|
238
249
|
export function planFolderMoves(root: string): {
|
|
239
250
|
moves: FolderMove[]
|
|
240
251
|
collisions: string[]
|
|
252
|
+
names: Map<string, string>
|
|
241
253
|
} {
|
|
254
|
+
const dir = evidenceDir(root)
|
|
255
|
+
const existing = folderNames(dir)
|
|
242
256
|
const moves: FolderMove[] = []
|
|
243
257
|
const collisions: string[] = []
|
|
258
|
+
const names = new Map<string, string>()
|
|
259
|
+
let next = nextOrdinal(existing)
|
|
260
|
+
|
|
261
|
+
const present = byFirstAppearance(
|
|
262
|
+
PROMOTED_FOLDERS.map((folder) => ({
|
|
263
|
+
name: folder,
|
|
264
|
+
dir: sourcePath(root, folder),
|
|
265
|
+
})).filter((folder) => existsSync(folder.dir)),
|
|
266
|
+
)
|
|
244
267
|
|
|
245
|
-
for (const folder of
|
|
246
|
-
const
|
|
247
|
-
if (
|
|
248
|
-
|
|
249
|
-
const to = destinationPath(root, folder)
|
|
250
|
-
if (existsSync(to)) {
|
|
251
|
-
collisions.push(to)
|
|
268
|
+
for (const { name: folder, dir: from } of present) {
|
|
269
|
+
const landed = existing.find((entry) => slugOf(entry) === folder)
|
|
270
|
+
if (landed !== undefined) {
|
|
271
|
+
collisions.push(join(dir, landed))
|
|
252
272
|
continue
|
|
253
273
|
}
|
|
254
274
|
|
|
255
|
-
|
|
275
|
+
const name = numberedName(next, folder)
|
|
276
|
+
next += 1
|
|
277
|
+
names.set(folder, name)
|
|
278
|
+
moves.push({ folder, from, to: join(dir, name) })
|
|
256
279
|
}
|
|
257
280
|
|
|
258
|
-
|
|
281
|
+
for (const folder of PROMOTED_FOLDERS) {
|
|
282
|
+
if (existsSync(sourcePath(root, folder))) continue
|
|
283
|
+
|
|
284
|
+
const landed = existing.find((entry) => slugOf(entry) === folder)
|
|
285
|
+
if (landed !== undefined) names.set(folder, landed)
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
return { moves, collisions, names }
|
|
259
289
|
}
|
|
260
290
|
|
|
261
291
|
/**
|
|
@@ -267,11 +297,8 @@ export function planScratchEvidence(
|
|
|
267
297
|
root: string,
|
|
268
298
|
sources: readonly ScratchEvidenceSource[],
|
|
269
299
|
): ScratchEvidencePlan {
|
|
270
|
-
const { moves, collisions } = planFolderMoves(root)
|
|
271
|
-
const
|
|
272
|
-
(folder) => !collisions.includes(destinationPath(root, folder)),
|
|
273
|
-
)
|
|
274
|
-
const rewrites = buildRewrites(folders)
|
|
300
|
+
const { moves, collisions, names } = planFolderMoves(root)
|
|
301
|
+
const rewrites = buildRewrites(names)
|
|
275
302
|
const entries: CitationEntry[] = []
|
|
276
303
|
|
|
277
304
|
for (const source of sources) {
|
package/src/record-root.ts
CHANGED
|
@@ -65,11 +65,15 @@ export const RECORD_ENTRIES: readonly string[] = [
|
|
|
65
65
|
SCRATCH,
|
|
66
66
|
'README.md',
|
|
67
67
|
'diagrams',
|
|
68
|
+
'evidence',
|
|
69
|
+
'feedback',
|
|
68
70
|
'groundwork',
|
|
69
71
|
'intake',
|
|
70
72
|
'memory',
|
|
73
|
+
'picks',
|
|
71
74
|
'plans',
|
|
72
75
|
'proposals',
|
|
76
|
+
'ready',
|
|
73
77
|
'review',
|
|
74
78
|
'tasks',
|
|
75
79
|
'teach',
|
package/standards/index.md
CHANGED
|
@@ -27,6 +27,7 @@ Reference docs for consistent authoring across the toolkit and target projects.
|
|
|
27
27
|
- [Pull request reference](pr.md): Pull request title and body conventions
|
|
28
28
|
- [Publish reference](publish.md): Scan an author runs against finished text, the cross-reference form each destination takes, and the response to an unreadable source
|
|
29
29
|
- [Readme reference](readme.md): Readme voice, structure, and content conventions
|
|
30
|
+
- [Ready reference](ready.md): Folder layout, ordinal naming, the overview frontmatter, the thin-plan contract, and the archive lifecycle for a finished-file handoff
|
|
30
31
|
- [Requirements reference](requirements.md): Shape and content rules for canon/REQUIREMENTS.md
|
|
31
32
|
- [Governance rule reference](rule.md): Rule frontmatter, body shape, and voice for .claude/rules files
|
|
32
33
|
- [Session map reference](session.md): Filename and location, the sections a handoff carries, the write and read procedures, and how a role extends it
|
package/standards/memory.md
CHANGED
|
@@ -88,7 +88,7 @@ Capture the pattern rather than the recovery. What was tried, what failed, and w
|
|
|
88
88
|
|
|
89
89
|
## Links
|
|
90
90
|
|
|
91
|
-
Link a related entry as `[[name]]`, where `name` is the target's filename stem without the extension. Link freely:
|
|
91
|
+
Link a related entry as `[[name]]`, where `name` is the target's filename stem without the extension. Link freely: an entry sits flat at the top level and the links are the only structure among them. `review/` and `archive/` hold receipts and retirements rather than entries, so neither takes a link.
|
|
92
92
|
|
|
93
93
|
- Place links inside the body part they support, not in a list of their own at the end.
|
|
94
94
|
- A link naming an entry nobody has written yet is legal, and it marks a rule worth writing rather than a defect.
|
package/standards/plan.md
CHANGED
|
@@ -85,6 +85,8 @@ A constraint measured against work in flight expires when that work merges, and
|
|
|
85
85
|
|
|
86
86
|
A dead constraint fails silently in the expensive direction. A session honoring one ships the dangling citation the change created and reports success, where a session crossing a live constraint collides visibly and is caught.
|
|
87
87
|
|
|
88
|
+
A constraint naming a `.canon/ready/` folder is a third shape beside the two above. It makes that folder's files the verbatim source for the paths this plan's `**Files to touch:**` lists, per `ready.md`, so the executing session copies those paths rather than authoring them.
|
|
89
|
+
|
|
88
90
|
### Risks
|
|
89
91
|
|
|
90
92
|
- Name the collision rather than the category. A risk a reader cannot act on is padding.
|
package/standards/publish.md
CHANGED
|
@@ -40,7 +40,7 @@ This check is one of the two the destination rule above scopes. The reader insid
|
|
|
40
40
|
|
|
41
41
|
A phase label is one way text names the board, and a path under a record root is the other. Both resolve for a reader holding this checkout and neither resolves for anyone else, so this check is the second one the destination rule scopes.
|
|
42
42
|
|
|
43
|
-
Two shapes get past a reader scanning for a bare label. A code span quoting a label is still the label, so read a span whose whole content is one as a hit and leave a longer token inside a span alone, which is a fixture name rather than a reference. The second shape is a path under a record root, gitignored and therefore absent from every clone, so `.canon/
|
|
43
|
+
Two shapes get past a reader scanning for a bare label. A code span quoting a label is still the label, so read a span whose whole content is one as a hit and leave a longer token inside a span alone, which is a fixture name rather than a reference. The second shape is a path under a record root, gitignored and therefore absent from every clone, so `.canon/feedback/` names a folder the remote's reader cannot open.
|
|
44
44
|
|
|
45
45
|
Under the tracked `canon/` and `.claude/` folders there is no hit, since `canon/context/governance/rules.md` resolves everywhere. `.canon/` carries no such carve-out: one ignore line covers the root whole, so every path beneath it is a hit regardless of which folder names it.
|
|
46
46
|
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Ready reference
|
|
3
|
+
description: Folder layout, ordinal naming, the overview frontmatter, the thin-plan contract, and the archive lifecycle for a finished-file handoff
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Ready reference
|
|
7
|
+
|
|
8
|
+
Applies to a ready folder at `.canon/ready/<nn>-<slug>/`. A warm session that has already written a skill, a rule, or another finished file uses it to hand the exact text to the worker that ships it, since a plan only describes a change and a cold worker reading a description writes the file again from scratch. The folder holds the finished files themselves, laid out at their destination paths, so the worker's job is to copy rather than to author.
|
|
9
|
+
|
|
10
|
+
The folder is gitignored, and backed wherever a records remote is configured: `canon records push` and `canon records pull` protect it against the machine being lost there, refuse with `no-remote` where it is not, and protect nothing against a folder deleted before anyone has pushed. That is why the archive step below is a move rather than a cleanup.
|
|
11
|
+
|
|
12
|
+
## Scope
|
|
13
|
+
|
|
14
|
+
Governs a ready folder under `.canon/ready/<nn>-<slug>/`: folder layout, ordinal naming, the overview's frontmatter, what the mirrored tree holds, the thin-plan contract that ships it, and the lifecycle from the live folder to the archive.
|
|
15
|
+
|
|
16
|
+
Does not govern:
|
|
17
|
+
|
|
18
|
+
- The thin plan itself, its filename, its sections, and its suggested-and-answer contract: `plan.md`
|
|
19
|
+
- The task file that reaches a ready folder through a plan, and the origin line pointing back at it: `tasks.md`
|
|
20
|
+
- Voice, rhythm, and sentence construction: the `write-human` skill
|
|
21
|
+
- Headings, punctuation, word choice, and file references: `markdown.md`
|
|
22
|
+
- Whether a change earns a ready folder over a plan a worker builds from scratch, which belongs to the warm session deciding how to hand off its own work
|
|
23
|
+
|
|
24
|
+
## What a working ready folder looks like
|
|
25
|
+
|
|
26
|
+
A ready folder works when a worker that has never seen the warm session's conversation can copy from it alone:
|
|
27
|
+
|
|
28
|
+
- Which destination path does each file land at, and does the folder hold nothing else?
|
|
29
|
+
- What is the worker still responsible for that the files themselves do not carry, such as a docs sync, a sandbox scenario, or a test?
|
|
30
|
+
- What branch type does the change take?
|
|
31
|
+
- Is every path the folder mirrors also declared in the thin plan's `**Files to touch:**`?
|
|
32
|
+
|
|
33
|
+
A ready folder failing these is non-conforming even when it satisfies every shape rule below.
|
|
34
|
+
|
|
35
|
+
## Folder name
|
|
36
|
+
|
|
37
|
+
- Name the folder `<nn>-<slug>`, a two-digit zero-padded ordinal followed by a kebab-case slug matching the plan's own slug.
|
|
38
|
+
- The ordinal marks a folder per handoff, opened once by the warm session that writes it. It runs on its own sequence, separate from groundwork and intake's shared one, since a ready folder is not a measurement track.
|
|
39
|
+
- With no folder holding an entry yet, the first one opened takes `01`. Read the highest existing `.canon/ready/<nn>-*/` folder, including the archive, and take the next integer.
|
|
40
|
+
- Never renumber an existing folder. The ordinal is the order it opened, and the pull request that shipped it cites the folder by that name.
|
|
41
|
+
|
|
42
|
+
## 00-overview.md
|
|
43
|
+
|
|
44
|
+
Every ready folder carries `00-overview.md` at its root, beside the mirrored tree. It orients the worker and states what the files themselves cannot.
|
|
45
|
+
|
|
46
|
+
- `title` (required): the change in sentence case
|
|
47
|
+
- `description` (required): one line naming what the handoff carries
|
|
48
|
+
- `type` (required): the branch type the plan should take, one of the types `branch.md` fixes
|
|
49
|
+
- `destinations` (required): the list of destination paths the folder mirrors, matching the thin plan's `**Files to touch:**` exactly
|
|
50
|
+
|
|
51
|
+
```yaml
|
|
52
|
+
---
|
|
53
|
+
title: <Change in sentence case>
|
|
54
|
+
description: <one line naming what the handoff carries>
|
|
55
|
+
type: <feat | fix | chore | ...>
|
|
56
|
+
destinations:
|
|
57
|
+
- <path/to/file>
|
|
58
|
+
---
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Below the frontmatter, state in prose what the worker still owns beyond copying the files: a docs sync, a sandbox scenario update, a test the files do not include, or "nothing further" where the files are the whole of the change.
|
|
62
|
+
|
|
63
|
+
## The mirrored tree
|
|
64
|
+
|
|
65
|
+
- Every other file in the folder sits at the same relative path its destination has in the project, so `standards/ready.md` inside the destination tree sits at `<nn>-<slug>/standards/ready.md` inside the ready folder.
|
|
66
|
+
- Carry no file the destination tree would not carry. A ready folder is a source for `git mv`-shaped copies, not a scratch pad for the warm session's own notes. Anything else belongs in the plan or in the pull request body.
|
|
67
|
+
- Write each file exactly as it should land. The worker copies verbatim and edits only what the gate or the overview's own list requires, so a placeholder or a half-finished passage ships as written.
|
|
68
|
+
|
|
69
|
+
## The thin-plan contract
|
|
70
|
+
|
|
71
|
+
- A ready folder ships through an ordinary task row and a plan at `.canon/plans/feature-<slug>.md`, per `plan.md`. No new plan shape exists for it.
|
|
72
|
+
- Name the ready folder in the plan's `**Constraints:**`, stating that the folder's files are the verbatim source for the paths the plan's `**Files to touch:**` lists.
|
|
73
|
+
- List every destination path in `**Files to touch:**`, matching `00-overview.md`'s `destinations` field. A path the plan omits is invisible to `plan-reach`'s collision check, so a mismatch between the two lists is a defect in the plan rather than a variant the standard permits.
|
|
74
|
+
- Keep the plan itself thin. Its `**Files to touch:**` entries may point at the ready folder's own copy for the reason behind each file rather than restating it, since the overview and the files already carry the detail a plan would otherwise duplicate.
|
|
75
|
+
|
|
76
|
+
## Lifecycle
|
|
77
|
+
|
|
78
|
+
- Write the ready folder in the same session that writes the files it carries. A folder assembled later from memory is a plan with extra steps, not a handoff.
|
|
79
|
+
- Move the folder to `.canon/ready/archive/<nn>-<slug>/` by hand when the task that shipped it archives. No board verb currently automates this move. `canon tasks archive` moves the task and its plan and leaves the ready folder where it is.
|
|
80
|
+
- Never delete a ready folder. The archived copy sits beside the merged pull request as the exact text that shipped, the way an archived plan sits beside the reasoning that produced it.
|
|
81
|
+
|
|
82
|
+
## Anti-patterns
|
|
83
|
+
|
|
84
|
+
- **The folder with an undeclared destination.** A file the plan's `**Files to touch:**` does not list passes the collision check unseen, and a second track can write the same path without either side finding out.
|
|
85
|
+
- **The rewritten copy.** A worker that reads the folder's files as inspiration and writes its own version loses the exact text the handoff exists to carry.
|
|
86
|
+
- **The folder as scratch.** Notes, alternates, or draft passages left in the folder beside the real files leave the worker guessing which is the source.
|
|
87
|
+
- **The folder left live after shipping.** A ready folder nobody moves to the archive reads as unshipped work to the next session that lists the live folder.
|
|
88
|
+
|
|
89
|
+
## Template
|
|
90
|
+
|
|
91
|
+
```markdown
|
|
92
|
+
.canon/ready/<nn>-<slug>/
|
|
93
|
+
├── 00-overview.md
|
|
94
|
+
└── <path/to/file> # mirrors the destination tree, one entry per file
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
```yaml
|
|
98
|
+
---
|
|
99
|
+
title: <Change in sentence case>
|
|
100
|
+
description: <one line naming what the handoff carries>
|
|
101
|
+
type: <feat | fix | chore | ...>
|
|
102
|
+
destinations:
|
|
103
|
+
- <path/to/file>
|
|
104
|
+
---
|
|
105
|
+
```
|
package/standards/skill.md
CHANGED
|
@@ -210,7 +210,7 @@ Without this skill, a session <observed failure>, <observed failure>.
|
|
|
210
210
|
### Output and tuning
|
|
211
211
|
|
|
212
212
|
- Skill success lines emit the full relative path from the project root (`<dir>/<file>`) for any file written, updated, or deleted. A bare filename names a file the reader cannot open. The `## Output` section of the project's instruction file sets the form that path takes, so a skill body states which path is emitted and leaves the form to that section.
|
|
213
|
-
- Before a skill writes anything, decide whether the output is a deliverable the project keeps or a toolkit session record. A deliverable lands among the project's own tracked files. A session record lands under `.canon/`, in the named subfolder for its kind (`tasks/`, `plans/`, `review/`, `memory/`, `groundwork/`, `intake/`, `proposals/`, `diagrams/`, `teach/`, or `walkthroughs/`, with `tmp/` for scratch nothing else claims), never in a folder the body invents. `canon/ARCHITECTURE.md`'s per-folder decisions are the precedent for which kind takes which folder.
|
|
213
|
+
- Before a skill writes anything, decide whether the output is a deliverable the project keeps or a toolkit session record. A deliverable lands among the project's own tracked files. A session record lands under `.canon/`, in the named subfolder for its kind (`tasks/`, `plans/`, `review/`, `memory/`, `groundwork/`, `intake/`, `proposals/`, `diagrams/`, `teach/`, `ready/`, `feedback/`, `picks/`, `evidence/`, `transcripts/`, or `walkthroughs/`, with `tmp/` for scratch nothing else claims), never in a folder the body invents. A `review/` writer names its file `<kind>-<slug>.md` and writes it flat, and an `evidence/` folder takes the next two-digit ordinal as `<nn>-<slug>/`, numbered in the order the folders first appeared. `canon/ARCHITECTURE.md`'s per-folder decisions are the precedent for which kind takes which folder.
|
|
214
214
|
- Codify a skill's posted or generated output as a fenced template, and keep the body consistent with every capability the frontmatter description names.
|
|
215
215
|
- When a skill gathers user input or pre-seeds a template, attach a concrete proposed default to every question, derived from project context. Accept "use defaults" as a bulk-confirm.
|
|
216
216
|
- Separate correctness axes (routing, sourcing, escalation, decline) from shape axes (line count, formatting, variant sprawl) when tuning a skill. Tighten only on correctness regressions. Do not convert soft caps to hard caps for aesthetic drift when correctness passes.
|
|
@@ -33,6 +33,16 @@ case "$file_path" in
|
|
|
33
33
|
*) exit 0 ;;
|
|
34
34
|
esac
|
|
35
35
|
|
|
36
|
+
# A shell `case` `*` crosses `/`, so the match above also catches a receipt
|
|
37
|
+
# under memory/review/ or a retired entry under memory/archive/. Neither is
|
|
38
|
+
# a pen entry the index renders, so both exit here before the regen call.
|
|
39
|
+
case "$file_path" in
|
|
40
|
+
*/.claude/memory/review/* | */.canon/memory/review/* | \
|
|
41
|
+
*/.claude/memory/archive/* | */.canon/memory/archive/*)
|
|
42
|
+
exit 0
|
|
43
|
+
;;
|
|
44
|
+
esac
|
|
45
|
+
|
|
36
46
|
case "$file_path" in
|
|
37
47
|
*/.claude/memory/index.md | */.canon/memory/index.md) exit 0 ;;
|
|
38
48
|
esac
|