@erclx/canon 4.53.0 → 4.55.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/README.md +8 -0
- package/claude/.claude-plugin/plugin.json +1 -1
- package/claude/skills/canon-cli/SKILL.md +1 -1
- package/claude/skills/claude-feature/SKILL.md +1 -1
- package/claude/skills/claude-orchestrate/references/orchestrator-dispatch.md +7 -3
- package/claude/skills/claude-planner/SKILL.md +1 -1
- package/claude/skills/context-draft/REQUIREMENT.md +37 -0
- package/claude/skills/context-draft/SKILL.md +59 -0
- package/claude/skills/create-skill/REQUIREMENT.md +1 -1
- package/claude/skills/create-standard/SKILL.md +1 -1
- package/claude/skills/index-lookup/REQUIREMENT.md +35 -0
- package/claude/skills/index-lookup/SKILL.md +42 -0
- package/claude/skills/wireframe-draft/REQUIREMENT.md +38 -0
- package/claude/skills/wireframe-draft/SKILL.md +64 -0
- package/claude/skills/youtube-transcripts/SKILL.md +1 -1
- package/docs/agents/commands.md +1 -0
- package/docs/agents/demo.md +11 -8
- package/docs/agents/index.md +1 -1
- package/docs/agents/indexes.md +17 -1
- package/docs/workflow/ai-workflow.md +15 -12
- package/governance/rules/core/085-worktrees.md +2 -0
- package/package.json +1 -1
- package/scripts/core/regen-agent-fixture.sh +235 -0
- package/src/claude/cases/authoring.ts +10 -0
- package/src/claude/cases/misc.ts +4 -0
- package/src/commands/demo.ts +25 -1
- package/src/commands/indexes.ts +67 -0
- package/src/demo/container.ts +61 -0
- package/src/demo/drive.ts +67 -9
- package/src/indexes/list.ts +64 -0
- package/src/indexes/render.ts +1 -1
- package/tooling/claude/seeds/.claude/hooks/index-reminder.sh +1 -1
- package/tooling/web/configs/scripts/screenshot.sh +1 -1
package/README.md
CHANGED
|
@@ -10,6 +10,14 @@ canon is a CLI and Claude Code plugin that stops your AI conventions drifting ap
|
|
|
10
10
|
|
|
11
11
|
The counts above are read from the catalogs when the image is built, so they're what the repo actually ships today.
|
|
12
12
|
|
|
13
|
+
## It runs on itself
|
|
14
|
+
|
|
15
|
+
The workflow this toolkit ships is the workflow that built it. Several Claude Code sessions run at once, each in its own git worktree on its own branch, and each opens its own pull request.
|
|
16
|
+
|
|
17
|
+

|
|
18
|
+
|
|
19
|
+
That is the landing page's own agent view, recorded from a local build by `canon demo run`. The session rows behind it are a real `canon sessions list --json` read. The activity text and the pull request number are transcribed, because no verb here reports either.
|
|
20
|
+
|
|
13
21
|
## Why
|
|
14
22
|
|
|
15
23
|
If you work across more than one repository and your AI setup has started to drift between them, this is for you. Every AI coding setup accumulates the same assets. Prompts to reuse, rules agents should follow, slash commands, skills, seed docs, sync scripts. Once you have enough projects, your copies drift and your agents stop getting consistent signals.
|
|
@@ -102,4 +102,4 @@ Run `canon tooling sync <stack> <target> --check` for the list resolved against
|
|
|
102
102
|
|
|
103
103
|
## Source of truth
|
|
104
104
|
|
|
105
|
-
- Full semantics live in the toolkit's
|
|
105
|
+
- Full semantics live in the toolkit's own context entries. This skill is the target-session summary. When they disagree, the context docs win.
|
|
@@ -93,7 +93,7 @@ Omit empty sections. Do not print `None identified.` in chat.
|
|
|
93
93
|
|
|
94
94
|
Derive a 2-to-4-word kebab-case slug from the feature description. Write the full plan to `.canon/plans/feature-<slug>.md` at the main worktree root, not the current worktree. Resolve that root the way `claude-worktree` does. Create the directory if it does not exist.
|
|
95
95
|
|
|
96
|
-
From a linked worktree the file-editing tools refuse that path, so the plan goes out through `Bash`. Send the `mkdir -p` and the heredoc as two plain commands rather than joining them with `&&`, which is refused as compound.
|
|
96
|
+
From a linked worktree, or from a background session sitting at the main root with none entered, the file-editing tools refuse that path, so the plan goes out through `Bash`. Send the `mkdir -p` and the heredoc as two plain commands rather than joining them with `&&`, which is refused as compound.
|
|
97
97
|
|
|
98
98
|
The file follows the template in `${CLAUDE_SKILL_DIR}/../../standards/plan.md`. Copy the shape from there rather than from this body, so one edit to the standard moves every plan.
|
|
99
99
|
|
|
@@ -157,9 +157,10 @@ controller that hands an operator two chained blocks to paste as separate
|
|
|
157
157
|
messages risks both landing as one, where everything after the first
|
|
158
158
|
command's name is read as that command's own argument and the second command
|
|
159
159
|
never fires, measured four times out of four on 2026-09-02.
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
160
|
+
A slash command expands as a user invocation only at position zero of a
|
|
161
|
+
prompt, and a later one in the same text reaches the session as prose instead.
|
|
162
|
+
The fix is what the template above already takes: one message, one command,
|
|
163
|
+
at position zero.
|
|
163
164
|
|
|
164
165
|
### What the brief may carry
|
|
165
166
|
|
|
@@ -227,6 +228,9 @@ build shape above reaches `claude-worker`.
|
|
|
227
228
|
No branch and no worktree exist here and none is created. A planner writes one
|
|
228
229
|
gitignored file at the main worktree root, so this shape names the row's task
|
|
229
230
|
file rather than a branch and opens with the role instead of a worktree call.
|
|
231
|
+
That write meets the isolation guard the same way a linked worktree's
|
|
232
|
+
main-root write does, with no worktree here to redirect it to, so
|
|
233
|
+
`claude-planner` sends it as a `Bash` heredoc rather than through `Write`.
|
|
230
234
|
|
|
231
235
|
```bash
|
|
232
236
|
claude --bg --model <model> -n "planner-<project>-<slug>" "Run /canon:claude-planner, then /canon:claude-feature <task>. Your controller is the session whose sessionId is <dispatcher-id>. Resolve its current name from that id through canon sessions list --json, which carries sessionId per row, at the moment you send, and never resolve an addressee by name prefix. Message it when the plan lands, carrying the path and what the task file got wrong, and message it again if you stop on a question."
|
|
@@ -21,7 +21,7 @@ from here.
|
|
|
21
21
|
|
|
22
22
|
## Where the session stands
|
|
23
23
|
|
|
24
|
-
- Write one file, the plan, at `.canon/plans/feature-<slug>.md` on the main worktree root. Everything else this session touches is a read.
|
|
24
|
+
- Write one file, the plan, at `.canon/plans/feature-<slug>.md` on the main worktree root. Everything else this session touches is a read. This session holds no worktree, so send the file as a plain `Bash` heredoc past the same main-root refusal a linked worktree meets. The route skips the write-matched hooks, and they are no-ops on a plan file.
|
|
25
25
|
- Never enter a worktree, never create a branch, and never write a tracked file. A planner that builds has stopped being one, and the row loses the independent read the worker's own session was going to bring to it.
|
|
26
26
|
- Resolve `.canon/plans/`, `.canon/tasks/`, and `.canon/review/` at the main worktree root. Those folders are gitignored, so a copy beside a linked worktree is absent rather than empty.
|
|
27
27
|
- Plan the row the launch named. Report a second row met while reading rather than planning it, since which rows run is the controller's call.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: context-draft
|
|
3
|
+
description: Why a brand-new .claude/context/<domain>.md entry needs a catalog collision check and a confirm step, not the refresh path claude-docs already owns
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Context draft requirement
|
|
7
|
+
|
|
8
|
+
## Gap
|
|
9
|
+
|
|
10
|
+
Without this skill, a session documenting a domain that has no context entry yet either invents a shape from memory or reaches for the refresh mechanism, which reads an existing entry and a diff and has neither to work from for a domain that never had one. Either way the entry ships with no read of `standards/context.md` and no check against the catalog for a sibling already covering the same ground under a different name.
|
|
11
|
+
|
|
12
|
+
## Must
|
|
13
|
+
|
|
14
|
+
- Read `standards/context.md` before drafting, since the frontmatter contract and the three-question test are what make the entry arguable against a sibling
|
|
15
|
+
- Check the domain against the existing catalog by slug and by title-and-description, not by slug alone, since a domain can be covered under a name the topic phrase does not guess
|
|
16
|
+
- Default a brand-new entry to a flat file, since a fresh domain never holds the three or more sub-areas the standard requires before it earns a folder
|
|
17
|
+
- Confirm the resolved path and the full content with the user before writing, since placement is a judgment call with no diff to preview it against
|
|
18
|
+
- Run `canon indexes regen` on `.claude/context/` after writing, so the catalog picks up the new domain immediately rather than drifting until the next unrelated regen
|
|
19
|
+
|
|
20
|
+
## Must not
|
|
21
|
+
|
|
22
|
+
- Refresh or rewrite an existing entry. A domain already covered refuses toward the refresh mechanism.
|
|
23
|
+
- Hand-edit `.claude/context/index.md`. It regenerates from sibling frontmatter, and a hand edit is overwritten on the next regen.
|
|
24
|
+
- 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.
|
|
25
|
+
|
|
26
|
+
## Guards
|
|
27
|
+
|
|
28
|
+
- No domain given: stop and ask what domain the entry should cover.
|
|
29
|
+
- The derived slug already resolves to `.claude/context/<slug>.md` or `.claude/context/<slug>/index.md`: stop and point at the refresh mechanism instead.
|
|
30
|
+
- The catalog already covers the domain under a different name: stop the same way, checked against the titles and descriptions the Placement step already reads.
|
|
31
|
+
|
|
32
|
+
## Out of scope
|
|
33
|
+
|
|
34
|
+
- Refreshing an existing `.claude/context/<domain>.md` entry against a diff: `claude-docs`
|
|
35
|
+
- Drafting a `.claude/wireframes/<surface>.md` file: `wireframe-draft`
|
|
36
|
+
- Drafting a `docs/*.md` page: `docs-draft`
|
|
37
|
+
- Drafting a standard, a snippet, or a governance rule: `create-standard`, `create-snippet`, `create-rule`
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: context-draft
|
|
3
|
+
description: Drafts a brand-new `.claude/context/<domain>.md` entry against `standards/context.md`, checks the catalog for a name-or-topic collision, decides flat-file placement, confirms with the user, then writes. Use when asked to "write a context entry for X", "document the X domain", "add a context entry for X", or "create a .claude/context page for X" where no existing entry covers the domain. Do NOT use to refresh an existing entry against a diff, which is `claude-docs`.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Context draft
|
|
7
|
+
|
|
8
|
+
Drafts one brand-new `.claude/context/<domain>.md` entry end to end: read the standard, decide whether the domain is already covered under a different name, confirm the draft with the user, then write.
|
|
9
|
+
|
|
10
|
+
Read these files in parallel:
|
|
11
|
+
|
|
12
|
+
- `${CLAUDE_SKILL_DIR}/../../standards/context.md`: the three questions an entry must answer, its frontmatter, required and expected sections, and what stays out of it
|
|
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
|
+
## Guards
|
|
17
|
+
|
|
18
|
+
- If no domain is given, stop: `❌ No domain given. Name the domain this entry should cover.`
|
|
19
|
+
- Derive a kebab-case slug from the domain and check whether `.claude/context/<slug>.md` or `.claude/context/<slug>/index.md` already exists. Either resolving means the domain is already covered under that exact name. Stop: `❌ <slug> already has a context entry. Use claude-docs to refresh it instead.`
|
|
20
|
+
|
|
21
|
+
## Placement
|
|
22
|
+
|
|
23
|
+
- Read `.claude/context/index.md` and check every title and description it lists against the domain. The Guards check above only catches an exact-slug collision, and a domain already covered under a different name still resolves here at no extra cost, since this read already runs.
|
|
24
|
+
- Stop the same way on a match: `❌ <path> already covers this domain under a different name. Use claude-docs to refresh it instead.`
|
|
25
|
+
- Default a brand-new entry to a flat file, `.claude/context/<slug>.md`. A domain starts as one page's worth of narrative, and the standard only splits it into a folder once it holds three or more sub-areas, which a fresh domain never does on day one.
|
|
26
|
+
|
|
27
|
+
## Draft
|
|
28
|
+
|
|
29
|
+
- Read the domain's own folders and files well enough to answer the standard's three questions: where things live, why they are that way, and how to add one more of what the domain holds.
|
|
30
|
+
- Draft `title` and `description` frontmatter, then `## Overview`, `## Layout` (folder ownership lines only, never a file-by-file list), and `## Decisions` or `## Gotchas` wherever the domain's history supplies a non-obvious choice or a workaround worth preserving. Omit an expected section with nothing to put in it rather than padding it.
|
|
31
|
+
- Draft against `${CLAUDE_SKILL_DIR}/../../standards/context.md`'s template and ordering: `Overview`, `Layout`, `Decisions`, `Gotchas`, then anything else.
|
|
32
|
+
|
|
33
|
+
## Confirm
|
|
34
|
+
|
|
35
|
+
- Show the resolved path and the full drafted content before writing.
|
|
36
|
+
- Confirm both with the user. This skill waits for that answer rather than treating the tool permission dialog as the gate, since placement here is a judgment call with no diff to preview it against.
|
|
37
|
+
|
|
38
|
+
## Write
|
|
39
|
+
|
|
40
|
+
- Write the file at the confirmed path, creating the folder when it is absent.
|
|
41
|
+
- Run `canon markdown audit <path>`.
|
|
42
|
+
- Run `canon indexes regen .claude/context`, so the domain appears in `.claude/context/index.md` immediately rather than drifting until the next unrelated regen.
|
|
43
|
+
|
|
44
|
+
## Response format
|
|
45
|
+
|
|
46
|
+
### Preview
|
|
47
|
+
|
|
48
|
+
**Domain:** `<domain>`
|
|
49
|
+
**Placement:** `<path>`
|
|
50
|
+
|
|
51
|
+
```markdown
|
|
52
|
+
<drafted frontmatter and body>
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### After confirmation
|
|
56
|
+
|
|
57
|
+
```plaintext
|
|
58
|
+
✅ Drafted: <path>
|
|
59
|
+
```
|
|
@@ -35,4 +35,4 @@ A third failure is a folder created for a moment a rule, a verb, or an existing
|
|
|
35
35
|
## Out of scope
|
|
36
36
|
|
|
37
37
|
- Editing an existing skill, which the authoring standard and the skill's own requirement govern
|
|
38
|
-
- Whether anything ends up invoking the new skill: the usage census
|
|
38
|
+
- Whether anything ends up invoking the new skill: the usage census the toolkit's own context entry tracks, read once the skill has run
|
|
@@ -23,7 +23,7 @@ Creates one standard file. Read these files in parallel:
|
|
|
23
23
|
|
|
24
24
|
Emit the full path on its own line.
|
|
25
25
|
|
|
26
|
-
- In the toolkit: this is the authoring source. Remind the user to run `bun run check` to regenerate the consumed copy under `.claude/`. That pass also regenerates the `standards/index.md` entry, and the user adds a row to the standards table in `.claude/context/standards/overview.md`.
|
|
26
|
+
- In the toolkit: this is the authoring source. Remind the user to run `bun run check` to regenerate the consumed copy under `.claude/`. That pass also regenerates the `standards/index.md` entry, and the user adds a row to the standards table in `.claude/context/standards/overview.md`. <!-- canon-allow-reference: audience-branched, only a toolkit-repo reader reaches this line and that reader can open the path -->
|
|
27
27
|
- In a project: the file is project-local and no toolkit command touches it. Remind the user to copy it to the toolkit repo, under `standards/<slug>.md`, if it should ship to every project.
|
|
28
28
|
|
|
29
29
|
Separate the two by whether the folder already held toolkit-authored standards before this write, since a project authoring its own uses the same path.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: index-lookup
|
|
3
|
+
description: Why a topic search over the tracked index catalog needs its own skill, and why a folder outside `list`'s walk gets a named pointer instead of a search hit
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Index lookup requirement
|
|
7
|
+
|
|
8
|
+
## Gap
|
|
9
|
+
|
|
10
|
+
Without this skill, `canon indexes list --json` exists as a verb with nobody wrapping it into a topic-search request. A session either greps the tree by hand, which misses everything the catalog already states in `title` and `description` rather than in file contents, or answers from whichever folder it happened to open, which reports a topic as undocumented when the topic only sits outside the walked corpus: a gitignored indexed folder such as `.canon/tasks/` or `.canon/memory/`, or a README-based record catalog such as `.canon/groundwork/`, neither of which `list` ever reaches.
|
|
11
|
+
|
|
12
|
+
## Must
|
|
13
|
+
|
|
14
|
+
- Run `canon indexes list --json` and match the topic against every entry's `title`, `description`, and `path`
|
|
15
|
+
- Check whether the project carries a gitignored indexed folder or a README-based record catalog outside `list`'s walk before naming any of them, since a folder absent from the project names nothing
|
|
16
|
+
- Report zero hits inside the walked corpus as zero hits, never as "not documented," since a folder outside the walk can still hold the answer
|
|
17
|
+
|
|
18
|
+
## Must not
|
|
19
|
+
|
|
20
|
+
- Search file contents. A miss against `title`, `description`, and `path` is the whole answer, and grepping the tree is a different request.
|
|
21
|
+
- Extend `canon indexes list` to read a `README.md` catalog or to bypass the gitignore filter. Both are accepted trade-offs the verb already carries, and widening either is a CLI change, not a skill-body change.
|
|
22
|
+
- Regenerate an index on its own initiative. Reporting a stale-looking entry is this skill's job, and writing the fix belongs to `canon indexes regen`.
|
|
23
|
+
- Fire from a request to browse a file whose path is already known, or to search source code, both of which this skill answers nothing for
|
|
24
|
+
- Assume this skill's own invocation frequency needs no check. The reminder hook names it beside `canon indexes list --json`, and a session recognizing a topic-lookup request can trigger it by description, but whether anything reaches for it beyond an operator typing its name has no answer at creation time, so a review pass some months in should read that back rather than take it on faith.
|
|
25
|
+
|
|
26
|
+
## Guards
|
|
27
|
+
|
|
28
|
+
- `canon indexes list` does not resolve on an older install. Report that rather than falling back to a manual walk, since a hand-rolled walk here restates the CLI logic this skill exists to call.
|
|
29
|
+
- A folder failing frontmatter validation drops out of `entries` and its message lands in `errors`, per the verb's own per-folder isolation. Report the error alongside the match rather than treating it as a reason to stop.
|
|
30
|
+
|
|
31
|
+
## Out of scope
|
|
32
|
+
|
|
33
|
+
- Regenerating or scaffolding an index, which `canon indexes regen` and the `setup-indexes` skill own
|
|
34
|
+
- Reading a folder's contents once a hit names it, which is an ordinary file read rather than part of the lookup
|
|
35
|
+
- Chaining this skill into `setup-indexes`'s bootstrap flow as a verification step. Left independent: `setup-indexes` already validates through `canon indexes regen --dry-run`, and a second skill call inside a bootstrap flow duplicates a check that already runs.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: index-lookup
|
|
3
|
+
description: Answers a topic search over every tracked index.md catalog in the project by running `canon indexes list --json` and matching the topic against each entry's title, description, and path, then reports the hits or names why there are none. Names the gitignored task, memory, and diagram catalogs and the groundwork and intake record folders as pointers outside its walked corpus, so it never claims a topic is undocumented when the topic only sits there. Use when asked "where is X documented", "is there a page about X", "search the docs for X", "find the index entry for X", or "what covers X". Do NOT use to grep source code, browse a file whose path is already known, or regenerate an index, which is `canon indexes regen`.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Index lookup
|
|
7
|
+
|
|
8
|
+
Answers a topic search over the project's tracked `index.md` catalogs, not a text search over file contents. Matches a topic string against every entry's `title`, `description`, and `path`, drawn from wherever `canon indexes list --json` walks.
|
|
9
|
+
|
|
10
|
+
## Steps
|
|
11
|
+
|
|
12
|
+
1. Resolve the project root with `git rev-parse --show-toplevel`, falling back to the working directory when the read fails.
|
|
13
|
+
2. Run `canon indexes list --json` from that root.
|
|
14
|
+
3. Read `errors` first. A folder failing frontmatter validation drops out of `entries` and lands its message in `errors` instead, per the verb's own per-folder isolation, so report an error alongside the match rather than reading it as a reason to stop.
|
|
15
|
+
4. Match the topic case-insensitively as a substring against each entry's `title`, `description`, and `path`. Report every match. A lookup with no ranking is honest about what it found, and a single best guess is not.
|
|
16
|
+
5. Check whether the project carries a gitignored indexed folder or a README-based record catalog outside `list`'s walk: `.canon/tasks/`, `.canon/memory/`, `.canon/diagrams/`, `.canon/groundwork/`, `.canon/intake/`. Test each for existence and at least one file inside it before naming it. A folder absent from this project names nothing.
|
|
17
|
+
6. Report the hits, plus a pointer to any outside-the-walk folder found present, per Output below.
|
|
18
|
+
|
|
19
|
+
## Rules
|
|
20
|
+
|
|
21
|
+
- Report zero hits as zero hits, never as "not documented." The topic can sit inside a folder step 5 found and named, so an empty walked corpus is a fact about the search, not about the project.
|
|
22
|
+
- Never search file contents. A miss against `title`, `description`, and `path` is the whole answer, and a request that needs a text search calls for grepping the tree instead.
|
|
23
|
+
- Never regenerate or edit an index. Report an entry that reads as stale rather than running `canon indexes regen` on this skill's own initiative.
|
|
24
|
+
- Report an absent `canon indexes list` subcommand rather than falling back to a manual walk. It ships with the CLI, so a project on an older install meets a missing verb, and a hand-rolled walk here restates the CLI logic this skill exists to call instead.
|
|
25
|
+
|
|
26
|
+
## Output
|
|
27
|
+
|
|
28
|
+
```plaintext
|
|
29
|
+
Index lookup: "<topic>"
|
|
30
|
+
|
|
31
|
+
Hits:
|
|
32
|
+
- <path>: <title> — <description>
|
|
33
|
+
|
|
34
|
+
Outside the walked corpus (check by hand):
|
|
35
|
+
- <folder>: <one-line reason it sits outside list's walk>
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Replace the "Hits" block with `No catalog entry matched "<topic>".` when nothing matched. Omit "Outside the walked corpus" when the project carries none of the five folders from step 5, or when every one it carries is empty.
|
|
39
|
+
|
|
40
|
+
## Reference
|
|
41
|
+
|
|
42
|
+
Run `canon docs indexes` for the `canon indexes list` flags, exit codes, and JSON shape. It resolves from the toolkit rather than from the target's own tree.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: wireframe-draft
|
|
3
|
+
description: Why a brand-new .claude/wireframes/<surface>.md file needs a real draft and a tier-detect step, not the stub the wireframe-sweep already writes
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Wireframe draft requirement
|
|
7
|
+
|
|
8
|
+
## Gap
|
|
9
|
+
|
|
10
|
+
Without this skill, a session drafting a wireframe for a surface with no file yet either invents an ASCII layout from memory with no read of `standards/wireframes.md`, or waits on the wireframe-sweep, which only fires against a diff and only ever writes a bare `TODO` stub rather than a real layout, copy, and behavior draft. Neither path checks whether a visual-design tier above ASCII is already in play for the project before drafting the tier-0 file.
|
|
11
|
+
|
|
12
|
+
## Must
|
|
13
|
+
|
|
14
|
+
- Read `standards/wireframes.md` before drafting, since the frontmatter contract, the layout and variant rules, and the Transcription-wireframes branch are what make the file arguable against a sibling
|
|
15
|
+
- Walk the whole `.claude/wireframes/` tree, including a grouped surface's own subfolder, before drafting, since a top-level-only check misses a nested match
|
|
16
|
+
- Detect an existing higher tier from `.claude/DESIGN.md` and the wireframes tree and report it, never build a companion render for it, since no shipped mechanism produces one
|
|
17
|
+
- Draft in transcription mode, citing the real source, when the surface names an already-built component. Draft in role-intent mode otherwise.
|
|
18
|
+
- Confirm the resolved path, the detected tier, and the full content with the user before writing, since the mode decision and the tier read are judgment calls with no diff to preview either against
|
|
19
|
+
- Run `canon indexes regen` on `.claude/wireframes/` after writing, so the catalog picks up the new surface immediately rather than drifting until the next unrelated regen
|
|
20
|
+
|
|
21
|
+
## Must not
|
|
22
|
+
|
|
23
|
+
- Build a tier-1 or tier-2 rendering mechanism, an Excalidraw round trip, or any companion render. Detecting and reporting a higher tier is the whole of this skill's reach past ASCII.
|
|
24
|
+
- Hand-edit `.claude/wireframes/index.md`. It regenerates from sibling frontmatter, and a hand edit is overwritten on the next regen.
|
|
25
|
+
- 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.
|
|
26
|
+
|
|
27
|
+
## Guards
|
|
28
|
+
|
|
29
|
+
- No surface given: stop and ask what surface the wireframe should cover.
|
|
30
|
+
- The derived slug already matches a file anywhere in the `.claude/wireframes/` tree, flat or nested: stop and point at editing that file directly, since no dedicated skill owns a full rewrite of an existing surface.
|
|
31
|
+
|
|
32
|
+
## Out of scope
|
|
33
|
+
|
|
34
|
+
- Stubbing a surface a diff touched, or reporting drift in an existing wireframe against a diff: `claude/skills/claude-docs/references/wireframe-sweep.md`
|
|
35
|
+
- Drafting a `.claude/context/<domain>.md` entry: `context-draft`
|
|
36
|
+
- Drafting a `docs/*.md` page: `docs-draft`
|
|
37
|
+
- Drafting a standard, a snippet, or a governance rule: `create-standard`, `create-snippet`, `create-rule`
|
|
38
|
+
- Building or wiring an actual tier-1 or tier-2 rendering pipeline: the visual design workflow's own tier guidance, out of reach of a hand-drafting skill
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: wireframe-draft
|
|
3
|
+
description: Drafts a brand-new `.claude/wireframes/<surface>.md` file against `standards/wireframes.md`, walks the tree for a name collision, detects an existing higher visual-design tier without building one, confirms with the user, then writes. Use when asked to "draft a wireframe for X", "write the wireframe for this surface", "add a .claude/wireframes entry for X", or "wireframe this screen" where no surface file covers it yet. Do NOT use to fix a stale TODO stub or report wireframe drift against a diff, which is `claude-docs`'s wireframe-sweep step.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Wireframe draft
|
|
7
|
+
|
|
8
|
+
Drafts one brand-new `.claude/wireframes/<surface>.md` file end to end: read the standard, decide whether the surface is already covered, detect but never build a higher visual-design tier, confirm the draft with the user, then write.
|
|
9
|
+
|
|
10
|
+
Read these files in parallel:
|
|
11
|
+
|
|
12
|
+
- `${CLAUDE_SKILL_DIR}/../../standards/wireframes.md`: the three questions a wireframe must answer, its frontmatter, layout and variant rules, the Transcription-wireframes branch, and what moves to a context entry instead
|
|
13
|
+
- `${CLAUDE_SKILL_DIR}/../../standards/markdown.md`: banned words, punctuation, and formatting for the prose around the fences
|
|
14
|
+
- The `write-human` skill: voice, rhythm, and sentence construction for the prose around the fences
|
|
15
|
+
|
|
16
|
+
This skill stays fully independent of `claude/skills/claude-docs/references/wireframe-sweep.md`, which only ever writes a bare `TODO` stub for a surface a diff touched and reports drift against one a wireframe already covers. Neither the stub nor the drift check is a draft, and this skill never reads or writes through that mechanism.
|
|
17
|
+
|
|
18
|
+
## Guards
|
|
19
|
+
|
|
20
|
+
- If no surface is given, stop: `❌ No surface given. Name the surface this wireframe should cover.`
|
|
21
|
+
- Derive a kebab-case slug from the surface. Walk the whole `.claude/wireframes/` tree, including a surface nested inside a grouped subfolder, rather than checking the top level alone. A match at any depth means the surface already has a file. Stop: `❌ <path> already covers this surface. Edit it directly; this skill only drafts a surface with no file yet.`
|
|
22
|
+
|
|
23
|
+
## Tier detection
|
|
24
|
+
|
|
25
|
+
- Read `.claude/DESIGN.md` and every existing `.claude/wireframes/` file for a tier signal: a Stitch, Excalidraw, or Figma reference, or a marker naming one of them.
|
|
26
|
+
- State the detected tier at the confirm step. Always draft the tier-0 ASCII file regardless of what is detected, since that is the only shape this skill or any other shipped mechanism produces. Report a higher tier rather than attempting a companion render for it.
|
|
27
|
+
- Default silently to tier 0 when nothing is detected.
|
|
28
|
+
|
|
29
|
+
## Draft
|
|
30
|
+
|
|
31
|
+
- Decide the mode before drafting. When the surface names an already-built component or file, open that source and draft in transcription mode, citing the render function, the stylesheet rule, or the built file each region and label traces to, per the standard's Transcription-wireframes section.
|
|
32
|
+
- Draft in role-intent mode otherwise: label each region by its role, never by a class name or a token value.
|
|
33
|
+
- Draft `title` and `description` frontmatter, then one `##` heading per layout variant, each holding its own ASCII `plaintext` fence with `←` role annotations, followed by `## Copy` and `## Behavior` sections against `${CLAUDE_SKILL_DIR}/../../standards/wireframes.md`'s template.
|
|
34
|
+
- Add a second layout variant only when the layout itself changes across a breakpoint or state, never for a spacing difference alone.
|
|
35
|
+
- Leave out algorithms, event-handler code, framework prop or class names outside transcription mode, and anything else the standard sends to a context entry instead.
|
|
36
|
+
|
|
37
|
+
## Confirm
|
|
38
|
+
|
|
39
|
+
- Show the resolved path, the detected tier, and the full drafted content before writing.
|
|
40
|
+
- Confirm all three with the user. This skill waits for that answer rather than treating the tool permission dialog as the gate, since the mode decision and the tier read are judgment calls with no diff to preview either against.
|
|
41
|
+
|
|
42
|
+
## Write
|
|
43
|
+
|
|
44
|
+
- Write the file at the confirmed path, creating a grouped subfolder only when the surface belongs beside siblings that already share one.
|
|
45
|
+
- Run `canon markdown audit <path>` against the prose outside the fenced block.
|
|
46
|
+
- Run `canon indexes regen .claude/wireframes`, so the surface appears in `.claude/wireframes/index.md` immediately rather than drifting until the next unrelated regen.
|
|
47
|
+
|
|
48
|
+
## Response format
|
|
49
|
+
|
|
50
|
+
### Preview
|
|
51
|
+
|
|
52
|
+
**Surface:** `<surface>`
|
|
53
|
+
**Placement:** `<path>`
|
|
54
|
+
**Detected tier:** `<tier-0 | tier-1 | tier-2 | none detected>`
|
|
55
|
+
|
|
56
|
+
```markdown
|
|
57
|
+
<drafted frontmatter and body>
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### After confirmation
|
|
61
|
+
|
|
62
|
+
```plaintext
|
|
63
|
+
✅ Drafted: <path>
|
|
64
|
+
```
|
|
@@ -5,7 +5,7 @@ description: Fetches a YouTube video transcript with metadata frontmatter into t
|
|
|
5
5
|
|
|
6
6
|
# YouTube transcripts
|
|
7
7
|
|
|
8
|
-
Turn a pasted YouTube URL into a markdown file with YAML frontmatter and a cleaned prose body. The `canon transcripts` command owns the fetch, VTT cleanup, and frontmatter. Do not reimplement
|
|
8
|
+
Turn a pasted YouTube URL into a markdown file with YAML frontmatter and a cleaned prose body. The `canon transcripts` command owns the fetch, the VTT cleanup, and the frontmatter shape. Do not reimplement or restate any of it here.
|
|
9
9
|
|
|
10
10
|
## Guards
|
|
11
11
|
|
package/docs/agents/commands.md
CHANGED
|
@@ -20,6 +20,7 @@ Full help: `canon <command> --help`. Behavior notes for the install and sync ver
|
|
|
20
20
|
| `canon sandbox check` | Score a provisioned sandbox against a scenario expectation (`--json` for the verdict) |
|
|
21
21
|
| `canon sandbox coverage` | Report which scenarios declare expectations (`--json`, `--strict`, `--skills`) |
|
|
22
22
|
| `canon indexes regen` | Regenerate `index.md` files from sibling frontmatter |
|
|
23
|
+
| `canon indexes list [path]` | Flatten every folder index under a path into one `{path, title, description}` catalog (`--json`) |
|
|
23
24
|
| `canon docs [topic]` | Emit toolkit reference docs (`list`, or a topic by name) |
|
|
24
25
|
| `canon design render` | Render `.claude/DESIGN.md` tokens to HTML and CSS |
|
|
25
26
|
| `canon design regen` | Rewrite this repository's `.claude/DESIGN.md` and `src/design/base.css` from `src/design/tokens.ts` |
|
package/docs/agents/demo.md
CHANGED
|
@@ -38,19 +38,22 @@ A step's caption from the draft renders as an overlay while its hold plays, so t
|
|
|
38
38
|
|
|
39
39
|
When `ffmpeg` is on PATH, the run also writes an mp4 beside the webm, since webm plays in a `<video>` tag but nothing else accepts it. A target without `ffmpeg` still gets the webm and a line naming what to install, and the run does not fail over the missing converter.
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
|
44
|
-
|
|
|
45
|
-
| `--
|
|
46
|
-
| `--
|
|
47
|
-
| `--
|
|
41
|
+
`--gif` adds a third file from the same converter, and it is opt-in where the mp4 is not. A gif runs several times the size of the webm it derives from, and the destination that needs one is a README on a host that strips `<video>`, which GitHub does. The filter generates a palette from the source and then applies it, rather than quantizing per frame, since a per-frame palette is what makes a recording of flat interface colors band and shimmer. It applies that palette without dithering, because the command records applications rather than photographs and the dither writes noise the encoder then stores. One recording measured 3,193,715 bytes dithered against 2,701,941 without, with the same text region cropped from both and read as identical. A missing converter is reported the same way it is for the mp4, so an absent `ffmpeg` costs the gif and not the run.
|
|
42
|
+
|
|
43
|
+
| Option | Behavior |
|
|
44
|
+
| ---------------- | ------------------------------------------------------------------- |
|
|
45
|
+
| `--out <dir>` | Directory to write into, overriding what the plan names |
|
|
46
|
+
| `--cursor <dir>` | Cursor theme folder to draw the pointer from |
|
|
47
|
+
| `--no-video` | Write only the still |
|
|
48
|
+
| `--no-still` | Write only the recording |
|
|
49
|
+
| `--gif` | Also write a gif, for a host that strips video |
|
|
50
|
+
| `--json` | Add a record on stdout carrying every path written and the duration |
|
|
48
51
|
|
|
49
52
|
A step waits on its `waitFor` selector becoming visible and then holds for its own `holdMs`, which is what puts a finished state on screen long enough to read. `navigate` uses the plan's URL unless the step names its own.
|
|
50
53
|
|
|
51
54
|
## The pointer is painted inside the page
|
|
52
55
|
|
|
53
|
-
The browser engine
|
|
56
|
+
The browser engine offers an annotation of its own that draws a dot on the interacted element and a title naming the API call it made, and this recorder does not turn it on. It paints no cursor, so a run relying on it looks like the pointer teleports between targets, and the two overlays below supersede it: a real cursor where the dot is a marker, and the beat's narration where the title reads `Mouse move`. Running both put four overlays on the frame, and the two the engine drew were the two a viewer reads as noise.
|
|
54
57
|
|
|
55
58
|
The recorder injects a pointer element before navigation and moves it through the engine's pointer with interpolated steps rather than through the element-clicking helper, which resolves a target and jumps to it. The step count is the whole difference between a cursor that travels and one that appears, and how many steps a move takes is derived from the machine's own round-trip cost rather than fixed, so the same plan glides at roughly the same pace on a loaded machine as an idle one. It also reads the element under it on every move and switches between an arrow, a hand, and a text beam, so it reflects the page the way a real cursor does.
|
|
56
59
|
|
package/docs/agents/index.md
CHANGED
|
@@ -20,7 +20,7 @@ CLI catalog and invocation rules for agents, split by command domain. Start with
|
|
|
20
20
|
- [Docs](docs.md): How canon docs resolves the toolkit's own reference surface from an install root, and how a split domain is named
|
|
21
21
|
- [Driver](driver.md): Walking a page through named interactions, the probe catalog and the false finding each one carries, why viewport heights are never defaulted, and what each refusal reports
|
|
22
22
|
- [Merge gate](gate.md): Running the gate this repository verifies a branch with, what the stage table holds and what stays a script, how the changed set scopes three stages, and why a stage that cannot read its input reports rather than passing
|
|
23
|
-
- [Indexes](indexes.md): Flags, exit codes, and JSON shape for canon indexes regen, plus when
|
|
23
|
+
- [Indexes](indexes.md): Flags, exit codes, and JSON shape for canon indexes regen and canon indexes list, plus when regen auto-stages what it rewrote
|
|
24
24
|
- [Install and sync](install-and-sync.md): What each install and sync verb writes, refuses, or leaves alone, and how drift is attributed in a target project
|
|
25
25
|
- [Intake](intake.md): Reading intake folder counts and items, the three read states an item can be in, landing a batch of selections in one cluster, the refusal reasons, and why a call is scoped to one file
|
|
26
26
|
- [Key Changes bijection](key-changes.md): Comparing the files a pull request body's Key Changes names against its own diff, the two directions and the split inside each that decides what is worth raising, the span rules the extractor was measured into, and the three refusals that separate a clean pass from a read that produced nothing
|
package/docs/agents/indexes.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Indexes
|
|
3
|
-
description: Flags, exit codes, and JSON shape for canon indexes regen, plus when
|
|
3
|
+
description: Flags, exit codes, and JSON shape for canon indexes regen and canon indexes list, plus when regen auto-stages what it rewrote
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Indexes
|
|
@@ -32,4 +32,20 @@ Skills can parse drift without branching on exit code:
|
|
|
32
32
|
canon indexes regen --dry-run --json | jq '.results[] | select(.action == "would-write")'
|
|
33
33
|
```
|
|
34
34
|
|
|
35
|
+
## List
|
|
36
|
+
|
|
37
|
+
`canon indexes list [path]` walks every folder index under `path` (default: cwd) and flattens each folder's own `title`/`subtitle` plus every sibling's `title`/`description` into one catalog, sorted by path relative to the walk root.
|
|
38
|
+
|
|
39
|
+
| Option | Behavior |
|
|
40
|
+
| -------- | ------------------------------------------ |
|
|
41
|
+
| `--json` | Emit `{ root, entries, errors }` on stdout |
|
|
42
|
+
|
|
43
|
+
Each entry is `{ path, title, description }`. `path` is relative to the resolved root, and an `index.md` file's own row uses its `subtitle` as `description`.
|
|
44
|
+
|
|
45
|
+
A folder failing frontmatter validation lands its message in `errors` and drops out of `entries` rather than failing the whole walk, matching `regen`'s per-folder isolation. Every mode writes one `ERROR:` line per error to stderr.
|
|
46
|
+
|
|
47
|
+
Exit codes: `0` no errors, `1` root not a directory, or a folder failed frontmatter validation.
|
|
48
|
+
|
|
49
|
+
A git-ignored indexed folder, such as `.canon/tasks/` or `.canon/memory/`, never appears in the output. `listIndexes` filters candidates through `git check-ignore` the same way `regen`'s whole-repo walk does, which is the right default for a documentation lookup since those rows are session scratch, but it is a gap against `regen`'s positional-path mode, which bypasses that filter for those two folders.
|
|
50
|
+
|
|
35
51
|
For the system rationale, frontmatter contract, when to adopt, and bootstrap path, see `.claude/context/indexes.md`.
|
|
@@ -284,24 +284,27 @@ This section is the corpus the coverage claim is measured against: every name `c
|
|
|
284
284
|
|
|
285
285
|
### Generate an artifact on demand
|
|
286
286
|
|
|
287
|
-
| Skill | When to use
|
|
288
|
-
| -------------------------- |
|
|
289
|
-
| `canon:create-rule` | For a project-specific governance rule the toolkit does not ship
|
|
290
|
-
| `canon:create-skill` | For a new `SKILL.md`
|
|
291
|
-
| `canon:create-snippet` | For a reusable prompt
|
|
292
|
-
| `canon:create-standard` | For a new authoring convention
|
|
293
|
-
| `canon:docs-draft` | For a brand-new `docs/*.md` page, drafted against `standards/docs.md`
|
|
294
|
-
| `canon:
|
|
295
|
-
| `canon:
|
|
296
|
-
| `canon:
|
|
297
|
-
| `canon:
|
|
298
|
-
| `canon:
|
|
287
|
+
| Skill | When to use |
|
|
288
|
+
| -------------------------- | ------------------------------------------------------------------------------------------------- |
|
|
289
|
+
| `canon:create-rule` | For a project-specific governance rule the toolkit does not ship |
|
|
290
|
+
| `canon:create-skill` | For a new `SKILL.md` |
|
|
291
|
+
| `canon:create-snippet` | For a reusable prompt |
|
|
292
|
+
| `canon:create-standard` | For a new authoring convention |
|
|
293
|
+
| `canon:docs-draft` | For a brand-new `docs/*.md` page, drafted against `standards/docs.md` |
|
|
294
|
+
| `canon:context-draft` | For a brand-new `.claude/context/<domain>.md` entry, drafted against `standards/context.md` |
|
|
295
|
+
| `canon:wireframe-draft` | For a brand-new `.claude/wireframes/<surface>.md` file, drafted against `standards/wireframes.md` |
|
|
296
|
+
| `canon:bash-script` | For an interactive, human-facing shell tool |
|
|
297
|
+
| `canon:bash-cli-script` | For a non-interactive automation, CI, or pipeline script |
|
|
298
|
+
| `canon:ci-workflow` | For a GitHub Actions workflow file |
|
|
299
|
+
| `canon:canon-slides-draft` | For a deck, drafted as `.claude/SLIDES.md` and rendered to PowerPoint |
|
|
300
|
+
| `canon:canon-screencast` | For a recording script with beats and defaults already seeded |
|
|
299
301
|
|
|
300
302
|
### Answer a question at any point
|
|
301
303
|
|
|
302
304
|
| Skill | When to use |
|
|
303
305
|
| --------------------------- | ------------------------------------------------------------------------------ |
|
|
304
306
|
| `canon:canon-cli` | Before a sync or install, to learn what it overwrites, merges, or leaves alone |
|
|
307
|
+
| `canon:index-lookup` | To find where a topic is documented across the tracked `index.md` catalogs |
|
|
305
308
|
| `canon:youtube-transcripts` | When a video transcript is wanted in the repo as context |
|
|
306
309
|
| `canon:claude-teach` | To learn a subject across sessions, in a workspace that holds the progress |
|
|
307
310
|
| `canon:write-human` | Before drafting or revising prose, for voice, rhythm, and density |
|
|
@@ -15,3 +15,5 @@ description: Route tracked-file writes and shared session scratch correctly from
|
|
|
15
15
|
- From a linked worktree, `Edit` and `Write` are refused for every main-root path, session scratch included. The refusal names session isolation and points at the worktree copy, which is a second gitignored file no later session reads, so never take that redirect.
|
|
16
16
|
- `Read` resolves against the main root normally from a linked worktree. A main-root write reaches it only through `Bash`, as one plain command rather than a compound one, which is refused for complexity.
|
|
17
17
|
- Route a main-root write by what it does to the file. Creating a whole file goes out as one plain `Bash` command carrying a heredoc. Changing a line inside a file that already exists goes through a command that resolves the main root in-process, because the shell route for that case is the stream editor this file bans.
|
|
18
|
+
- A background session that entered no worktree at all meets the identical refusal writing to the main root, since the guard gates on isolation rather than on sitting inside a linked worktree. A planner writing its plan file from no worktree takes the same heredoc route for that reason.
|
|
19
|
+
- The heredoc route costs nothing on `.canon/plans/` and `.canon/review/`, which no `PostToolUse` hook watches, and costs the index on `.canon/tasks/` and `.canon/memory/`, since a hook matching `Write|Edit|MultiEdit` never fires on `Bash`. Regenerate positionally: in-process where a verb such as `canon tasks archive` already calls it, elsewhere by an explicit `canon indexes regen` call.
|