@erclx/canon 5.69.0 → 5.71.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/CHANGELOG.md +25 -0
- package/README.md +33 -159
- package/assets/brand/mark.svg +17 -9
- package/claude/.claude-plugin/plugin.json +1 -1
- package/claude/skills/app-drive/SKILL.md +3 -2
- package/claude/skills/app-drive/references/drive-record.md +52 -10
- package/claude/skills/app-drive/references/isolate.md +1 -1
- package/claude/skills/design-pick/SKILL.md +1 -0
- package/claude/skills/git-pr/references/task-number.md +13 -0
- package/claude/skills/markdown-craft/references/markdown.md +1 -0
- package/claude/skills/role-orchestrator/references/orchestrator-cloud-launch.md +1 -0
- package/claude/skills/role-orchestrator/references/orchestrator-launch.md +6 -20
- package/claude/skills/role-orchestrator/references/orchestrator-reviewer-launch.md +10 -0
- package/claude/skills/role-orchestrator/references/orchestrator-talk-launch.md +30 -0
- package/claude/skills/task-board/references/tasks-record-lines.md +40 -0
- package/claude/skills/task-board/references/tasks.md +4 -8
- package/claude/skills/ui-craft/references/copy.md +4 -1
- package/claude/skills/ui-film/REQUIREMENT.md +4 -2
- package/claude/skills/ui-film/SKILL.md +24 -11
- package/claude/skills/ui-film/references/compose-craft.md +81 -0
- package/claude/skills/ui-film/references/config.md +6 -1
- package/claude/skills/ui-film/references/handoff.md +13 -3
- package/claude/skills/ui-film/references/take-craft.md +27 -1
- package/docs/index.md +1 -0
- package/docs/migrations/by-hand.md +107 -0
- package/docs/migrations/by-verb.md +118 -0
- package/docs/migrations/index.md +14 -0
- package/docs/target/index.md +1 -2
- package/docs/target/projects.md +2 -2
- package/docs/target/sync.md +22 -2
- package/docs/workflow/ai-workflow.md +1 -1
- package/governance/ledger/skills/ui-craft/copy.md +8 -4
- package/package.json +3 -1
- package/scripts/core/design-sync.ts +204 -0
- package/scripts/core/regen-web-favicon.ts +27 -12
- package/scripts/core/regen-web-previews.ts +8 -1
- package/scripts/core/render-film.ts +179 -0
- package/src/capture/frame-values.ts +12 -12
- package/src/commands/markdown.ts +6 -1
- package/src/commands/records.ts +3 -2
- package/src/commands/sandbox.ts +9 -2
- package/src/commands/take.ts +159 -11
- package/src/commands/tasks.ts +133 -0
- package/src/design/favicon.ts +85 -13
- package/src/design/reference.ts +98 -0
- package/src/design/render.ts +16 -14
- package/src/design/tokens.ts +4 -3
- package/src/gate/stages.ts +6 -0
- package/src/init/steps.ts +2 -2
- package/src/markdown/colons.ts +102 -16
- package/src/migrate/status.ts +3 -3
- package/src/records/validate.ts +14 -2
- package/src/sandbox/expect.ts +32 -0
- package/src/sandbox/headless/run.ts +6 -3
- package/src/take/camera.ts +99 -10
- package/src/take/film.ts +35 -2
- package/src/take/fixtures/input.html +138 -0
- package/src/take/keys.ts +193 -0
- package/src/take/log.ts +94 -1
- package/src/take/perform.ts +165 -10
- package/src/take/plan.ts +101 -6
- package/src/take/screencast.ts +28 -3
- package/src/take/stepper.ts +122 -18
- package/src/tasks/archive.ts +54 -1
- package/src/tasks/record.ts +118 -0
- package/src/tasks/validate.ts +37 -0
- package/docs/target/migrations.md +0 -205
package/src/tasks/record.ts
CHANGED
|
@@ -15,6 +15,9 @@ import {
|
|
|
15
15
|
readPendingBranches,
|
|
16
16
|
readPlanTargets,
|
|
17
17
|
readPullRequest,
|
|
18
|
+
readSessions,
|
|
19
|
+
SESSION_ID_PATTERN,
|
|
20
|
+
SESSIONS_PREFIX,
|
|
18
21
|
tasksDir,
|
|
19
22
|
} from '@/tasks/archive'
|
|
20
23
|
import { checkWaiting, type LinkPromotion, promoteOnLink } from '@/tasks/board'
|
|
@@ -34,6 +37,9 @@ const ORIGIN_PREFIXES = ['Plan:', 'Groundwork:', 'Intake:', 'Issue:'] as const
|
|
|
34
37
|
*
|
|
35
38
|
* `several-plans` answers a `Plan:` line that already links more than one plan.
|
|
36
39
|
* `plan-link` cannot know which link to drop, so it writes nothing.
|
|
40
|
+
*
|
|
41
|
+
* `no-name` answers a session id the roster no longer lists, called with no
|
|
42
|
+
* name, since an id written alone reads as nobody to the next reader.
|
|
37
43
|
*/
|
|
38
44
|
export const RECORD_REFUSALS = [
|
|
39
45
|
'no-board',
|
|
@@ -44,6 +50,7 @@ export const RECORD_REFUSALS = [
|
|
|
44
50
|
'no-plan',
|
|
45
51
|
'several-plans',
|
|
46
52
|
'bad-input',
|
|
53
|
+
'no-name',
|
|
47
54
|
] as const
|
|
48
55
|
|
|
49
56
|
export type RecordRefusal = (typeof RECORD_REFUSALS)[number]
|
|
@@ -88,6 +95,18 @@ export interface PlanRecorded {
|
|
|
88
95
|
|
|
89
96
|
export type PlanOutcome = PlanRecorded | RecordRefused
|
|
90
97
|
|
|
98
|
+
export interface SessionRecorded {
|
|
99
|
+
readonly ok: true
|
|
100
|
+
readonly stem: string
|
|
101
|
+
readonly path: string
|
|
102
|
+
readonly sessionId: string
|
|
103
|
+
/** The name the line carries for the id, which a repeat call never renames. */
|
|
104
|
+
readonly name: string
|
|
105
|
+
readonly action: Exclude<LineAction, 'corrected'>
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export type SessionOutcome = SessionRecorded | RecordRefused
|
|
109
|
+
|
|
91
110
|
export interface OutcomesClosed {
|
|
92
111
|
readonly ok: true
|
|
93
112
|
readonly stem: string
|
|
@@ -228,6 +247,47 @@ export function clearPendingBranch(
|
|
|
228
247
|
return { text: lines.join('\n'), changed: true }
|
|
229
248
|
}
|
|
230
249
|
|
|
250
|
+
/**
|
|
251
|
+
* Names a session on the `Sessions:` line, keyed on the id, so a dispatcher
|
|
252
|
+
* and `git-pr` recording the same worker write it once. The line sits below
|
|
253
|
+
* every other line a task carries above its outcomes, so a pull request
|
|
254
|
+
* recorded later lands above it.
|
|
255
|
+
*/
|
|
256
|
+
export function writeSessionsLine(
|
|
257
|
+
text: string,
|
|
258
|
+
name: string,
|
|
259
|
+
sessionId: string,
|
|
260
|
+
): { readonly text: string; readonly action: SessionRecorded['action'] } {
|
|
261
|
+
const entry = `${name} (${sessionId})`
|
|
262
|
+
const lines = text.split('\n')
|
|
263
|
+
const existing = lines.findIndex((line) => line.startsWith(SESSIONS_PREFIX))
|
|
264
|
+
|
|
265
|
+
if (existing !== -1) {
|
|
266
|
+
if (lines[existing].includes(`(${sessionId})`)) {
|
|
267
|
+
return { text, action: 'unchanged' }
|
|
268
|
+
}
|
|
269
|
+
lines[existing] = `${lines[existing].trimEnd()}, ${entry}`
|
|
270
|
+
return { text: lines.join('\n'), action: 'appended' }
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
const line = `${SESSIONS_PREFIX} ${entry}`
|
|
274
|
+
const anchor = lastOriginLine(lines, [
|
|
275
|
+
...ORIGIN_PREFIXES,
|
|
276
|
+
'Pull request:',
|
|
277
|
+
PENDING_PREFIX,
|
|
278
|
+
])
|
|
279
|
+
if (anchor !== undefined) {
|
|
280
|
+
lines.splice(anchor + 1, 0, line)
|
|
281
|
+
return { text: lines.join('\n'), action: 'added' }
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
const heading = lines.findIndex((entry) => entry.startsWith('# '))
|
|
285
|
+
if (heading === -1) return { text: `${line}\n${text}`, action: 'added' }
|
|
286
|
+
|
|
287
|
+
lines.splice(heading + 1, 0, '', line)
|
|
288
|
+
return { text: lines.join('\n'), action: 'added' }
|
|
289
|
+
}
|
|
290
|
+
|
|
231
291
|
export type PlanLineWrite =
|
|
232
292
|
| {
|
|
233
293
|
readonly ok: true
|
|
@@ -566,6 +626,64 @@ export async function recordPlan(
|
|
|
566
626
|
}
|
|
567
627
|
}
|
|
568
628
|
|
|
629
|
+
/**
|
|
630
|
+
* Records a session that worked a task on its `Sessions:` line. The caller
|
|
631
|
+
* resolves `name` from the roster or takes it from `--name`, and an undefined
|
|
632
|
+
* name refuses rather than writing a bare id. The id is checked first, since a
|
|
633
|
+
* malformed one is a caller defect and every later check would hide it.
|
|
634
|
+
*/
|
|
635
|
+
export async function recordSession(
|
|
636
|
+
root: string,
|
|
637
|
+
selector: RecordSelector,
|
|
638
|
+
sessionId: string,
|
|
639
|
+
name: string | undefined,
|
|
640
|
+
): Promise<SessionOutcome> {
|
|
641
|
+
if (!SESSION_ID_PATTERN.test(sessionId)) {
|
|
642
|
+
return refuse(
|
|
643
|
+
'bad-input',
|
|
644
|
+
`Not a full sessionId: ${sessionId}. Pass the whole id canon sessions list --json carries.`,
|
|
645
|
+
[sessionId],
|
|
646
|
+
)
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
if (name === undefined) {
|
|
650
|
+
return refuse(
|
|
651
|
+
'no-name',
|
|
652
|
+
`No live session carries ${sessionId}, so its name cannot be read. Pass --name.`,
|
|
653
|
+
[sessionId],
|
|
654
|
+
)
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
const trimmed = name.trim()
|
|
658
|
+
if (trimmed.length === 0 || /[\r\n]/.test(trimmed)) {
|
|
659
|
+
return refuse('bad-input', 'A session name is one non-empty line.', [name])
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
const opened = await openTask(root, selector)
|
|
663
|
+
if ('ok' in opened) return opened
|
|
664
|
+
|
|
665
|
+
const { stem, path } = opened
|
|
666
|
+
const written = writeSessionsLine(
|
|
667
|
+
await readFile(path, 'utf8'),
|
|
668
|
+
trimmed,
|
|
669
|
+
sessionId,
|
|
670
|
+
)
|
|
671
|
+
if (written.action !== 'unchanged') await writeFile(path, written.text)
|
|
672
|
+
|
|
673
|
+
const listed = readSessions(written.text).find(
|
|
674
|
+
(entry) => entry.sessionId === sessionId,
|
|
675
|
+
)
|
|
676
|
+
|
|
677
|
+
return {
|
|
678
|
+
ok: true,
|
|
679
|
+
stem,
|
|
680
|
+
path,
|
|
681
|
+
sessionId,
|
|
682
|
+
name: listed?.name ?? trimmed,
|
|
683
|
+
action: written.action,
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
|
|
569
687
|
/**
|
|
570
688
|
* Marks the named outcomes `[x]` in place. `task-complete` runs this against a
|
|
571
689
|
* board it can read and cannot edit from a linked worktree, and the positions
|
package/src/tasks/validate.ts
CHANGED
|
@@ -10,7 +10,9 @@ import {
|
|
|
10
10
|
readPendingBranches,
|
|
11
11
|
readPlanTargets,
|
|
12
12
|
readPullRequest,
|
|
13
|
+
readSessions,
|
|
13
14
|
resolveLivePlan,
|
|
15
|
+
SESSIONS_PREFIX,
|
|
14
16
|
tasksDir,
|
|
15
17
|
} from '@/tasks/archive'
|
|
16
18
|
import {
|
|
@@ -66,6 +68,7 @@ export const FINDING_KINDS = [
|
|
|
66
68
|
'blocker-settled',
|
|
67
69
|
'blocker-unresolved',
|
|
68
70
|
'blocker-declined',
|
|
71
|
+
'sessions-misshapen',
|
|
69
72
|
] as const
|
|
70
73
|
|
|
71
74
|
export type FindingKind = (typeof FINDING_KINDS)[number]
|
|
@@ -841,6 +844,39 @@ async function planDisagreement(
|
|
|
841
844
|
}
|
|
842
845
|
}
|
|
843
846
|
|
|
847
|
+
/**
|
|
848
|
+
* Reports a `Sessions:` line that does not parse as name and id pairs, since
|
|
849
|
+
* the reader takes such a line as naming nobody and a retro would find the
|
|
850
|
+
* sessions gone. A row whose task file is gone is left to `task-unresolved`.
|
|
851
|
+
*/
|
|
852
|
+
async function checkSessions(
|
|
853
|
+
rows: readonly BoardRow[],
|
|
854
|
+
dir: string,
|
|
855
|
+
): Promise<Finding[]> {
|
|
856
|
+
const found = await Promise.all(
|
|
857
|
+
rows.map(async (row): Promise<Finding | undefined> => {
|
|
858
|
+
if (!row.stem) return undefined
|
|
859
|
+
const file = join(dir, `${row.stem}.md`)
|
|
860
|
+
if (!existsSync(file)) return undefined
|
|
861
|
+
|
|
862
|
+
const text = await readFile(file, 'utf8')
|
|
863
|
+
const line = text
|
|
864
|
+
.split('\n')
|
|
865
|
+
.find((entry) => entry.startsWith(SESSIONS_PREFIX))
|
|
866
|
+
if (line === undefined || readSessions(text).length > 0) return undefined
|
|
867
|
+
|
|
868
|
+
return {
|
|
869
|
+
kind: 'sessions-misshapen',
|
|
870
|
+
group: row.group,
|
|
871
|
+
subject: row.stem,
|
|
872
|
+
message: `carries "${line}", which does not read as name (sessionId) pairs, so no session it names can be recovered. Rewrite it through canon tasks session.`,
|
|
873
|
+
}
|
|
874
|
+
}),
|
|
875
|
+
)
|
|
876
|
+
|
|
877
|
+
return found.filter((finding): finding is Finding => finding !== undefined)
|
|
878
|
+
}
|
|
879
|
+
|
|
844
880
|
/**
|
|
845
881
|
* Tests the claim a group name makes about a plan. `## Needs a plan` says none
|
|
846
882
|
* is live and `## Up next` says one is written, and neither group has a `Plan`
|
|
@@ -1638,6 +1674,7 @@ export async function validateBoard(
|
|
|
1638
1674
|
...checkMapping(rows, backlog, dir),
|
|
1639
1675
|
...(await groupRuleFindings(rows, root)),
|
|
1640
1676
|
...(await checkPlanAgreement(rows, dir, root)),
|
|
1677
|
+
...(await checkSessions(rows, dir)),
|
|
1641
1678
|
...(await checkStaleTouches(rows, root)),
|
|
1642
1679
|
...checkCellWidth(rows),
|
|
1643
1680
|
...checkOrdering(rows),
|
|
@@ -1,205 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: Target migrations
|
|
3
|
-
description: One-time moves a project scaffolded under an older toolkit runs before its next sync
|
|
4
|
-
category: Agent surface
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# Target migrations
|
|
8
|
-
|
|
9
|
-
Each section is a move a project runs once, when it was scaffolded before the change it names. Run `canon upgrade` first, then `canon migrate status --json` to list the moves a project still needs in the order to run them. The recurring sync that follows is in [target sync](sync.md).
|
|
10
|
-
|
|
11
|
-
`canon:target-update` is the guided path through both. It runs the moves in that order once you approve its preview.
|
|
12
|
-
|
|
13
|
-
## Move the records first, once
|
|
14
|
-
|
|
15
|
-
Gitignored session records, being the task board, plans, review reports, and scratch, moved from `.claude/` to `.canon/`. Run these from inside the project, and read the `ok` field of the `--json` record rather than the exit code.
|
|
16
|
-
|
|
17
|
-
```bash
|
|
18
|
-
canon tooling sync claude . --write
|
|
19
|
-
canon migrate records --json
|
|
20
|
-
canon migrate records --write --json
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
The first line takes the `.canon/` ignore entry. The second reports and the third applies, repointing files that cite a moved folder and deleting a `.gitignore` line `.canon/` covers, as `dropped`. A line naming an old path keeps it via `canon-keep-record-root` on that line or the nearest non-blank one above.
|
|
24
|
-
|
|
25
|
-
Then sweep the citations inside the records, which the verb above never reaches.
|
|
26
|
-
|
|
27
|
-
```bash
|
|
28
|
-
canon migrate record-tree --json
|
|
29
|
-
canon migrate record-tree --write --json
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
It covers `diagrams`, `memory`, `plans`, `proposals`, `review`, `tasks`, and `teach`. Read the report before `--write`. The record tree is untracked, and a wrong rewrite has no undo.
|
|
33
|
-
|
|
34
|
-
## Back records up off this machine, once
|
|
35
|
-
|
|
36
|
-
Run `canon records push` once a private repository exists. It prints the one-time setup command when it finds none, and `canon init` prints the same reminder.
|
|
37
|
-
|
|
38
|
-
## Move rules off the flat layout, once
|
|
39
|
-
|
|
40
|
-
Installed rules moved from `.claude/rules/<subdir>/` to `.claude/rules/canon/<subdir>/`. On the flat layout `canon gov sync` exits 0 reporting `No governance surfaces found in target`, and `canon gov install` lands a second copy.
|
|
41
|
-
|
|
42
|
-
```bash
|
|
43
|
-
canon migrate rule-layout --json
|
|
44
|
-
canon migrate rule-layout --write --json
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
Run it once, ahead of `canon gov sync` or `canon gov install`.
|
|
48
|
-
|
|
49
|
-
## Rename the skill citations, once
|
|
50
|
-
|
|
51
|
-
Plugin skills dropped their `claude-` prefix, so `canon:claude-docs` is now `canon:context-fold`. Five drafters merged into `write-doc`, seven `draft-` skills took verb-first names, and four joined their family. No old name keeps a pointer, and `canon migrate skill-names --write` moves a project. <!-- canon-keep-retired -->
|
|
52
|
-
|
|
53
|
-
| Old name | New name |
|
|
54
|
-
| ------------------ | ----------------------------------------------- |
|
|
55
|
-
| `draft-doc` | `write-doc` <!-- canon-keep-retired --> |
|
|
56
|
-
| `draft-figure` | `draw-figure` <!-- canon-keep-retired --> |
|
|
57
|
-
| `draft-identity` | `design-identity` <!-- canon-keep-retired --> |
|
|
58
|
-
| `draft-slides` | `make-deck` <!-- canon-keep-retired --> |
|
|
59
|
-
| `draft-and-pick` | `design-pick` <!-- canon-keep-retired --> |
|
|
60
|
-
| `draft-ready` | `plan-ready` <!-- canon-keep-retired --> |
|
|
61
|
-
| `draft-screencast` | `script-screencast` <!-- canon-keep-retired --> |
|
|
62
|
-
| `pick-by-eye` | `design-pick` <!-- canon-keep-retired --> |
|
|
63
|
-
| `ui-record` | `ui-film` <!-- canon-keep-retired --> |
|
|
64
|
-
| `ux-audit` | `ui-audit` <!-- canon-keep-retired --> |
|
|
65
|
-
| `ux-measure` | `ui-measure` <!-- canon-keep-retired --> |
|
|
66
|
-
|
|
67
|
-
Replace a citation of a skill with no successor by hand, or delete the sentence.
|
|
68
|
-
|
|
69
|
-
- `canvas` is now `canvas-board`. The sweep rewrites only `canon:canvas` and `skills/canvas`, so replace a bare mention by hand. <!-- canon-keep-retired -->
|
|
70
|
-
- `draft-ready` is rewritten only as `canon:draft-ready` and `skills/draft-ready`, since bare it also describes a pull request, so replace a bare mention by hand. <!-- canon-keep-retired -->
|
|
71
|
-
- `design-extract` and `sketch-design` are replaced by `canon:canvas-board`. <!-- canon-keep-retired -->
|
|
72
|
-
- `review-branch`, `seed-sync`, `restate-plainly`, `bash-cli-script`, `canon-operator`, `canon-rollout`, and `canon-feedback-triage` have no successor <!-- canon-keep-retired -->
|
|
73
|
-
- `create-standard`, `markdown-propose`, `memory-review`, `project-commands`, `repo-metadata`, `ux-walkthrough`, and `plan-ready` have no successor <!-- canon-keep-retired -->
|
|
74
|
-
|
|
75
|
-
The `memory` record kind left `canon records`, so `canon records validate memory` refuses as an unknown kind and `canon records migrate` is gone.
|
|
76
|
-
|
|
77
|
-
- `canon repo metadata`, `canon autoship`, and the `120-bash` rule are gone, and `canon gov sync` removes the rule <!-- canon-keep-retired -->
|
|
78
|
-
- `memory-capture`, the `603-memory` rule, and the `memory` standard are gone, so send a lesson to the context entry that owns the fact <!-- canon-keep-retired -->
|
|
79
|
-
|
|
80
|
-
Two held files run, `.husky/post-merge` and `.claude/hooks/pr-create-log.sh`, and a stale copy calls a missing binary or names a removed skill. Resync what the toolkit owns before sweeping what the project wrote, and run the second line once per stack, naming a held hook with `--replace`.
|
|
81
|
-
|
|
82
|
-
```bash
|
|
83
|
-
canon gov sync
|
|
84
|
-
canon tooling sync <stack> . --write
|
|
85
|
-
canon migrate skill-names --json
|
|
86
|
-
canon migrate skill-names --write --json
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
## Rename the pull request template headings, once
|
|
90
|
-
|
|
91
|
-
The template headings are now `## Key changes` and `## Technical context`, and `canon labels scan` compares case exactly. Rename them in `.github/pull_request_template.md`, or delete it and run `canon tooling sync base . --write`.
|
|
92
|
-
|
|
93
|
-
## Move the surfaces off `.claude/`, once
|
|
94
|
-
|
|
95
|
-
`context/`, `wireframes/`, `ARCHITECTURE.md`, `REQUIREMENTS.md`, `DESIGN.md`, and the install stamp folder, now `canon/config/`, moved under `canon/`. `rules/`, `skills/`, `hooks/`, and `settings.json` stay where Claude Code reads them.
|
|
96
|
-
|
|
97
|
-
```bash
|
|
98
|
-
canon migrate surface-roots --json
|
|
99
|
-
canon migrate surface-roots --write --json
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
It moves each surface with `git mv` and repoints every tracked citation. No other command notices a surface left at `.claude/`.
|
|
103
|
-
|
|
104
|
-
## Delete the retired snippets, once
|
|
105
|
-
|
|
106
|
-
A project scaffolded while snippets installed may hold `.claude/snippets/` or a root `snippets/`.
|
|
107
|
-
|
|
108
|
-
```bash
|
|
109
|
-
canon sync --check . --json | jq '.reverse'
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
- `dropped` is the toolkit's copy, unchanged, so delete it
|
|
113
|
-
- `unattributed` is often an edited copy, so read what changed first
|
|
114
|
-
- `project` is the project's own content, so leave it
|
|
115
|
-
|
|
116
|
-
From the registry the walk reports `historyUnavailable`, so check both paths by hand.
|
|
117
|
-
|
|
118
|
-
## Stop calling the standards verb, once
|
|
119
|
-
|
|
120
|
-
`canon standards <name>` is gone, and a call now fails with a too-many-arguments error. Replace each call with the skill that owns the standard, at `references/<name>.md`. <!-- canon-allow-reference: verb retired -->
|
|
121
|
-
|
|
122
|
-
| Skill | Standards |
|
|
123
|
-
| ----------------- | ------------------------------------------------------------- |
|
|
124
|
-
| `task-board` | `board`, `tasks`, `tasks-decline` |
|
|
125
|
-
| `context-fold` | `context` |
|
|
126
|
-
| `canvas-board` | `canvas`, `design` <!-- canon-keep-retired --> |
|
|
127
|
-
| `docs-sync` | `docs`, `readme` |
|
|
128
|
-
| `draw-figure` | `figures`, `mermaid` |
|
|
129
|
-
| `create-rule` | `rule` |
|
|
130
|
-
| `create-skill` | `skill`, `skill-paths`, `skill-practice`, `skill-requirement` |
|
|
131
|
-
| `git-branch` | `branch`, `slug` |
|
|
132
|
-
| `git-commit` | `commit`, `versioning` |
|
|
133
|
-
| `git-pr` | `pr`, `publish` |
|
|
134
|
-
| `markdown-craft` | `markdown` |
|
|
135
|
-
| `teach-workspace` | `glossary`, `teach` <!-- canon-keep-retired --> |
|
|
136
|
-
| `plan-groundwork` | `groundwork`, `groundwork-spikes` |
|
|
137
|
-
| `plan-intake` | `intake` |
|
|
138
|
-
| `plan-feature` | `plan`, `plan-lifecycle` |
|
|
139
|
-
| `plan-ready` | `ready` <!-- canon-keep-retired --> |
|
|
140
|
-
| `write-doc` | `requirements`, `wiki` |
|
|
141
|
-
| `session-map` | `session` |
|
|
142
|
-
|
|
143
|
-
The `standard` name became `skill-reference.md` in `create-skill`.
|
|
144
|
-
|
|
145
|
-
## Keep or delete the wireframes folder, your call
|
|
146
|
-
|
|
147
|
-
The wireframes record is retired, and nothing deletes what a project holds.
|
|
148
|
-
|
|
149
|
-
- `canon/wireframes/` stays yours and unaudited. Keep it as notes or delete it.
|
|
150
|
-
- Delete the `@canon/wireframes/index.md` line in your `CLAUDE.md` with the folder. `canon claude sync` does not rewrite it.
|
|
151
|
-
- `canon gov sync` removes `.claude/rules/canon/standards/wireframes.md`
|
|
152
|
-
|
|
153
|
-
## Keep or delete the retired product files, your call
|
|
154
|
-
|
|
155
|
-
The learning workspace, deck renderer, app recorder, canvas, and design install are retired with their verbs, and nothing deletes what a project holds.
|
|
156
|
-
|
|
157
|
-
- `.canon/teach/` holds HTML that opens as it is <!-- canon-keep-retired -->
|
|
158
|
-
- `.canon/slides/` and a `demos/` folder hold sources nothing renders any more, so delete them once nothing cites them <!-- canon-keep-retired -->
|
|
159
|
-
- Move the `.claude/design/project/` values, `fonts/`, and `fonts.css` to the stylesheet your `canon/DESIGN.md` lead names, then delete `.claude/design/`
|
|
160
|
-
|
|
161
|
-
A reference to a retired skill takes a hand edit.
|
|
162
|
-
|
|
163
|
-
- Replace a `canon:teach-workspace` reference with `canon:teach-craft` by hand, since `canon migrate skill-names` does not rewrite it <!-- canon-keep-retired -->
|
|
164
|
-
- Delete a `canon:make-deck`, `canon:script-screencast`, `canon:record-screencast`, `canon:read-frames`, or `canon:video-craft` reference, since none has a successor <!-- canon-keep-retired -->
|
|
165
|
-
- Delete a `canon:canvas-board` reference too. Frameboard, which `canon:design-pick` drives, reads each `.canon/canvas/` folder as a project, so move a kept page under one <!-- canon-keep-retired -->
|
|
166
|
-
|
|
167
|
-
## Move decisions out of a held architecture record, once
|
|
168
|
-
|
|
169
|
-
The toolkit no longer seeds `canon/ARCHITECTURE.md`, and a held file and its `CLAUDE.md` import stay. Move a trap a session would hit into that domain's `## Gotchas`, then delete the file and its `@canon/ARCHITECTURE.md` line.
|
|
170
|
-
|
|
171
|
-
## Deny subagents and merges, and turn auto memory off, once
|
|
172
|
-
|
|
173
|
-
The seeded `.claude/settings.json` now denies the `Agent` and `Task` tools and both merge commands, and sets `autoMemoryEnabled` to `false`. `canon claude sync` never rewrites a settings file you hold, so it warns while the file holds no default or lacks a merge entry. Removing `Agent` and `Task` later draws no warning.
|
|
174
|
-
|
|
175
|
-
```bash
|
|
176
|
-
canon migrate session-defaults --json
|
|
177
|
-
canon migrate session-defaults --write --json
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
The verb only adds a key that is absent. A person who wants auto memory back sets it in their own `.claude/settings.local.json`.
|
|
181
|
-
|
|
182
|
-
The verb adds `Bash(canon pr merge:*)` and `Bash(gh pr merge:*)` so a session cannot merge. A project migrated before them runs `--write` once more, which also restores `Agent` and `Task` for a person who removed them to allow subagents, so remove them again after.
|
|
183
|
-
|
|
184
|
-
## Move the capture cases out of the harness, once
|
|
185
|
-
|
|
186
|
-
A web project's `e2e/screenshot.ts` is a config. It now loads `CASES` from a seeded `e2e/capture/cases.ts` that sync copies once and never overwrites. A harness you edited is held on `--write`, so the new one lands only once you pass `--replace e2e/screenshot.ts`.
|
|
187
|
-
|
|
188
|
-
- Copy your cases from the old `e2e/screenshot.ts` into `e2e/capture/cases.ts`, then sync with `--replace e2e/screenshot.ts`.
|
|
189
|
-
- Evidence now defaults to `e2e/evidence/`. Set `export const EVIDENCE_ROOT = 'evidence'` in `e2e/capture/cases.ts` to keep a committed baseline at the old path.
|
|
190
|
-
- A run from a folder with no `e2e/capture/cases.ts` exits 1 and names the file.
|
|
191
|
-
|
|
192
|
-
## Fold the ui rules onto one pointer, once
|
|
193
|
-
|
|
194
|
-
Eleven ui rules moved unchanged into the `ui-craft` skill, being `a11y`, `keyboard`, `pointer`, `forms`, `motion`, `ux-controls`, `ux-completeness`, `surface-capture`, `copy`, `interface-casing`, and `link-behavior`. Update the plugin, then sync, which folds each one you hold and `design-taste.md` onto one `craft.md` pointer without local edits.
|
|
195
|
-
|
|
196
|
-
```bash
|
|
197
|
-
canon gov sync .
|
|
198
|
-
```
|
|
199
|
-
|
|
200
|
-
## Group a long paths section in `CLAUDE.md`, once
|
|
201
|
-
|
|
202
|
-
The `## Key paths` section of `CLAUDE.md` now keeps to 5 bullets in a row, and every other section stays exempt. `canon claude sync` never rewrites a `CLAUDE.md` you hold, so it warns with the line of each longer run.
|
|
203
|
-
|
|
204
|
-
- Regroup the section by hand under H3s, each opening on a one-sentence lead.
|
|
205
|
-
- List `CLAUDE.md` in `canon/config/markdown.toml` to gate it from then on.
|