@erclx/canon 5.16.0 → 5.18.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.
Files changed (57) hide show
  1. package/claude/.claude-plugin/plugin.json +1 -1
  2. package/claude/skills/deploy-app/REQUIREMENT.md +44 -0
  3. package/claude/skills/deploy-app/SKILL.md +45 -0
  4. package/claude/skills/{deploy-cloudflare/SKILL.md → deploy-app/references/cloudflare.md} +5 -9
  5. package/claude/skills/deploy-app/references/vercel.md +72 -0
  6. package/claude/skills/draft-figure/REQUIREMENT.md +8 -2
  7. package/claude/skills/draft-figure/SKILL.md +19 -4
  8. package/claude/skills/draft-wireframes/SKILL.md +1 -1
  9. package/claude/skills/teach-workspace/SKILL.md +1 -1
  10. package/claude/skills/teach-workspace/references/lesson-craft.md +1 -1
  11. package/docs/agents/architecture-record.md +12 -4
  12. package/docs/agents/canvas.md +13 -1
  13. package/docs/agents/commands.md +2 -2
  14. package/docs/agents/context-audit-checks.md +1 -1
  15. package/docs/agents/context-audit.md +4 -4
  16. package/docs/agents/demo.md +3 -1
  17. package/docs/agents/index.md +2 -2
  18. package/docs/agents/teach.md +2 -2
  19. package/docs/workflow/skill-map.md +9 -9
  20. package/docs/workflow/visual-design-workflow.md +8 -15
  21. package/governance/rules/claude/566-output.md +3 -5
  22. package/governance/rules/claude/575-hooks.md +1 -1
  23. package/package.json +1 -1
  24. package/src/audits/catalog.ts +46 -1
  25. package/src/canvas/address.ts +73 -39
  26. package/src/canvas/client/inspector.tsx +241 -33
  27. package/src/canvas/client/pages-panel.tsx +51 -0
  28. package/src/canvas/client/shell.css +126 -1
  29. package/src/canvas/client/state.ts +120 -4
  30. package/src/canvas/client/theme-panel.tsx +55 -0
  31. package/src/canvas/content.ts +14 -3
  32. package/src/canvas/edit.ts +360 -0
  33. package/src/canvas/server.ts +50 -5
  34. package/src/canvas/tokens.ts +82 -0
  35. package/src/claude/cases/misc.ts +5 -1
  36. package/src/commands/canvas.ts +95 -1
  37. package/src/commands/context.ts +85 -5
  38. package/src/commands/demo.ts +2 -0
  39. package/src/commands/teach.ts +3 -1
  40. package/src/context/architecture.ts +98 -18
  41. package/src/context/gate.ts +30 -3
  42. package/src/context/requirements.ts +77 -0
  43. package/src/demo/drive.ts +36 -7
  44. package/src/demo/timeline.ts +64 -0
  45. package/src/gate/measures.ts +69 -28
  46. package/src/gate/stages.ts +5 -5
  47. package/src/teach/workspace.ts +61 -6
  48. package/standards/architecture.md +13 -7
  49. package/standards/figures.md +1 -0
  50. package/standards/requirements.md +4 -0
  51. package/tooling/claude/reference.md +1 -1
  52. package/tooling/claude/seeds/.claude/hooks/path-form.sh +2 -4
  53. package/tooling/claude/seeds/.claude/hooks/search-reminder.sh +35 -0
  54. package/tooling/claude/seeds/.claude/settings.json +9 -0
  55. package/tooling/cloudflare/configs/.github/workflows/deploy.yml +2 -2
  56. package/tooling/cloudflare/reference.md +1 -1
  57. package/claude/skills/deploy-cloudflare/REQUIREMENT.md +0 -37
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "canon",
3
3
  "description": "Runs your agent's work and keeps its code good, on one setup for every repo.",
4
- "version": "5.16.0",
4
+ "version": "5.18.0",
5
5
  "author": {
6
6
  "name": "Eric Le",
7
7
  "url": "https://github.com/erclx"
@@ -0,0 +1,44 @@
1
+ ---
2
+ name: deploy-app
3
+ description: What the deploy setup gap is on each host, which of the manual steps this skill closes, and why the credential and the custom domain stay the operator's
4
+ ---
5
+
6
+ # Deploy app requirement
7
+
8
+ ## Gap
9
+
10
+ Without this skill, a deploy setup is a sequence performed from memory. Most of its repeated acts touch a service rather than the tree, so no workflow file can absorb them. One of those acts has already cost a broken deploy: the account ID displayed in the Cloudflare dashboard is truncated, and a value copied from there is wrong in a way that only shows up at deploy time. That is the Cloudflare instance of the general rule, that an ID comes from the host CLI's own session or files and never from a page a person copies out of.
11
+
12
+ The same sequence repeats on Vercel with different calls, so a skill per host would duplicate every guard and stop. Picking the wrong host is its own failure: a project mid-migration carries both hosts' files, and a silent pick creates a project on the account the operator was leaving.
13
+
14
+ ## Must
15
+
16
+ - Pick the host from the signals the project already carries, and ask the operator when it carries none or both
17
+ - Create the host's project through its own CLI: `wrangler pages project create` or `vercel project add` and `vercel link`
18
+ - Fetch every account, org, or project ID from the host CLI's own session or files rather than have it typed or pasted
19
+ - Stop for the operator to issue the API token and run `gh secret set` for it themselves
20
+ - Verify every secret the host needs is present with `gh secret list` before continuing
21
+ - Stop for the operator at the custom domain step, since DNS sits outside the tree
22
+ - Call `wrangler`, `vercel`, and `gh` directly for every step those tools already cover
23
+
24
+ ## Must not
25
+
26
+ - Accept an API token as input in any form. The toolkit verifies a secret exists, never what it contains.
27
+ - Take an ID from the operator rather than from the host CLI's own session or files
28
+ - Default to a host when the signals are absent or disagree
29
+ - Reimplement a host CLI call or `gh secret set` as a hand-built API call
30
+ - Seed a deploy workflow for Vercel, whose git integration already deploys on push
31
+ - Open a pull request or merge
32
+
33
+ ## Guards
34
+
35
+ - `wrangler` or `vercel` not authenticated: stop and name the login command
36
+ - `gh` not authenticated: stop and name the login command
37
+ - A secret missing after the token stop: stop and name which one
38
+
39
+ ## Out of scope
40
+
41
+ - Attaching a custom domain through the Cloudflare REST API instead of the dashboard. Measured absent from `wrangler pages` at plan time and the REST API was not read, so the dashboard stop stays for this pass.
42
+ - Running the deploy itself once secrets and the domain are set. On Cloudflare that is the seeded `deploy.yml` workflow, triggered by a push to main. On Vercel it is the git integration.
43
+ - A Vercel `tooling/` stack or a CI-gated Vercel deploy workflow.
44
+ - Reconfiguring an existing project's build settings on either host.
@@ -0,0 +1,45 @@
1
+ ---
2
+ name: deploy-app
3
+ description: Sets up a deploy for the current project on Cloudflare Pages or Vercel by picking the host the project already carries, creating the host's project, setting the IDs it needs as repository secrets, and stopping for the operator to issue the API token and attach the custom domain. Calls `wrangler`, `vercel`, and `gh` rather than reimplementing them. Use when asked to "set up the deploy", "deploy this to Cloudflare Pages", "deploy this to Vercel", "set up the Pages project", "set up a Vercel project", or "connect this repo to Cloudflare". Do NOT use to run an already-configured deploy, which the host's own push trigger does, or to reconfigure an existing project's build settings.
4
+ ---
5
+
6
+ # Deploy app
7
+
8
+ Runs the one-time setup a deploy needs before the host can publish on push, stopping for the acts only the operator can take. The procedure is the same on every host, and each host's CLI calls and stop points live in its own reference.
9
+
10
+ ## Guards
11
+
12
+ - Never accept an API token as input, in a prompt, an argument, or a file. Verify a secret's presence with `gh secret list` rather than asking for or reading its content.
13
+ - Read every account, org, or project ID from the host CLI's own session or files, never from the operator, and pipe it into `gh secret set` rather than reporting it first.
14
+ - Never reimplement a host CLI call or `gh secret set` as a hand-built HTTP call. Call the tools directly.
15
+ - If the project name is not supplied, derive it from the repository's own name (`basename` of `git remote get-url origin`, stripped of a trailing `.git`) and confirm it in the preview rather than asking first.
16
+
17
+ ## Step 1: pick the host
18
+
19
+ Read the tree for these signals before running any command. A file that exists counts as a signal even when it is empty or stale, since the host reference's own guard is what judges whether it still works.
20
+
21
+ | Signal | Host |
22
+ | ------------------------------------------------------------------------ | ----------------- |
23
+ | `wrangler.toml` or `wrangler.jsonc` at the root | cloudflare |
24
+ | a `pages deploy` line in any `.github/workflows/` file | cloudflare |
25
+ | `.vercel/project.json` | vercel |
26
+ | `vercel.json` at the root | vercel |
27
+ | a `wrangler` or `vercel` entry in `package.json` scripts or dependencies | the host it names |
28
+
29
+ - Signals for one host only: take that host.
30
+ - Signals for both, or for neither: ask the operator through the structured question surface, naming each signal found. Never default to a host, since a silent pick deploys to the wrong account.
31
+ - A host the operator named in the request wins over the signals. Say which signals disagreed with it, if any.
32
+
33
+ Report the pick on one line before the next step: `Host: <host>, from <signal>`.
34
+
35
+ ## Step 2: check gh
36
+
37
+ If `gh auth status` fails, stop: `❌ gh is not authenticated. Run gh auth login, then re-invoke.`
38
+
39
+ ## Step 3: run the host's steps
40
+
41
+ Read `${CLAUDE_SKILL_DIR}/references/<host>.md` for the host Step 1 picked, `cloudflare.md` or `vercel.md`, and run its steps in order, stopping wherever it stops. Each reference opens with its own CLI guard, creates the project, sets the IDs as secrets, stops for the token, verifies the secrets, stops for the custom domain, and hands off.
42
+
43
+ ## Step 4: hand off
44
+
45
+ Report that setup is complete and name what deploys on the next push, in the words the host reference's handoff gives. Do not invoke `git-pr` or `git-ship` from here. The operator or the controlling session decides when to open that pull request.
@@ -1,19 +1,15 @@
1
1
  ---
2
- name: deploy-cloudflare
3
- description: Sets up a Cloudflare Pages deploy for the current project by creating the Pages project, fetching the account ID, and stopping twice for the operator to issue the API token and attach the custom domain. Calls `wrangler` and `gh` rather than reimplementing them. Use when asked to "set up Cloudflare deploy", "deploy this to Cloudflare Pages", "set up the Pages project", or "connect this repo to Cloudflare". Do NOT use to run an already-configured deploy, which the seeded workflow does on push, or to reconfigure an existing Pages project's build settings.
2
+ title: Cloudflare Pages
3
+ description: The wrangler and gh calls a Cloudflare Pages deploy needs, the two stops for the API token and the custom domain, and the handoff to the seeded deploy workflow
4
4
  ---
5
5
 
6
- # Deploy Cloudflare
6
+ # Cloudflare Pages
7
7
 
8
- Runs the one-time setup a Cloudflare Pages deploy needs before the seeded `deploy.yml` workflow can run, stopping twice for the two acts only the operator can take.
8
+ Run these steps once the body's Pick step resolves to Cloudflare.
9
9
 
10
- ## Guards
10
+ ## Guard
11
11
 
12
12
  - If `wrangler whoami` fails, stop: `❌ wrangler is not authenticated. Run wrangler login, then re-invoke.`
13
- - If `gh auth status` fails, stop: `❌ gh is not authenticated. Run gh auth login, then re-invoke.`
14
- - Never accept a Cloudflare API token as input, in a prompt, an argument, or a file. Verify a secret's presence with `gh secret list` rather than asking for or reading its content.
15
- - Never reimplement `wrangler pages project create` or `gh secret set` as a hand-built HTTP call. Call the tools directly.
16
- - If the project name is not supplied, derive it from the repository's own name (`basename` of `git remote get-url origin`, stripped of a trailing `.git`) and confirm it in the preview rather than asking first.
17
13
 
18
14
  ## Step 1: create the Pages project
19
15
 
@@ -0,0 +1,72 @@
1
+ ---
2
+ title: Vercel
3
+ description: The vercel and gh calls a Vercel deploy needs, the two stops for the token and the custom domain, and the handoff to the git integration that deploys on push
4
+ ---
5
+
6
+ # Vercel
7
+
8
+ Run these steps once the body's Pick step resolves to Vercel. Read `vercel <command> --help` before each call, since flags move between CLI releases and the installed one is the authority.
9
+
10
+ ## Guard
11
+
12
+ - If `vercel whoami` fails, stop: `❌ vercel is not authenticated. Run vercel login, then re-invoke.`
13
+ - If `command -v jq` fails, stop: `❌ jq is not installed. Install it, then re-invoke.` Step 3 pipes its output into a secret, and a missing reader would set that secret empty while `gh secret list` still lists its name.
14
+
15
+ ## Step 1: create and link the project
16
+
17
+ Skip the `project add` when `.vercel/project.json` already exists, and run the link anyway. A file left from a deleted or renamed project still counts as a signal, so the link is what judges it, failing on a project that is gone and rewriting the file against the one that answers.
18
+
19
+ ```bash
20
+ vercel project add <project-name>
21
+ vercel link --yes --project <project-name>
22
+ ```
23
+
24
+ The link writes `.vercel/project.json` and adds `.vercel` to `.gitignore`. Report the command's own failure output and stop rather than retrying on a name collision. A project already existing under that name is the operator's to resolve.
25
+
26
+ ## Step 2: connect the repository
27
+
28
+ ```bash
29
+ vercel git connect
30
+ ```
31
+
32
+ Vercel deploys on push only once the project is connected to the repository, so this call is what makes the handoff true. Report its failure output and stop, since a project with no connection publishes nothing on push.
33
+
34
+ ## Step 3: set the org and project IDs
35
+
36
+ Read both IDs from `.vercel/project.json`, which the link just wrote, rather than asking the operator to copy them from the dashboard. Confirm the file carries both before setting anything, since `jq -r` prints `null` for a missing key and exits zero, and `gh secret list` in Step 5 reads names rather than values:
37
+
38
+ ```bash
39
+ jq -e '(.orgId | type == "string" and length > 0) and (.projectId | type == "string" and length > 0)' .vercel/project.json >/dev/null
40
+ ```
41
+
42
+ On a non-zero exit, stop: `❌ .vercel/project.json carries no orgId or projectId. Delete it and re-invoke so the link writes it again.` Otherwise pipe each ID straight into its secret rather than printing it first:
43
+
44
+ ```bash
45
+ jq -r .orgId .vercel/project.json | gh secret set VERCEL_ORG_ID
46
+ jq -r .projectId .vercel/project.json | gh secret set VERCEL_PROJECT_ID
47
+ ```
48
+
49
+ No workflow reads these today. They are what a GitHub Actions job calling `vercel` reads, so a project that later moves to CI-gated deploys finds them set.
50
+
51
+ ## Step 4: stop for the token
52
+
53
+ Stop: `⏸ Create a Vercel token at the Vercel account settings, then run: gh secret set VERCEL_TOKEN. Confirm here once that's done.`
54
+
55
+ This is the one credential the skill never touches. Resume only once the operator confirms the token is set.
56
+
57
+ ## Step 5: verify the secrets
58
+
59
+ ```bash
60
+ gh secret list
61
+ ```
62
+
63
+ - `VERCEL_ORG_ID`, `VERCEL_PROJECT_ID`, and `VERCEL_TOKEN` present: continue.
64
+ - Any missing: stop and name which one, with the command that sets it.
65
+
66
+ ## Step 6: stop for the custom domain
67
+
68
+ `vercel domains add <domain> <project-name>` attaches the domain to the project, and the DNS record that points the domain at Vercel is the operator's. Run the add only when the operator names the domain, then stop: `⏸ Point <domain>'s DNS at Vercel as vercel domains inspect <domain> describes, then confirm here.`
69
+
70
+ ## Step 7: hand off
71
+
72
+ Report that setup is complete and that Vercel's git integration deploys every push, with production on the default branch and a preview on every other. No workflow is seeded for Vercel, since one would deploy each push a second time.
@@ -9,12 +9,17 @@ description: Why a figure decides between Mermaid and freehand SVG before drawin
9
9
 
10
10
  Without this skill, a session asked for a figure reaches for whichever path it thought of first. A graph-shaped subject gets model-authored SVG coordinates nobody checked against a render, drifting from the hand-drawn look every other figure in the project carries. A subject that is not graph-shaped gets forced through Mermaid's node-and-edge model, producing a diagram that answers a different question than the one asked. Either failure ships a figure a reader cannot trust, and a figure exists only to be trusted at a glance.
11
11
 
12
+ A teach lesson breaks the Mermaid path outright. The lesson letters its figures in a hand font the renderer cannot load, so the render sizes every label in a narrower fallback face and the lesson clips the text it actually shows. The check then reads the standalone image, rendered in that same fallback, and passes a figure the reader sees clipped. Both happened on one lesson, where every group title clipped mid-word and only a capture taken inside the lesson showed it.
13
+
12
14
  The color failure is the quiet one. Mermaid's own theme writes literal hex values, and a figure carrying one stops re-coloring itself the moment the host page switches its palette, which the figure standard's own accessibility bar rules out.
13
15
 
14
16
  ## Must
15
17
 
16
18
  - Apply the standard's earn-its-place bar before drawing anything
17
19
  - Decide between the Mermaid path and the freehand path by whether the subject reduces to a graph, not by which is faster to produce
20
+ - Draw a figure bound for a teach lesson freehand whatever its shape, since the lesson's hand font is one the renderer cannot measure
21
+ - Verify a figure bound for a rendered page by capturing it inside that page, and fall back to the standalone render only where the destination has no page to load
22
+ - Keep the scoped overflow style as the documented fallback for a clipped group title wherever the Mermaid path still runs
18
23
  - Render the Mermaid path with the hand-drawn look and the figure font stack, never with Mermaid's default look
19
24
  - Rewrite every literal color the renderer wrote into the custom property the host stylesheet defines
20
25
  - Read the Mermaid render back and judge it against what the figure means to say, the same verification `draft-diagram` runs for the architecture surface
@@ -22,7 +27,8 @@ The color failure is the quiet one. Mermaid's own theme writes literal hex value
22
27
 
23
28
  ## Must not
24
29
 
25
- - Force a non-graph-shaped subject through Mermaid, or route a graph-shaped one through freehand SVG coordinates a model authored by hand
30
+ - Force a non-graph-shaped subject through Mermaid, or route a graph-shaped one through freehand SVG coordinates a model authored by hand outside a teach lesson
31
+ - Report a figure bound for a rendered page as verified from the standalone render alone
26
32
  - Ship a literal hex color on either path
27
33
  - Report a clean verification when the Mermaid render was skipped or a defect survived
28
34
  - Loop past two correction passes on a surviving defect
@@ -39,4 +45,4 @@ The color failure is the quiet one. Mermaid's own theme writes literal hex value
39
45
  - The toolkit's own `.canon/diagrams/` architecture surface, which shares no code, font, or visual language with this convention: `draft-diagram`
40
46
  - Mermaid's own layout, budgets, and label rules for the fence itself: the mermaid standard, cited rather than restated here
41
47
  - A UI wireframe or screen mockup: `draft-wireframes`
42
- - `teach-workspace`'s own lesson-figure authoring, which stays inline rather than calling this skill
48
+ - Which lesson needs a figure and where it sits among the lesson's blocks: `teach-workspace`, which calls this skill to draw one
@@ -27,10 +27,11 @@ Apply the standard's bar: a relationship, a boundary, a path, or a before-and-af
27
27
 
28
28
  ## Step 3: decide the render path
29
29
 
30
+ - **A teach lesson**, meaning the destination is a lesson page in a learning workspace's `lessons/` folder: draw it through Step 5 whatever its shape. The lesson letters its figures in a hand font the renderer cannot load, so a Mermaid render measures its labels in a narrower face and the lesson clips them.
30
31
  - **Graph-shaped**, meaning the relationship, boundary, or path is already what a flowchart or sequence diagram expresses: draw it through Step 4.
31
32
  - **Not graph-shaped**, meaning the subject is a spatial or physical arrangement no flowchart reduces to: draw it through Step 5.
32
33
 
33
- State which path was picked and why in one sentence. The standard states this as a render-first policy rather than a ban on any tool-exported drawing, so a graph-shaped subject always routes through Mermaid even though that is itself an external renderer.
34
+ Take the first that matches, and state which path was picked and why in one sentence. The standard states this as a render-first policy rather than a ban on any tool-exported drawing, so outside a teach lesson a graph-shaped subject always routes through Mermaid even though that is itself an external renderer.
34
35
 
35
36
  ## Step 4: the Mermaid path
36
37
 
@@ -51,6 +52,8 @@ Render both formats in one pass: the SVG is what ships inside the `<figure>`, an
51
52
  Use `bunx` when bun is available, falling back to `npx -y @mermaid-js/mermaid-cli ...` otherwise.
52
53
 
53
54
  - Rewrite every stroke, fill, and text color the renderer wrote as a literal hex value into the custom property the host stylesheet defines, per the standard's color rule. Mermaid's own theme has no notion of a custom property, so this is a source edit made to the rendered SVG, not a config option.
55
+ - Expect a group title or a long label to clip once the destination shows it in the hand font, since the renderer sized its box in a fallback face.
56
+ - When the in-page check shows a clipped title, add a `<style>` inside the SVG, scoped to that SVG's own id, that sets `overflow: visible` on the clipped label's `foreignObject` and centers the label within it, so the wider text spills past both edges evenly. The style hides the mismatch for a title and does nothing for a node label crowding its box, which takes a shorter label instead.
54
57
  - Check whether the project ran `canon design css --figures`. The figure and figcaption styling ships unconditionally either way, but that flag alone embeds the Virgil and Excalifont font files. Without it, the figure falls back to the browser's own generic `cursive` face rather than the intended hand-drawn font, and Step 7's output names that gap when the flag was not passed.
55
58
 
56
59
  ## Step 5: the freehand path
@@ -58,7 +61,7 @@ Use `bunx` when bun is available, falling back to `npx -y @mermaid-js/mermaid-cl
58
61
  - Author the SVG by hand: plain shapes and lines authored directly in the markup.
59
62
  - Follow the standard's `## Color and accessibility` section for every fill, stroke, and accessible name.
60
63
 
61
- There is no external render to verify a freehand drawing against. The check here is the stroke-and-fill audit above and a read of the markup against what the subject means to show, done once rather than looped.
64
+ There is no external render to verify a freehand drawing against before it is written. The check here is the stroke-and-fill audit above and a read of the markup against what the subject means to show, done once rather than looped. Hand-placed coordinates can drift out of line where a layout engine would not, so a freehand figure bound for a rendered page also takes Step 7's in-page capture.
62
65
 
63
66
  ## Step 6: wrap, caption, and verify
64
67
 
@@ -66,12 +69,23 @@ There is no external render to verify a freehand drawing against. The check here
66
69
  - On the Mermaid path, read the rendered PNG back and judge it against what the figure means to say, the same check `draft-diagram` Steps 5 and 6 run for the architecture surface. Fix the mermaid source and re-render on a defect. Stop after two correction passes. When a defect survives, keep the figure and name the defect in the output rather than reporting a false verification.
67
70
  - On either path, confirm the figure still reads once every color and font it depends on is stripped to its fallback, per the standard's own working-figure bar.
68
71
  - When the render fails for any reason, no browser engine, no network, no package manager, continue to Step 7 and name the skipped check. A missing renderer degrades the loop rather than failing it.
72
+ - When the destination is a rendered page, an HTML file a browser loads, the check that counts is the figure inside that page, which Step 7 runs once the figure is written. The standalone PNG is measured in the renderer's own fonts and can read clean while the page clips it. A markdown destination has no page to load, so the standalone check above is the whole check there.
69
73
 
70
74
  ## Step 7: confirm and write
71
75
 
72
76
  Show the destination path, the decided render path, and the full `<figure>` markup before writing. Confirm with the user, since the graph-shaped decision and the render verdict are judgment calls with no diff to preview either against.
73
77
 
74
- Write the figure into the destination document at the location the user named. Renders under `.canon/tmp/figures/` are verification artifacts, and the scratch PNG and JSON config are deleted after Step 6 confirms, since only the SVG ships.
78
+ Write the figure into the destination document at the location the user named.
79
+
80
+ When the destination is a rendered page, capture the figure inside it and read the capture against what the figure means to say:
81
+
82
+ ```bash
83
+ canon capture <destination> --selector figure --out .canon/tmp/figures/
84
+ ```
85
+
86
+ Narrow the selector to this figure, such as by an id on its `<figure>`, when the page carries more than one. Fix a clipped label, a misaligned shape, or an arrow that misses its target in the destination and capture again, within the same two correction passes Step 6 allows. A clipped group title on the Mermaid path takes the scoped overflow style Step 4 states. When the capture fails, keep the figure and name the skipped check in the output, the same way Step 6 treats a failed render.
87
+
88
+ Renders and captures under `.canon/tmp/figures/` are verification artifacts, and the scratch PNGs, the stamps the capture writes beside them, and the JSON config are deleted once the checks confirm, since only the SVG ships.
75
89
 
76
90
  ## Output
77
91
 
@@ -88,6 +102,7 @@ Write the figure into the destination document at the location the user named. R
88
102
 
89
103
  ```plaintext
90
104
  ✅ Drafted figure in <path>
91
- Verified render. <defect or skipped check, one line, omitted when clean>
105
+ Render path: <mermaid | freehand>
106
+ Verified <in page | as a standalone render>. <defect or skipped check, one line, omitted when clean>
92
107
  <Font not embedded: run `canon design css --figures` to ship Virgil and Excalifont. Omitted when the project already ran it.>
93
108
  ```
@@ -24,7 +24,7 @@ This skill stays fully independent of `context-fold`'s wireframe coverage sweep,
24
24
 
25
25
  ## Tier detection
26
26
 
27
- - Read `canon/DESIGN.md` and every existing `canon/wireframes/` file for a tier signal: a Stitch, Excalidraw, or Figma reference, or a marker naming one of them.
27
+ - Read `canon/DESIGN.md` and every existing `canon/wireframes/` file for a tier signal: an Excalidraw or Figma reference, or a marker naming one of them.
28
28
  - State the detected tier at the confirm step. Always draft the regions-and-states shape regardless of what is detected, since that is the only shape this skill or any other shipped mechanism produces, adding the ASCII sketch fence only when the layout is not built yet. Report a higher tier rather than attempting a companion render for it.
29
29
  - Default silently to tier 0 when nothing is detected.
30
30
 
@@ -69,7 +69,7 @@ canon teach resource <topic> --json \
69
69
  --lead "<title>=<url>"
70
70
  ```
71
71
 
72
- Each flag repeats, and the pair splits on the first `=` so a URL carrying one survives. A URL already listed is refused rather than repeated.
72
+ Each flag repeats, and the pair splits on the first `=` so a URL carrying one survives. A listed URL is refused, but `--read` moves an opened lead.
73
73
 
74
74
  A claim nothing was read for is the failure this step exists against. Where no source is reachable, say so in the lesson and mark what rests on recall.
75
75
 
@@ -40,7 +40,7 @@ Decide the figure once per lesson, before writing the body.
40
40
 
41
41
  1. Name the one relationship, boundary, path, or before-and-after the lesson is about. A lesson about none ends here, with `Figure: none, <why it names no structure>` on the reply.
42
42
  2. Hold it against the bar in `${CLAUDE_SKILL_DIR}/../../standards/figures.md`, which also carries the drawing rules.
43
- 3. Draw it through `canon:draft-figure` into a `raw` block in the body, before the quiz entry and never inside it or after its feedback, which breaks the stepper's gating. Report it, never hand-draw, when that skill does not resolve.
43
+ 3. Draw it hand-written through `canon:draft-figure` into a `raw` block before the quiz, never inside it or after its feedback, which breaks the stepper's gating. Report it, never draw it yourself, if the skill does not resolve.
44
44
  4. Or write one line on why prose carries it better, such as a structure an earlier lesson gave.
45
45
 
46
46
  A structure lesson takes step 3 or 4, never neither. Put the outcome on the reply's `Figure:` line, off the lesson page. Never draw to satisfy the step, or on every section (`## Restraint`).
@@ -1,11 +1,11 @@
1
1
  ---
2
2
  title: Architecture record
3
- description: The five findings canon context audit reads off the architecture record, being the entry cap, revisit sentence, and length gates the record states for itself, the claim coverage report, and the word counts
3
+ description: The findings canon context audit reads off the architecture record, being the entry cap, revisit sentence, length, decision word, and risk bullet gates the record states for itself, the claim coverage report, and the word counts, plus the requirements record's word cap
4
4
  ---
5
5
 
6
6
  # Architecture record
7
7
 
8
- Five findings from `canon context audit` read `canon/ARCHITECTURE.md` rather than a folder, and only the first three are facts. The other checks the audit runs are in `context-audit-checks.md`.
8
+ Seven findings from `canon context audit` read `canon/ARCHITECTURE.md` rather than a folder, and only the first five are facts. One more reads `canon/REQUIREMENTS.md`. The other checks the audit runs are in `context-audit-checks.md`.
9
9
 
10
10
  The entry cap check counts the record's decisions against the cap it states for itself, in a clause of the form `This record holds at most 12 decisions.` Like the length check, the cap belongs to the record rather than to the toolkit, so a record stating none is measured and never gated. A decision is a `###` heading outside a fenced block, so the template a standard shows does not count, and a heading carrying two decisions counts once. The JSON record carries what it read as `architecture.entryCap`, absent where the record states no cap, and the audit catalog counts a record past it as `recordOverCount`.
11
11
 
@@ -17,12 +17,20 @@ A record stating no such rule is measured and reported and never gated, which is
17
17
 
18
18
  What the derivation costs where it does apply is that the ceiling rises when a decision is added and falls for nothing, so the check passes exactly when the file grew. It gates anyway, because a record that states a limit for itself and makes it computable from a count has turned it into a fact, which is what separates it from every judgment the audit reports. A rewrite of the declaring sentence past the clauses the check reads falls back to reporting rather than to a stale ceiling, so the failure shows up in the run's own output.
19
19
 
20
+ The decision word check counts each decision's prose against the cap the record states in a clause of the form `at most 150 words a decision`. The count runs below the `###` heading with fenced lines dropped, so neither the heading nor a template block inside a decision counts, and the report and the gate read the same number. The JSON record carries the clause as `architecture.wordCap`, and the audit catalog counts the decisions past it as `recordOverWords`, absent where the record states no clause.
21
+
22
+ The risk bullet check counts every list item under `## Risks / open questions`, nested ones included, against a clause of the form `at most 6 risk bullets`, since a nested bullet is weight the reader pays for like any other. Both clauses can share the entry cap's sentence, and each gates only a record stating it, for the reason the cap does. A record stating a risk cap and carrying no Risks section is reported as absent rather than passed as zero bullets. The JSON record carries the clause as `architecture.riskCap` and the count as `architecture.risksBullets`, and the audit catalog counts a section past its cap as `recordOverRisks`, absent where the record states no clause.
23
+
20
24
  The coverage report classifies each decision as carrying a countable claim, a structural invariant, or neither, then reports each testable entry against whether it names a check that exists. A countable claim carries a figure a run could recompute, and an invariant quantifies over a named tree closely enough that a walk could falsify it. A check is a `scripts/**.sh` path the entry spells that is on disk, or a `canon` invocation matching a registered audit, so coverage reads the entry rather than the tree and a claim some check happens to cover without the entry saying so reads as unchecked.
21
25
 
22
26
  Three limits are stated on every run rather than hidden. The countable signal reads digits alone, so a measured claim written in words reads as uncounted. Entries are counted by heading, and one heading holding several decisions counts once. Nothing is stored, so an entry rewritten tomorrow is classified afresh the next time the verb runs and no verdict goes stale.
23
27
 
24
28
  The report gates nothing. Deciding whether a sentence states a claim is a judgment no parser settles, so the output names candidates for a reader. This answers a different question from the verification anchors `standards/architecture.md` describes, which record that one cited number was re-read. That mechanism says whether a marked figure held, and this one says how much of the record could be checked at all.
25
29
 
26
- The fifth finding is a word count, measured in words rather than lines: one figure for the whole record and one per decision. `standards/architecture.md` asks a session to judge the file's weight by reading it rather than by counting it, and reads the word figure alongside that judgment when one is available. A paragraph written one source line to a paragraph passes the rendered-line measure other checks use while still reading heavy, which is the gap a word count closes without turning into a second cap.
30
+ The seventh finding is a word count for the whole record, measured in words rather than lines. A paragraph written one source line to a paragraph passes the rendered-line measure other checks use while still reading heavy, which is the gap a word count closes. The whole-record figure gates nothing under any mode, since the per-decision cap above already bounds what a decision adds.
31
+
32
+ The `## Risks / open questions` section is weighed the same way, reported apart from the whole-record figure. The JSON record carries the whole-record figure as `architecture.words`, the section figure as `architecture.risksWords` where the record carries the heading, and the per-decision figure as `architecture.decisions[].words`.
33
+
34
+ ## The requirements record
27
35
 
28
- The `## Risks / open questions` section is weighed the same way, reported apart from the whole-record figure since the standard singles it out for holding only what is still open. This finding gates nothing under any mode. The JSON record carries the whole-record figure as `architecture.words`, the section figure as `architecture.risksWords` where the record carries the heading, and the per-decision figure as `architecture.decisions[].words`.
36
+ The audit reads `canon/REQUIREMENTS.md` under its own step and counts every word below the frontmatter against the cap the record states in a clause of the form `This record holds at most 600 words.` The cap is the record's own, so a record stating none is measured and never gated, and a project with no record is reported as out of scope. The JSON record carries the reading as `requirements`, null where the project carries no record and absent under `--citations-only`, and the audit catalog counts a record past its cap as `requirementsOverWords`.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  title: Canvas
3
- description: The canvas server, its content format, and the verbs that list, arrange, select, and capture frames
3
+ description: The canvas server, its content format, and the verbs that list, arrange, select, edit, and capture frames
4
4
  ---
5
5
 
6
6
  # Canvas
@@ -29,6 +29,18 @@ The operator can also pick one element inside a frame, by clicking it on the sur
29
29
 
30
30
  A pick is refused as `address-mismatch` when the browser builds elements the file never states, such as a `tbody` a table leaves out or the document wrapper around a fragment. The shell sends its own element count beside the index, so a frame the two sides count differently is reported rather than recorded against the wrong element. A pick is refused as `stale-address` when the frame file changed between the frame being served and the pick arriving, since every served frame carries the hash of its file and the shell sends that hash back.
31
31
 
32
+ ## Edit
33
+
34
+ `canvas edit <page>/<frame> --element <index> --set <property>=<value>` sets one property of the element at that index, the same index `canvas selection` reports. The properties are `text`, `color`, `background-color`, `font-size`, `font-weight`, `width`, `height`, `padding`, `gap`, and `flex-direction`. A style property is written into the element's inline `style`, replacing that property and leaving the others as they were, and an empty value drops it.
35
+
36
+ `text` replaces the text of an element holding text alone and refuses one holding other elements as `not-text-only`. Every byte outside the element stays as it was. `--json` emits the page, frame, file, path, and the file's new `hash`.
37
+
38
+ The operator edits the same set from the inspector, which posts to the same writer with the hash the frame was served with. An edit made against a version of the file Claude has since rewritten is refused as `stale-address` and the shell reloads the frame, so nothing lands on a shifted element. A color picked from the project's tokens is written as `var(--<name>)`. Both writers take the frame file's lock, and an edit that keeps the selected element where it was keeps the selection fresh.
39
+
40
+ Inline style beats a class, so an operator's edit masks a class change Claude makes later. Read a frame's inline styles before restyling it, and remove one the change should replace. A property outside the set, or a value carrying `;`, `{`, `}`, `<`, `>`, or a line break, is refused as `invalid-edit`.
41
+
42
+ The Theme tab in the shell lists what the token stylesheet defines, grouped as color, spacing, radius, font family, font size, and other. The page record at `/api/pages` carries the same list as `tokens.groups`.
43
+
32
44
  ## Capture
33
45
 
34
46
  `canvas capture <page>/<frame>` renders one frame as a PNG, and `canvas capture <page>` renders every frame on the page. Each goes through a server started for the call, so the injected tokens are in the image, and renders at the frame's own width from the layout, so a media query resolves there. It never captures the file on disk.
@@ -34,7 +34,7 @@ One row per top-level command, in the order `canon --help` prints them. A domain
34
34
  | `canon drive <url> <run>` | Walk a page through named interactions and measure each state |
35
35
  | `canon transcripts <url>` | Fetch a YouTube transcript with metadata frontmatter (needs `yt-dlp`) |
36
36
  | `canon teach <verb>` | Open and author learning workspaces |
37
- | `canon canvas <verb>` | Serve a local canvas of pages and HTML frames, arrange them, and capture them |
37
+ | `canon canvas <verb>` | Serve a local canvas of pages and HTML frames, arrange, edit, and capture them |
38
38
  | `canon sandbox [cat:cmd]` | Run sandbox scenarios, toolkit-only like the tree it reads |
39
39
  | `canon tasks <verb>` | Read and write the task board, the plans it cites, and its archive |
40
40
  | `canon intake <verb>` | Report intake folders and write answers into them |
@@ -96,7 +96,7 @@ Each domain exposes a consistent shape where applicable: `list`, `install`, `syn
96
96
  - `demo`, in `demo.md`: `compile`, `run`, `frames`
97
97
  - `inventory`, described above: `run`
98
98
  - `teach`, in `teach.md`: `list`, `open`, `resource`, `glossary`, `lesson`, `stylesheet`, `nav`, `render`
99
- - `canvas`, described below: `serve`, `list`, `page add`, `page rename`, `frame add`, `frame move`, `selection`, `capture`
99
+ - `canvas`, described below: `serve`, `list`, `page add`, `page rename`, `frame add`, `frame move`, `selection`, `edit`, `capture`
100
100
  - `sandbox`, in `sandbox.md`: `reset`, `clean`, `check`, `coverage`
101
101
  - `tasks`, in `tasks.md`: `next-label`, `archive`, `decline`, `plan-citations`, `plan-answers`, `plan-branch`, `plan-reach`, `plan-link`, `pull-request`, `outcome`, `list`, `validate`
102
102
  - `intake`, in `intake.md`: `list`, `answer`
@@ -65,7 +65,7 @@ Fenced blocks are excluded, which keeps a pinned version in an install command f
65
65
 
66
66
  ## The architecture record
67
67
 
68
- Five findings read `canon/ARCHITECTURE.md` rather than a folder: an entry cap, a revisit sentence closing each decision, and a length ceiling, each gating only where the record states it for itself, a claim coverage report, and a word count. What each reads and why the last two gate nothing are in `architecture-record.md`.
68
+ Seven findings read `canon/ARCHITECTURE.md` rather than a folder: an entry cap, a revisit sentence closing each decision, a length ceiling, a word cap a decision, and a risk bullet cap, each gating only where the record states it for itself, a claim coverage report, and a word count. One more reads `canon/REQUIREMENTS.md` against the word cap it states. What each reads and why the last two architecture findings gate nothing are in `architecture-record.md`.
69
69
 
70
70
  ## Wireframe states
71
71
 
@@ -5,7 +5,7 @@ description: Running the audit, its flags and folder scope, the exit codes, the
5
5
 
6
6
  # Context audit
7
7
 
8
- `canon context audit [path]` reports the structural state of the folders following the index-plus-entry contract, meaning a generated `index.md` beside entries carrying frontmatter, and it measures `canon/ARCHITECTURE.md` beside them. It reads and reports. Fixing what it finds is separate work. What each finding means is in `context-audit-checks.md`, and what the architecture record's five findings mean is in `architecture-record.md`.
8
+ `canon context audit [path]` reports the structural state of the folders following the index-plus-entry contract, meaning a generated `index.md` beside entries carrying frontmatter, and it measures `canon/ARCHITECTURE.md` beside them. It reads and reports. Fixing what it finds is separate work. What each finding means is in `context-audit-checks.md`, and what the architecture and requirements records' findings mean is in `architecture-record.md`.
9
9
 
10
10
  Findings stated over every markdown file rather than over a context entry are measured by `canon markdown audit`, described in `markdown-audit.md`. That command resolves no folder, so it reaches trees this one refuses.
11
11
 
@@ -37,11 +37,11 @@ A run where no requested name resolves refuses, whichever list it read. Naming t
37
37
 
38
38
  ## Exit codes
39
39
 
40
- Exit codes are `0` for a clean run, `1` for a refusal, and `2` for a gating finding. An unresolved citation gates under every mode. An architecture record that states its own line allowances gates when it is past the ceiling those derive, on any run that measures it, which is every mode except `--citations-only`. A record that states an entry cap gates the same way when it holds more decisions than the cap, and one stating that every decision closes with a revisit sentence gates when a decision lacks it. A record stating none of the three is reported and never gated.
40
+ Exit codes are `0` for a clean run, `1` for a refusal, and `2` for a gating finding. An unresolved citation gates under every mode. An architecture record that states its own line allowances gates when it is past the ceiling those derive, on any run that measures it, which is every mode except `--citations-only`. A record that states an entry cap gates the same way when it holds more decisions than the cap, one stating that every decision closes with a revisit sentence gates when a decision lacks it, and one stating a word cap a decision or a risk bullet cap gates past either. A requirements record stating a word cap gates past it. A record stating none of these is reported and never gated.
41
41
 
42
- `bun run check` in the toolkit repository reads all three of the record's rules through its own Architecture record stage rather than through this verb, since the verb's only gating stage there runs `--citations-only` and never opens the record.
42
+ `bun run check` in the toolkit repository reads every one of these rules through its own Canonical records stage rather than through this verb, since the verb's only gating stage there runs `--citations-only` and never opens either record.
43
43
 
44
- Entry length, reference form, table, provenance, the record's claim classification, and every word figure print and return `0` under every mode, because each is a judgment or a weight read alongside one, and failing a push on either would make the check something to route around.
44
+ Entry length, reference form, table, provenance, the record's claim classification, and every word figure no record caps print and return `0` under every mode, because each is a judgment or a weight read alongside one, and failing a push on either would make the check something to route around.
45
45
 
46
46
  Required-section, index, and wireframe-states findings sit between the two. All three are answerable from the file rather than weighed, so `--gate` promotes them to failing codes while a bare run leaves them advisory. Sketch-with-evidence sits with the printed measures instead, for the reason `context-audit-checks.md` states: it reads a whole entry against whether any of its states has evidence, not one layout against its own evidence, so a conforming file can still trip it. The toolkit runs the bare form against itself and the widened form against the seed tree, described below.
47
47
 
@@ -26,7 +26,7 @@ Each demo owns a folder, `demos/<slug>/`, and `compile` writes the plan into it.
26
26
  | `plan.json` | yes | The compiled plan, with its hand-tuned timing |
27
27
  | `index.html` | yes | The HyperFrames composition, when the demo is wrapped |
28
28
  | `demo.gif` | yes | The one deliverable a README embeds |
29
- | `take/` | no | The raw recording and its still, written by `run` |
29
+ | `take/` | no | The raw recording, its still, and its timeline |
30
30
  | `renders/` | no | The composed mp4, written by the render |
31
31
 
32
32
  A project carries `demos/*/take/` and `demos/*/renders/` in its `.gitignore`, since both are one command away and a webm is large. A plan compiled before this layout, at `demos/<slug>.json`, still runs by path, because only the default moved.
@@ -58,6 +58,8 @@ A recording that has to match both themes takes one plan per scheme, committed s
58
58
 
59
59
  A step's caption from the draft renders as an overlay while its hold plays, so the narration a person wrote is what shows on screen rather than the name of the action the engine performed.
60
60
 
61
+ Beside the webm, the run writes `<video-basename>.timeline.json`, so a composition can aim a zoom at the moment and the place of an action rather than adding up holds by hand. It holds an `entries` array with one entry per step, each carrying the step's `index`, its `kind`, and `startMs` and `endMs` counted from the recording's first frame. A step ends once its hold has played. A click, fill, or hover entry also carries `box`, the target's `x`, `y`, `width`, and `height` in viewport pixels, which are the video frame's own coordinates. A navigate, scroll, wait, or hold entry carries no `box`, and the file is still written. A run under `--no-video` writes no timeline, since there is no video for it to sit beside. The `--json` record names the file under `timeline`, and `null` when none was written.
62
+
61
63
  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.
62
64
 
63
65
  `--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.
@@ -8,9 +8,9 @@ category: Agent surface
8
8
 
9
9
  CLI catalog and invocation rules for agents, split by command domain. Start with overview.
10
10
 
11
- - [Architecture record](architecture-record.md): The five findings canon context audit reads off the architecture record, being the entry cap, revisit sentence, and length gates the record states for itself, the claim coverage report, and the word counts
11
+ - [Architecture record](architecture-record.md): The findings canon context audit reads off the architecture record, being the entry cap, revisit sentence, length, decision word, and risk bullet gates the record states for itself, the claim coverage report, and the word counts, plus the requirements record's word cap
12
12
  - [Audits](audits.md): Running every health check as one set, what the single verdict means, the exit code each outcome takes, the retained baseline and the delta it reports, and which corpora are kept out of the record
13
- - [Canvas](canvas.md): The canvas server, its content format, and the verbs that list, arrange, select, and capture frames
13
+ - [Canvas](canvas.md): The canvas server, its content format, and the verbs that list, arrange, select, edit, and capture frames
14
14
  - [Capture](capture.md): Rendering HTML sources to PNG, what the command asserts about fonts, and why the selector has no default
15
15
  - [Census](census.md): Tracked-plus-untracked file count, a breakdown by extension, and a line total that skips whatever reads as binary
16
16
  - [Command catalog](commands.md): Every top-level command with its purpose, each domain's subcommands and the page describing them, the browser commands, and the version skew report
@@ -83,7 +83,7 @@ canon teach resource regular-expressions \
83
83
 
84
84
  The pair splits on the first `=`, so a URL carrying its own separator survives intact. Say in the title which claims rest on the source, since the entry is the only place a later session reads that from. Which sources qualify is the source ladder in `canon standards teach`, and a source below its first two rungs also names why no higher one covers the claim.
85
85
 
86
- A URL either heading already lists is refused rather than written twice. Two entries for one source split what rests on it across two lines, and a reader checking a claim then finds half of the answer.
86
+ A URL either heading already lists is refused rather than written twice. Two entries for one source split what rests on it across two lines, and a reader checking a claim then finds half of the answer. The exception is a `--read` URL already under `## Leads`, which moves to `## Read` under the title the call carries, since opening a lead is how it becomes read. A `--read` URL already under `## Read`, and any `--lead` URL already listed, stays refused, and a refusal leaves the whole batch unwritten.
87
87
 
88
88
  A URL a file displays inside a fence does not count as listed, which is how a workspace quoting the entry format in its own prose is read as the sample it is.
89
89
 
@@ -142,7 +142,7 @@ Read `url` off the record rather than building one from the port that was asked
142
142
  | `exists` | A workspace already covers the topic an open names |
143
143
  | `no-file` | The workspace carries no file the verb writes into |
144
144
  | `no-section` | `RESOURCES.md` carries no heading the entries belong under |
145
- | `listed` | A URL is already listed under either heading |
145
+ | `listed` | A URL is already read, or a lead is offered as listed |
146
146
  | `defined` | A term already carries a glossary entry |
147
147
  | `bad-input` | The command line is malformed, before any folder is read |
148
148
 
@@ -12,15 +12,15 @@ This page is the corpus the coverage claim is measured against: every name `cano
12
12
 
13
13
  ## Set up a project
14
14
 
15
- | Skill | When to use |
16
- | ------------------------- | ----------------------------------------------------------------------------------------------------------- |
17
- | `canon:target-setup` | On a fresh scaffold, to detect the stack and run the install chain, or to reach one phase of it alone |
18
- | `canon:canon-operator` | On a project that already exists, to read what it carries before an install is picked |
19
- | `canon:sketch-design` | Before `design-extract`'s greenfield path, to trace a design direction from reference images or URLs |
20
- | `canon:design-extract` | Before the first UI feature, to draft `canon/DESIGN.md` |
21
- | `canon:draft-diagram` | Once the architecture is written, to draft per-kind entries under `.canon/diagrams/` |
22
- | `canon:deploy-cloudflare` | Once a project is ready to publish, to set up its Cloudflare Pages deploy and stop for the token and domain |
23
- | `canon:repo-metadata` | When the GitHub About text, homepage, or topics may have drifted, to reconcile them against the README |
15
+ | Skill | When to use |
16
+ | ---------------------- | ----------------------------------------------------------------------------------------------------------- |
17
+ | `canon:target-setup` | On a fresh scaffold, to detect the stack and run the install chain, or to reach one phase of it alone |
18
+ | `canon:canon-operator` | On a project that already exists, to read what it carries before an install is picked |
19
+ | `canon:sketch-design` | Before `design-extract`'s greenfield path, to trace a design direction from reference images or URLs |
20
+ | `canon:design-extract` | Before the first UI feature, to draft `canon/DESIGN.md` |
21
+ | `canon:draft-diagram` | Once the architecture is written, to draft per-kind entries under `.canon/diagrams/` |
22
+ | `canon:deploy-app` | Once a project is ready to publish, to set up its Cloudflare or Vercel deploy and stop for token and domain |
23
+ | `canon:repo-metadata` | When the GitHub About text, homepage, or topics may have drifted, to reconcile them against the README |
24
24
 
25
25
  ## Decide what to build
26
26