@erclx/canon 4.101.0 → 4.103.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 +5 -6
- package/claude/skills/canon-cli/SKILL.md +4 -1
- package/claude/skills/canon-rollout/SKILL.md +7 -6
- package/claude/skills/draft-readme/REQUIREMENT.md +2 -0
- package/claude/skills/draft-readme/SKILL.md +9 -1
- package/claude/skills/git-ship/SKILL.md +3 -7
- package/claude/skills/memory-capture/SKILL.md +0 -6
- package/claude/skills/memory-review/REQUIREMENT.md +1 -1
- package/claude/skills/memory-review/SKILL.md +2 -3
- package/claude/skills/plan-groundwork/SKILL.md +3 -2
- package/claude/skills/target-check/REQUIREMENT.md +42 -0
- package/claude/skills/target-check/SKILL.md +91 -0
- package/claude/skills/target-check/references/domains.md +88 -0
- package/claude/skills/ui-checklist/SKILL.md +17 -0
- package/docs/agents/commands.md +1 -1
- package/docs/agents/install-and-sync.md +7 -1
- package/docs/agents/scripting.md +1 -1
- package/docs/target-projects.md +3 -1
- package/docs/workflow/ai-workflow.md +16 -13
- package/governance/rules/ci/700-ci-workflow.md +11 -0
- package/package.json +1 -1
- package/scripts/core/regen-web-favicon.ts +9 -40
- package/scripts/core/regen-web-previews.ts +1 -0
- package/src/claude/cases/setup.ts +8 -0
- package/src/commands/design.ts +8 -2
- package/src/commands/tooling.ts +92 -19
- package/src/design/css.ts +5 -2
- package/src/design/favicon.ts +33 -0
- package/src/design/render.ts +46 -6
- package/src/design/tokens.ts +1 -1
- package/standards/groundwork.md +8 -2
- package/standards/readme.md +22 -3
- package/tooling/astro/manifest.toml +1 -0
- package/tooling/base/manifest.toml +2 -2
- package/tooling/base/reference.md +1 -1
- package/tooling/nextjs/manifest.toml +1 -0
- package/tooling/web/configs/.github/workflows/readme-screenshot.yml +110 -0
- package/tooling/web/configs/e2e/screenshot.ts +69 -15
- package/tooling/web/configs/scripts/lib/preview-server.sh +31 -0
- package/tooling/web/configs/scripts/readme-screenshot.sh +26 -0
- package/tooling/web/configs/scripts/screenshot.sh +1 -24
- package/tooling/web/manifest.toml +1 -0
- package/tooling/web/reference.md +6 -1
|
@@ -11,7 +11,7 @@ Chain the post-plan pipeline in a single run. Every step has a stop condition. S
|
|
|
11
11
|
## Guards
|
|
12
12
|
|
|
13
13
|
- All `.canon/plans/` and `.canon/review/` reads resolve at the main worktree root, not the current worktree. Resolve that root the way `session-worktree` does.
|
|
14
|
-
- Derive `<slug>` per `${CLAUDE_SKILL_DIR}/../../standards/slug.md`. This skill takes the stop rather than the `latest` fallback, since it commits and opens a pull request. If empty, stop: `❌ Detached HEAD. Checkout the feature branch first.` This slug is provisional. It is superseded once `session-worktree` runs, whether at Step 0 or before this chain began. Every later step keys its output on the slug that run resolves, being the worktree, the review receipt,
|
|
14
|
+
- Derive `<slug>` per `${CLAUDE_SKILL_DIR}/../../standards/slug.md`. This skill takes the stop rather than the `latest` fallback, since it commits and opens a pull request. If empty, stop: `❌ Detached HEAD. Checkout the feature branch first.` This slug is provisional. It is superseded once `session-worktree` runs, whether at Step 0 or before this chain began. Every later step keys its output on the slug that run resolves, being the worktree, the review receipt, and the branch, regardless of which plan Step 1 reads.
|
|
15
15
|
- Resolve `<plan>` in Step 1, ahead of any other read.
|
|
16
16
|
- If the working tree has uncommitted changes unrelated to the plan, stop: `❌ Uncommitted changes outside the plan. Commit or stash before autoshipping.`
|
|
17
17
|
|
|
@@ -188,7 +188,7 @@ This chain owns the receipt's lifetime, which is what makes the Output block's c
|
|
|
188
188
|
|
|
189
189
|
## Step 8: ship
|
|
190
190
|
|
|
191
|
-
Invoke `canon:git-ship`. That body owns the sequence, being the verify gate, memory capture, both doc syncs, staging, the commit grouping, the branch rename, the pull request, the CI watch,
|
|
191
|
+
Invoke `canon:git-ship`. That body owns the sequence, being the verify gate, memory capture, both doc syncs, staging, the commit grouping, the branch rename, the pull request, and the CI watch, along with the reason each step sits where it does. This step used to restate that list and the two drifted apart with nothing comparing them, so read the order there and never here.
|
|
192
192
|
|
|
193
193
|
One thing this chain adds. Mark the pull request as a draft as soon as `git-ship`'s pull request step returns, ahead of its CI watch, then read the flag back:
|
|
194
194
|
|
|
@@ -207,21 +207,20 @@ Placement is why the call sits ahead of the watch rather than after it. Marking
|
|
|
207
207
|
|
|
208
208
|
## Output
|
|
209
209
|
|
|
210
|
-
Respond with up to
|
|
210
|
+
Respond with up to four lines:
|
|
211
211
|
|
|
212
212
|
```plaintext
|
|
213
213
|
✅ Autoshipped (<state>): <PR url>
|
|
214
214
|
<N minor findings kept in .canon/review/branch-<slug>.md>
|
|
215
215
|
<N facts routed to context entries>
|
|
216
216
|
<N memories captured in .canon/memory/>
|
|
217
|
-
<Memory proposal at .canon/memory/review/memory-review-<slug>.md>
|
|
218
217
|
```
|
|
219
218
|
|
|
220
219
|
`<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.
|
|
221
220
|
|
|
222
|
-
Omit the second line if there were no minor findings, and the third if nothing routed. Omit the fourth
|
|
221
|
+
Omit the second line if there were no minor findings, and the third if nothing routed. Omit the fourth if `memory-capture` wrote no memory file this session. A run that routes every fact and writes none is the shape to expect, and it reports three lines.
|
|
223
222
|
|
|
224
|
-
This block replaces the one `git-ship` closes on rather than following it. The two carry the same
|
|
223
|
+
This block replaces the one `git-ship` closes on rather than following it. The two carry the same two trailing lines and differ on the two above them, since the first names the state the read returned and the second reports the minor findings Step 7 kept, neither of which that body has a counterpart for. Emitting both reports one run twice and buries the state under a `✅ Shipped` that does not name it.
|
|
225
224
|
|
|
226
225
|
## Failure recovery
|
|
227
226
|
|
|
@@ -31,7 +31,7 @@ Consult before running an unfamiliar `canon` verb, before a sync or install, or
|
|
|
31
31
|
|
|
32
32
|
A golden config is any file a stack ships under `configs/`, and the category is wider than its name suggests. It carries the CI workflow, the git hooks, the end-to-end harness, the shell scripts under `scripts/`, and the editor settings, alongside the linters and compilers a reader expects. A stack inherits its parent's configs, so syncing `astro` also writes everything `web` and `base` hold.
|
|
33
33
|
|
|
34
|
-
Run `canon tooling
|
|
34
|
+
Run `canon tooling diff <stack> <target>` for the list resolved against a real target. It reports every path, writes nothing, and exits 1 when any differs. The list below is what the stacks hold as shipped, before any chain resolution.
|
|
35
35
|
|
|
36
36
|
<!-- generated:tooling-paths -->
|
|
37
37
|
|
|
@@ -91,12 +91,15 @@ Run `canon tooling sync <stack> <target> --check` for the list resolved against
|
|
|
91
91
|
|
|
92
92
|
### web
|
|
93
93
|
|
|
94
|
+
- `.github/workflows/readme-screenshot.yml`
|
|
94
95
|
- `.github/workflows/verify.yml`
|
|
95
96
|
- `.vscode/extensions.json`
|
|
96
97
|
- `.vscode/settings.json`
|
|
97
98
|
- `e2e/home.spec.ts`
|
|
98
99
|
- `e2e/screenshot.ts`
|
|
99
100
|
- `eslint.config.js`
|
|
101
|
+
- `scripts/lib/preview-server.sh`
|
|
102
|
+
- `scripts/readme-screenshot.sh`
|
|
100
103
|
- `scripts/screenshot.sh`
|
|
101
104
|
- `scripts/verify.sh`
|
|
102
105
|
- `scripts/worktree-port.sh`
|
|
@@ -88,7 +88,7 @@ Report each dispatch by naming the target, the clone, the branch, the model, and
|
|
|
88
88
|
|
|
89
89
|
1. Address every finding whatever its severity. A minor is a finding, and a reviewer calling one non-blocking does not close the pass that raised it.
|
|
90
90
|
2. Resolve who holds the branch before dispatching anybody. Run `canon sessions list --branch chore/agents --repository <clone> --json` and read the count rather than the first row.
|
|
91
|
-
- A live session holds it: send that session the findings and name `canon:review-address` for it to run, which is step
|
|
91
|
+
- A live session holds it: send that session the findings and name `canon:review-address` for it to run, which is step 7 of `## The worker role` and the step that session already stands at. Never name this skill in that message. This body carries `disable-model-invocation: true`, which blocks the `Skill` tool rather than only suppressing an auto-trigger, and a session acting on an inbound message reaches a skill that way and no other, so a message naming this one halts the address leg with the branch built and the findings unread. A launch prompt is the one route to a flagged body, which is why the dispatch above names this skill and this message must not. Assuming the worker was gone is what one hand-driven pass got wrong. All four sessions that opened those pull requests were still alive holding their worktrees hours later, and of two fresh addressers sent over them, one refused on the worktree lock and one cut a second worktree on the same branch, which would have put two sessions pushing to one ref.
|
|
92
92
|
- No live session holds it: dispatch a fresh worker into that clone and brief it with the findings, since it holds none of the reasoning behind the diff.
|
|
93
93
|
- More than one row: report the ambiguity and stop rather than picking among candidates.
|
|
94
94
|
3. Re-review when the answer lands, scoped to the commits added since. A worker's reply never closes a target. One fix for two minor findings closed both and introduced four more, every one of them in prose that fix added, and a loop trusting the reply merges that.
|
|
@@ -101,11 +101,12 @@ One session, one target, from the worktree entry to the merge of the branch it o
|
|
|
101
101
|
|
|
102
102
|
1. Confirm the clone is current. Fetch, then compare against the origin's default branch. Report a checkout that is behind and stop, rather than branching from a stale base.
|
|
103
103
|
2. Enter a worktree. Invoke `canon:session-worktree chore/agents`, which takes the branch as its tier 0 argument and enters a linked worktree inside this target. Branching in the checkout itself is what this avoids, since the operator may be working in it.
|
|
104
|
-
3.
|
|
105
|
-
4.
|
|
106
|
-
5.
|
|
107
|
-
6.
|
|
108
|
-
7.
|
|
104
|
+
3. Check what this target holds. Invoke `canon:target-check`, which reports per domain what the target carries against what the toolkit ships and repairs nothing. It runs before any repair so the wave reads one stated set of domains per target rather than whatever each session decided to examine.
|
|
105
|
+
4. Diagnose and repair. Invoke `canon:canon-operator`, which reads `canon sync --check . --json` and routes each finding to the command or the skill that owns it. Do not restate that routing here and do not edit a managed file by hand.
|
|
106
|
+
5. Commit and open the pull request through `canon:git-commit` and `canon:git-pr`, handing each the fixed shape above rather than taking the title the generator derives from the diff.
|
|
107
|
+
6. Announce as the pull request opens, carrying its URL, its number, and the branch, to whoever dispatched this session. That transition is the one moment only this session can observe.
|
|
108
|
+
7. Answer the review. Invoke `canon:review-address`, which pulls the findings and the CI state on this branch's open pull request, fixes each in the working tree, replies, and pushes. Answer every finding whatever its severity.
|
|
109
|
+
8. Stop there. Do not mark the pull request ready, do not merge, and do not declare the review closed. A narrow re-review posts `## Review closed`.
|
|
109
110
|
|
|
110
111
|
Send a block out as a message before it becomes an interactive prompt. A session already waiting on input never reaches the tool round an inbound message drains at, so an answer relayed afterwards arrives under the open question and changes nothing.
|
|
111
112
|
|
|
@@ -16,6 +16,7 @@ A README whose real documentation lives in `canon/context/` or `docs/` was a sec
|
|
|
16
16
|
- Read `standards/readme.md` before drafting, since its `## Voice` section is scoped to a repository-root README and yields to `write-human`'s reference voice everywhere else
|
|
17
17
|
- Detect every project type the standard's `## Content` list applies to, from the manifest and the tree, rather than drafting against the closest single type
|
|
18
18
|
- Treat an existing README with no H1, or with headings that name only the scaffold that wrote it, as unedited generator output to draft over rather than a page to sync section by section
|
|
19
|
+
- Read the header block's slots off the repository, being the mark, the claim, the live link, and the product screenshot, and skip the link and the screenshot for a project with no page, so every element traces to a file or field the project holds
|
|
19
20
|
- Verify a candidate badge by the value it would render rather than by a fetch's status code, since a badge service answers 200 for a query it cannot satisfy
|
|
20
21
|
- Confirm the resolved path, the detected types, the badge candidates, and the full content with the user before writing, since project-type detection and badge selection are judgment calls with no diff to preview them against
|
|
21
22
|
|
|
@@ -23,6 +24,7 @@ A README whose real documentation lives in `canon/context/` or `docs/` was a sec
|
|
|
23
24
|
|
|
24
25
|
- Rewrite an authored README. One carrying an H1 that names the project refuses toward `docs-sync`.
|
|
25
26
|
- Offer to overwrite an authored README on the refusal path, or propose conforming it to what this skill would have drafted. A target project's own citations into its README are invisible from here, so the refusal reports rather than proposes.
|
|
27
|
+
- Invent a screenshot or a mark the project does not hold, or write a placeholder path for one. An omitted slot is a correct page and an invented image is the failure.
|
|
26
28
|
- Assume this skill's own invocation frequency needs no check. Whether anything reaches for it beyond an author typing its name has no answer at creation time, so a review pass some months in should read that back rather than take the assumption on faith.
|
|
27
29
|
|
|
28
30
|
## Guards
|
|
@@ -27,10 +27,16 @@ Read these files in parallel:
|
|
|
27
27
|
- Read the project's manifest (`package.json`, `pyproject.toml`, `Cargo.toml`, or equivalent) for a `bin` field or CLI entry point, an installable package name, and its declared dependencies.
|
|
28
28
|
- Check for a `claude/skills/` or `.claude/skills/` folder, a `plugin.json`, or a marketplace manifest, each naming an agent-facing or marketplace-distributed surface.
|
|
29
29
|
- A project is often several of these at once. Note every type that applies rather than stopping at the first match, since the Draft step covers each one the project actually is.
|
|
30
|
+
- Check for a page. A dependency on a site framework or a site config file in the manifest or the tree marks a project as having one. Read a live URL separately, from a `homepage` field or a deploy config, since a project can have a page and no known URL.
|
|
31
|
+
- A monorepo can carry a page in one package and a CLI in another, so both signals may fire. Report each rather than picking one.
|
|
32
|
+
- Look for the mark and the screenshot among images the project already commits: scan the existing README for image references, then the asset and public folders.
|
|
30
33
|
|
|
31
34
|
## Draft
|
|
32
35
|
|
|
33
36
|
- Draft the page against `${CLAUDE_SKILL_DIR}/../../standards/readme.md`: H1, a 2-3 sentence description in plain text, then the required sections, then whichever optional sections and per-type content the Detect step found.
|
|
37
|
+
- Open the page with the standard's header block, filling each slot from what Detect found: mark, title, badges, a one-line claim from the manifest description, the live link, then the product screenshot.
|
|
38
|
+
- Fill the screenshot slot only with an image the project already commits, referenced with alt text naming what it depicts. This skill cannot capture one. Omit the slot when no such image exists and say so in the preview. Never write a placeholder path.
|
|
39
|
+
- Omit the link and the screenshot for a project with no page, and the mark for a project with none, without a note in the drafted page. A project with a page and no known URL gets the screenshot slot, and the Confirm step asks for the link.
|
|
34
40
|
- Cover every applicable project type from the standard's `## Content` list rather than picking the closest one.
|
|
35
41
|
- Candidate badges: check for a published package (a registry field in the manifest), a CI workflow, and a `LICENSE` file.
|
|
36
42
|
- State each candidate's rendered value in the preview rather than trusting a fetch's status code, since a badge service answers 200 for a query it cannot satisfy.
|
|
@@ -38,7 +44,8 @@ Read these files in parallel:
|
|
|
38
44
|
|
|
39
45
|
## Confirm
|
|
40
46
|
|
|
41
|
-
- Show the resolved path, the detected project types, the badge candidates and what backs each one, and the full drafted content before writing.
|
|
47
|
+
- Show the resolved path, the detected project types, the header slots filled or skipped with the reason for each, the badge candidates and what backs each one, and the full drafted content before writing.
|
|
48
|
+
- The skill can confirm that an image file exists and is referenced, and it cannot verify the picture shows the product. Ask the user to look at it in the preview.
|
|
42
49
|
- Confirm with the user. This skill waits for that answer rather than treating the tool permission dialog as the gate, since project-type detection and badge selection are judgment calls with no diff to preview them against.
|
|
43
50
|
|
|
44
51
|
## Write
|
|
@@ -52,6 +59,7 @@ Read these files in parallel:
|
|
|
52
59
|
|
|
53
60
|
**Target:** `<path>` (root | nested)
|
|
54
61
|
**Detected:** `<project types>`
|
|
62
|
+
**Header:** `<each slot as filled (source) or skipped (reason)>`
|
|
55
63
|
**Badges:** `<candidates, or none>`
|
|
56
64
|
|
|
57
65
|
```markdown
|
|
@@ -32,7 +32,6 @@ Run `git diff --cached --name-only 2>/dev/null` to check for staged files. If ou
|
|
|
32
32
|
7. Invoke `canon:git-branch` to rename branch to match conventional format
|
|
33
33
|
8. Invoke `canon:git-pr` to push branch and open pull request
|
|
34
34
|
9. After the PR opens, watch CI. Poll `canon pr checks <number> --json` until the record's `state` leaves `pending`, branching on that field rather than on the exit, and fall back to `gh pr checks <number>` when no record comes back at all, which is a target whose CLI predates the verb. On `passing`, continue. On `failing`, stop the sequence and report the failing check with its URL. Do not auto-fix. This step may output on failure, the one exception to the no-text-between-steps rule.
|
|
35
|
-
10. If step 1 wrote or updated at least one memory file, invoke `canon:memory-review` scoped to those entries to propose fixes while session context is fresh. If the pen got nothing, skip this step.
|
|
36
35
|
|
|
37
36
|
A caller wrapping this sequence may act between step 8 and step 9, which is the one gap the order leaves open, since the pull request exists there and nothing has read its checks yet. `auto-ship` marks the pull request draft in it. Nothing else may go there, and a caller that needs a step anywhere else in the sequence is asking for a change to this body rather than for a place to stand.
|
|
38
37
|
|
|
@@ -48,19 +47,16 @@ An installed binary carrying no `plan-reach` subcommand reports the reach unread
|
|
|
48
47
|
|
|
49
48
|
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
49
|
|
|
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
|
-
|
|
53
50
|
## After completion
|
|
54
51
|
|
|
55
|
-
Output up to
|
|
52
|
+
Output up to three lines:
|
|
56
53
|
|
|
57
54
|
```plaintext
|
|
58
55
|
✅ Shipped
|
|
59
56
|
<N facts routed to context entries>
|
|
60
57
|
<N memories captured in .canon/memory/>
|
|
61
|
-
<Memory proposal at .canon/memory/review/memory-review-<slug>.md>
|
|
62
58
|
```
|
|
63
59
|
|
|
64
|
-
Omit the second line if nothing routed
|
|
60
|
+
Omit the second line if nothing routed and the third if `memory-capture` wrote no memory file this session.
|
|
65
61
|
|
|
66
|
-
Emit nothing here when a wrapping caller states it closes on its own block. `auto-ship` is that caller and its block carries these same
|
|
62
|
+
Emit nothing here when a wrapping caller states it closes on its own block. `auto-ship` is that caller and its block carries these same two trailing lines above a first line naming the draft state, so emitting both reports one run twice. A caller that states no such thing gets this block, which is every direct invocation.
|
|
@@ -100,12 +100,6 @@ When anything routed, add a line naming the handoff so the caller knows a `docs-
|
|
|
100
100
|
|
|
101
101
|
Omit that line when the caller runs `docs-fold` itself later in its own chain.
|
|
102
102
|
|
|
103
|
-
When at least one memory file was written or updated, add a closing line so the standalone caller proposes fixes while context is fresh:
|
|
104
|
-
|
|
105
|
-
`→ Run /memory-review to propose fixes for the pen before the session ends.`
|
|
106
|
-
|
|
107
|
-
The ship skills run review Propose themselves, so this line is for the standalone `/memory-capture` path.
|
|
108
|
-
|
|
109
103
|
If nothing was captured, output:
|
|
110
104
|
|
|
111
105
|
`✅ Nothing worth capturing.`
|
|
@@ -9,7 +9,7 @@ description: What memory review is for, the gaps it closes, and why every action
|
|
|
9
9
|
|
|
10
10
|
Without this skill, the memory folder grows and never drains. Entries pile up restating rules a durable surface already carries, nothing decides which memory has earned a place in one, and a rule that does get promoted arrives verbatim in a file whose voice it does not match. The folder then reads as a second source of truth that no surface points at.
|
|
11
11
|
|
|
12
|
-
A pen the caller cannot face is the same gap wearing a different shape. Routing at capture takes the domain facts and whatever the ownership test leaves stays, in whatever mix of types that is, so the folder still reaches a size nobody reads in one sitting.
|
|
12
|
+
A pen the caller cannot face is the same gap wearing a different shape. Routing at capture takes the domain facts and whatever the ownership test leaves stays, in whatever mix of types that is, so the folder still reaches a size nobody reads in one sitting. The full sweep is what an operator asks for when the cross-session duplicates are the point. An entry leaving the pen is archived rather than deleted, because a folder git does not hold gives a wrong bulk call no undo.
|
|
13
13
|
|
|
14
14
|
## Must
|
|
15
15
|
|
|
@@ -30,12 +30,11 @@ If the user re-pings the skill with no new phrase and a receipt exists, default
|
|
|
30
30
|
|
|
31
31
|
## Propose phase
|
|
32
32
|
|
|
33
|
-
Propose is the
|
|
33
|
+
Propose is the entry point for a standalone run. The ship skills stop at capture and never invoke it.
|
|
34
34
|
|
|
35
35
|
### Scope
|
|
36
36
|
|
|
37
|
-
- **
|
|
38
|
-
- **Full sweep:** when invoked standalone with no named set, classify every entry in the pen, including entries carried from earlier sessions, so cross-session duplicates merge into one rule.
|
|
37
|
+
- **Full sweep:** classify every entry in the pen, including entries carried from earlier sessions, so cross-session duplicates merge into one rule.
|
|
39
38
|
|
|
40
39
|
### Step 1: read the memory folder
|
|
41
40
|
|
|
@@ -21,7 +21,7 @@ Read `${CLAUDE_SKILL_DIR}/../../standards/groundwork.md` before writing any file
|
|
|
21
21
|
|
|
22
22
|
- Write only inside `.canon/groundwork/<nn>-<slug>/`. A feature plan, source changes, a standard, a rule, and a reference doc all live outside that folder, so this one rule forbids every one of them.
|
|
23
23
|
- One exception, at close only: write one task file recording what the track concluded.
|
|
24
|
-
- A second exception, for what a spike reads: write
|
|
24
|
+
- A second exception, for what a spike reads as bulk input: write a large fixture under `.canon/tmp/runs/groundwork-fixtures/<slug>/`. Keep it out of `.canon/groundwork/` so mode detection never matches a fixture as a track. A fixture a headless run is pointed at goes outside the repository instead, per the rule in `## Running a spike`. An arm script and a checkout a claim rests on are not fixtures, and go inside the track under `scripts/` and `clones/`, per the standard.
|
|
25
25
|
- What a spike produces stays inside the track rather than joining the two exceptions above: write evidence a spike file cites under `.canon/groundwork/<nn>-<slug>/evidence/`, which the first rule already permits. Mode detection matches entries at the top level of the tracks directory, so the sibling the fixtures rule guards against cannot be a folder nested inside a track, and the scratch path holds only what can be deleted without loss, which a recording a finding rests on is not.
|
|
26
26
|
- A `draft-and-pick` run invoked from inside a live track follows its own branch for this, writing to `evidence/` here rather than `.canon/tmp/<slug>/`.
|
|
27
27
|
- Reading is not restricted. External research is in scope, so read documentation, comparable projects, and papers whenever a live question needs them.
|
|
@@ -33,12 +33,13 @@ Read `${CLAUDE_SKILL_DIR}/../../standards/groundwork.md` before writing any file
|
|
|
33
33
|
A track may run an experiment to settle an open question without stopping to ask. What it takes depends on what the experiment does.
|
|
34
34
|
|
|
35
35
|
- Reading or computing: run it. Unrestricted reading already covers this, and it is what most spikes turn out to be.
|
|
36
|
+
- Anything that processes an input: start against a sample and scale up after it works, per the sample rule in the standard's spikes section, which bounds it on size, duration, and spend.
|
|
36
37
|
- Writing a fixture this session reads or provisions itself: run it, under the fixtures path above. Provisioning is the usual blocker rather than spend, and it costs nothing.
|
|
37
38
|
- Spawning a billed headless session: run up to three, then ask before spawning more. The bound is a run count rather than a budget, because a headless run reports its total cost only after it finishes, so a dollar ceiling is reportable and not enforceable while a run count is checkable before spawning.
|
|
38
39
|
|
|
39
40
|
A fixture a headless run is pointed at goes outside the repository, under `mktemp -d`, and never under `.canon/tmp/`. A session started anywhere beneath the project root loads that project's `CLAUDE.md` and `.claude/rules/` through the ancestor chain, so an in-repo fixture measures the repository instead of the arm. Record the fixture as contaminated and re-run it outside if this is discovered after the fact, because the result reads as evidence either way.
|
|
40
41
|
|
|
41
|
-
Record method, result, measured cost, and caveats in `08-spikes.md`. Put whatever the run produced that the record cites in `evidence/` beside it, so a reader checking a claim opens the artifact rather than taking the prose for it
|
|
42
|
+
Record method, result, measured cost, and caveats in `08-spikes.md`. Put whatever the run produced that the record cites in `evidence/` beside it, so a reader checking a claim opens the artifact rather than taking the prose for it, and keep the arm scripts in `scripts/`. Reach for a test harness the project already carries before building one, and copy how it isolates its fixture rather than only what it asserts.
|
|
42
43
|
|
|
43
44
|
## Step 1: detect the mode
|
|
44
45
|
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: target-check
|
|
3
|
+
description: What the target check is for, the gap it closes, and the repairing it refuses
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Target check requirement
|
|
7
|
+
|
|
8
|
+
## Gap
|
|
9
|
+
|
|
10
|
+
Without this skill, a session landing in a target project decides for itself what to look at. `canon-rollout` dispatches a worker into each target and gets a pull request out, and nothing told that worker what a target holds against what the toolkit ships, so a wave is only as good as whatever each session happened to examine. Four hand-driven repairs across two waves examined four different sets of surfaces and none of them read the same domain twice.
|
|
11
|
+
|
|
12
|
+
The second half of the gap is silence. A session that runs a verb the target's binary does not carry, or reads a report key that is absent, has no instruction telling it apart from a clean answer, so an unexamined domain reaches the reader as a domain that passed.
|
|
13
|
+
|
|
14
|
+
## Must
|
|
15
|
+
|
|
16
|
+
- Report one section per domain, so a reader can tell which surface a finding came from
|
|
17
|
+
- Read each domain through the verb that already owns that comparison, rather than inspecting the same files by hand, since the verb is the surface under test
|
|
18
|
+
- Take the installed domains from the catalog the report returns rather than from a list in the body, so a domain the toolkit adds later needs no edit here
|
|
19
|
+
- Report a refusal, an absent key, and a missing subcommand as unread, naming the cause, so an unexamined domain never reads as a passing one
|
|
20
|
+
- Report the Claude harness as unchecked on every run while no verb answers for it, as a row rather than an omission
|
|
21
|
+
- Report the toolkit version first, since a target behind on the binary explains every unread section under it
|
|
22
|
+
- Run every read non-interactively by default, because every caller in the near term is a dispatched worker with nobody present to answer a prompt
|
|
23
|
+
|
|
24
|
+
## Must not
|
|
25
|
+
|
|
26
|
+
- Repair a finding, write a file in the target, or open a pull request. A check that repaired as it read leaves the reader unable to tell a finding from a fix, and the wave decides what to fix.
|
|
27
|
+
- Emit a verdict across the domains. Five answer from verbs and one answers from nothing, so any roll-up is a figure that lies about the sixth.
|
|
28
|
+
- Answer the harness domain by file inspection. A section reaching a verdict from a hand-rolled read is exactly what the other five sections avoid, and a hole a reader can see is worth more than a number nobody can trace.
|
|
29
|
+
- Hardcode a stack, rule, or domain name. A name written into the body goes stale on its own cadence.
|
|
30
|
+
|
|
31
|
+
## Guards
|
|
32
|
+
|
|
33
|
+
- `canon` absent from the path: stop, since no domain can be read
|
|
34
|
+
- No `.claude/` at the working root: stop and name the scaffold command, since nothing is installed to check
|
|
35
|
+
- The working root is the toolkit itself: stop and name `canon-rollout`, since this skill reads what the toolkit installed into rather than the source
|
|
36
|
+
|
|
37
|
+
## Out of scope
|
|
38
|
+
|
|
39
|
+
- Document health, which asks a content question rather than a structural one and takes its own surface
|
|
40
|
+
- Repairing anything a section names. Each routes to the command or skill that owns it.
|
|
41
|
+
- A target's own routes, which `canon inventory` reports as a listing rather than a verdict and which is a fact about the project rather than about what the toolkit ships
|
|
42
|
+
- First-time scaffold, which is `setup-init`, and per-intent routing of a single toolkit operation, which is `canon-operator`
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: target-check
|
|
3
|
+
description: Reports what a target project holds against what the toolkit currently ships, one section per domain, reading through `canon` verbs rather than inspecting files. Use when asked to "check this target", "what has this project fallen behind on", "is this project current with the toolkit", "run the target check", or as the first thing a rollout worker runs after entering a target. Do NOT use to repair a finding, which the owning command or skill does, and do NOT use in the toolkit repository itself.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Target check
|
|
7
|
+
|
|
8
|
+
Reports, per domain, what this target holds against what the toolkit currently ships. It reports and never repairs, so whoever read the report decides what to fix.
|
|
9
|
+
|
|
10
|
+
Six domains carry the report. Five answer from a verb that already exists and the sixth answers from nothing, which it says rather than omitting. `${CLAUDE_SKILL_DIR}/references/domains.md` holds what each one reads, what current looks like, and where a finding routes. This body holds the order, the guards, and the report shape.
|
|
11
|
+
|
|
12
|
+
## Guards
|
|
13
|
+
|
|
14
|
+
- `canon` absent from the path: stop. `❌ canon is not on PATH, so no domain can be read.`
|
|
15
|
+
- No `.claude/` directory at the working root: stop. `❌ No .claude/ here, so nothing is installed to check. Run canon init first.`
|
|
16
|
+
- A `claude/skills/` folder at the working root, with no leading dot: stop. `❌ This is the toolkit itself rather than a target. canon-rollout takes a change out to the targets.` A target receives skills at `.claude/skills/` and authors none, so the spelling without the dot separates the source from what it installs into.
|
|
17
|
+
- Run every command under `CANON_NON_INTERACTIVE=1` and prompt at no point. Every caller in the near term is a worker a wave dispatched, with nobody present to answer, so the non-interactive path is the only path rather than a flag a caller remembers.
|
|
18
|
+
- Branch on each record's own fields rather than on an exit status. An operator's shell profile may wrap `canon` in a function whose status comes from a trailing command, which reports every refusal as success.
|
|
19
|
+
|
|
20
|
+
## Step 1: read the reports
|
|
21
|
+
|
|
22
|
+
Run these from the target root, in parallel:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
CANON_NON_INTERACTIVE=1 canon sync --check . --json
|
|
26
|
+
CANON_NON_INTERACTIVE=1 canon context audit --json
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
The first answers five domains from one read, being `skew`, `domains`, `seeds`, `tooling`, and the layout fields `unmigrated`, `superseded`, and `reverse`. The second deepens a domain that first read only counts.
|
|
30
|
+
|
|
31
|
+
Then run `CANON_NON_INTERACTIVE=1 canon records validate <kind> --json` once per record folder the target carries, taking `<kind>` from what is present under the record root rather than from a list held here.
|
|
32
|
+
|
|
33
|
+
### The tooling read takes a stack, always
|
|
34
|
+
|
|
35
|
+
The tooling comparison runs last, because it needs a value the first read returns. Take `<stack>` from the first name in the report's `tooling.chain`, which records the stack nearest the target, and pass it:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
CANON_NON_INTERACTIVE=1 canon tooling sync --check <stack>
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Refuse the domain and report it unread when `chain` names nothing, rather than running the command bare. A bare call reaches the stack prompt, and the non-interactive variable this skill's Guards make mandatory resolves that prompt to the first option in the catalog instead of refusing it. The domain would then compare every target against whichever stack sorts first, and report drift that is an artifact of the wrong comparison rather than anything the target did. It would fire on every run rather than on an edge, since nothing about the target is read on the way to that default.
|
|
42
|
+
|
|
43
|
+
Read every installed domain from the catalog the report returns rather than from a name written into this body. `domains` enumerates what the target actually stamped, so a domain the toolkit adds later reaches this report with no edit here, and a name hardcoded here is a bug.
|
|
44
|
+
|
|
45
|
+
## Step 2: report each domain
|
|
46
|
+
|
|
47
|
+
Report the six in this order, one section each, per `${CLAUDE_SKILL_DIR}/references/domains.md`:
|
|
48
|
+
|
|
49
|
+
1. Toolkit version
|
|
50
|
+
2. The `canon/` folder
|
|
51
|
+
3. Governance rules
|
|
52
|
+
4. Tooling
|
|
53
|
+
5. Seeds
|
|
54
|
+
6. The Claude harness
|
|
55
|
+
|
|
56
|
+
Give each section three things and nothing else: the state, the evidence the state was read from, and the command or skill that repairs it. Naming the repair is not running it.
|
|
57
|
+
|
|
58
|
+
### Unread is not current
|
|
59
|
+
|
|
60
|
+
A refused command, an absent key, or a subcommand the target's binary does not carry leaves a domain unread. Report it as unread, name which read could not be taken, and name the cause. Reading an absent key as an empty answer reports a clean target to a project nothing looked at, which is the failure this report exists to replace.
|
|
61
|
+
|
|
62
|
+
The version domain is what makes that case legible rather than mysterious. A target a release behind is missing verbs the other five sections call, so the version section is read first and its state explains every unread section under it.
|
|
63
|
+
|
|
64
|
+
### No verdict across the six
|
|
65
|
+
|
|
66
|
+
Report a state per domain and no number over them. Five sections answer from verbs and the sixth answers from nothing, so any roll-up is a figure that lies about the sixth. `canon inventory` reports a listing rather than a verdict for the same reason, and it is absent from the six here because its subject is a target's own routes rather than what the toolkit ships.
|
|
67
|
+
|
|
68
|
+
## Step 3: stop at the report
|
|
69
|
+
|
|
70
|
+
Repair nothing, write no file in the target, and open no pull request. A wave decides what to fix after reading this, and a check that repaired as it read would leave the reader unable to tell a finding from a fix.
|
|
71
|
+
|
|
72
|
+
## Output
|
|
73
|
+
|
|
74
|
+
Lead with the table, then one detail block per domain that is not current:
|
|
75
|
+
|
|
76
|
+
```markdown
|
|
77
|
+
Target check: `<path>`, against canon `<version>`.
|
|
78
|
+
|
|
79
|
+
| Domain | State | Evidence |
|
|
80
|
+
| ---------------- | ------------------------- | --------------------------------- |
|
|
81
|
+
| Toolkit version | current / behind / unread | `skew.installed` against `latest` |
|
|
82
|
+
| `canon/` folder | current / behind / unread | what the layout fields named |
|
|
83
|
+
| Governance rules | current / behind / unread | the per-state counts |
|
|
84
|
+
| Tooling | current / behind / unread | what a sync would change |
|
|
85
|
+
| Seeds | current / behind / unread | the per-state counts |
|
|
86
|
+
| Claude harness | unchecked | no verb reads it |
|
|
87
|
+
|
|
88
|
+
No overall verdict. The harness row is unchecked rather than passing.
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Keep the harness row `unchecked` on every run until a verb reads it. A domain left out of the table reads as a domain that passed, which is the one shape the row exists to prevent.
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Target check domains
|
|
3
|
+
description: What each of the six domains reads, what counts as current, and where a finding routes
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Target check domains
|
|
7
|
+
|
|
8
|
+
One section per domain, in the order the body reports them. Each names the read, what current looks like, what the states mean, and the command or skill a finding routes to. Naming a repair is not running one.
|
|
9
|
+
|
|
10
|
+
## 1. Toolkit version
|
|
11
|
+
|
|
12
|
+
Read `skew` off `canon sync --check . --json`. It carries `state`, `installed`, and `latest`.
|
|
13
|
+
|
|
14
|
+
- Current: `state` reads `current`, or `installed` equals `latest`.
|
|
15
|
+
- Behind: `installed` trails `latest`. Name both versions.
|
|
16
|
+
- Unread: no `skew` key, or the whole report refused. Say the version could not be read and treat every section under it as read against an unknown binary.
|
|
17
|
+
|
|
18
|
+
Routes to `canon upgrade`, which reinstalls with the manager that installed it.
|
|
19
|
+
|
|
20
|
+
This domain is first because it conditions the other five. A target a release behind carries an older verb surface, so a section reporting unread below may be reporting a missing subcommand rather than a missing surface, and the version state is what separates those two readings.
|
|
21
|
+
|
|
22
|
+
## 2. The `canon/` folder
|
|
23
|
+
|
|
24
|
+
Read three fields off the same report, then two verbs:
|
|
25
|
+
|
|
26
|
+
- `unmigrated`: a domain still at the root layout with nothing under `.claude/`. The most urgent finding, because such a domain reports no drift of its own while being entirely behind.
|
|
27
|
+
- `superseded`: a file a newer seed folder replaced. No command moves it, since the content is the project's own.
|
|
28
|
+
- `reverse`: `unclaimed` names folders at roots the toolkit stopped shipping, each with an `attribution` of `dropped`, `unattributed`, or `project`. `migrations` names a proposal-only skill with a live case here and the `reason` behind it.
|
|
29
|
+
- `canon context audit --json`: required sections, entry length, citations, and index drift across the context folder.
|
|
30
|
+
- `canon records validate <kind> --json`, once per record folder the target carries.
|
|
31
|
+
|
|
32
|
+
- Current: `unmigrated` and `superseded` both empty, `reverse.unclaimed` carrying nothing outside `project` attribution, and both verbs finding nothing.
|
|
33
|
+
- Behind: any of those carrying an entry. Name the entry and its attribution.
|
|
34
|
+
- Unread: `historyUnavailable` set on `reverse`, a `reverse` key the report does not carry at all, or either verb refusing. A missing `reverse` key is a binary predating the field rather than a target with nothing unclaimed.
|
|
35
|
+
|
|
36
|
+
Routes by finding. `unmigrated` routes to a relocation the user runs, since no command moves it. `superseded` routes to `migration-superseded`. A `migrations` entry routes to the skill its `skill` field names, spelled as the report spells it. An `unclaimed` folder carrying `project` attribution routes nowhere, since history proved the project owns it.
|
|
37
|
+
|
|
38
|
+
## 3. Governance rules
|
|
39
|
+
|
|
40
|
+
Read `domains` off the report and take every entry it carries rather than naming governance here. Each entry carries `stamped`, per-state `counts`, and `entries` with a `state` and a `rel` path.
|
|
41
|
+
|
|
42
|
+
The states are `matching`, `stale`, `customized`, `drifted`, `orphaned`, `stranded`, and `missing`.
|
|
43
|
+
|
|
44
|
+
- Current: every count but `matching` reads zero.
|
|
45
|
+
- Behind: any other count is non-zero. Report the counts and name the paths behind `stale` and `missing`, which a sync repairs, separately from `customized` and `drifted`, which the project wrote and a sync would overwrite.
|
|
46
|
+
- Unread: `stamped` false with no entries, or the domain absent from the array while the target carries installed rules.
|
|
47
|
+
|
|
48
|
+
Routes to `canon <domain> sync`, or to `canon sync` for every installed domain at once. Read the `canon-cli` skill before naming either, since a command name says nothing about what it does to a file already there, and a `customized` entry is exactly the file a sync takes back.
|
|
49
|
+
|
|
50
|
+
## 4. Tooling
|
|
51
|
+
|
|
52
|
+
Read the `tooling` block off the report first, because the comparison command needs a value it carries.
|
|
53
|
+
|
|
54
|
+
Read `measured` before anything under it. Every count is zero when `measured` is false, which is an absence of measurement rather than a measured zero.
|
|
55
|
+
|
|
56
|
+
On a measured report, take `<stack>` from the first name in `chain` and run `canon tooling sync --check <stack>`. Never run it bare. The stack argument is what the target carries, and omitting it reaches a prompt that the non-interactive variable resolves to the catalog's first entry rather than refusing, which compares the target against a stack it does not use and reports the difference as drift.
|
|
57
|
+
|
|
58
|
+
- Current: `measured` true, `chain` naming stacks the toolkit still ships, and `--check` reporting nothing it would change.
|
|
59
|
+
- Behind: `--check` naming files it would replace, or `counts.gitignore` carrying missing managed entries.
|
|
60
|
+
- Unread: `measured` false. It splits three ways, and each is reported as unmeasured with its cause named rather than as clean. An empty `chain` at a workspace root is by design, since a chain there would guess at what the packages hold. An empty `chain` anywhere else means no tooling install is recorded. A `chain` carrying names the toolkit no longer ships means injecting would write against a retired name.
|
|
61
|
+
|
|
62
|
+
Routes to `canon tooling sync <stack>`, or to `canon tooling inject --gitignore <stack>` for ignore entries alone, taking `<stack>` the same way the comparison above does. An unmeasured report names no stack, so it routes to neither.
|
|
63
|
+
|
|
64
|
+
`canon tooling diff` is the verb this section wants and it does not exist yet. `--check` answers the same question today and stays working as an alias by design, so the retarget when that verb lands is a change of name rather than of behavior.
|
|
65
|
+
|
|
66
|
+
## 5. Seeds
|
|
67
|
+
|
|
68
|
+
Read `seeds.entries` off the report. Each entry is `matching`, `stale`, `drifted`, or `missing`, and the set spans `CLAUDE.md`, the `canon/` records, the generated indexes, `.claude/settings.json`, and the hook scripts under `.claude/hooks/`.
|
|
69
|
+
|
|
70
|
+
- Current: every entry reads `matching`.
|
|
71
|
+
- Behind: anything else. Report `stale` and `missing` separately from `drifted`, which means the content matches no version the toolkit ever published, so the project wrote it.
|
|
72
|
+
- Unread: `historyUnavailable` set on `seeds`, which leaves every difference unattributed. Say so rather than reporting a file as untouched.
|
|
73
|
+
|
|
74
|
+
Routes to `seed-sync`, which proposes per-section edits without overwriting a customization. It is a proposal rather than a write, which is why a `drifted` `CLAUDE.md` routes there rather than to a sync.
|
|
75
|
+
|
|
76
|
+
A seed entry matching says the file's bytes match the shipped seed. It says nothing about whether the harness those files configure is wired, which is the next domain.
|
|
77
|
+
|
|
78
|
+
## 6. The Claude harness
|
|
79
|
+
|
|
80
|
+
No verb reads this domain. Report it `unchecked` on every run and report it as a row rather than omitting it.
|
|
81
|
+
|
|
82
|
+
What goes unread is whether the target's hooks fire, whether `.claude/settings.json` registers them, which plugin version the target's sessions actually load, and whether the marketplace cache matches what the toolkit ships.
|
|
83
|
+
|
|
84
|
+
Confirm the gap against the live surface rather than against a list held here, by reading `canon claude --help` and the help of any subcommand under it that sounds like an answer. A list written into this file freezes on the day it was written and would report a gap a later release had closed. `canon claude skills drift` is the verb that comes nearest, and it reads the toolkit's own history against a ref, which says what moved upstream rather than what this target holds. Report the domain checked, with what the verb answered, on the run where a verb does answer one of the four questions above.
|
|
85
|
+
|
|
86
|
+
Reading it by file inspection is the alternative and it is refused. Every other section here answers from the verb under test, and a section answering from a hand-rolled read of the same files reaches a verdict nothing else in the report is entitled to make. A hole a reader can see is worth more than a number nobody can trace.
|
|
87
|
+
|
|
88
|
+
`canon claude plugin-update` is what an operator runs to bring a cache forward. Name it as the action available rather than as a repair for a finding, since no finding was taken.
|
|
@@ -31,6 +31,23 @@ Group visual items by feature area. Use `- [ ]` checkbox syntax, and write each
|
|
|
31
31
|
- [ ] <action> → <expected visual result>
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
+
## The widths block
|
|
35
|
+
|
|
36
|
+
A screenshot shows one width, so a reviewer cannot tell from the picture alone whether any other width was looked at. When a change touches layout, spacing, or anything responsive, put this block above the visual items, since it frames what the screenshots beside it can support:
|
|
37
|
+
|
|
38
|
+
```markdown
|
|
39
|
+
**Widths:**
|
|
40
|
+
|
|
41
|
+
Seen at: <the widths the reviewer looked at>
|
|
42
|
+
Not seen at: <the widths nobody looked at, or "none">
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Leave both lines for the reviewer to complete. This session cannot verify a width, so the block asks what was seen and never asserts coverage. Fix no width list in the block, since which widths matter belongs to the project.
|
|
46
|
+
|
|
47
|
+
Keep the `Not seen at:` line even when the answer is "none", so an omission reads as a claim rather than a gap.
|
|
48
|
+
|
|
49
|
+
Omit the block when the change cannot differ by width, such as copy, color, or a state that renders the same everywhere, the way the missing-test heading is omitted below.
|
|
50
|
+
|
|
34
51
|
## The missing-test list
|
|
35
52
|
|
|
36
53
|
Name every automatable change this branch ships with no test, one per line, with the layer `test-craft` would place it at. Do not write the test and do not read the project's test config to write one against.
|
package/docs/agents/commands.md
CHANGED
|
@@ -22,7 +22,7 @@ Full help: `canon <command> --help`. Behavior notes for the install and sync ver
|
|
|
22
22
|
| `canon indexes regen` | Regenerate `index.md` files from sibling frontmatter |
|
|
23
23
|
| `canon indexes list [path]` | Flatten every folder index under a path into one `{path, title, description}` catalog (`--json`) |
|
|
24
24
|
| `canon docs [topic]` | Emit toolkit reference docs (`list`, or a topic by name) |
|
|
25
|
-
| `canon design render` | Render `canon/DESIGN.md` tokens to HTML and CSS
|
|
25
|
+
| `canon design render` | Render `canon/DESIGN.md` tokens to HTML and CSS, declaring each vendored face the typography table names with `--embed-fonts` |
|
|
26
26
|
| `canon design regen` | Rewrite this repository's `canon/DESIGN.md` and `src/design/base.css` from `src/design/tokens.ts` |
|
|
27
27
|
| `canon design board` | Generate a static page set indexing tokens, surfaces, wireframes, past candidates, components, and references against a caller-resolved `--root` (`--out`), defaulting to the main worktree |
|
|
28
28
|
| `canon design css` | Emit the design tokens and components as CSS on stdout (`--no-components` for properties alone) |
|
|
@@ -75,6 +75,12 @@ toolkit's own `snippets/`, so a session reaches one at its `@` reference with
|
|
|
75
75
|
no copy to reconcile. `canon snippets list --json` carries the catalog and
|
|
76
76
|
`canon snippets create` is the one verb left that still writes a file.
|
|
77
77
|
|
|
78
|
+
## Tooling diff and sync
|
|
79
|
+
|
|
80
|
+
`canon tooling diff <stack> [target]` is the read-only comparison, and a session asking what differs reaches for it by default. It writes nothing and exits 1 when anything differs and 0 when nothing does, so it gates CI. `--json` adds the scan record on stdout with `ok: true`, and the frame goes to stderr. A refusal such as an unknown stack, an excluded stack, or a toolkit-root target still exits 1 and answers `{ ok: false, reason, message }`, so a caller branches on the record and reads a typo'd stack name as a refusal rather than as drift.
|
|
81
|
+
|
|
82
|
+
`canon tooling sync <stack> [target] --check` reports the same list and always exits 0. It stays for scripts that already call it. `sync` itself writes only under `--write`, and a headless run with neither flag reports and exits 1.
|
|
83
|
+
|
|
78
84
|
## Install guards
|
|
79
85
|
|
|
80
86
|
`canon gov install` requires its first argument under
|
|
@@ -188,7 +194,7 @@ since `src/tooling/` runs its own inject machinery and has no walk to attribute.
|
|
|
188
194
|
The chain is ordered nearest stack first, which is what a `--skip` run needs:
|
|
189
195
|
recording the leaf alone would send the next report measuring against a layer the
|
|
190
196
|
target deliberately does not carry. The report loads exactly those stacks, scans
|
|
191
|
-
them the way `canon tooling
|
|
197
|
+
them the way `canon tooling diff` would, and counts what differs per category
|
|
192
198
|
under `tooling.counts`.
|
|
193
199
|
|
|
194
200
|
`measured` is the field the section exists for. A target carrying no chain
|
package/docs/agents/scripting.md
CHANGED
|
@@ -78,7 +78,7 @@ surface is in `skills-audit.md`.
|
|
|
78
78
|
CANON_NON_INTERACTIVE=1 canon tooling create astro
|
|
79
79
|
|
|
80
80
|
# Report what a stack would change, writing nothing
|
|
81
|
-
CANON_NON_INTERACTIVE=1 canon tooling
|
|
81
|
+
CANON_NON_INTERACTIVE=1 canon tooling diff astro /path/to/project
|
|
82
82
|
|
|
83
83
|
# Sync a stack into a target project, overwriting its golden configs
|
|
84
84
|
CANON_NON_INTERACTIVE=1 canon tooling sync astro /path/to/project --write
|
package/docs/target-projects.md
CHANGED
|
@@ -215,6 +215,8 @@ Neither `canon sync --check` nor any other command notices a surface still sitti
|
|
|
215
215
|
|
|
216
216
|
`canon sync --check <path>` reports what has drifted without writing anything. It splits each difference by cause, which is the question that decides what to do next.
|
|
217
217
|
|
|
218
|
+
`canon:target-check` is the same reading grouped by domain rather than by cause, run from inside the project. It reports the toolkit version, the `canon/` folder, governance rules, tooling, and seeds from the verbs that own each comparison, and reports the Claude harness as unchecked because no verb reads it. It repairs nothing, so it is what to run before deciding rather than instead of deciding.
|
|
219
|
+
|
|
218
220
|
#### The binary first
|
|
219
221
|
|
|
220
222
|
The report opens by naming the binary running it. The installed version reads against the newest published one, and a version behind that points you at `canon upgrade`, since every section under it is a reading taken by whichever toolkit you happen to have. An unreachable registry reports unknown with its reason rather than failing, so `--exit-code` still gates on the drift the check measured locally and an offline machine stays green.
|
|
@@ -265,7 +267,7 @@ Add `--json` for the machine-readable report, and `--exit-code` to fail a CI job
|
|
|
265
267
|
|
|
266
268
|
Tooling reports under a section of its own, and `measured` there says whether the target ever recorded a chain. One that never ran a tooling sync reports unmeasured rather than clean, which is what separates tooling nobody has looked at from tooling that is current. A workspace root records nothing either way, since each package resolves its own chain.
|
|
267
269
|
|
|
268
|
-
Reconcile the configs with `canon tooling
|
|
270
|
+
Reconcile the configs with `canon tooling diff <stack> <path>` to read which files differ, then run `canon tooling sync <stack> <path> --write` to apply them. The drift report counts categories and the diff names paths, which is the difference worth knowing before a golden config the project edited is replaced.
|
|
269
271
|
|
|
270
272
|
### Catch-all
|
|
271
273
|
|