@erclx/canon 4.109.0 → 4.111.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/{canon-feedback-file → canon-feedback}/REQUIREMENT.md +7 -6
- package/claude/skills/{canon-feedback-file → canon-feedback}/SKILL.md +9 -19
- package/claude/skills/canon-feedback-triage/REQUIREMENT.md +1 -1
- package/claude/skills/canon-feedback-triage/SKILL.md +1 -1
- package/claude/skills/canon-operator/REQUIREMENT.md +2 -2
- package/claude/skills/canon-operator/SKILL.md +3 -4
- package/claude/skills/draft-wiki/REQUIREMENT.md +42 -0
- package/claude/skills/draft-wiki/SKILL.md +83 -0
- package/claude/skills/git-issue/REQUIREMENT.md +1 -1
- package/claude/skills/git-issue/SKILL.md +1 -1
- package/claude/skills/target-check/references/domains.md +2 -2
- package/docs/agents/install-and-sync.md +4 -13
- package/docs/agents/teach.md +4 -2
- package/docs/target-projects.md +0 -2
- package/docs/workflow/ai-workflow.md +8 -11
- package/package.json +1 -1
- package/scripts/core/capture-home.sh +59 -0
- package/src/claude/cases/authoring.ts +5 -0
- package/src/claude/cases/setup.ts +3 -24
- package/src/commands/sync.ts +0 -16
- package/src/design/components.ts +459 -147
- package/src/shipped/references.ts +1 -2
- package/src/sync/reverse.ts +3 -74
- package/src/teach/nav.ts +410 -58
- package/claude/skills/migration-claude-md/REQUIREMENT.md +0 -40
- package/claude/skills/migration-claude-md/SKILL.md +0 -79
- package/claude/skills/migration-context/REQUIREMENT.md +0 -36
- package/claude/skills/migration-context/SKILL.md +0 -97
- package/claude/skills/migration-standards-drop/REQUIREMENT.md +0 -55
- package/claude/skills/migration-standards-drop/SKILL.md +0 -113
- package/claude/skills/migration-superseded/REQUIREMENT.md +0 -44
- package/claude/skills/migration-superseded/SKILL.md +0 -115
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: canon-feedback
|
|
3
|
-
description: Why a toolkit defect is reported from session context alone, and what
|
|
2
|
+
name: canon-feedback
|
|
3
|
+
description: Why a toolkit defect is reported from session context alone, and what opening an issue through the CLI replaces
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Canon feedback
|
|
6
|
+
# Canon feedback requirement
|
|
7
7
|
|
|
8
8
|
## Gap
|
|
9
9
|
|
|
@@ -18,8 +18,9 @@ The last failure is the session's own effort. Asked to report, a session starts
|
|
|
18
18
|
- Build the report from what the session already holds
|
|
19
19
|
- Name the surface and its type, since the toolkit routes on that rather than on the symptom
|
|
20
20
|
- Write the stated fallback for a field the session cannot fill, so an empty field reads as absent rather than as unreported
|
|
21
|
-
-
|
|
22
|
-
-
|
|
21
|
+
- Open a GitHub issue on the toolkit repo through the CLI so the report lands where triage reads it, and print the returned URL on its own line
|
|
22
|
+
- Say which file and which reason when the issue call fails and the report falls back to a local folder, since a silent fallback leaves it where nothing reads it
|
|
23
|
+
- Hold a report the operator marks sensitive, since the issue is public
|
|
23
24
|
- Fall back to printing the block when the CLI is absent, so the report still exists
|
|
24
25
|
|
|
25
26
|
## Must not
|
|
@@ -36,5 +37,5 @@ The last failure is the session's own effort. Asked to report, a session starts
|
|
|
36
37
|
|
|
37
38
|
- Fixing the defect, which happens in the toolkit repository against its own source
|
|
38
39
|
- Draining the queue this fills: `canon-feedback-triage`
|
|
39
|
-
- Filing an issue against the current project
|
|
40
|
+
- Filing an issue against the current project, which `git-issue` does and this skill cannot delegate to, since that skill targets the current repository
|
|
40
41
|
- Complaints about tooling the toolkit does not own
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: canon-feedback
|
|
3
|
-
description: Format a
|
|
2
|
+
name: canon-feedback
|
|
3
|
+
description: Format a report about something broken, missing, or off in canon and open it as a GitHub issue on the toolkit repo via `canon feedback --github`, where the toolkit's triage reads it. Use when asked to "send this to the toolkit", "report this to canon", "file toolkit feedback", or "give the toolkit feedback about X". Do NOT use for general complaints about other tooling, IDE issues, or in-project bugs that do not implicate canon surfaces.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Canon feedback
|
|
6
|
+
# Canon feedback
|
|
7
7
|
|
|
8
|
-
Format a `## Toolkit feedback` block from the current session, then
|
|
8
|
+
Format a `## Toolkit feedback` block from the current session, then open it as a GitHub issue labeled `feedback` on the toolkit repo. `canon-feedback-triage` reads that queue.
|
|
9
9
|
|
|
10
10
|
## Guards
|
|
11
11
|
|
|
@@ -69,9 +69,9 @@ Detect whether `canon` is on PATH:
|
|
|
69
69
|
command -v canon >/dev/null 2>&1
|
|
70
70
|
```
|
|
71
71
|
|
|
72
|
-
|
|
72
|
+
The destination is a public GitHub issue on the toolkit repo, so the report leaves the machine. Hold it and ask when the operator has marked it sensitive, and never send it on a guess.
|
|
73
73
|
|
|
74
|
-
|
|
74
|
+
Before the pipe below, run the scan in `${CLAUDE_SKILL_DIR}/../../standards/publish.md` against the composed block, phase-label half included. Nothing else checks what reaches the remote, so this scan is the only gate.
|
|
75
75
|
|
|
76
76
|
```bash
|
|
77
77
|
cat <<'EOF' | canon feedback --github
|
|
@@ -81,19 +81,9 @@ cat <<'EOF' | canon feedback --github
|
|
|
81
81
|
EOF
|
|
82
82
|
```
|
|
83
83
|
|
|
84
|
-
The CLI opens a GitHub issue on the toolkit repo and prints the issue URL
|
|
84
|
+
The CLI opens a GitHub issue labeled `feedback` on the toolkit repo and prints the issue URL, which this skill reports back on its own line. It needs `gh` authenticated. `git-issue` is not the route, since it files on the current repository and this report belongs on the toolkit's.
|
|
85
85
|
|
|
86
|
-
From a toolkit checkout,
|
|
87
|
-
|
|
88
|
-
```bash
|
|
89
|
-
cat <<'EOF' | canon feedback
|
|
90
|
-
## Toolkit feedback
|
|
91
|
-
|
|
92
|
-
...
|
|
93
|
-
EOF
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
It writes to `.canon/feedback/feedback-<slug>-<ts>.md` and prints the absolute path on stdout. Report the printed path back to the user on its own line, in the form the project's instruction file sets under `## Output`.
|
|
86
|
+
From a toolkit checkout, a call that produces no URL falls back to `.canon/feedback/feedback-<slug>-<ts>.md` and prints the reason on stderr. Say so in the same reply, naming the file and the reason, since a silent fallback leaves the report where nothing reads it. A target project has no such folder, so a failed call there prints the block in chat.
|
|
97
87
|
|
|
98
88
|
If `canon` is not on PATH, fall back: print the block in chat and tell the user `📋 Copy the block above into a toolkit-repo session.`
|
|
99
89
|
|
|
@@ -109,4 +99,4 @@ A `--github` run from a toolkit checkout whose GitHub call fails warns and write
|
|
|
109
99
|
## Notes
|
|
110
100
|
|
|
111
101
|
- `canon feedback` resolves the toolkit root from the running `canon` binary's source location. If multiple toolkit clones exist on the machine, the first `canon` on PATH wins.
|
|
112
|
-
- The
|
|
102
|
+
- The local folder is a fallback for a failed issue call, and nothing reads it on a schedule. The issue is the durable record.
|
|
@@ -35,6 +35,6 @@ The queue also fails to drain even when the work ships. A fix merged with no lin
|
|
|
35
35
|
|
|
36
36
|
## Out of scope
|
|
37
37
|
|
|
38
|
-
- Filing new feedback: `canon-feedback
|
|
38
|
+
- Filing new feedback: `canon-feedback`
|
|
39
39
|
- Writing the plan a plan-worthy issue needs: `plan-feature`
|
|
40
40
|
- Triage of issues carrying any other label, which surface here by design only under the feedback label
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: canon-feedback-triage
|
|
3
|
-
description: Triage open GitHub issues labeled `feedback` in the toolkit repo. List them, pick one, classify it as a direct fix or plan-worthy work, route to the right skill, and link the issue for close-out. Use when asked to "triage toolkit feedback", "work through the feedback issues", "process feedback issues", or "what feedback is open". Do NOT use to file new feedback (that is `canon-feedback
|
|
3
|
+
description: Triage open GitHub issues labeled `feedback` in the toolkit repo. List them, pick one, classify it as a direct fix or plan-worthy work, route to the right skill, and link the issue for close-out. Use when asked to "triage toolkit feedback", "work through the feedback issues", "process feedback issues", or "what feedback is open". Do NOT use to file new feedback (that is `canon-feedback`), or for general GitHub issue triage unrelated to toolkit feedback.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Canon feedback triage
|
|
@@ -26,8 +26,8 @@ The last failure is a section no route reaches. `## Route` maps an intent or a d
|
|
|
26
26
|
- Resolve every stack, rule, snippet, and standard name from a catalog at runtime
|
|
27
27
|
- Run the CLI non-interactively and report the command run, what changed, and the full path of anything written
|
|
28
28
|
- Read the overwrite contract from the body before any install or sync, and name each surface it lists as overwritten before running one
|
|
29
|
-
- Read the reverse walk beside the forward sections, so a folder the toolkit stopped shipping
|
|
30
|
-
-
|
|
29
|
+
- Read the reverse walk beside the forward sections, so a folder the toolkit stopped shipping reaches the user
|
|
30
|
+
- Name an unmigrated domain's root and install path for the user to move themselves, since no skill covers the move
|
|
31
31
|
- Route a measurement intent to the audit offers from the route table itself, rather than leaving the section reachable only by reading past the table
|
|
32
32
|
- Rank a lifecycle row against the audit offers where the route table itself states it, so a session acting on the lifecycle row reads the ranking without opening the section being ranked
|
|
33
33
|
- Offer every audit whose surface the target carries, and offer none whose surface it lacks
|
|
@@ -25,10 +25,10 @@ Run `canon sync --check . --json` before routing. It reports what a target is be
|
|
|
25
25
|
Read seven fields off the report and carry each to `## Route`:
|
|
26
26
|
|
|
27
27
|
- `unmigrated`: a domain sitting at the root layout with nothing under `.claude/`. The most urgent finding, because that domain reports no drift of its own while being entirely behind
|
|
28
|
-
- `superseded`: a file a newer seed folder replaced. No command moves it, since the content is the project's own, so this routes to
|
|
28
|
+
- `superseded`: a file a newer seed folder replaced. No command moves it, since the content is the project's own, so this routes to `canon:target-check` for the full per-domain reading rather than ending at the report
|
|
29
29
|
- `seeds`: entries are `matching`, `stale`, `drifted`, or `missing`. Anything but `matching` needs the seed handoff
|
|
30
30
|
- `domains[].entries`: per-file `stale`, `customized`, `stranded`, and `orphaned` as before
|
|
31
|
-
- `reverse`: what the target holds that no live catalog claims. `unclaimed` lists folders at roots the toolkit stopped shipping, each with an `attribution` of `dropped`, `unattributed`, or `project`. Act on the first two and leave `project` alone, which history proved the project owns
|
|
31
|
+
- `reverse`: what the target holds that no live catalog claims. `unclaimed` lists folders at roots the toolkit stopped shipping, each with an `attribution` of `dropped`, `unattributed`, or `project`. Act on the first two and leave `project` alone, which history proved the project owns
|
|
32
32
|
- `historyUnavailable` on a domain, on `seeds`, or on `reverse`: nothing could be dated, so treat every difference as unverified and say so rather than reporting a file as untouched. It is set on `reverse` when the toolkit itself ships without history, which is the registry-install case, so the walk found nothing rather than finding a clean target
|
|
33
33
|
- `tooling`: read `measured` first. Every count under it is zero when it is false, which is an absence of measurement rather than a measured zero. Past that, `chain` names the stacks the install resolved, nearest first, and `counts.gitignore` counts the managed ignore entries the target is missing.
|
|
34
34
|
|
|
@@ -43,8 +43,7 @@ Map the stated intent, or what `## Diagnose` found, to one lifecycle phase, then
|
|
|
43
43
|
The two can name different rows, and a reply answers both rather than picking one. Run or hand off what the finding names, then answer the intent in the same reply. A measurement intent therefore reaches the audit offers below even on a target whose diagnostic found scaffold work, which is the case a session leaving from the scaffold row would otherwise never read.
|
|
44
44
|
|
|
45
45
|
- A domain in `unmigrated`: name it, the root path, and the install path. No command moves it, so the user runs the relocation themselves
|
|
46
|
-
-
|
|
47
|
-
- Anything in `superseded`: name which files and what replaced them, then hand off to `migration-superseded`. Both skills propose, so neither moves nor deletes the file
|
|
46
|
+
- Anything in `superseded`: name which files and what replaced them, then hand off to `canon:target-check`, which reports and never moves or deletes the file
|
|
48
47
|
- A folder in `unclaimed`: name it and the attribution it carries. No command moves it and the content may be the project's own, so the decision is the user's
|
|
49
48
|
|
|
50
49
|
- First-time scaffold of a fresh project: hand off to `target-setup`
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: draft-wiki
|
|
3
|
+
description: Why a brand-new wiki reference page needs both placement tests, a catalog collision check, and a sourced read before anything is written
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Wiki draft requirement
|
|
7
|
+
|
|
8
|
+
## Gap
|
|
9
|
+
|
|
10
|
+
Without this skill, a session asked for a wiki page writes one from training knowledge, which is the single thing the wiki standard forbids outright, and nothing in the resulting file shows that it happened. It also files the page by where the request came from rather than by who owns the subject, so material about the project itself lands in the wiki and material about a third-party tool acquires a folder the standard never sanctioned.
|
|
11
|
+
|
|
12
|
+
The standard can state all of this and still be read by nothing, which is the condition this skill was written into in the toolkit. A page written under that condition conforms by the author's memory rather than by a read, and it ships looking identical to one that was checked.
|
|
13
|
+
|
|
14
|
+
## Must
|
|
15
|
+
|
|
16
|
+
- Read the wiki standard before drafting, since the placement tests and the sourcing rule are the two things a session gets wrong from memory
|
|
17
|
+
- Run both placement tests and refuse on either, since a page passing one and failing the other is still non-conforming
|
|
18
|
+
- Check the subject against the catalog by title and description, not by slug alone, since a subject can be covered under a name the slug does not guess
|
|
19
|
+
- Build the draft on a fetched read and stop when the fetch fails, since a page written from recall is indistinguishable from a checked one once it ships
|
|
20
|
+
- Confirm the path, the source, and the content with the user before writing, since the standard forbids writing a wiki file unasked
|
|
21
|
+
- Name the folder by resolving what the standard states rather than by carrying a path in the body, since the body ships to projects whose layout this repository does not set
|
|
22
|
+
|
|
23
|
+
## Must not
|
|
24
|
+
|
|
25
|
+
- Widen the folder split to admit a subject the second placement test rejects. That is a change to the standard, argued there.
|
|
26
|
+
- Edit or refresh a page that already exists. A collision refuses toward editing the existing page rather than drafting a second one.
|
|
27
|
+
- Substitute recall for a failed fetch, even for a subject the session believes it knows.
|
|
28
|
+
|
|
29
|
+
## Guards
|
|
30
|
+
|
|
31
|
+
- No subject given: stop and ask what subject the page should cover.
|
|
32
|
+
- The wiki root does not resolve: say so and ask before creating it, since a project holding no wiki has never taken the placement rule.
|
|
33
|
+
- The slug already resolves to a page: stop and point at editing that page.
|
|
34
|
+
- The catalog already covers the subject under a different name: stop the same way, checked against the titles and descriptions the Collision step already reads.
|
|
35
|
+
|
|
36
|
+
## Out of scope
|
|
37
|
+
|
|
38
|
+
- Editing or refreshing a wiki page that already exists: a plain edit against the same standard
|
|
39
|
+
- Drafting a `docs/*.md` page: `draft-docs`
|
|
40
|
+
- Drafting a `canon/context/<domain>.md` entry: `draft-context`
|
|
41
|
+
- Voice, rhythm, and sentence construction in the drafted page: the `write-human` skill
|
|
42
|
+
- Punctuation, headings, and word choice in the drafted page: the markdown standard
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: draft-wiki
|
|
3
|
+
description: Drafts a brand-new wiki reference page for a subject owned outside this repository, against the wiki standard. Checks the two placement tests and the catalog for a collision, sources the subject from its owner rather than from training knowledge, confirms with the user, then writes. Use when asked to "write a wiki page for X", "add a wiki reference for X", "document X in the wiki", or "create a reference page for X" where no page covers the subject yet. Do NOT use to edit or refresh a page that already exists, which is a plain edit against the same standard. Do NOT use for a subject this repository owns, which is `draft-docs` or `draft-context`.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Wiki draft
|
|
7
|
+
|
|
8
|
+
Drafts one brand-new wiki reference page end to end: read the standard, settle placement, check the catalog for a collision, source the subject from its owner, confirm the draft with the user, then write.
|
|
9
|
+
|
|
10
|
+
Read these files in parallel:
|
|
11
|
+
|
|
12
|
+
- `${CLAUDE_SKILL_DIR}/../../standards/wiki.md`: the two placement tests, the frontmatter contract, the naming convention, the sourcing rule, and the page template
|
|
13
|
+
- `${CLAUDE_SKILL_DIR}/../../standards/markdown.md`: banned words, punctuation, and formatting for all generated text
|
|
14
|
+
- The `write-human` skill: voice, rhythm, and sentence construction for all generated text
|
|
15
|
+
|
|
16
|
+
The standard's `## Placement` section names the folder a page lands in and the vendor subfolder under it. Resolve both from the project root and call them `<wiki-root>` and `<vendor>` below, so the body states the rule once and the standard stays the one owner of the path.
|
|
17
|
+
|
|
18
|
+
## Guards
|
|
19
|
+
|
|
20
|
+
- If no subject is given, stop: `❌ No subject given. Name the subject this page should cover.`
|
|
21
|
+
- If `<wiki-root>` does not resolve, say so and ask whether to create it before drafting. A project carrying no such folder has never taken the standard's placement rule, so creating it is a decision rather than a step.
|
|
22
|
+
|
|
23
|
+
## Placement
|
|
24
|
+
|
|
25
|
+
The standard sets two tests and a page has to pass both. Run them before drafting anything, since a page failing either is non-conforming however well it is written.
|
|
26
|
+
|
|
27
|
+
- **Owned outside this repository.** A subject describing how this repository works fails. Refuse and route it: `❌ <subject> is owned by this project, so it belongs in the docs surface, a context entry, or a skill body. Use draft-docs or draft-context.`
|
|
28
|
+
- **Owned by the vendor the folder split covers.** The standard names one owner and one subfolder. A third-party tool or a vendor-neutral concept fails, however reference-like it reads. Refuse and route it: `❌ <subject> is outside the wiki's folder split. Route it to the docs surface or a skill body rather than adding a second folder for it.`
|
|
29
|
+
|
|
30
|
+
Do not widen the split to admit a subject. Adding a sibling folder is a change to the standard, argued there, rather than a placement this skill takes on its own.
|
|
31
|
+
|
|
32
|
+
## Collision
|
|
33
|
+
|
|
34
|
+
- Derive the page slug per the standard's `## Naming` section and check whether `<wiki-root>/<vendor>/<slug>.md` already exists. If it does, stop: `❌ <path> already covers this subject. Edit that page against the standard instead of drafting a second one.`
|
|
35
|
+
- Read `<wiki-root>/<vendor>/index.md` and check every title and description it lists against the subject. The slug check above only catches an exact filename collision, and a subject already covered under a different name still resolves here at no extra cost, since this read already runs.
|
|
36
|
+
- Stop the same way on a match: `❌ <path> already covers this subject under a different name. Edit that page instead.`
|
|
37
|
+
|
|
38
|
+
## Source
|
|
39
|
+
|
|
40
|
+
The standard forbids working from training knowledge, so the draft is built on a read rather than on recall.
|
|
41
|
+
|
|
42
|
+
- Fetch current information through the `claude-code-guide` agent for any subject that agent covers. Its answer is the source the page is written from.
|
|
43
|
+
- Reach a subject the agent does not cover through the owner's own published documentation.
|
|
44
|
+
- Say the fetch failed and stop rather than substituting recall. A page sourced from memory is the failure the rule exists to prevent, and it ships looking identical to one that was checked.
|
|
45
|
+
- Close the intro with the `Source:` sentence the standard requires, linking the canonical page where one exists and naming the owner alone where the subject has no single URL.
|
|
46
|
+
- Stamp the read date on a source revised without notice, as `read <date>`. A claim traced to an undated read cannot be checked against what was actually read.
|
|
47
|
+
|
|
48
|
+
## Draft
|
|
49
|
+
|
|
50
|
+
- Draft `title` and `description` frontmatter against the standard's contract, then the intro paragraph closing on `Source:`, then the reference sections.
|
|
51
|
+
- Draft against the standard's template and keep its ordering.
|
|
52
|
+
- Write what the fetch returned rather than what the subject is assumed to do.
|
|
53
|
+
- Answer one question per section and stop. A reader arrives to settle something specific rather than to read the page through.
|
|
54
|
+
- Mark a claim the fetch left unsettled rather than smoothing over it. An unmarked gap reads as a checked fact.
|
|
55
|
+
|
|
56
|
+
## Confirm
|
|
57
|
+
|
|
58
|
+
- Show the resolved path, the source the page was built from, and the full drafted content before writing.
|
|
59
|
+
- Confirm all three with the user. This skill waits for that answer rather than treating the tool permission dialog as the gate, since the standard states outright that a wiki file is not written unasked.
|
|
60
|
+
|
|
61
|
+
## Write
|
|
62
|
+
|
|
63
|
+
- Write the file at the confirmed path.
|
|
64
|
+
- Run `canon markdown audit <path>`.
|
|
65
|
+
- Run `canon indexes regen <wiki-root>/<vendor>`, naming the folder the page landed in rather than the root above it. The verb rewrites the `index.md` sitting in the folder it is given and does not walk down, so regenerating at the root leaves the vendor catalog untouched and the new page missing from the one the Collision step reads. A page absent there is invisible to the next run, which then drafts a second page on the same subject.
|
|
66
|
+
|
|
67
|
+
## Response format
|
|
68
|
+
|
|
69
|
+
### Preview
|
|
70
|
+
|
|
71
|
+
**Subject:** `<subject>`
|
|
72
|
+
**Placement:** `<path>`
|
|
73
|
+
**Source:** `<owner, and the read it came from>`
|
|
74
|
+
|
|
75
|
+
```markdown
|
|
76
|
+
<drafted frontmatter and body>
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### After confirmation
|
|
80
|
+
|
|
81
|
+
```plaintext
|
|
82
|
+
✅ Drafted: <path>
|
|
83
|
+
```
|
|
@@ -33,6 +33,6 @@ Without this skill, an issue takes the shape of whatever the session was saying.
|
|
|
33
33
|
|
|
34
34
|
## Out of scope
|
|
35
35
|
|
|
36
|
-
- Reporting a toolkit defect from a target project, which `canon-feedback
|
|
36
|
+
- Reporting a toolkit defect from a target project, which `canon-feedback` owns. That path opens an issue on the toolkit repository rather than the current one.
|
|
37
37
|
- Triaging issues already filed, which `canon-feedback-triage` owns
|
|
38
38
|
- Opening a pull request, which `git-pr` owns
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: git-issue
|
|
3
|
-
description: Format a bug or task from the current session into a GitHub issue and file it on the current repo via `gh issue create`. Use when asked to "file an issue", "open an issue", "log this bug", "raise an issue", or "track this as an issue". Do NOT use to report a toolkit defect from a target project (that is `canon-feedback
|
|
3
|
+
description: Format a bug or task from the current session into a GitHub issue and file it on the current repo via `gh issue create`. Use when asked to "file an issue", "open an issue", "log this bug", "raise an issue", or "track this as an issue". Do NOT use to report a toolkit defect from a target project (that is `canon-feedback`), or to open a pull request (that is `git-pr`).
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Git issue
|
|
@@ -25,7 +25,7 @@ Read three fields off the same report, then two verbs:
|
|
|
25
25
|
|
|
26
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
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`.
|
|
28
|
+
- `reverse`: `unclaimed` names folders at roots the toolkit stopped shipping, each with an `attribution` of `dropped`, `unattributed`, or `project`.
|
|
29
29
|
- `canon context audit --json`: required sections, entry length, citations, and index drift across the context folder.
|
|
30
30
|
- `canon records validate <kind> --json`, once per record folder the target carries.
|
|
31
31
|
|
|
@@ -33,7 +33,7 @@ Read three fields off the same report, then two verbs:
|
|
|
33
33
|
- Behind: any of those carrying an entry. Name the entry and its attribution.
|
|
34
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
35
|
|
|
36
|
-
Routes by finding. `unmigrated` routes to a relocation the user runs, since no command moves it. `superseded` routes to
|
|
36
|
+
Routes by finding. `unmigrated` routes to a relocation the user runs, since no command moves it. `superseded` routes to a split the user makes, since no command moves the content and no skill proposes it. An `unclaimed` folder carrying `project` attribution routes nowhere, since history proved the project owns it.
|
|
37
37
|
|
|
38
38
|
## 3. Governance rules
|
|
39
39
|
|
|
@@ -256,11 +256,9 @@ seed tree rather than from a fixed set of filenames, so a folder added later is
|
|
|
256
256
|
covered without a code change. Only an exact stem matches, which leaves a
|
|
257
257
|
suffixed variant such as `TASKS-ARCHIVE.md` unreported.
|
|
258
258
|
|
|
259
|
-
|
|
260
|
-
`
|
|
261
|
-
destination shape
|
|
262
|
-
writing. Where a folder has no governing standard, the entry earns a named
|
|
263
|
-
refusal rather than a shape nobody stated.
|
|
259
|
+
No skill splits the file. The standard governing `replacedBy` is the one the
|
|
260
|
+
`appliesTo` the standards catalog declares, and `canon standards <name>` reads
|
|
261
|
+
its destination shape, so the split is the project's own to make.
|
|
264
262
|
|
|
265
263
|
`unmigrated` names a domain sitting at the root layout an older toolkit installed
|
|
266
264
|
to, with nothing at the path the current one reads. It carries `rootPath`,
|
|
@@ -350,7 +348,7 @@ check.
|
|
|
350
348
|
`reverse` is the one section built by walking the target rather than the
|
|
351
349
|
catalog. Every other surface enumerates toolkit-owned keys and asks whether the
|
|
352
350
|
target matches, so a folder the toolkit deleted appears in none of them. It
|
|
353
|
-
carries `unclaimed
|
|
351
|
+
carries `unclaimed` and `historyUnavailable`.
|
|
354
352
|
|
|
355
353
|
`unclaimed` names a folder the target holds at a top-level path the toolkit once
|
|
356
354
|
shipped and has since deleted. The candidate roots come from the toolkit's own
|
|
@@ -381,13 +379,6 @@ colliding on a retired name costs the walk no reads. The cost is that a file the
|
|
|
381
379
|
toolkit shipped and the target renamed goes unmatched, the same limit the
|
|
382
380
|
`unmigrated` count carries.
|
|
383
381
|
|
|
384
|
-
`migrations` names a proposal-only skill with a live case in this target. It
|
|
385
|
-
fires on a `CLAUDE.md` past 250 lines for `migration-claude-md`, and on a `docs/` folder
|
|
386
|
-
holding markdown with no populated `canon/context/` for `migration-context`.
|
|
387
|
-
Each entry carries the skill name and the measurement behind it, so a consumer
|
|
388
|
-
can check the proposal before running it. Without the field both skills are
|
|
389
|
-
documented and unreachable from any report.
|
|
390
|
-
|
|
391
382
|
#### What counts toward the gate
|
|
392
383
|
|
|
393
384
|
`unmigrated` counts toward `--exit-code`, since running the relocation closes it.
|
package/docs/agents/teach.md
CHANGED
|
@@ -133,7 +133,7 @@ It reports three things. `lesson` is the numbered path the lesson takes, derived
|
|
|
133
133
|
|
|
134
134
|
A lesson written against this record carries its chrome as four empty marker pairs rather than hand-composed markup: `canon:teach:style`, `canon:teach:header`, `canon:teach:footnav`, and `canon:teach:scripts`. `canon teach nav`, below, fills them from what the workspace holds on disk.
|
|
135
135
|
|
|
136
|
-
`canon teach stylesheet <topic>` writes the
|
|
136
|
+
`canon teach stylesheet <topic>` writes the pair every lesson in the workspace renders through, seeded from the design source so a workspace renders in the system every other surface does. The two halves are written on different terms. `assets/base.css` holds the generated design layer and is rewritten on every run, which is the only way a change to the shared chrome reaches a workspace that already exists. `assets/course.css` is the half a workspace owns, so it refuses to overwrite, reporting `written` as false where the workspace already carries one, and `--force` takes the seed back over it. Each workspace used to carry a hand-authored palette, which is how the course styling forked once per workspace, so a lesson adds its own rules under the seed and reaches a value through its custom property rather than restating the hex.
|
|
137
137
|
|
|
138
138
|
Each `quiz` entry carries `order`, the authored option indices in presentation order where index `0` is the correct answer, and `answer`, the one-based position that answer lands in. Both travel together because a caller deriving the position itself is a caller that can derive it wrongly.
|
|
139
139
|
|
|
@@ -172,10 +172,12 @@ canon teach nav regular-expressions --json
|
|
|
172
172
|
|
|
173
173
|
With no topic it rewrites every workspace. The teach-root listing is always rewritten regardless, since it reports on every workspace and a scoped run leaving it stale would be a second kind of drift this verb exists to end.
|
|
174
174
|
|
|
175
|
-
A lesson carries its chrome as four marker pairs the authoring skill writes empty: `canon:teach:style`, `canon:teach:header`, `canon:teach:footnav`, and `canon:teach:scripts`. This verb splices each one from the current workspace state, embedding the shared stylesheet, rebuilding the breadcrumb and jump menus, the prev/next footer nav, and the behavior scripts, and leaves the authored `<h1>`, lede, body, and quiz between the header and the footnav untouched.
|
|
175
|
+
A lesson carries its chrome as four marker pairs the authoring skill writes empty: `canon:teach:style`, `canon:teach:header`, `canon:teach:footnav`, and `canon:teach:scripts`. This verb splices each one from the current workspace state, embedding the shared stylesheet and the script that settles the course panel before the page paints, rebuilding the course sidebar, the breadcrumb and jump menus, the prev/next footer nav, and the behavior scripts, and leaves the authored `<h1>`, lede, body, and quiz between the header and the footnav untouched.
|
|
176
176
|
|
|
177
177
|
A workspace carrying no `course.css` gets its stylesheet pair seeded first, so the contents page it links is never unstyled, and an existing `course.css` is never overwritten. The embedded copy drops the seed's `@import` line, which resolved against the lesson's own folder and never loaded anything.
|
|
178
178
|
|
|
179
|
+
That seeding fires on the absent file alone, so a workspace already holding a `course.css` has neither half rewritten here and its lessons go on embedding the sheet they were built against. A change to the shared chrome therefore takes `canon teach stylesheet <topic>` per workspace first, which rewrites `assets/base.css`, and then this verb to embed the result. Running this one alone renders every lesson missing whatever the change added, and nothing reports it.
|
|
180
|
+
|
|
179
181
|
A lesson missing one of the four marker pairs is refused by name rather than rewritten, and every other lesson in the run still rewrites. The record's `skipped` list carries the refused files and which marker each is missing.
|
|
180
182
|
|
|
181
183
|
The `style` region carries the quiz stepper after the workspace stylesheet, for every lesson but the one shape named three paragraphs down, so it wins the cascade at equal specificity and reaches a workspace seeded before it existed. The stepper is CSS over the radio inputs a quiz is written from: it hides every question that follows one holding no checked input, and hides a question's feedback until that question does. The general sibling combinator is what keeps that from depending on the markup contract holding, since it selects the same questions as the adjacent one for a quiz written correctly and goes on gating when anything sits between two of them, where the adjacent one matches nothing and shows them all at once. Gating there rather than in a script is what keeps a later stem from answering an earlier question with nothing to bind, and the whole block sits inside `@supports selector(:has(*))`, so an engine without `:has()` renders every question rather than a stepper showing nothing. Feedback there follows the workspace stylesheet, shown by one that says nothing about `.fb` and hidden by one grown under the retired script.
|
package/docs/target-projects.md
CHANGED
|
@@ -261,8 +261,6 @@ Each entry carries a verdict, since a dropped folder and one the project wrote a
|
|
|
261
261
|
|
|
262
262
|
Nothing acts on any of them, and the verdict is what makes the list safe to read.
|
|
263
263
|
|
|
264
|
-
The same field names a proposal-only skill with a live case here under `migrations`, which is how `canon:migration-claude-md` and `canon:migration-context` become reachable. Each entry carries the measurement behind the proposal rather than the proposal alone.
|
|
265
|
-
|
|
266
264
|
Add `--json` for the machine-readable report, and `--exit-code` to fail a CI job when a target falls behind. Files the project authored itself never count toward that exit code, and neither do superseded artifacts, seed drift, tooling, or anything the reverse walk reports, since each names content the project is expected to edit or place itself. An unmigrated domain does count, because running the relocation closes it.
|
|
267
265
|
|
|
268
266
|
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.
|
|
@@ -285,17 +285,13 @@ This section is the corpus the coverage claim is measured against: every name `c
|
|
|
285
285
|
|
|
286
286
|
### Keep the project current with the toolkit
|
|
287
287
|
|
|
288
|
-
| Skill
|
|
289
|
-
|
|
|
290
|
-
| `canon:target-check`
|
|
291
|
-
| `canon:seed-sync`
|
|
292
|
-
| `canon:
|
|
293
|
-
| `canon:
|
|
294
|
-
| `canon:
|
|
295
|
-
| `canon:migration-standards-drop` | When the project still holds an installed `.claude/standards/` tree |
|
|
296
|
-
| `canon:canon-feedback-file` | When something in the toolkit is broken, missing, or off |
|
|
297
|
-
| `canon:canon-feedback-triage` | In the toolkit repo, to work through the open feedback issues |
|
|
298
|
-
| `canon:canon-rollout` | In the toolkit repo, to take one change out to every consuming project at once |
|
|
288
|
+
| Skill | When to use |
|
|
289
|
+
| ----------------------------- | -------------------------------------------------------------------------------------- |
|
|
290
|
+
| `canon:target-check` | In a target project, to report per domain what it holds against what the toolkit ships |
|
|
291
|
+
| `canon:seed-sync` | After a toolkit update, to reconcile installed seeds without losing customizations |
|
|
292
|
+
| `canon:canon-feedback` | When something in the toolkit is broken, missing, or off, to open an issue on it |
|
|
293
|
+
| `canon:canon-feedback-triage` | In the toolkit repo, to work through the open feedback issues |
|
|
294
|
+
| `canon:canon-rollout` | In the toolkit repo, to take one change out to every consuming project at once |
|
|
299
295
|
|
|
300
296
|
### Generate an artifact on demand
|
|
301
297
|
|
|
@@ -309,6 +305,7 @@ This section is the corpus the coverage claim is measured against: every name `c
|
|
|
309
305
|
| `canon:draft-ready` | For finished files a worker should copy, written as a ready folder with its overview, thin plan, and task |
|
|
310
306
|
| `canon:draft-context` | For a brand-new `canon/context/<domain>.md` entry, drafted against `standards/context.md` |
|
|
311
307
|
| `canon:draft-wireframes` | For a brand-new `canon/wireframes/<surface>.md` file, drafted against `standards/wireframes.md` |
|
|
308
|
+
| `canon:draft-wiki` | For a brand-new wiki reference page on a subject owned outside the project, drafted against `standards/wiki.md` |
|
|
312
309
|
| `canon:draft-figure` | For a hand-drawn figure inside an existing doc, drafted against `standards/figures.md` and rendered through Mermaid or freehand SVG |
|
|
313
310
|
| `canon:draft-readme` | For a project's `README.md`, drafted against `standards/readme.md` |
|
|
314
311
|
| `canon:bash-script` | For an interactive, human-facing shell tool |
|
package/package.json
CHANGED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Builds the landing page, captures it, and stages the frames over
|
|
3
|
+
# assets/evidence/home, the baseline `canon pr evidence` compares against.
|
|
4
|
+
#
|
|
5
|
+
# Two workflows call it. pr-visual-checks.yml stages the frames into the runner
|
|
6
|
+
# tree to diff them against the baseline, and refresh-capture-frames.yml stages
|
|
7
|
+
# them to commit as the new baseline. Both need the same frames, so one script
|
|
8
|
+
# keeps the two from drifting apart.
|
|
9
|
+
#
|
|
10
|
+
# `tooling/web/configs/e2e/screenshot.ts` is reused as is. This checkout has no
|
|
11
|
+
# web/package.json, so the preview server and the cases run against the
|
|
12
|
+
# root-level scripts rather than through screenshot.sh, which assumes a
|
|
13
|
+
# per-project `bun run build`/`bun run preview` pair.
|
|
14
|
+
set -e
|
|
15
|
+
set -o pipefail
|
|
16
|
+
|
|
17
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
18
|
+
PROJECT_ROOT="${PROJECT_ROOT:-$(cd "$SCRIPT_DIR/../.." && pwd)}"
|
|
19
|
+
|
|
20
|
+
PORT=4321
|
|
21
|
+
BASE_URL="http://localhost:$PORT"
|
|
22
|
+
BASELINE="$PROJECT_ROOT/assets/evidence/home"
|
|
23
|
+
|
|
24
|
+
cd "$PROJECT_ROOT"
|
|
25
|
+
|
|
26
|
+
bun run web:build
|
|
27
|
+
|
|
28
|
+
bun run web:preview &
|
|
29
|
+
PREVIEW_PID=$!
|
|
30
|
+
trap 'kill "$PREVIEW_PID" 2>/dev/null || true' EXIT
|
|
31
|
+
|
|
32
|
+
for _ in $(seq 1 40); do
|
|
33
|
+
curl -sSf "$BASE_URL/" >/dev/null 2>&1 && break
|
|
34
|
+
sleep 0.25
|
|
35
|
+
done
|
|
36
|
+
curl -sSf "$BASE_URL/" >/dev/null 2>&1 || {
|
|
37
|
+
echo "Preview server not responding on port $PORT after 10s." >&2
|
|
38
|
+
exit 1
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
(cd web && SCREENSHOT_BASE_URL="$BASE_URL" bun ../tooling/web/configs/e2e/screenshot.ts)
|
|
42
|
+
|
|
43
|
+
# The committed tree is cleared first rather than copied over. A copy only adds
|
|
44
|
+
# and overwrites, so a section dropped from the case list would leave its
|
|
45
|
+
# frames in place and a diff would see no change. Clearing first shows that
|
|
46
|
+
# section as a deletion.
|
|
47
|
+
rm -rf "$BASELINE"
|
|
48
|
+
mkdir -p "$BASELINE"
|
|
49
|
+
cp -R web/screenshots/localhost/home/. "$BASELINE/"
|
|
50
|
+
|
|
51
|
+
# The sweep holds all four widths and this repository commits two, 320 and
|
|
52
|
+
# 1280. The case list is the place to change if that set moves.
|
|
53
|
+
find "$BASELINE" \( -name '768--*.png' -o -name '1536--*.png' \) -delete
|
|
54
|
+
|
|
55
|
+
# The shared golden config names the case that emulates nothing `default`, and
|
|
56
|
+
# this repository's baseline names that frame `light`.
|
|
57
|
+
find "$BASELINE" -name '*--default.png' -execdir sh -c 'mv "$1" "${1%--default.png}--light.png"' _ {} \;
|
|
58
|
+
|
|
59
|
+
echo "capture-home: staged frames in assets/evidence/home"
|
|
@@ -61,6 +61,11 @@ export const AUTHORING_CASES: readonly SkillCase[] = [
|
|
|
61
61
|
'Draft a wireframe for the settings panel, nothing under canon/wireframes covers that surface yet.',
|
|
62
62
|
expect: 'draft-wireframes',
|
|
63
63
|
},
|
|
64
|
+
{
|
|
65
|
+
prompt:
|
|
66
|
+
'Write a wiki reference page for Claude Code output styles, no page covers that subject yet.',
|
|
67
|
+
expect: 'draft-wiki',
|
|
68
|
+
},
|
|
64
69
|
{
|
|
65
70
|
prompt: 'Say what that dense answer actually means in plain terms.',
|
|
66
71
|
expect: 'restate-plainly',
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import type { SkillCase } from '@/claude/skills-rank'
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* `target-setup`, `
|
|
5
|
-
*
|
|
6
|
-
* surfaces.
|
|
4
|
+
* `target-setup`, `canon-*`, and `create-rule`: scaffolding and the
|
|
5
|
+
* toolkit's own reference and feedback surfaces.
|
|
7
6
|
*
|
|
8
7
|
* The five `target-setup` cases are one skill read through five entry phrasings
|
|
9
8
|
* rather than five rows that collapsed to a duplicate. Each names a different
|
|
@@ -36,26 +35,6 @@ export const SETUP_CASES: readonly SkillCase[] = [
|
|
|
36
35
|
'Check that the dev server actually starts and the end-to-end suite passes against the scaffold.',
|
|
37
36
|
expect: 'target-setup',
|
|
38
37
|
},
|
|
39
|
-
{
|
|
40
|
-
prompt:
|
|
41
|
-
'This CLAUDE.md file has grown huge, break it apart into the tiered context model.',
|
|
42
|
-
expect: 'migration-claude-md',
|
|
43
|
-
},
|
|
44
|
-
{
|
|
45
|
-
prompt:
|
|
46
|
-
'Move the agent-flavored docs out of the docs folder and into context.',
|
|
47
|
-
expect: 'migration-context',
|
|
48
|
-
},
|
|
49
|
-
{
|
|
50
|
-
prompt:
|
|
51
|
-
'This file was replaced by a folder, help me split its content into it.',
|
|
52
|
-
expect: 'migration-superseded',
|
|
53
|
-
},
|
|
54
|
-
{
|
|
55
|
-
prompt:
|
|
56
|
-
'This project still carries a copy of the standards folder, get rid of it and point everything at the CLI.',
|
|
57
|
-
expect: 'migration-standards-drop',
|
|
58
|
-
},
|
|
59
38
|
{
|
|
60
39
|
prompt:
|
|
61
40
|
"Before I run this sync, tell me exactly what it's going to overwrite.",
|
|
@@ -64,7 +43,7 @@ export const SETUP_CASES: readonly SkillCase[] = [
|
|
|
64
43
|
{
|
|
65
44
|
prompt:
|
|
66
45
|
'Something about the toolkit itself is broken, write it up and send it back to the maintainers.',
|
|
67
|
-
expect: 'canon-feedback
|
|
46
|
+
expect: 'canon-feedback',
|
|
68
47
|
},
|
|
69
48
|
{
|
|
70
49
|
prompt:
|
package/src/commands/sync.ts
CHANGED
|
@@ -189,7 +189,6 @@ function renderCheck(report: CheckReport): void {
|
|
|
189
189
|
}
|
|
190
190
|
|
|
191
191
|
renderUnclaimed(report)
|
|
192
|
-
renderMigrations(report)
|
|
193
192
|
|
|
194
193
|
outro()
|
|
195
194
|
// Scanned domains only. Tooling renders a section on every managed target, so
|
|
@@ -334,21 +333,6 @@ function describeUnclaimed(entry: UnclaimedFolder): string {
|
|
|
334
333
|
return `${counted}, content published at ${entry.since.slice(0, 7)}`
|
|
335
334
|
}
|
|
336
335
|
|
|
337
|
-
/**
|
|
338
|
-
* The proposal-only skills no other field reaches.
|
|
339
|
-
*/
|
|
340
|
-
function renderMigrations(report: CheckReport): void {
|
|
341
|
-
const { migrations } = report.reverse
|
|
342
|
-
if (migrations.length === 0) return
|
|
343
|
-
|
|
344
|
-
logStep('Migrations with a case here')
|
|
345
|
-
|
|
346
|
-
for (const candidate of migrations) {
|
|
347
|
-
logWarn(candidate.reason)
|
|
348
|
-
logInfo(`Run /canon:${candidate.skill} for a proposal.`)
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
|
|
352
336
|
async function runSync(target: string): Promise<number> {
|
|
353
337
|
intro('canon sync')
|
|
354
338
|
|