beehaven 0.8.27 → 0.8.33

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 (49) hide show
  1. package/dist/agents-md-text.js +64 -0
  2. package/dist/browser-login.js +14 -4
  3. package/dist/build-channel.js +2 -2
  4. package/dist/claude-bridge.js +12 -9
  5. package/dist/clearly.js +6 -4
  6. package/dist/cli.js +27 -8
  7. package/dist/commands/agents-md.js +118 -0
  8. package/dist/commands/daemon-cmd.js +2 -0
  9. package/dist/commands/help.js +21 -0
  10. package/dist/commands/self-update.js +32 -5
  11. package/dist/commands/workspace.js +22 -5
  12. package/dist/daemon-client.js +10 -6
  13. package/dist/daemon-entry.js +1 -0
  14. package/dist/daemon-process.js +125 -0
  15. package/dist/daemon.js +131 -62
  16. package/dist/dashboard.js +118 -6
  17. package/dist/ipc-auth.js +3 -1
  18. package/dist/ipc-client.js +7 -6
  19. package/dist/ipc-path.js +92 -0
  20. package/dist/ipc-server.js +33 -33
  21. package/dist/npm-update.js +138 -0
  22. package/dist/relay-presets.js +3 -4
  23. package/dist/setup-service.js +9 -4
  24. package/dist/verb-surface.js +1 -0
  25. package/dist/watcher.js +9 -23
  26. package/dist/windows-hide.js +77 -0
  27. package/package.json +1 -1
  28. package/scripts/sync-skills.mjs +6 -0
  29. package/skills/agent-doodle-space/SKILL.md +1 -1
  30. package/skills/agent-home/SKILL.md +1 -1
  31. package/skills/beehaven-cli/SKILL.md +12 -0
  32. package/skills/brand-identity/SKILL.md +37 -14
  33. package/skills/clearly-agent/SKILL.md +24 -4
  34. package/skills/clearly-canvas/SKILL.md +88 -11
  35. package/skills/clearly-canvas/authoring.md +61 -10
  36. package/skills/clearly-canvas/example.mjs +72 -69
  37. package/skills/clearly-canvas/review.mjs +106 -12
  38. package/skills/clearly-docs/SKILL.md +151 -0
  39. package/skills/clearly-init/SKILL.md +135 -0
  40. package/skills/clearly-workflows/SKILL.md +90 -0
  41. package/skills/clearly-workspace/SKILL.md +1 -1
  42. package/skills/codebase-map/SKILL.md +1 -1
  43. package/skills/design-craft/SKILL.md +14 -6
  44. package/skills/design-craft/references.md +95 -0
  45. package/skills/index.json +48 -12
  46. package/skills/layout-systems/SKILL.md +14 -11
  47. package/skills/pair-on-canvas/SKILL.md +1 -1
  48. package/skills/sticker-pack/SKILL.md +132 -0
  49. package/skills/visualize/SKILL.md +188 -0
@@ -1,7 +1,8 @@
1
1
  ---
2
2
  name: brand-identity
3
3
  description: >-
4
- Build a complete brand identity on a Clearly canvas the way a studio does —
4
+ Needs a terminal with the beehaven CLI (Claude Code, Codex, Gemini CLI); in a chat with only the Clearly connector, say so and use the clearly_* tools instead.
5
+ Design the requested logo or brand identity on a Clearly canvas —
5
6
  brief, mark, wordmark, lockups and clear space, palette, type system,
6
7
  applications, and a spec board someone else can build from. Use when asked
7
8
  for a brand, a logo, an identity, a rebrand, a visual system, brand
@@ -13,10 +14,14 @@ description: >-
13
14
 
14
15
  # brand-identity — a system, not a picture of a logo
15
16
 
16
- ⚠⚠ **THE DELIVERABLE IS A SYSTEM SOMEONE ELSE CAN BUILD WITH.** A single mark on a white
17
- artboard is not an identity; it is a drawing. Pentagram's identity work ships a symbol, a
18
- wordmark, a graphic system, a palette, a type system and the guidelines that let an in-house
19
- team keep it consistent. That is the shape to copy.
17
+ Match the user's scope. For a logo concept, deliver the editable mark/wordmark, primary and
18
+ one-color use, a small-size check, and the requested application. A logo plus landing page does
19
+ not require merchandise, storefronts or a complete guideline deck. Add those when requested or
20
+ when a concrete use in the brief requires them.
21
+
22
+ For a complete identity request, the deliverable is a system someone else can build with:
23
+ symbol, wordmark, palette, typography, applications and guidelines. Sections 6–8 describe that
24
+ larger scope; they are optional for a narrow concept.
20
25
 
21
26
  Read **`design-craft`** first or alongside — grid, type scale, colour roles and the studio
22
27
  pass are assumed here.
@@ -60,15 +65,31 @@ handover. A mark of hand-placed béziers does not, and it shows.
60
65
  | **Counter-form** | the shape is the NEGATIVE space between forms | clever marks that survive one colour |
61
66
  | **Modular** | one unit repeated/rotated on a grid | systems, networks, collectives |
62
67
 
63
- **Build it as an `svg` node with a stated viewBox and derived numbers:**
68
+ **Build it from native layers, every number derived from the construction** — the way an
69
+ identity designer works in Figma, so each part of the mark stays a named, editable layer in the
70
+ brand colour (never one generated or hand-written SVG):
64
71
 
65
72
  ```jsonc
66
- {"action":"canvas.create-node","args":{"name":"mark","type":"svg","x":120,"y":120,"w":240,"h":240,
67
- "svg":"<svg viewBox='0 0 240 240' xmlns='http://www.w3.org/2000/svg'>…</svg>"}}
73
+ {"batch":[
74
+ {"action":"frame.create","args":{"name":"Mark","x":120,"y":120,"w":240,"h":240}},
75
+ {"action":"canvas.create-node","args":{"type":"ellipse","name":"mark/ring","parentId":"Mark",
76
+ "x":20,"y":20,"w":200,"h":200,"fill":"#1B4DFF"}},
77
+ {"action":"canvas.create-node","args":{"type":"ellipse","name":"mark/counter","parentId":"Mark",
78
+ "x":70,"y":70,"w":100,"h":100,"fill":"#FFFFFF"}},
79
+ {"action":"vector.create","args":{"name":"mark/blade","parentId":"Mark","closed":true,"fill":"#1B4DFF",
80
+ "points":[{"x":120,"y":20},{"x":220,"y":120},{"x":120,"y":120}]}},
81
+ {"action":"canvas.group","args":{"ids":["mark/ring","mark/counter","mark/blade"],"name":"mark"}}
82
+ ]}
68
83
  ```
69
84
 
70
- ⚠ **`<text>` inside an `svg` node does NOT render headlessly** — no system fonts are loaded.
71
- Wordmarks are real text nodes, or outlined paths. Never live `<text>` in the mark.
85
+ Here R = 100: the counter is R/2, the blade's corners sit on the circle. Curves are
86
+ `vector.create` points with `hIn`/`hOut` control points (absolute coordinates) placed where the
87
+ construction says; a quarter-circle's handle sits 0.552·R from its anchor. A counter-form is a
88
+ ground-colour shape layered on top; `vector.boolean` makes a true cut-out when an editor is open.
89
+ Raw SVG (`type:"svg"`) is only for importing a mark the client already has.
90
+
91
+ ⚠ **Wordmarks are real text nodes, or outlined paths** — and `<text>` inside an imported `svg`
92
+ node does NOT render headlessly (no system fonts are loaded).
72
93
 
73
94
  **Test the mark against these before going further. A mark that fails any of them is not done:**
74
95
 
@@ -93,7 +114,9 @@ good. If it does not work in flat black, the shape is wrong and the gradient is
93
114
  - ⚠ **A wordmark is always tracked tighter than body text.** At display size, `letterSpacing`
94
115
  −1 to −4. Then fix the specific pairs the font gets wrong (an uppercase A next to a V, a
95
116
  T next to a lowercase o).
96
- - **Lockups are a fixed set, not an invitation.** Ship exactly these and say so:
117
+ - **For a full identity, define this fixed set.** For a concept, deliver the requested lockup
118
+ plus the mark-only and one-color forms needed for its smallest use. Additional lockups are
119
+ optional unless the brief asks for them:
97
120
 
98
121
  ```
99
122
  primary mark + wordmark, horizontal ← the default
@@ -225,11 +248,11 @@ Run `design-craft`'s studio pass, plus these identity-specific ones:
225
248
  ```
226
249
  □ Rendered the mark at 24px and LOOKED at it
227
250
  □ Mark works in flat black, flat white, and knocked out
228
- □ Every lockup has stated clear space and minimum size
251
+ □ Every delivered lockup has stated clear space and minimum size
229
252
  □ Palette has a dark-ground variant and role sentences
230
253
  □ Type scale has NUMBERS, not just face names
231
- □ At least 4 real applications, at real proportions
232
- □ Misuse section exists
254
+ □ Requested applications at real proportions (4–6 for a full identity; the requested surface for a concept)
255
+ □ Misuse section exists for a full identity; a concise use note is enough for a logo concept
233
256
  □ Put the mark beside the competitor named in UNLIKE — still distinct?
234
257
  □ Can someone build a new asset from this board without asking a question?
235
258
  ```
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: clearly-agent
3
- description: Work in a Clearly workspace AS an agent — sign in with an identity, resume a session, read your brief (what changed since you were last here, your recents, your unfiled drafts), and understand whose work you are creating. TRIGGER on the first `beehaven` call of any session, on "Not an agent" / "agent login" refusals, and when the user asks "who am I acting as", "what was I doing", "what have I made", "why can't the agent see this", "why is my work invisible", or "run this as a different agent". Read this BEFORE clearly-canvas or clearly-workspace — both need an identity and neither will work without one.
3
+ description: Needs a terminal with the beehaven CLI (Claude Code, Codex, Gemini CLI); in a chat with only the Clearly connector, say so and use the clearly_* tools instead. Work in a Clearly workspace AS an agent — sign in with an identity, resume a session, read your brief (what changed since you were last here, your recents, your unfiled drafts), and understand whose work you are creating. TRIGGER on the first `beehaven` call of any session, on "Not an agent" / "agent login" refusals, and when the user asks "who am I acting as", "what was I doing", "what have I made", "why can't the agent see this", "why is my work invisible", or "run this as a different agent". Read this BEFORE clearly-canvas or clearly-workspace — both need an identity and neither will work without one.
4
4
  ---
5
5
 
6
6
  # clearly-agent — who you are, and what that makes your work
@@ -190,6 +190,19 @@ task changes a product's UI, the composition comes FIRST: build the screen and i
190
190
  `canvas.review` it, link it to the ticket (`work-link {ticketId, kind:"design", refKind:"composition",
191
191
  refId}`), then implement. `clearly-canvas` §0 has the details.
192
192
 
193
+ No brand yet (`brand-tokens` answers `brand-not-found`) for a real company? Ask the person for their
194
+ website rather than inventing a palette, then:
195
+
196
+ 1. `beehaven call brand-import '{"url":"theirsite.com","dryRun":true}'` — colours by role, faces, logos,
197
+ voice and shape, each with its reason in `provenance`. Tell the person what you read.
198
+ 2. Ask what to call the brand (`suggestedName` is what the site calls itself — a suggestion, not a default).
199
+ 3. `beehaven call brand-import '{"url":"theirsite.com","name":"<their answer>"}'` saves it (the read is
200
+ reused; the first brand becomes the workspace default). Without `name` nothing is saved:
201
+ `brand-name-required`.
202
+
203
+ `brandId` + `apply:["colors","type"]` refreshes an existing brand as a new version instead. Licensed faces
204
+ come back set in the closest free one — `faces` says which.
205
+
193
206
  ## When a write is refused
194
207
 
195
208
  `agent-denied-create` / `-update` / `-delete` mean your **capability matrix** said no. It covers the
@@ -203,6 +216,11 @@ governance. Each resource's delete cell is `none`, `own`, or `all`; `own` means
203
216
  `created_by: agent:<your-id>`. Missing or legacy author data is not yours. Permanent deletion is
204
217
  human-only; agent deletes use a recoverable archive, tombstone, or checkpoint.
205
218
 
219
+ Removing canvas layers is an **update**, including `canvas.delete`, block removal, and placed
220
+ design layers. You may remove layers from any visible canvas within your edit scope, regardless
221
+ of its author. The server requires an undo checkpoint first. Deleting or archiving the whole
222
+ canvas still follows delete-own/delete-all (CAN2-128).
223
+
206
224
  Only agents whose owner is currently a workspace owner or admin can use admin or delete-all. The
207
225
  server checks this on every call: if your owner is demoted, your scope drops to write/delete-own.
208
226
  After an owner is promoted again, a human must explicitly re-grant the higher scope.
@@ -215,15 +233,17 @@ owner/admin-owned agent can be granted it. Check yours before a destructive step
215
233
  beehaven call agent-capabilities-get '{}' # { scope, matrix, summary }
216
234
  ```
217
235
 
218
- ⚠ `permission_scope: 'write'` lets you delete only your own work. A refusal on another author's
219
- item is the contract working, not a bug. ⚠ You cannot change permissions — yours or another agent's;
236
+ ⚠ `permission_scope: 'write'` lets you archive/remove only your own workspace items; editing layers
237
+ inside an editable canvas follows the update rule above. A permission refusal is the contract
238
+ working, not a bug. ⚠ You cannot change permissions — yours or another agent's;
220
239
  ask the owner.
221
240
 
222
241
  ## Traps that cost real time
223
242
 
224
243
  - ⚠ **`beehaven env` first.** `prod` and `staging` are different databases and `--env` does not
225
244
  exist on `call` — the daemon *is* the env. Every number is meaningless if you are on the wrong one.
226
- - ⚠ **A deploy does not reach a resident DO.** `beehaven stop && sleep 15 && beehaven start --headless`.
245
+ - ⚠ **Verify a deploy by the response's runtime version.** Allow propagation and retry read-only
246
+ checks; do not restart the user's daemon to force a resident DO onto a new version.
227
247
  - ⚠⚠ **Check the `as <agent>` on your first call.** An identity archived in this workspace still
228
248
  mints (identities are account-level), but the workspace refuses its session. Current CLIs say so
229
249
  (`⚠ Signed in, but this workspace refused …`, exit 1) and then refuse every call as that
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  name: clearly-canvas
3
3
  description: >-
4
+ Needs a terminal with the beehaven CLI (Claude Code, Codex, Gemini CLI); in a chat with only the Clearly connector, say so and use the clearly_* tools instead.
4
5
  Design and revise editable compositions on a Clearly canvas using the beehaven
5
6
  CLI: posters, campaigns, decks, page mockups, diagrams, spatial reviews, and
6
7
  project plans built from LIVE workspace objects (boards, tickets, documents,
@@ -19,22 +20,34 @@ The deliverable is a composition that communicates a specific idea at its intend
19
20
  viewing size, with editable, well-named layers. Successful RPCs prove that nodes were
20
21
  stored. A rendered image you have inspected is the evidence for visual quality.
21
22
 
23
+ Use the same working method as a designer in Figma: artboards, named editable layers,
24
+ text styles, reusable components, auto-layout and constraints; explicit responsive states;
25
+ then inspect the pixels and refine. Read `authoring.md` and discover the current catalog
26
+ before assuming an operation is missing. Typography defaults to Auto; use `140%` or `24px`
27
+ for explicit line heights. Keep unsupported capabilities and unverified rendering visible
28
+ in the handoff; a familiar workflow does not prove every Figma feature is implemented.
29
+
22
30
  For a small correction, keep the existing direction and make the smallest useful edit.
23
31
  For a new composition or substantial redesign, use the workflow below.
24
32
 
33
+ Keep the requested scope. A landing concept with a logo needs its page layouts and a usable
34
+ logo; add application boards or a full guideline system only when the brief calls for them.
35
+ Read only relevant references. Save large tool responses once and print compact summaries.
36
+
25
37
  ## The studio bar — what "done" means, every time
26
38
 
27
39
  Load **`design-craft`** before any new visual work: grid, type scale, colour roles,
28
40
  spacing, optical correction, the studio pass. It ships beside this skill; `layout-systems`
29
41
  covers multi-artboard grids. This skill covers the canvas mechanics.
30
42
 
31
- A composition is done when every requested artboard meets all four conditions:
43
+ A composition is done when every requested artboard meets all five conditions:
32
44
 
33
45
  1. **`canvas.review` verdict is `clean` or `look`.** `fix` means a probable defect
34
46
  remains: text colliding or covered, contrast under WCAG (4.5:1 body, 3:1 display),
35
47
  type below the artboard's legible floor, missing media, text overflowing its box,
36
- placeholder copy. Fix it. When it is deliberate, pass the check name or layer in
37
- `ignore` and say why in the handoff.
48
+ placeholder copy. Fix it. For an intentional finding, use
49
+ `accept:[{check,ids:[node IDs],reason}]`. Accepted findings stay visible and return `look`.
50
+ Legacy `ignore` can suppress multiple checks and is not an unconditional pass.
38
51
  2. **Every `look` finding was looked at**: type-size and palette sprawl, near-miss
39
52
  alignment, copy against the trim, text over imagery. Act on it or say why not.
40
53
  3. **You inspected the rendered PNG** against design-craft's studio pass, covering what no
@@ -42,6 +55,12 @@ A composition is done when every requested artboard meets all four conditions:
42
55
  one accent, orphans, consistency.
43
56
  4. **The first read works at delivery size.** At thumbnail size, the thing that should
44
57
  win does win.
58
+ 5. **The document behaves as a design.** Inspect its frame tree: sections and UI containers
59
+ own their contents and background fills; rows, stacks and grids use live auto layout
60
+ with deliberate Hug/Fill/Fixed sizing. Resize a representative container and lengthen
61
+ its copy on a duplicate, then verify reflow and containment. Keep intentional artwork
62
+ positioned inside named artwork frames. Record these checks separately from visual QA;
63
+ `canvas.review` does not prove hierarchy or reflow.
45
64
 
46
65
  A new composition almost always needs at least one revision after its first render. If
47
66
  the pass finds nothing, look again at the thumbnail. If there is still nothing, say what
@@ -54,8 +73,9 @@ build from them — redrawing a button the library already has is how designs dr
54
73
  product they describe.
55
74
 
56
75
  ```sh
57
- beehaven call brand-tokens '{}' # colours (light + dark), type roles, radius, logos, voice
58
- beehaven call component-list '{"query":"<brand or kind>"}' # parts, with props, variants and the code they mirror
76
+ beehaven call brand-tokens '{"compact":true}' # roles without repeated CSS/prose
77
+ beehaven call brand-import '{"url":"theirsite.com","dryRun":true}' # no brand yet? read it off their website
78
+ beehaven call component-list '{"query":"<kind>","compact":true}' # IDs, dimensions and prop names
59
79
  beehaven call component-instantiate '{"compositionId":"<id>","instances":[
60
80
  {"id":"<component>","x":96,"y":200,"variant":"Light"},
61
81
  {"id":"<component>","x":96,"y":280,"variant":"Light","props":{"label":"Save changes"}}]}'
@@ -68,8 +88,9 @@ beehaven call component-instantiate '{"compositionId":"<id>","instances":[
68
88
  `component-create` (or `{ fromCompositionId, nodeId }` to save one you drew).
69
89
  - Component node coordinates are relative to the component ROOT, even under an inner
70
90
  frame — the opposite of `canvas.create-node`, where x/y follow `parentId`.
71
- - If the workspace has a brand kit, it IS the system for the brief: use its roles, faces
72
- and voice rather than inventing a palette. Change the brand itself only when asked.
91
+ - For Clearly product UI, use its brand kit. For a separate client, use that client's kit
92
+ and supplied assets. A requested new client identity is scoped to that composition;
93
+ it does not change the workspace's default brand.
73
94
 
74
95
  **UX design before implementation.** When the work is a change to a product's UI, the
75
96
  composition is the design the code will answer to: show the real states (empty, loading,
@@ -103,10 +124,46 @@ can read and edit artifact records, while canvas-specific actions use the CLI.
103
124
  beehaven env
104
125
  beehaven connect home
105
126
  beehaven agent login <name> --label "Design <artifact>" --client cli
106
- beehaven call canvas-perceive '{"compositionId":"<id>","format":"json"}'
127
+ beehaven call canvas-perceive '{"compositionId":"<id>","outline":true}'
107
128
  beehaven call canvas-catalog '{"query":"create-node"}'
108
129
  ```
109
130
 
131
+ Read a canvas the way you read a repository: `canvas-perceive {outline:true}` is `tree` (artboards,
132
+ sections, layer counts, first copy, EMPTY sections — a few hundred bytes); `{frame:"<id or name>"}`
133
+ opens one frame like a file (its layers indented, positions relative to their parent);
134
+ `{find:"Start free"}` is `grep` (copy, layer names or `#hex`, with each match's frame path). Use
135
+ `format:"json"` only when you need every field of every node. Every `canvas-act` write returns
136
+ `diagnostics` — a lint of the artboards it touched (text overflow, collisions, covered text,
137
+ contrast) — treat them like compiler errors and fix them in the next batch. `canvas.review` is still
138
+ the pixel check and the ticket gate.
139
+
140
+ A canvas is planned like a git repository: its own plan board, a WORK TICKET for the request, and
141
+ COMMITS — one ticket per coherent layer or section of a larger change.
142
+ `design-start {title, brandId?}` makes a PRIVATE DRAFT canvas, bound to the brand, with its private
143
+ plan board and the work ticket, and returns `{ compositionId, ticketId, ticketKey, boardId, brand }`.
144
+ Same title again returns the same draft. Nothing is shared until it is filed:
145
+ `design-file {compositionId, projectId | projectTitle}` moves the canvas — plan board and every
146
+ ticket with it — into the project the person chose and sends the work ticket to in-review. Ask which
147
+ project unless they named one; a close-but-different title answers `similar-projects` with
148
+ candidates. Repeat-safe.
149
+ Plan a larger change before drawing, the way you would split a big code change into commits:
150
+ `design-plan {compositionId, commits: ["Grid, type and colour styles", "Nav", "Hero", …]}` (drafts
151
+ and filed canvases alike) adds ordered commit tickets under the work ticket. `sections: true` uses
152
+ the landing-page set (set up frames and styles, nav bar, hero, highlights, offer, story, call to
153
+ action, footer, mobile, states); `phases: true` and a `brief` add the studio method (brief, research,
154
+ structure, direction, design, review) — load the `design-process` skill. Order commits so each
155
+ builds on the last and can be reviewed alone. Build ONE commit per canvas-act batch that ends with
156
+ `canvas.review` of the artboard and carries
157
+ `"ticket":{"id":"<key>","status":"done","resolution":"<what changed>"}` — it lands only if that
158
+ review is clean or look; `result.ticket` says whether it did, and the ticket logs the canvas
159
+ revision and the layers the commit changed. Auto-layout, gradients, shadows, drawing and placeholders:
160
+ see "Technique" in [authoring.md](authoring.md).
161
+
162
+ `composition-board-get {compositionId}` reads the plan back. `design-start` with a project, ticket or
163
+ `phases` still sets up planned work directly (kept for one release).
164
+ For an existing task, reuse its ticket/project. Check one unknown action with
165
+ `beehaven explain <action>` or a filtered catalog; do not download the entire registry.
166
+
110
167
  Use the composition supplied by the user. If none is named, inspect recent titles and
111
168
  context; create a clearly titled composition for new work instead of modifying an
112
169
  arbitrary recent canvas. File shared work into its project.
@@ -161,8 +218,11 @@ hand-author hundreds of coordinates in a chat message.
161
218
  Check contrast on the actual ground. Use the user's real brand assets.
162
219
  - Choose relevant imagery, a meaningful diagram, a product view or a deliberate
163
220
  typographic treatment. Decorative blobs and random stock photos do not prove a
164
- product claim. Native SVG/paths suit diagrams and vector art; raster generation
165
- suits imagery when an image tool is available.
221
+ product claim. Draw marks, icons, illustrations and diagrams yourself from native
222
+ layers (shapes, vector.create pen paths, text, groups), the way a designer works in
223
+ Figma, so every part stays named and editable. Raster generation suits photographic
224
+ imagery when an image tool is available. Raw SVG (an svg node, or a generated SVG)
225
+ is for importing an existing file or a requested SVG, never the default.
166
226
  - Define repeated components once. Vary composition where the content changes.
167
227
  A deck of identical cards has little rhythm even when every card aligns.
168
228
  - Keep important copy and layers editable. Do not flatten the whole composition
@@ -188,6 +248,10 @@ For a single page, establish the complete hierarchy before polishing small detai
188
248
  Use a batch for each coherent build or revision, with descriptive unique layer names.
189
249
  Parent content to its artboard. Inspect every operation result and rollback status.
190
250
  Save your builder and returned IDs so revisions are targeted and reproducible.
251
+ Check `ignoredFields`, `rejectedFields`, `warnings`, `outcome` and `canvasChanges` as well as
252
+ `ok/count`. `matched` is not `updated`. An unchanged or partly ignored request does not prove
253
+ the intended edit happened. Read `composition-detail {includeScene:true}` from its top-level
254
+ `nodes`; never treat a missing response field as an empty scene. Keep executed payloads immutable.
191
255
 
192
256
  ⚠ **Batch, never loop.** One `canvas-act` batch of hundreds of steps is one scene read,
193
257
  persisted every 50 steps, and the workspace stays responsive for everyone in it while it
@@ -225,6 +289,12 @@ It invokes `canvas.review` on one persisted snapshot and returns:
225
289
  type and palette sprawl, near-miss edges, trim crowding, text over imagery;
226
290
  - the placeholder/overflow audit, measured text fit, and a preview PNG.
227
291
 
292
+ For several artboards, write their IDs/names as a JSON array and use:
293
+ `node <skill-directory>/review.mjs --many <composition-id> <ids.json> <output-directory>`.
294
+ This uses `canvas.review-many`: one scene read, separate findings per artboard and compact
295
+ preview handles. Review only artboards changed since their verified snapshot. The helper versions
296
+ existing output paths so before/after evidence is retained.
297
+
228
298
  The helper prints the verdict and every finding. Work until the verdict is `clean` or
229
299
  `look`, as described in the studio bar above. If the installed worker lacks `canvas.review`,
230
300
  use a real frame ID with `--perceive` for a preview-only check and run the text measurement
@@ -232,9 +302,16 @@ and audit separately. A failed or missing render means visual verification is in
232
302
 
233
303
  ```sh
234
304
  # A deliberate finding — say why in the handoff:
235
- beehaven call canvas-act '{"compositionId":"<id>","action":"canvas.review","args":{"ids":["<frame>"],"ignore":["text-over-image"]}}'
305
+ beehaven call canvas-act '{"compositionId":"<id>","action":"canvas.review","args":{"ids":["<frame>"],"accept":[{"check":"text-over-image","ids":["<text-id>","<image-id>"],"reason":"Intentional type over this photograph; rendered contrast was inspected."}]}}'
236
306
  ```
237
307
 
308
+ Asset storage is a reference-aware pipeline: an SVG may have `svgRef` instead of inline markup.
309
+ Do not shrink or recreate it just because the inline field is absent. Replace it with
310
+ `canvas.update-nodes {ids, patch:{svg:<complete markup>}}`; references are managed by the action.
311
+ Use `canvas.fonts` before choosing an unfamiliar family/weight. Fallback metrics are not exact.
312
+ Use `canvas.editor-state {requireLive:true,includePixels:true}` to verify the responding editor.
313
+ An agent camera and a navigation delivery count do not prove the person's view was framed.
314
+
238
315
  Inspect the actual image and identify concrete defects, not generic praise:
239
316
 
240
317
  | Lens | What to judge |
@@ -10,8 +10,8 @@ Use a local builder and pass JSON through `@file` or stdin. Do not interpolate c
10
10
  SVG or code into shell strings. Here is a minimal native-node pattern; replace its
11
11
  visual decisions with the brief's system:
12
12
 
13
- For a complete editable three-artboard example, inspect [example.mjs](example.mjs).
14
- It demonstrates tokens, reusable helpers and varied compositions; it writes a payload
13
+ For desktop, mobile and dark examples, inspect [example.mjs](example.mjs).
14
+ It demonstrates nested flow containers, Hug/Fill sizing and framed artwork; it writes a payload
15
15
  without making remote calls. Run `node <skill-directory>/example.mjs <composition-id>`.
16
16
  Use its construction approach, not its fictional brand or aesthetic, for other briefs.
17
17
 
@@ -21,18 +21,22 @@ const compositionId = process.argv[2];
21
21
  const grid = { w: 1440, h: 900, margin: 88, gap: 24 };
22
22
  const color = { paper: '#F3F0E8', ink: '#172824', accent: '#CB482F' };
23
23
  const type = {
24
- display: { family: 'Inter', size: 88, fontWeight: 700, lineHeight: 1.05, letterSpacing: -2 },
25
- body: { family: 'Inter', size: 24, fontWeight: 400, lineHeight: 1.4 },
24
+ display: { family: 'Inter', size: 88, fontWeight: 700, lineHeight: '105%', letterSpacing: -2 },
25
+ body: { family: 'Inter', size: 24, fontWeight: 400, lineHeight: '140%' },
26
26
  };
27
27
  const batch = [];
28
28
  const add = (action, args) => batch.push({ action, args });
29
29
  add('frame.create', { name: '01-opening', x: 0, y: 0, w: grid.w, h: grid.h, fill: color.paper });
30
- const text = (name, copy, x, y, w, role) => add('canvas.create-node', {
31
- name, type: 'text', parentId: '01-opening', x, y, w,
30
+ add('frame.create', { name: 'hero-copy', parentId: '01-opening', w: 740, h: 400, fill: 'transparent' });
31
+ const text = (name, copy, role) => add('canvas.create-node', {
32
+ name, type: 'text', parentId: 'hero-copy', w: 740,
32
33
  text: copy, fill: color.ink, ...type[role],
33
34
  });
34
- text('opening-title', 'Ideas take\nshape here.', grid.margin, 120, 740, 'display');
35
- text('opening-deck', 'An editable visual system for the next chapter.', grid.margin, 360, 580, 'body');
35
+ text('opening-title', 'Ideas take shape here.', 'display');
36
+ text('opening-deck', 'An editable visual system for the next chapter.', 'body');
37
+ add('canvas.update-nodes', { ids: ['opening-title', 'opening-deck'], patch: { layoutSizingH: 'fill' } });
38
+ add('canvas.auto-layout', { id: 'hero-copy', direction: 'v', gap: 24, sizingH: 'fixed', sizingV: 'hug' });
39
+ add('canvas.auto-layout', { id: '01-opening', direction: 'v', gap: 64, padding: grid.margin, sizingH: 'fixed', sizingV: 'hug' });
36
40
  // Continue with the brief's central visual, supporting evidence and footer.
37
41
  writeFileSync('/tmp/canvas-build.json', JSON.stringify({ compositionId, batch }));
38
42
  ```
@@ -49,8 +53,21 @@ do not blindly resend only skipped operations. Mixed live/headless actions may h
49
53
  different rollback behavior. Use deterministic layer names and returned IDs to avoid
50
54
  duplicate content during retries.
51
55
 
56
+ Also check ignored/rejected fields, warnings, mutation outcome and actual changed IDs. A matched
57
+ node or `ok:true` receipt alone is not proof of an update. The bundled `assertReceipt` helper can
58
+ reject partial drops; `requireChange:true` rejects an unexpected no-op. A deliberate replay may
59
+ be unchanged and should reuse its previous evidence instead of recreating nodes.
60
+ Keep executed payloads and returned-ID manifests separate from regenerated plans.
61
+
52
62
  ## Node shape and coordinates
53
63
 
64
+ Choose ownership before coordinates: page → section → row/stack/grid → content. Put
65
+ the container's background, border and radius on its frame. Auto layout owns positions
66
+ in content flow; use Hug for content height and Fill for flexible width. Keep deliberate
67
+ overlays and illustrations inside artwork frames. A native editable layer alone does
68
+ not establish a usable document structure. Frames also make scoped perception cheaper:
69
+ read the outline and the section you are editing instead of a full scene dump.
70
+
54
71
  Fields are flat: `{name,type,x,y,w,h,text,size,family,fontWeight,fill,...}`.
55
72
  Use `text` for copy, `size` for type size, numeric `fontWeight`, and `w`/`h` for bounds.
56
73
  Create normalizes hex colours; raw stored scenes use RGBA arrays in 0..1.
@@ -71,12 +88,27 @@ Create normalizes hex colours; raw stored scenes use RGBA arrays in 0..1.
71
88
  moves/resizes use the catalog's frame/arrangement/scale actions; do not assume a patch
72
89
  reflows children.
73
90
  - Build backgrounds before foregrounds. Use `canvas.order` to change stacking.
91
+
92
+ For create/update geometry, `coordinateSpace:"world"` or `"parent"` makes the intent explicit.
93
+ Default behavior remains compatible with the rules above. Receipts include normalized world
94
+ bounds and parent offsets where available. Template coordinates remain relative to their root.
95
+ An SVG's bytes may be stored in `svgRef` once it exceeds the inline limit; this is valid artwork,
96
+ not a missing node. Replacing `svg` clears and rebuilds its reference automatically. Never patch
97
+ `svgRef` manually or guess its storage URL. Image `fit` is explicitly `contain` or `cover`.
74
98
  - Name nodes uniquely; use returned IDs where names collide. Parent content to its
75
99
  frame so movement, selection, clipping and reviews can treat it as one artifact.
76
100
  - Give an intended stroke both `stroke` and `strokeWidth`. Zero explicitly removes it.
77
101
 
78
102
  ## Typography
79
103
 
104
+ Line height defaults to **Auto**, from the font itself. Use `lineHeight:"140%"` for a
105
+ percentage of font size or `lineHeight:"24px"` for fixed leading. Numeric values in old
106
+ scenes remain multipliers (`1.4` = `140%`); new designs should carry explicit units.
107
+ Changing font size scales % leading and leaves px leading fixed. Paragraph spacing is
108
+ `paragraphSpacing` in px after a hard newline, never a soft wrap. In a fixed-height
109
+ box, `vAlign:"middle"` centers the line boxes; `"bottom"` anchors their bottom. Do not
110
+ compensate with spaces, empty lines or hand-tuned y offsets.
111
+
80
112
  For prose, set `w` and omit `h` to enable auto-height. Omit both axes only for short
81
113
  single-line labels whose width should hug content. A fixed box sets that axis explicitly;
82
114
  it does not guarantee text will clip safely. Headless auto-height is an estimate from
@@ -86,7 +118,7 @@ then inspect the rendered result in the editor.
86
118
  ```json
87
119
  {"compositionId":"<id>","action":"canvas.measure-text","args":{
88
120
  "text":"Ideas take shape here.","family":"Inter","size":88,"fontWeight":700,
89
- "letterSpacing":-2,"lineHeight":1.05,"maxWidth":740}}
121
+ "letterSpacing":-2,"lineHeight":"105%","maxWidth":740}}
90
122
  ```
91
123
 
92
124
  Use measured `height`/`lineCount` to place the next block. Measure the exact copy, font,
@@ -106,8 +138,27 @@ and tokens when relevant. Constraints reflow children on frame resize; they do n
106
138
  a static canvas into a responsive website. Design explicit mobile artboards when the
107
139
  deliverable requires them, with content order and hierarchy reconsidered for the width.
108
140
 
141
+ ## Technique
142
+
143
+ - CONTAINERS: page sections, cards, sidebars and toolbars are named frames that own their content and background fill. Use live auto-layout for content rows, stacks and grids, with explicit Hug/Fill/Fixed sizing; position overlays and artwork deliberately within their owning frames. A rectangle behind sibling text is not a container. Verify the frame tree, resize a representative container and lengthen its copy on a duplicate before completion; record reflow checks separately from pixel review.
144
+ - FIGMA WORKFLOW: approach this canvas as a designer working in Figma. Read the brand and component library; compose artboards from named editable frames, text, shapes and component instances; use auto-layout, constraints, styles and variables; create deliberate desktop/mobile and light/dark states; inspect at delivery size, iterate, then review the final edit. Discover the current canvas-catalog before assuming a familiar Figma operation is unavailable. Its headlessActions identify what runs without an open editor; live-only actions need an editor. Report an unsupported capability accurately rather than inventing an operation or claiming universal feature parity.
145
+
146
+ - TYPOGRAPHY: lineHeight defaults to "auto", using the resolved font metrics. Author percentages as "140%" and absolute leading as "24px"; legacy numeric 1.4 still means 140%. Percentage leading follows font size; px leading stays fixed until the Scale tool scales the artwork. paragraphSpacing is px between hard-newline paragraphs, never soft wraps. For Auto width omit w/h; for Auto height set w and omit h; for a fixed box set w/h. Explicit layoutSizingH/V "fixed" or "fill" overrides legacy autoWidth/autoHeight. align is left|center|right|justify; vAlign is top|middle|bottom and applies to fixed-height boxes. Measure exact copy/font/weight/width using canvas.measure-text, then inspect the pixels; do not center text with spaces or arbitrary y offsets.
147
+
148
+ The same rules the in-app assistant works to (canvas-catalog returns them as `technique`).
149
+
150
+ - AUTO-LAYOUT: rows, stacks and grids are a frame whose children you create in reading order, then canvas.auto-layout { id, direction: "h" | "v" | "grid", gap, padding, align, justify, hug }. hug:false keeps the frame size; justify "space-between" | "space-around" | "space-evenly" are the Auto gaps; align:"baseline" lines up text in a row. Grids take columns, rows, columnGap, rowGap, columnSizes / rowSizes ("fill", "2fr", "hug", px). wrap:true flows into new rows; give Fill cards a minW so they wrap where you mean. Child settings go on the child via canvas.update-nodes: layoutSizingH/V "fill" | "hug" | "fixed", minW / maxW / minH / maxH, gridColumn / gridRow / gridColumnSpan, layoutPositioning:"absolute". The frame stays live: children created into it (parentId) flow in. Spacing variables: canvas.variable { op: "bind", ids, field, name }.
151
+ - GRADIENTS: gradient { kind, angle, stops: [{ offset, color }] } replaces the solid fill. angle is the direction the colour travels: 0 = left to right, 90 = top to bottom, 45 = top-left to bottom-right (not CSS degrees). Use two or three stops from the brand palette, and keep text off a busy gradient or check its contrast in canvas.review.
152
+ - SHADOWS AND BLUR: effects on any node. A soft card shadow is { type: "drop-shadow", x: 0, y: 4, blur: 16, spread: 0, color: "#0000001F" }; frosted glass is { type: "background-blur", blur: 16 }. Never fake a shadow with an extra rectangle.
153
+ - DRAWING: build every mark, icon, illustration and diagram shape from native layers, as a designer does in Figma, never as one generated SVG file. Primitives are canvas.create-node rect and ellipse; curves are pen paths, vector.create { name, parentId, points: [{ x, y, hIn?: { x, y }, hOut?: { x, y } }], closed, fill or stroke, strokeWidth }, where hIn/hOut are absolute control points: use few anchors with smooth handles. It also takes d (SVG path data, converted to native editable points) or shape: petal|circle|polygon|star|arc|spiral with cx, cy and sizes; strokeCap/strokeJoin apply. Reshape in place with canvas.update-nodes { ids, patch: { points | d | shape } }. Draw a repeated part once: canvas.repeat { id, count, around | cx, cy } turns one petal into a flower; canvas.rotate { ids, angle, cx, cy }; canvas.boolean { ids, op: "union" | "subtract" | "intersect" | "exclude" } (exact, editable operands). Work back to front: ground, big silhouettes in flat brand colours, then features, then details and highlights; check the silhouette in canvas.review before detailing. Name layers by part ("fox/ear-left"), group each figure with canvas.group { ids, name } and set overlap with canvas.order { ids, op }. Keep one stroke weight per drawing. Photographic or painterly imagery is a placed raster. Raw SVG stays supported but is never the default: when an SVG is asked for, write the markup yourself as an svg node, canvas.create-node { type: "svg", name, w, h, svg } with <svg viewBox="0 0 W H"> matching w and h, or import existing markup the same way; never an SVG generation pipeline.
154
+ - COMPUTED GEOMETRY: shapes from math (radial petals, spirals, grids) are computed and drawn in ONE call: canvas-act { compositionId, script } runs JavaScript with geo.petal/circle/arc/star/polygon/spiral/smooth/rotate/radial/grid/bounds (degrees, 0 = 3 o'clock, clockwise) and a read-only scene list, then applies the { action, args } steps it returns. Never copy numbers from one tool result into another call.
155
+ - SHEETS: several concepts or variants go on canvas.sheet { name, title, subtitle, cards or count, cols, cardW, cardH }: a live wrap grid of card frames that own their captions, so rows never overlap. Draw into a card with parentId = its id.
156
+ - MEASURE: answer spacing, overlap and alignment questions with canvas.measure { frame } or { ids } and quote its numbers, never from memory or a preview.
157
+ - PLACEHOLDERS: until real imagery exists, draw a native placeholder at the final size in a muted brand tone, never a flat accent block: a rect with the slot radius plus a simple motif (an ellipse sun, a vector.create mountain), grouped with canvas.group and named "<section> image placeholder", with any label in its own text node.
158
+ - SECTIONS: one frame per page section, named exactly as its ticket says, inside the page artboard. Build a section in one canvas-act batch that ends with canvas.review of the artboard and carries ticket: { id: "<its key>", status: "done", resolution: "<what changed>" }. The ticket moves only when that review is clean or look; result.ticket says whether it did. Then start the next section.
159
+
109
160
  Use `arrow.create {from,to,routing,label}` for connected diagrams, so arrows remain bound
110
- when nodes move. Use native shapes and SVG for custom vector details. Keep labels as
161
+ when nodes move. Draw custom vector details natively (shapes, vector.create pen paths); raw SVG only imports an existing file. Keep labels as
111
162
  native text so they remain editable and measurable.
112
163
 
113
164
  Use `canvas.place {kind,id,x,y,w,h,name,parentId?}` to put a workspace object (document,