@erclx/canon 5.15.0 → 5.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/claude/.claude-plugin/plugin.json +1 -1
- package/claude/skills/draft-figure/REQUIREMENT.md +8 -2
- package/claude/skills/draft-figure/SKILL.md +19 -4
- package/claude/skills/draft-wiki/SKILL.md +1 -1
- package/claude/skills/draft-wireframes/SKILL.md +1 -1
- package/claude/skills/plan-groundwork/SKILL.md +1 -1
- package/claude/skills/search-craft/REQUIREMENT.md +57 -0
- package/claude/skills/search-craft/SKILL.md +83 -0
- package/claude/skills/teach-workspace/SKILL.md +1 -1
- package/claude/skills/teach-workspace/references/lesson-craft.md +1 -1
- package/docs/agents/canvas.md +36 -0
- package/docs/agents/commands.md +3 -3
- package/docs/agents/demo.md +3 -1
- package/docs/agents/index.md +1 -0
- package/docs/agents/teach.md +2 -2
- package/docs/workflow/skill-map.md +1 -0
- package/docs/workflow/visual-design-workflow.md +8 -15
- package/governance/rules/claude/566-output.md +3 -5
- package/governance/rules/claude/575-hooks.md +1 -1
- package/package.json +1 -1
- package/scripts/lib/sandbox-git.sh +2 -2
- package/src/canvas/address.ts +184 -0
- package/src/canvas/capture.ts +172 -0
- package/src/canvas/client/app.tsx +2 -0
- package/src/canvas/client/inspector.tsx +121 -0
- package/src/canvas/client/layers.tsx +118 -0
- package/src/canvas/client/pages-panel.tsx +47 -13
- package/src/canvas/client/shell.css +131 -1
- package/src/canvas/client/state.ts +186 -0
- package/src/canvas/client/surface.tsx +272 -20
- package/src/canvas/content.ts +307 -16
- package/src/canvas/server.ts +182 -13
- package/src/claude/cases/misc.ts +5 -0
- package/src/commands/canvas.ts +200 -3
- package/src/commands/demo.ts +2 -0
- package/src/commands/migrate.ts +1 -1
- package/src/commands/teach.ts +3 -1
- package/src/demo/drive.ts +36 -7
- package/src/demo/timeline.ts +64 -0
- package/src/migrate/rename.ts +5 -4
- package/src/teach/browser/compile.ts +44 -0
- package/src/teach/browser/dismiss.ts +76 -0
- package/src/teach/browser/focus-line.ts +19 -0
- package/src/teach/browser/glossary-filter.ts +44 -0
- package/src/teach/browser/head.ts +30 -0
- package/src/teach/browser/quiz.ts +19 -0
- package/src/teach/browser/sidebar.ts +233 -0
- package/src/teach/browser/theme.ts +18 -0
- package/src/teach/nav.ts +19 -374
- package/src/teach/workspace.ts +61 -6
- package/standards/figures.md +1 -0
- package/tooling/claude/reference.md +1 -1
- package/tooling/claude/seeds/.claude/hooks/path-form.sh +2 -4
- package/tooling/claude/seeds/.claude/hooks/search-reminder.sh +35 -0
- package/tooling/claude/seeds/.claude/settings.json +9 -0
|
@@ -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
|
-
-
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
```
|
|
@@ -40,7 +40,7 @@ Do not widen the split to admit a subject. Adding a sibling folder is a change t
|
|
|
40
40
|
The standard forbids working from training knowledge, so the draft is built on a read rather than on recall.
|
|
41
41
|
|
|
42
42
|
- Fetch current information through the `claude-code-guide` agent for any subject that agent covers. Its answer is the source the page is written from.
|
|
43
|
-
- Reach a subject the agent does not cover through the owner's own published documentation.
|
|
43
|
+
- Reach a subject the agent does not cover through the owner's own published documentation. Invoke `canon:search-craft` with the skill tool before searching for it, since finding the owner's documentation is the field-and-authority step that skill carries, and report it rather than proceeding silently when the skill does not resolve.
|
|
44
44
|
- Say the fetch failed and stop rather than substituting recall. A page sourced from memory is the failure the rule exists to prevent, and it ships looking identical to one that was checked.
|
|
45
45
|
- Close the intro with the `Source:` sentence the standard requires, linking the canonical page where one exists and naming the owner alone where the subject has no single URL.
|
|
46
46
|
- Stamp the read date on a source revised without notice, as `read <date>`. A claim traced to an undated read cannot be checked against what was actually read.
|
|
@@ -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:
|
|
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
|
|
|
@@ -24,7 +24,7 @@ Read `${CLAUDE_SKILL_DIR}/../../standards/groundwork.md` before writing any file
|
|
|
24
24
|
- A second exception, for what a spike reads as bulk input: write a large fixture under `.canon/tmp/runs/groundwork-fixtures/<slug>/`. Keep it out of `.canon/groundwork/` so mode detection never matches a fixture as a track. A fixture a headless run is pointed at goes outside the repository instead, per the rule in `## Running a spike`. An arm script and a checkout a claim rests on are not fixtures, and go inside the track under `scripts/` and `clones/`, per the standard.
|
|
25
25
|
- What a spike produces stays inside the track rather than joining the two exceptions above: write evidence a spike file cites under `.canon/groundwork/<nn>-<slug>/evidence/`, which the first rule already permits. Mode detection matches entries at the top level of the tracks directory, so the sibling the fixtures rule guards against cannot be a folder nested inside a track, and the scratch path holds only what can be deleted without loss, which a recording a finding rests on is not.
|
|
26
26
|
- A `draft-and-pick` run invoked from inside a live track follows its own branch for this, writing to `evidence/` here rather than `.canon/tmp/<slug>/`.
|
|
27
|
-
- Reading is not restricted. External research is in scope, so read documentation, comparable projects, and papers whenever a live question needs them.
|
|
27
|
+
- Reading is not restricted. External research is in scope, so read documentation, comparable projects, and papers whenever a live question needs them. Invoke `canon:search-craft` with the skill tool before an outside search, and report it rather than proceeding silently when the skill does not resolve.
|
|
28
28
|
- Every claim about a source outside the project carries a link to it. A source found and not read is listed as a lead and is never cited.
|
|
29
29
|
- Treat the folder as gitignored, and backed only where a records remote is configured: `canon records push` and `canon records pull` protect it against the machine being lost there and refuse with `no-remote` otherwise, and neither protects against a compaction dropping this session's own reasoning before anyone has pushed, so `07-next-session.md` repeats what it needs instead of pointing at its siblings.
|
|
30
30
|
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: search-craft
|
|
3
|
+
description: Why a session needs a thinking step before an outside search, deriving where a field's authorities live rather than taking the top-ranked result, and why that step is a method rather than a catalog of sites
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Search craft requirement
|
|
7
|
+
|
|
8
|
+
## Gap
|
|
9
|
+
|
|
10
|
+
Without this skill, a session reaching outside the project runs one generic `WebSearch` and takes what ranks highest. Nothing in the toolkit says how to search, and the two procedures that require an outside source, `plan-groundwork` and `draft-wiki`, give no route to one.
|
|
11
|
+
|
|
12
|
+
The miss is measured. On 2026-10-02 two queries ran twice each with identical text, once open and once with `allowed_domains` set to authorities the session derived itself with no list to consult.
|
|
13
|
+
|
|
14
|
+
- `css container queries browser support`: 1 of 9 open results came from MDN, and that one was a blog post rather than the reference page. The rest were third-party pages, three of them thin guides. Scoped to MDN, web.dev, and caniuse, 10 of 10 results were primary sources.
|
|
15
|
+
- The two summaries disagreed on a fact. The open one said Firefox shipped style queries in version 128, and the scoped one, reading caniuse, said 151. A direct fetch of the caniuse table returned 151, so a session that searched once would have reported the wrong version.
|
|
16
|
+
- `effect of minimum wage increase on employment evidence`: the open set mixed journals with advocacy groups and its summary leaned one way. Scoped to five authorities the session named, being a research bureau's working papers, the economists' professional association, a working-paper index, a policy institute, and a legislature's budget office, 7 of 9 results were working papers or official analysis, and the summary carried both the near-zero and the negative estimates.
|
|
17
|
+
- 2 of the 9 scoped economics results came from a domain outside the allow list, so the filter is not strict.
|
|
18
|
+
|
|
19
|
+
The authorities in both pairs were named by the session unprompted once it was asked to, which is the argument for a method over a list. Two queries at one run each show the effect exists and do not size it.
|
|
20
|
+
|
|
21
|
+
Access is a second gap a session cannot derive. Probed on 2026-10-02, Reddit refused its JSON search with a 403 and refused `WebFetch`, while its RSS feed answered 200. X redirected `curl` to a login page and returned 402 to `WebFetch`, so no free route reaches it.
|
|
22
|
+
|
|
23
|
+
## Must
|
|
24
|
+
|
|
25
|
+
- Name the field, or two, before a query is written
|
|
26
|
+
- Derive the field's authorities from the kind of body it trusts, and search for who they are first when unsure
|
|
27
|
+
- Run the query scoped to those authorities and open beside it, prefer the scoped result on a conflict, and say in the output that the two disagreed
|
|
28
|
+
- Use the open result for practitioner write-ups and news the authorities do not publish
|
|
29
|
+
- Warn that the domain filter is not strict, so a scoped result has its domain checked before it is cited
|
|
30
|
+
- Prefer a public API over a fetched and summarized page where one exists, since the API returns the dates, authors, and identifiers a citation needs
|
|
31
|
+
- Carry a dated access note grown only from a failure a session hit, and stop to ask the operator before any paid or logged-in route
|
|
32
|
+
- Close with the practice skill's excuses, red flags, and closing checklist, answering "the model already knows the good sites" and "one search was enough"
|
|
33
|
+
- Be loaded from the sourcing steps of `plan-groundwork` and `draft-wiki`, each reporting when the skill does not resolve
|
|
34
|
+
|
|
35
|
+
## Must not
|
|
36
|
+
|
|
37
|
+
- Name a site as the destination for a category of question. An example authority appears only inside the method as an illustration of deriving one, marked as such. A line reading "for economics, use X" is the catalog the operator ruled out and a reviewer reads against this line.
|
|
38
|
+
- Ship code. Access code a session needs repeatedly becomes a `canon` verb, never a script in the skill.
|
|
39
|
+
- Restate citation format, which belongs to the surface writing the citation
|
|
40
|
+
- Suggest scraping behind a login or a paywall
|
|
41
|
+
|
|
42
|
+
## Out of scope
|
|
43
|
+
|
|
44
|
+
- The form a citation takes: the procedure or standard writing it
|
|
45
|
+
- A Claude Code subject: the `claude-code-guide` agent, which `draft-wiki` already routes to
|
|
46
|
+
- Image generation, which makes a picture rather than finding a source
|
|
47
|
+
- Loading on every web search rather than on a research-shaped request: a hook matching `WebSearch`, planned on its own
|
|
48
|
+
- Whether a session already scopes searches without the skill, which only a run on a fresh research request without it would show
|
|
49
|
+
|
|
50
|
+
## Measured
|
|
51
|
+
|
|
52
|
+
2026-10-03, one Sonnet run of the toolkit's own sandbox scenario for this skill, a housing brief asking for linked notes and a prompt for the strongest evidence on whether rent control reduces housing supply. The skill sat in the project's skill folder and the run was allowed the skill, search, and fetch tools.
|
|
53
|
+
|
|
54
|
+
- No `Skill` call fired, so the description did not route a plain research request to the body.
|
|
55
|
+
- The run searched four times with no domain filter, naming authors and journals from recall, then fetched the papers' own pages. It never named the field, so the scenario's field pattern failed and the arm went red on one of its assertions.
|
|
56
|
+
|
|
57
|
+
The arm shows the trigger is the gap rather than the body: a session that never loads the skill cannot follow it. The pointers from `plan-groundwork` and `draft-wiki` reach only those procedures, and the hook matching `WebSearch` is the route for every other search. One run on one model shows the miss exists and does not size it.
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: search-craft
|
|
3
|
+
description: Carries the thinking step a session takes before it searches outside the project, naming the field, deriving who that field treats as authoritative, and running a search scoped to those sources beside an open one, plus a dated note on which sites refuse access. Use before any outside search for evidence, papers, documentation, statistics, or opinion, when a procedure loads it at its sourcing step, or when asked "find me the strongest evidence on X", "where should I look for this", "what does the research say", "find papers on", "look up the docs for", or "what are people saying about". Do NOT use to format a citation, which belongs to the surface writing it, to source a Claude Code subject, which is the `claude-code-guide` agent, or to generate an image, which is not search.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Search craft
|
|
7
|
+
|
|
8
|
+
A session reaching outside the project tends to run one generic search and take whatever ranks highest. Ranking rewards pages written to rank, so a field's thin "complete guide" pages and its advocates crowd out its reference material, and one search gives nothing to check a wrong fact against. This skill carries the step before the search: work out where the field's authoritative material lives, search there, and search openly beside it.
|
|
9
|
+
|
|
10
|
+
The procedure that loaded this skill owns what the result is for and where it is written. Nothing here formats a citation or decides what a finding means.
|
|
11
|
+
|
|
12
|
+
## Name the field
|
|
13
|
+
|
|
14
|
+
- Name the field the question sits in before writing a query. Name two when the question straddles them, such as a pricing question that is both law and economics.
|
|
15
|
+
- Name it at the level a practitioner would, being the discipline that argues about the answer, rather than the topic word in the question.
|
|
16
|
+
- Say the field in the output, so a reader can tell a wrong answer from a search run in the wrong place.
|
|
17
|
+
|
|
18
|
+
## Derive who the field trusts
|
|
19
|
+
|
|
20
|
+
- Ask what kind of body the field treats as settling a question, then name the bodies of that kind. The kinds recur across fields:
|
|
21
|
+
- the standards body or specification that defines the thing
|
|
22
|
+
- the reference documentation its practitioners cite
|
|
23
|
+
- the peer-reviewed papers and working papers of its professional society
|
|
24
|
+
- the official statistics office or regulator that publishes the numbers
|
|
25
|
+
- the project's own repository, changelog, or issue tracker, for a piece of software
|
|
26
|
+
- Derive the names. Never reach for a remembered list of sites per category, since a list rots with nobody noticing and the field's own kind of authority is what the derivation tests.
|
|
27
|
+
- Search for the authorities first when unsure who they are, such as asking where the field's practitioners publish or what its practitioners cite, and scope the real search only after that answer is read.
|
|
28
|
+
- As an illustration of deriving, not a list to reuse: a question on a browser feature's support sits in web platform engineering, whose authorities are the specification, the reference docs practitioners cite, and the compatibility tables built from browser releases. Each new question derives its own.
|
|
29
|
+
|
|
30
|
+
## Search twice
|
|
31
|
+
|
|
32
|
+
- Run the same query twice: once scoped to the derived authorities through `WebSearch`'s `allowed_domains`, and once open.
|
|
33
|
+
- Prefer the scoped result when the two disagree on a fact, and say in the output that they disagreed and which one was kept. Never pick one silently.
|
|
34
|
+
- Use the open result for what the authorities do not publish: practitioner write-ups, field reports, and news.
|
|
35
|
+
- Check the domain of every scoped result before citing it. The filter is not strict, and a scoped run can return results from outside its list.
|
|
36
|
+
- Fetch the authority's page itself to confirm a fact both searches summarized differently, since a search summary is a paraphrase and can carry the error.
|
|
37
|
+
|
|
38
|
+
## Prefer a structured source
|
|
39
|
+
|
|
40
|
+
- Prefer a source's public API over a fetched and summarized HTML page where one exists. An API returns the dates, authors, and identifiers a citation needs, and a summary of the page can drop or blur them.
|
|
41
|
+
- Reach the API with a plain request when it needs no key, rather than writing a wrapper for one search.
|
|
42
|
+
|
|
43
|
+
## Access note
|
|
44
|
+
|
|
45
|
+
Each line is a claim measured once, and `${CLAUDE_SKILL_DIR}/REQUIREMENT.md` records the date under its Gap. Sites change their blocking without notice, so re-check a line before relying on it. Add a line only for a failure a session actually hit, and record the date it hit in the requirement beside it.
|
|
46
|
+
|
|
47
|
+
- Reddit answers its RSS feed and refuses its JSON search with a 403. `WebFetch` is refused for the site.
|
|
48
|
+
- X answers nothing without paying or a login. `curl` redirects to a login page and `WebFetch` returns 402.
|
|
49
|
+
- Stop and ask the operator before any route that pays, logs in, or works around a refusal. Never suggest scraping behind a login.
|
|
50
|
+
|
|
51
|
+
## Excuses and rebuttals
|
|
52
|
+
|
|
53
|
+
| Excuse | Rebuttal |
|
|
54
|
+
| ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
55
|
+
| The model already knows the good sites | It does, and it does not use that knowledge unprompted. Left to rank, a search puts guides written to rank above a field's reference pages. |
|
|
56
|
+
| One search was enough | One search gives nothing to check a wrong fact against. The scoped search is what catches the open summary's error. |
|
|
57
|
+
| The open results look authoritative | Ranking rewards pages written to rank, so advocates and thin guides sit beside the field's own record and tilt the summary. |
|
|
58
|
+
| I scoped it, so every result is in scope | The domain filter is not strict, so a scoped search can return results from outside its list. |
|
|
59
|
+
| The summary already answers it | A summary paraphrases. Fetch the page when two summaries disagree, since that is where the error sits. |
|
|
60
|
+
|
|
61
|
+
## Red flags
|
|
62
|
+
|
|
63
|
+
- You are about to write a query and have not named the field.
|
|
64
|
+
- Every source you are about to cite came from one open search.
|
|
65
|
+
- You named an authority because it is a site you remember, not because it is the kind of body the field trusts.
|
|
66
|
+
- The scoped and open results disagree and the output does not say so.
|
|
67
|
+
- You are citing a scoped result whose domain you have not checked.
|
|
68
|
+
- You are about to pay, log in, or scrape to reach a source and have not asked the operator.
|
|
69
|
+
|
|
70
|
+
## Before handing over
|
|
71
|
+
|
|
72
|
+
- The output names the field, or both fields, the question was searched in.
|
|
73
|
+
- Every authority searched was derived from the kind of body the field trusts.
|
|
74
|
+
- The query ran scoped and open, and every disagreement between them is stated with the side kept.
|
|
75
|
+
- Every cited source's domain was checked, and a fact the summaries disagreed on was confirmed on the page itself.
|
|
76
|
+
- No paid, logged-in, or scraped route was taken without the operator's answer.
|
|
77
|
+
|
|
78
|
+
## What this delegates
|
|
79
|
+
|
|
80
|
+
- The form a citation takes: the surface writing it, such as the standard the procedure writes to
|
|
81
|
+
- A Claude Code subject: the `claude-code-guide` agent, which `draft-wiki` routes to
|
|
82
|
+
- Generating an image: whatever draws the surface, since making one is not search
|
|
83
|
+
- Access code a session needs repeatedly: a `canon` verb, never a script in this skill
|
|
@@ -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
|
|
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
|
|
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`).
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Canvas
|
|
3
|
+
description: The canvas server, its content format, and the verbs that list, arrange, select, and capture frames
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Canvas
|
|
7
|
+
|
|
8
|
+
`canon canvas` serves a local canvas of pages and HTML frames and gives an agent the verbs the operator's mouse has. A page is a folder under `.canon/canvas/`, a frame is one HTML file in it, and `layout.json` beside them holds each frame's box.
|
|
9
|
+
|
|
10
|
+
## Serve
|
|
11
|
+
|
|
12
|
+
`canvas serve` serves the canvas on `127.0.0.1`, walks ports like `canon serve`, refuses a `Host` other than loopback on its own port, and runs until interrupted. Each frame gets the project's token stylesheet injected, being this toolkit's tokens in its own checkout, else `.claude/design/base.css` plus anything under `.claude/design/project/`, else none with a notice. An open canvas reloads a frame whose file changes.
|
|
13
|
+
|
|
14
|
+
The write routes the shell posts to also refuse a request carrying an `Origin` other than the server's own, and a body that is not JSON.
|
|
15
|
+
|
|
16
|
+
## List and add
|
|
17
|
+
|
|
18
|
+
`canvas list --json` emits every page with its frames. `page add`, `page rename`, and `frame add` (`--width`, `--height`) each emit one record under `--json`, refusing a name that is not one path segment, a page that already exists, or a root that is not a directory, with the reason on stderr.
|
|
19
|
+
|
|
20
|
+
## Arrange and select
|
|
21
|
+
|
|
22
|
+
`frame move <page> <name> --x <px> --y <px>` rewrites one frame's position in `layout.json` and keeps its size. An omitted axis stays where the frame is. It refuses a frame or page that does not exist and a layout that does not parse.
|
|
23
|
+
|
|
24
|
+
The shell writes through the same writer when the operator drags a frame. Both take a lock file beside the layout, read it, merge their change, and replace it, so a drag released while a verb writes loses neither position. A writer that cannot get the lock within two seconds refuses with reason `busy`.
|
|
25
|
+
|
|
26
|
+
`canvas selection --json` emits `{ ok, selection }` with the page, frame, file, box, and path of the frame the operator selected, or `selection: null` when nothing is selected or the selected frame has since been removed. Read it when the operator says "this one".
|
|
27
|
+
|
|
28
|
+
The operator can also pick one element inside a frame, by clicking it on the surface or in the frame's layers tree. The selection then carries `element`, recording the `index` in document order, `tag`, `classes`, and `text` excerpt as they were at the pick. An edit to the frame since can shift that index onto another element, so `stale` turns true once the file's content no longer matches what the pick was made against. Check it before acting on the index.
|
|
29
|
+
|
|
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
|
+
|
|
32
|
+
## Capture
|
|
33
|
+
|
|
34
|
+
`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.
|
|
35
|
+
|
|
36
|
+
`--out` is the PNG for a frame and a folder for a page, defaulting to session scratch. `--json` emits `{ ok, captures }` with the path and pixel size of each frame. Each PNG is the frame's whole document, so its height follows the document and not the frame's box. The font check `canon capture` makes applies, so a frame naming a font the machine lacks fails with that reason. A refused capture reports `no-page` or `no-frame` for a target that does not exist, `no-server` when the server for the call cannot start, and `capture-failed` for an error the engine throws, such as a browser that will not launch.
|
package/docs/agents/commands.md
CHANGED
|
@@ -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,
|
|
37
|
+
| `canon canvas <verb>` | Serve a local canvas of pages and HTML frames, arrange them, 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`
|
|
99
|
+
- `canvas`, described below: `serve`, `list`, `page add`, `page rename`, `frame add`, `frame move`, `selection`, `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`
|
|
@@ -129,7 +129,7 @@ Subcommands no other page describes:
|
|
|
129
129
|
- `claude skills rank` scores either skill corpus's descriptions against a case corpus by TF-IDF cosine similarity, reporting rank-one and top-three (`--cases <path>`).
|
|
130
130
|
- `design regen` rewrites this repository's `canon/DESIGN.md` from `src/design/tokens.ts` and `src/design/base.css` from `src/design/neutral.ts`. `design css` emits the tokens and components as CSS on stdout, with `--no-components` for properties alone, and `design render` declares each vendored face the typography table names under `--embed-fonts`.
|
|
131
131
|
- `slides render` renders a `.claude/SLIDES.md` source into a PowerPoint deck and reports any unrecognized layout name on stderr, and `slides list --json` emits the layout catalog.
|
|
132
|
-
- `canvas
|
|
132
|
+
- `canvas`, with its verbs, content format, and write routes, is described in `canvas.md`.
|
|
133
133
|
- `labels scan` fails a pull request or a posted review whose title, body, or review comment carries a phase label, a label a code span quotes, a gitignored record path, a session link, a title word no dictionary holds, or a title breaking `standards/pr.md`'s format, casing, or length rule (`--event`, `--body-file`, `--json`).
|
|
134
134
|
- `repo metadata propose` compares a description, homepage, and topic set computed from the README and `package.json` against what the remote carries, writing nothing, and `repo metadata apply` writes an explicitly supplied set through `gh repo edit` (`--description`, `--homepage`, `--topics`).
|
|
135
135
|
|
package/docs/agents/demo.md
CHANGED
|
@@ -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
|
|
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.
|
package/docs/agents/index.md
CHANGED
|
@@ -10,6 +10,7 @@ CLI catalog and invocation rules for agents, split by command domain. Start with
|
|
|
10
10
|
|
|
11
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
|
|
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
14
|
- [Capture](capture.md): Rendering HTML sources to PNG, what the command asserts about fonts, and why the selector has no default
|
|
14
15
|
- [Census](census.md): Tracked-plus-untracked file count, a breakdown by extension, and a line total that skips whatever reads as binary
|
|
15
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
|
package/docs/agents/teach.md
CHANGED
|
@@ -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
|
|
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
|
|
|
@@ -50,6 +50,7 @@ This page is the corpus the coverage claim is measured against: every name `cano
|
|
|
50
50
|
| `canon:deprecation-migration` | When deleting or replacing code something may still call, to migrate its callers and prove none remain |
|
|
51
51
|
| `canon:code-craft` | Before writing a function, class, or module, to pick the shape the next change needs |
|
|
52
52
|
| `canon:review-craft` | When reviewing a change, for what to look for and how much evidence a finding needs |
|
|
53
|
+
| `canon:search-craft` | Before searching outside the project, to derive where the field's authorities publish and search there too |
|
|
53
54
|
| `canon:systematic-debugging` | When a test fails or a bug surfaces, to force root cause first |
|
|
54
55
|
| `canon:design-taste` | When drafting or judging an interface, or when output reads generic, to settle which decision comes first |
|
|
55
56
|
| `canon:ui-checklist` | After a UI change, to write what to look at and name what ships untested |
|
|
@@ -8,9 +8,9 @@ category: Workflow
|
|
|
8
8
|
|
|
9
9
|
Three tiers cover the range from prose-only design docs to a fully graphical design source of truth. Pick one per project based on how UI-heavy the work is, whether stakeholders review visuals, and whether a designer is involved. Tiers stack, so moving up does not invalidate work done at a lower tier.
|
|
10
10
|
|
|
11
|
-
The tier framework sits alongside [Claude Design](../../wiki/claude/design.md), the one catalog page in this range.
|
|
11
|
+
The tier framework sits alongside [Claude Design](../../wiki/claude/design.md), the one catalog page in this range. Excalidraw and the surrounding MCP and skill ecosystem are named inline below rather than catalogued separately. This page decides when to reach for what.
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
[Claude Design](../../wiki/claude/design.md), released 2026-04-17 and priced inside Claude subscriptions, is the ceiling tool for tier 1 and tier 2. Reserve it for codebase extraction and the richly annotated handoff bundle.
|
|
14
14
|
|
|
15
15
|
## Tier 0: prose only
|
|
16
16
|
|
|
@@ -56,21 +56,19 @@ A cell no source anchors ends in `? verify`, and the preview shows that marker b
|
|
|
56
56
|
|
|
57
57
|
ASCII and prose stay as source of truth. Add a visual render as a feedback surface for the agent and for human review.
|
|
58
58
|
|
|
59
|
-
- Stitch via MCP handles agent-driven generation of prototypes and design systems
|
|
60
59
|
- Excalidraw handles agent-driven wireframes when the round-trip canvas loop matters
|
|
61
60
|
- Claude Design joins only when codebase extraction or the annotated handoff bundle is worth the ceiling cost
|
|
62
61
|
|
|
63
|
-
|
|
62
|
+
Both produce derived artifacts, so human edits are review annotations rather than source changes.
|
|
64
63
|
|
|
65
64
|
### Seed shape
|
|
66
65
|
|
|
67
|
-
Same as tier 0 with
|
|
66
|
+
Same as tier 0 with one addition. `WIREFRAMES.md` opts into Excalidraw rendering via a top-of-file marker like `<!-- excalidraw: WIREFRAMES.excalidraw -->`. `DESIGN.md` stays human-maintained.
|
|
68
67
|
|
|
69
|
-
Impeccable, if installed, keeps its own root `DESIGN.md` and `PRODUCT.md` in
|
|
68
|
+
Impeccable, if installed, keeps its own root `DESIGN.md` and `PRODUCT.md` in its own format. These are separate files from the toolkit's `canon/DESIGN.md` and are not synced with it. Treat impeccable's pair as its own source of truth for its commands, and the toolkit's `canon/DESIGN.md` as the source other toolkit skills read.
|
|
70
69
|
|
|
71
70
|
### Tools
|
|
72
71
|
|
|
73
|
-
- Stitch via MCP at `stitch.googleapis.com/mcp`, Google's Gemini-powered design product. Agent-addressable through `generate_screen_from_text`, `edit_screens`, and `generate_variants`. Default pick for agent-driven visual generation. Free tier of 400 daily credits.
|
|
74
72
|
- Excalidraw canvas server on localhost plus the community [`yctimlin/mcp_excalidraw`](https://github.com/yctimlin/mcp_excalidraw) MCP shim, for projects that need an agent to draw, read back, and revise a canvas. MIT-licensed, plaintext JSON scene format. `describe_scene` and `get_canvas_screenshot` let the agent verify its own layout before claiming it is correct.
|
|
75
73
|
- Playwright MCP ([`microsoft/playwright-mcp`](https://github.com/microsoft/playwright-mcp)) for browser-side verification, driven off the accessibility tree rather than screenshots.
|
|
76
74
|
- Chrome DevTools MCP ([`ChromeDevTools/chrome-devtools-mcp`](https://github.com/ChromeDevTools/chrome-devtools-mcp)) for live frontend debugging: performance traces, network inspection, and DOM and CSS inspection.
|
|
@@ -88,17 +86,15 @@ Impeccable, if installed, keeps its own root `DESIGN.md` and `PRODUCT.md` in the
|
|
|
88
86
|
- Design decisions benefit from visual inspection
|
|
89
87
|
- A single contributor owns both design and implementation
|
|
90
88
|
|
|
91
|
-
###
|
|
89
|
+
### Excalidraw vs Claude Design in tier 1
|
|
92
90
|
|
|
93
|
-
The
|
|
94
|
-
|
|
95
|
-
Stitch via MCP generates polished prototypes from text and a provisioned design system, scripted from a Claude Code session. Output is human-facing and lives in Stitch. Free daily quota makes it the right pick for frequent iteration.
|
|
91
|
+
The two tools solve non-overlapping halves of the visual companion problem.
|
|
96
92
|
|
|
97
93
|
Excalidraw gives the agent a canvas it can read back over MCP. Output is agent-facing and persists as a JSON file in the repo. Pick it when Claude Code needs to iterate on wireframes autonomously, not when a human needs polished review artifacts.
|
|
98
94
|
|
|
99
95
|
Claude Design reads the raw codebase without prose curation and produces a polished handoff bundle with chat history. Weekly quota makes it expensive, so reserve it for the extraction pass or the final handoff moment, not daily iteration.
|
|
100
96
|
|
|
101
|
-
Most tier 1 projects pick one. Projects with a messy codebase and no curated `DESIGN.md` may want Claude Design once for the initial extraction
|
|
97
|
+
Most tier 1 projects pick one. Projects with a messy codebase and no curated `DESIGN.md` may want Claude Design once for the initial extraction.
|
|
102
98
|
|
|
103
99
|
## Tier 2: visual as source of truth
|
|
104
100
|
|
|
@@ -112,7 +108,6 @@ Design happens in a graphical tool. `canon/DESIGN.md` either regenerates from th
|
|
|
112
108
|
|
|
113
109
|
- Figma desktop app with the official [Figma Dev Mode MCP](https://www.figma.com/blog/introducing-claude-code-to-figma/) for teams with a dedicated designer already on Figma. Bidirectional sync and Code to Canvas capture of a running Claude Code UI into editable Figma frames.
|
|
114
110
|
- Claude Design with its Claude Code handoff bundle for teams without an existing Figma investment and for solo founders or PMs driving design themselves. One-way handoff, no bidirectional sync. See [Claude Design](../../wiki/claude/design.md).
|
|
115
|
-
- Stitch via MCP as a low-cost complement to either, used for bulk screen generation driven by Claude Code.
|
|
116
111
|
- Playwright and Chrome DevTools MCPs as in tier 1
|
|
117
112
|
|
|
118
113
|
### Skills
|
|
@@ -132,8 +127,6 @@ Figma wins when a dedicated designer already owns a Figma file, external collabo
|
|
|
132
127
|
|
|
133
128
|
Claude Design wins when nobody on the team has a Figma workflow yet and the handoff bundle with chat history is the intended implementation path. Claude Design's handoff is one-way, and its quota limits daily iteration, so it is most useful for the initial extraction pass and the final handoff moment rather than day-to-day design work.
|
|
134
129
|
|
|
135
|
-
Either of the above pairs cleanly with Stitch via MCP for agent-driven screen generation between the two anchor moments.
|
|
136
|
-
|
|
137
130
|
## Decision guide
|
|
138
131
|
|
|
139
132
|
Four questions. Each yes weighs toward a higher tier.
|
|
@@ -7,12 +7,10 @@ description: Report file paths correctly for the reading surface and group them
|
|
|
7
7
|
## Reporting paths
|
|
8
8
|
|
|
9
9
|
- After creating or modifying a file, include its path on its own line so the reader can open it. Do not paraphrase paths into prose ("the seeds folder", "your CLAUDE.md").
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
- On every other value, including unset, emit the path bare. A terminal emulator makes it clickable through its own path detection, and link markup defeats that.
|
|
13
|
-
- Both forms govern a path emitted in a response. A path written into a markdown file follows the markdown standard instead, which your toolkit resolves by name, and which backticks a file reference and never repeats it as a link label.
|
|
10
|
+
- Emit a path in the form the surface's own instructions give, such as a markdown link where the harness asks for one, and bare where it gives none. A terminal makes a bare path clickable through its own path detection, and link markup defeats that.
|
|
11
|
+
- That form governs a path emitted in a response. A path written into a markdown file follows the markdown standard instead, which your toolkit resolves by name, and which backticks a file reference and never repeats it as a link label.
|
|
14
12
|
- In a linked worktree (under `.claude/worktrees/<name>/`), emit the absolute path, since the editor is rooted at the main project root and a path relative to the worktree resolves nowhere there. Prefer the form a `PostToolUse` hook hands back after a write where one is installed.
|
|
15
13
|
|
|
16
14
|
## Grouping multiple files
|
|
17
15
|
|
|
18
|
-
- When the response covers multiple files, group paths under headers: `**Created:**`, `**Modified:**`, `**Deleted:**`. Every path under them takes
|
|
16
|
+
- When the response covers multiple files, group paths under headers: `**Created:**`, `**Modified:**`, `**Deleted:**`. Every path under them takes that form, not the first alone. For single-file changes, the path on its own line is enough.
|
|
@@ -9,7 +9,7 @@ paths:
|
|
|
9
9
|
|
|
10
10
|
## Reading a payload
|
|
11
11
|
|
|
12
|
-
- Open a hook that reads a payload with a bounded `IFS= read -r -d '' -t 2 input`, exiting non-zero on an empty payload. An unbounded `cat` blocks forever against a hand run or an open socket, holding the session open with it.
|
|
12
|
+
- Open a hook that reads a payload with a bounded `IFS= read -r -d '' -t 2 input`, exiting non-zero on an empty payload. An unbounded `cat` blocks forever against a hand run or an open socket, holding the session open with it.
|
|
13
13
|
|
|
14
14
|
## Silencing output
|
|
15
15
|
|
package/package.json
CHANGED
|
@@ -43,7 +43,7 @@ resolve_sandbox_git_identity() {
|
|
|
43
43
|
SANDBOX_GIT_NAME="${SANDBOX_GIT_NAME:-$(git config --global user.name 2>/dev/null || true)}"
|
|
44
44
|
SANDBOX_GIT_EMAIL="${SANDBOX_GIT_EMAIL:-$(git config --global user.email 2>/dev/null || true)}"
|
|
45
45
|
|
|
46
|
-
: "${SANDBOX_GIT_NAME:=
|
|
46
|
+
: "${SANDBOX_GIT_NAME:=canon-sandbox}"
|
|
47
47
|
: "${SANDBOX_GIT_EMAIL:=sandbox@example.com}"
|
|
48
48
|
|
|
49
49
|
export SANDBOX_GIT_NAME SANDBOX_GIT_EMAIL
|
|
@@ -57,7 +57,7 @@ configure_sandbox_git_identity() {
|
|
|
57
57
|
|
|
58
58
|
# Every scenario that needs a remote points at the same throwaway repository, so
|
|
59
59
|
# the name lives here rather than in each one.
|
|
60
|
-
SANDBOX_ANCHOR_REPO="
|
|
60
|
+
SANDBOX_ANCHOR_REPO="canon-sandbox"
|
|
61
61
|
|
|
62
62
|
# A scenario calls this from its own use_anchor hook rather than this file
|
|
63
63
|
# defining the hook. manage-sandbox.sh keys off `type -t use_anchor`, so
|