@clearlysh/beehaven 0.8.29 → 0.8.31

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.
@@ -0,0 +1,89 @@
1
+ ---
2
+ name: clearly-workflows
3
+ description: >-
4
+ Use the Clearly workspace as a COMPANY BRAIN — search the org's accumulated
5
+ context (decisions, facts, prompts, docs), write conclusions back so the next
6
+ agent inherits them instead of re-deriving them, and inherit the team's
7
+ skills. Use when a question is about what this company already decided or
8
+ knows, and after you work something out that the next person would otherwise
9
+ rediscover. Triggers: "what did we decide", "why did we do it this way", "has
10
+ anyone looked at this", "remember this", "write that down", "what do we know
11
+ about X", "company context", "our decisions", "prior art", "institutional
12
+ knowledge", "so nobody has to work this out again".
13
+ ---
14
+
15
+ > **Tool names below are written UNPREFIXED** (`clearly_read`). Your runtime may
16
+ > expose them with a server prefix — e.g.
17
+ > `mcp__plugin_clearly_clearly-staging__clearly_read`. **Match by suffix, not by
18
+ > exact name**: a skill written against the bare name resolves to nothing otherwise, and
19
+ > the failure looks like "the tool doesn't exist" rather than "the name is decorated".
20
+ >
21
+ > **If no such tool is callable at all**, the Clearly MCP server isn't authorised in this
22
+ > session — note that these skills still LIST when it isn't, so you find out by firing a
23
+ > dead call. Authorise it (`/mcp`, or `claude mcp`), or if you have a shell, use the
24
+ > `beehaven` CLI and its own `clearly-canvas` skill instead.
25
+
26
+ # Working a Clearly workspace (Company Brain)
27
+
28
+ Clearly is a **company brain over MCP**: every prompt + agent response is auto-cataloged into a searchable, ranked archive, with documents, decisions, and durable facts alongside. Treat it the way you'd treat a repo — read before you write, and write so the next agent inherits your work.
29
+
30
+ If the `clearly` server isn't connected yet, run the `clearly-init` skill first.
31
+
32
+ ## 1. Orient before you act
33
+
34
+ Run `beehaven call context-map` once at the start. It returns the brain's size (prompts / responses / facts), the recurring topics, and the org/teams it can federate across. Use it to decide whether the answer already exists.
35
+
36
+ ## 2. Retrieve context (don't re-derive it)
37
+
38
+ `beehaven call context-search '{ "query": …, "scope"?, "kinds"?, "limit"? }'` is ONE ranked search across prompts, agent responses, documents/PRDs, and facts — use it instead of guessing or asking the user what they already decided.
39
+
40
+ - `scope: "workspace"` (default) searches this workspace.
41
+ - `scope: "org"` **federates across every workspace in the org**, merges + re-ranks by relevance, and excludes private artifacts + personal facts. Use it for "what has anyone on the team decided/built about X".
42
+ - `kinds`: narrow to `["document"]`, `["prompt"]`, etc.
43
+
44
+ Each hit carries `kind`, `ref` (the id to fetch in full), `title`, `snippet`, `score`, and `meta` (intent, tags, `sourceWorkspace`).
45
+
46
+ **Always search before writing** — it prevents duplicate PRDs/decisions and surfaces prior context you'd otherwise miss.
47
+
48
+ ## 3. Write context BACK so it compounds
49
+
50
+ When you produce something durable — a PRD, a decision, a spec, a research summary — file it with `context-write`:
51
+
52
+ ```jsonc
53
+ beehaven call context-write '{
54
+ "title": "Per-seat billing decision",
55
+ "body": "We charge per seat; usage is per-seat with shared top-up overflow. Rationale: …",
56
+ "kind": "decision", // doc | note | decision | prd
57
+ "tags": ["billing","pricing"],
58
+ "fact": "Billing is per-seat with shared top-up", // optional one-line takeaway
59
+ "private": false // true → workspace-local, never federated across the org
60
+ }'
61
+ ```
62
+
63
+ It creates the document AND files a searchable catalog entry, so the very next `context-search` finds it. Mark anything sensitive `private: true`.
64
+
65
+ ⚠ **Why these are CLI calls and not MCP tools.** The MCP surface is seven tools split by what they do to an artifact (`clearly_catalog · _read · _write · _edit · _delete · _grep · _glob`); the Company Brain's verbs are workspace ACTIONS, reached by name through the shell. Once a document exists, `clearly_grep` and `clearly_read` open it like any other.
66
+
67
+ ## 4. Inherit the team's skills
68
+
69
+ The workspace has its own skills (procedures the team grew). Before improvising a multi-step task, check whether one exists:
70
+
71
+ - `beehaven call skill-list '{"includeWorkspace":true}'` → the skill cards (name + when-to-use).
72
+ - `beehaven call skill-get '{"id":"…"}'` → the full step-by-step instructions for the one whose trigger matches.
73
+
74
+ Follow the loaded procedure rather than inventing your own — that's how you work *the way this workspace works*.
75
+
76
+ ## Anything else
77
+
78
+ `beehaven actions` lists every workspace action with its description; `beehaven call <action> '<json>'` runs one. Reach for these when the seven MCP tools don't cover what you need — which is most things beyond reading, writing and searching artifacts.
79
+
80
+ ## Rules of thumb
81
+
82
+ - **Read → act → write back.** Search first; file durable outcomes so they persist.
83
+ - **`scope:"org"`** for cross-team questions; **`private:true`** for sensitive writes.
84
+
85
+ <!-- A "Schedule your future self" section documenting `clearly_schedule_wake` was removed on
86
+ 2026-08-02: the tool is in ZERO entries of mcp-server.ts's tool list and `schedule-wake` is
87
+ not a registered RPC, so every example here failed. Restore only when it is in tools/list. -->
88
+
89
+ - **Check `beehaven call skill-list`** before hand-rolling a known procedure.
package/skills/index.json CHANGED
@@ -17,7 +17,7 @@
17
17
  "project-plans.md",
18
18
  "review.mjs"
19
19
  ],
20
- "sha": "7d79406b37f611a8"
20
+ "sha": "b942eebe6f0397fb"
21
21
  },
22
22
  {
23
23
  "name": "agent-home",
@@ -53,7 +53,7 @@
53
53
  "files": [
54
54
  "SKILL.md"
55
55
  ],
56
- "sha": "cd891499599ccb7b"
56
+ "sha": "755db2d1ab8c759f"
57
57
  },
58
58
  {
59
59
  "name": "pair-on-canvas",
@@ -83,5 +83,40 @@
83
83
  "SKILL.md"
84
84
  ],
85
85
  "sha": "b3f47988cb9235b9"
86
+ },
87
+ {
88
+ "name": "visualize",
89
+ "files": [
90
+ "SKILL.md"
91
+ ],
92
+ "sha": "ce9410c1ba7b3457"
93
+ },
94
+ {
95
+ "name": "sticker-pack",
96
+ "files": [
97
+ "SKILL.md"
98
+ ],
99
+ "sha": "f029503ebae59c64"
100
+ },
101
+ {
102
+ "name": "clearly-docs",
103
+ "files": [
104
+ "SKILL.md"
105
+ ],
106
+ "sha": "388be4de86f59eb4"
107
+ },
108
+ {
109
+ "name": "clearly-init",
110
+ "files": [
111
+ "SKILL.md"
112
+ ],
113
+ "sha": "d4dfdd76c7c0a108"
114
+ },
115
+ {
116
+ "name": "clearly-workflows",
117
+ "files": [
118
+ "SKILL.md"
119
+ ],
120
+ "sha": "f26dbbc90929ebe7"
86
121
  }
87
122
  ]
@@ -0,0 +1,132 @@
1
+ ---
2
+ name: sticker-pack
3
+ description: Turn an idea into a printable, die-cut STICKER SHEET on a Clearly canvas — Clearly's own sticker-vending-machine pipeline surfaced as an agent skill. Generates a cohesive SET of transparent stickers, lays them out as a sheet (frame + gridded stickers + a vector kiss-cut cutline layer), and hands back a print-ready bundle. Load this when the user says "make me stickers / a sticker pack / a sticker sheet about X", "turn this into stickers", "design stickers for my brand / startup / cat", or "I want die-cut stickers". The fun, inherently-shareable corner of the canvas skill set.
4
+ ---
5
+
6
+ > **⚠ CANVAS AND STICKER WORK GO THROUGH THE CLI, NOT AN MCP TOOL.** Anything written
7
+ > `beehaven call <action>` below is a literal command. The MCP surface is seven tools split
8
+ > by operation; the ~1,000 workspace actions are reached by name through the shell.
9
+
10
+ # Sticker pack — idea → printable die-cut sheet
11
+
12
+ Stickers are the most organically viral thing Clearly makes: a generated die-cut pack someone actually prints and slaps on a laptop *is* the share. This skill drives Clearly's real sticker-vending pipeline — the same one behind the studio — straight onto a canvas.
13
+
14
+ Install the `beehaven` CLI, sign in as an agent, and connect the intended workspace first
15
+ (`clearly-init` handles setup). Then read `clearly-canvas` for the primitives and the
16
+ perceive→act→revise loop. This skill adds the **generation** step on top of it.
17
+
18
+ ## The one core tool (and a heads-up)
19
+
20
+ The sticker pipeline runs through **`sticker-sheet-gen`**, a real workspace action. It is NOT (yet) a dedicated MCP tool, so you call it through the generic dispatcher:
21
+
22
+ ```jsonc
23
+ beehaven call sticker-sheet-gen '{ … }'
24
+ ```
25
+
26
+ > ⚠ **This is a CLI action, not an MCP tool, and that is settled rather than pending.**
27
+ > `clearly_sticker_generate` **does not exist** and is not planned — an earlier version of this
28
+ > note called it a missing piece. The MCP surface is seven tools split by operation, and a
29
+ > per-feature tool for every workspace action is the 139-tool surface that was withdrawn. The
30
+ > action is production code — the same pipeline the paid studio uses — and the CLI reaches it with
31
+ > full attribution.
32
+
33
+ **It is slow (30–90s), async, and costs the user a sheet credit.** Pass a `compositionId` and the pipeline does the canvas work for you: when the art lands, it places a **transparent parent frame ("Sticker sheet")**, every cut-out sticker nested as its own `image` node (drag one out!), and the **die-cut contour as a nested vector `svg` layer ("Cutline (kiss-cut)")**. The cutline is true vector — exported as the spot cut layer, never rasterized.
34
+
35
+ The call awaits the pipeline (racing a 90s timeout) so you usually get the **full result back** — `{ ok, sheetId, stickerCount, sheetUrl, placed }`. If it ran long you get `{ sessionId, timedOut: true }`; then perceive until the frame appears (see step 2).
36
+
37
+ ## 1. Brief — turn the idea into a cohesive set
38
+
39
+ Don't just forward the user's sentence. Shape it into a **set with a through-line**: one subject family, one style, one palette, consistent line weight. Then list the concepts back before spending the credit.
40
+
41
+ > *"Stickers for your plant shop — I'm thinking a cohesive 9-sticker set, flat-color cottagecore, sage + terracotta palette, chunky outlines: 1) monstera leaf, 2) watering can, 3) 'plant mom' badge, 4) terracotta pot, 5) snail, 6) sun, 7) 'grow' lettering, 8) seed packet, 9) trowel. Generate this sheet?"*
42
+
43
+ A sticker sheet is ONE generation, not N — the model draws the whole cohesive grid. So the brief = the `prompt` (subject + vibe + palette), plus `style` and `stickerCount`.
44
+
45
+ ## 2. Generate — one call, drop on the canvas
46
+
47
+ Make a canvas first (or reuse one), then fire the gen with `compositionId` so it lands:
48
+
49
+ ```jsonc
50
+ beehaven call composition-create '{ "title": "Plant shop stickers" }'
51
+ // → { "id": "c_…" }
52
+
53
+ beehaven call sticker-sheet-gen '{
54
+ "compositionId": "c_…",
55
+ "prompt": "cottagecore plant-shop stickers: monstera leaf, watering can, terracotta pot, snail, sun, seed packet — flat color, chunky outlines, sage green + terracotta palette",
56
+ "style": "cottagecore",
57
+ "stickerCount": 9,
58
+ "bleedStyle": "halo",
59
+ "aspectRatio": "2:3"
60
+ }'
61
+ // → { ok:true, sheetId:"sht_…", stickerCount:9, sheetUrl:"https://…", placed:{ stickers:9, cutline:true } }
62
+ ```
63
+
64
+ Input shape (all optional except `prompt`):
65
+
66
+ | Field | Meaning |
67
+ |---|---|
68
+ | `prompt`* | what the stickers depict — subject, vibe, palette |
69
+ | `compositionId` | **pass it** — the canvas to drop the sheet onto (placeholder + frame + cutline) |
70
+ | `style` | preset: `kawaii`, `planner`, `cottagecore`, `doodle`, … (omit → inferred) |
71
+ | `stickerCount` | stickers on the sheet (e.g. 9, 16, 30). Default 30 |
72
+ | `bleedStyle` | `halo` (default — white sticker outline) or `full-bleed` |
73
+ | `aspectRatio` | sheet ratio: `1:1` `2:3` `3:2` `3:4` `4:3` `9:16` `16:9` |
74
+ | `quality` | `standard` (default, 4K) or `premium` |
75
+ | `seed` | reproducibility |
76
+
77
+ **Handle the async/loading case.** If the response is `{ sessionId, timedOut: true }` (no `placed`), the gen is still running — the ⏳ placeholder is already on the canvas. Poll until the real frame lands:
78
+
79
+ ```jsonc
80
+ canvas-perceive { "compositionId": "c_…", "format": "text" }
81
+ // look in `contents` for a frame named "Sticker sheet" with image children
82
+ // + an svg layer "Cutline (kiss-cut)". When it's there, the sheet is done.
83
+ ```
84
+
85
+ On a hard failure the response carries an `error` (`no_exports_remaining` → user needs to buy a sheet; `rate_limit_exceeded` → back off `retryAfter`s) and the credit is auto-refunded — relay that plainly, don't retry blindly.
86
+
87
+ ## 3. The sheet is already laid out — make it presentable
88
+
89
+ The pipeline placed the frame, the cut-out stickers (gridded, native pixel size), and the cutline layer in ONE write. Your job is polish, via `canvas-act` (see `clearly-canvas`):
90
+
91
+ - **Perceive first**, read the `backgroundColor`, then drop a `text` title over the frame: "Plant shop · 9 stickers · kiss-cut".
92
+ - A tiny caption noting the **"Cutline (kiss-cut)"** layer is the spot cut path (vector) — toggle it to preview the die-cut.
93
+ - If the grid is cramped, `canvas.update-nodes` to nudge the frame into the user's `gaze`.
94
+
95
+ Don't rebuild the grid by hand — the pipeline already nested everything correctly. Only add labels + framing context.
96
+
97
+ ## 4. Export — the printable bundle
98
+
99
+ When they're happy, pull the print kit:
100
+
101
+ ```jsonc
102
+ beehaven call sticker-sheet-export '{ "sheetId": "sht_…" }'
103
+ // → { zipUrl, pdfUrl, sheetUrl, stickerUrls:[…], stickerCount, hasCutFile:true }
104
+ ```
105
+
106
+ - `zipUrl` — the FULL kit: print-ready **PDF** + **cut-file SVG** (the spot cut layer) + every individual sticker PNG + the composited sheet.
107
+ - `pdfUrl` — drop straight into a Cricut / Roland / Stickermule flow.
108
+ - Omit `sheetId` to export their most recent sheet.
109
+
110
+ Hand the user the `pdfUrl` / `zipUrl` and tell them the SVG cut file is what a plotter reads for the die-cut contour.
111
+
112
+ ## 5. Keep the human in the loop
113
+
114
+ The whole point of the canvas is steering by gesture. After the sheet lands: *"It's on your canvas — tell me 'more like #2', 'swap to a blue palette', or 'add a cat'."* Then re-run `sticker-sheet-gen` with the revised `prompt`/`style`/`seed` (reuse `seed` to keep a look, change it to re-roll), and re-perceive. Iterate until they love it, *then* export.
115
+
116
+ ## The viral bit
117
+
118
+ A real die-cut pack — transparent stickers, a visible kiss-cut contour, a print-ready PDF the user actually sends to a sticker printer — is the single most shareable output Clearly has. People post the laptop, not the prompt. So make every sheet land clean: cohesive set, honest cutline, one screenshot that reads as "I generated these and printed them." The sticker IS the share.
119
+
120
+ ## Single-sticker fallback
121
+
122
+ For ONE vector sticker (not a sheet), draw it natively with `canvas-act` like a designer: shapes and `vector.create` pen paths in a frame, named and grouped, with the white border as its own closed path behind the art. Use `studio-image-generate` for a painterly raster sticker, and `format:'svg'` only when a generated SVG file is asked for. If `sticker-sheet-gen` is ever unavailable, the manual sheet = `studio-image-generate` per concept (transparent), then `canvas-act` → `frame.create` + one `canvas.create-node {type:'image'}` per sticker on a grid + a closed `vector.create` cutline outline. But that's the cold path — the pipeline above is the real, supported one.
123
+
124
+ ## Rules of thumb
125
+
126
+ - **One gen = one whole sheet.** Don't loop the call per sticker; the model draws the cohesive grid in a single pass.
127
+ - **Always pass `compositionId`** — that's what lands the placeholder, frame, stickers, and cutline. No `compositionId` = no canvas output.
128
+ - **It's slow + costs a credit.** Confirm the brief BEFORE generating; relay `no_exports_remaining` / `rate_limit_exceeded` plainly (credit auto-refunds on failure).
129
+ - **`timedOut:true` ≠ failed** — the gen is still running; `canvas-perceive` until the "Sticker sheet" frame appears.
130
+ - **The cutline is vector** ("Cutline (kiss-cut)" svg layer) — it's the spot cut path; the export SVG/PDF is what a plotter cuts.
131
+ - **Iterate by re-genning**, reuse `seed` to hold a look, then **export last**.
132
+ - **Reach `sticker-sheet-gen` / `sticker-sheet-export` with `beehaven call`** — they are workspace actions, not MCP tools, and will not become tools.
@@ -0,0 +1,188 @@
1
+ ---
2
+ name: visualize
3
+ description: Turn any concept, answer, or described system into a clean DIAGRAM on a Clearly spatial canvas instead of a wall of text. Load this when the user asks to "diagram this", "draw it", "sketch it", "map it out", "visualize this",
4
+ "explain visually", "show me how X works", "flowchart this", "make a diagram" — AND proactively whenever YOUR OWN answer would be clearer as a picture than a paragraph (a flow with branches, who-calls-whom, a schema, an architecture, options on axes). Picks the right diagram type for the content and builds it with the canvas primitives.
5
+ ---
6
+
7
+ > **⚠ CANVAS WORK GOES THROUGH THE CLI, NOT AN MCP TOOL.** Anything written
8
+ > `canvas-act { … }` / `canvas-perceive { … }` below is an ACTION, run as
9
+ > `beehaven call canvas-act '<the JSON>'`. The payloads are exactly as shown. The MCP
10
+ > surface is seven tools split by operation, and a single tool that dispatches 230
11
+ > caller-named canvas actions spans reads, writes and deletes at once — which is why the
12
+ > generic door is the shell instead. `clearly_read { target, type: "composition" }` still
13
+ > reads a canvas as an artifact.
14
+
15
+ # Visualize — draw it, don't write it
16
+
17
+ Some answers are paragraphs. Many are **pictures pretending to be paragraphs**: a flow with branches, a request hopping between services, a schema, a tradeoff matrix. The moment relationships matter, prose makes the reader rebuild the shape in their head. A diagram hands them the shape — spatial layout *is* the explanation, it's glanceable, and it's screenshot-shareable in a way a wall of text never is.
18
+
19
+ So: when you catch yourself about to write three paragraphs explaining how something connects, **draw it on the canvas instead** (and you can still say the one-line version in chat).
20
+
21
+ Prereq: the `beehaven` CLI is installed, signed in as an agent, and connected to the intended
22
+ workspace (run `clearly-init` if not). **Read `clearly-canvas` for the tool contract** —
23
+ `canvas-perceive` / `canvas-act` / `canvas-catalog`, `frame.create`, `canvas.create-node`
24
+ (text/rect/ellipse/svg/line), first-class `arrow.create`, and nesting via `parentId` with
25
+ frame-relative coordinates. This skill is the *diagram cookbook* on top of those primitives.
26
+
27
+ ## Pick the type (1-line heuristic each)
28
+
29
+ | If the content is… | Draw a… |
30
+ |---|---|
31
+ | an answer you'd write as multiple paragraphs | **Explain-an-answer** (boxes + arrows) |
32
+ | steps, especially with branches | **Flowchart** (boxes + decision diamonds) |
33
+ | who-talks-to-whom over time | **Sequence diagram** (lifelines + message arrows) |
34
+ | services / data stores and their calls | **Architecture** (frames + cylinders + arrows) |
35
+ | things and the relationships between them | **ER / schema** (entity boxes + cardinality lines) |
36
+ | one idea exploding outward into subtopics | **Mind-map** (central node + radial branches) |
37
+ | options scored on a few criteria | **Comparison matrix** (grid of cells) |
38
+
39
+ When unsure, ask: *is the story "then" (flowchart), "who" (sequence), "what's-related" (ER), or "which-is-better" (matrix)?*
40
+
41
+ ## The build loop (every diagram)
42
+
43
+ 1. **Get a canvas + perceive.** `canvas-perceive { compositionId, format:"text" }` → read `backgroundColor` (design WITH it — light ink on dark, dark ink on light) and `gaze.visibleWorldRect` (place work where the user is looking).
44
+ 2. **Batch the skeleton.** One `canvas-act` with a `batch` of frames + boxes on a grid. Capture every returned `{ id }`.
45
+ 3. **Wire the arrows** with `arrow.create {from, to}` — a first-class arrow that BINDS to the boxes (by returned id OR layer name) and FOLLOWS them when they move; `routing:"elbow"` for orthogonal flowcharts, `label` for the edge text (no separate label node needed). See clearly-canvas → Arrows / connectors.
46
+ 4. **Label** edges/branches with small `text` nodes at arrow midpoints.
47
+ 5. **Re-perceive** so the user can ink notes; read them back; revise with `canvas.update-nodes`.
48
+
49
+ Grid discipline matters more than anything: equal gutters (24–40px), aligned edges, generous whitespace. A diagram that breathes reads as designed.
50
+
51
+ ---
52
+
53
+ ## Recipe: Explain-an-answer
54
+
55
+ Your default upgrade from prose. **Layout:** 3–6 labelled boxes left→right (or top→down) in the order you'd say them, one arrow per "and then / because / leads to", a title text on top.
56
+
57
+ ```jsonc
58
+ canvas-act { "compositionId": "c_…", "batch": [
59
+ { "action": "canvas.create-node", "args": { "type":"text", "name":"title", "text":"How a request gets billed", "x":0, "y":-40, "size":24, "fontWeight":700, "fill":"#fff" } },
60
+ { "action": "canvas.create-node", "args": { "type":"rect", "name":"b1", "x":0, "y":0, "w":180, "h":72, "fill":"#1b2230", "stroke":"#3a465c", "radius":10 } },
61
+ { "action": "canvas.create-node", "args": { "type":"text", "name":"b1t", "text":"Member acts", "x":16, "y":26, "size":15, "fontWeight":600, "fill":"#e8edf5" } },
62
+ { "action": "canvas.create-node", "args": { "type":"rect", "name":"b2", "x":260, "y":0, "w":180, "h":72, "fill":"#1b2230", "stroke":"#3a465c", "radius":10 } },
63
+ { "action": "canvas.create-node", "args": { "type":"text", "name":"b2t", "text":"Debit seat budget", "x":276, "y":26, "size":15, "fontWeight":600, "fill":"#e8edf5" } },
64
+ { "action": "arrow.create", "args": { "from":"b1", "to":"b2", "routing":"elbow" } }
65
+ ]}
66
+ ```
67
+
68
+ Chain more boxes at `x += 260` per step. Branch (e.g. "budget exhausted → top-up") with a second arrow going down to an offset box.
69
+
70
+ ## Recipe: Flowchart / process
71
+
72
+ **Layout:** boxes top→down (or left→right), **rounded rect = action**, **diamond = decision**. Draw a diamond natively as a closed `vector.create` rhombus (4 points: top, right, bottom, left); give it two outgoing arrows labelled **Yes / No**.
73
+
74
+ ```jsonc
75
+ canvas-act { "compositionId":"c_…", "batch":[
76
+ { "action":"canvas.create-node", "args":{ "type":"rect", "name":"start", "x":120, "y":0, "w":160, "h":56, "fill":"#173a2a", "stroke":"#2f6b4d", "radius":28 } },
77
+ { "action":"canvas.create-node", "args":{ "type":"text", "name":"startt", "text":"Invite sent", "x":156, "y":18, "size":14, "fontWeight":600, "fill":"#d6f5e4" } },
78
+ { "action": "arrow.create", "args": { "from":"start", "to":"decide", "label":"yes", "routing":"elbow" } },
79
+ { "action":"canvas.create-node", "args":{ "type":"text", "name":"yesl", "text":"yes", "x":216, "y":74, "size":12, "fontWeight":600, "fill":"#7c8497" } }
80
+ ]}
81
+ ```
82
+
83
+ Rules: one entry, decisions are the only nodes with >1 exit, **every arrow labelled at branches**, keep the happy path straight and push error/No branches to the side.
84
+
85
+ ## Recipe: Sequence diagram
86
+
87
+ **Layout:** each actor is a column — a header box at top + a vertical lifeline (`type:"line"`) running down. Messages are **horizontal arrows** between lifelines; **time flows down**, so each later message sits at a larger `y`.
88
+
89
+ ```jsonc
90
+ canvas-act { "compositionId":"c_…", "batch":[
91
+ { "action":"canvas.create-node", "args":{ "type":"rect", "name":"a1", "x":0, "y":0, "w":120, "h":40, "fill":"#1b2230", "stroke":"#3a465c", "radius":8 } },
92
+ { "action":"canvas.create-node", "args":{ "type":"text", "name":"a1t", "text":"Web", "x":48, "y":12, "size":14, "fontWeight":600, "fill":"#e8edf5" } },
93
+ { "action":"canvas.create-node", "args":{ "type":"line", "name":"a1life", "x":60, "y":40, "w":0, "h":300, "stroke":"#3a465c" } },
94
+ { "action":"canvas.create-node", "args":{ "type":"rect", "name":"a2", "x":280, "y":0, "w":120, "h":40, "fill":"#1b2230", "stroke":"#3a465c", "radius":8 } },
95
+ { "action":"canvas.create-node", "args":{ "type":"text", "name":"a2t", "text":"Home DO", "x":312, "y":12, "size":14, "fontWeight":600, "fill":"#e8edf5" } },
96
+ { "action":"canvas.create-node", "args":{ "type":"line", "name":"a2life", "x":340, "y":40, "w":0, "h":300, "stroke":"#3a465c" } },
97
+ { "action": "arrow.create", "args": { "from":"a1life", "to":"a2life", "label":"check-quota(userId)" } },
98
+ { "action":"canvas.create-node", "args":{ "type":"text", "name":"m1t", "text":"check-quota(userId)", "x":120, "y":52, "size":12, "fontWeight":500, "fill":"#aab3c2" } }
99
+ ]}
100
+ ```
101
+
102
+ Place the message text just above its arrow. A return/response arrow points back left (flip `x1`/`x2`). Keep columns evenly spaced (~280px) so long labels fit.
103
+
104
+ ## Recipe: Architecture / system diagram
105
+
106
+ **Layout:** each service is a `frame` (so it can hold a label + sub-parts); **data stores are cylinders** drawn natively (a `rect` body with an `ellipse` cap on top and one behind at the bottom, grouped with `canvas.group`); arrows are calls. Cluster by tier — a row of frames per tier (client / edge / data), with a faint heading text per row.
107
+
108
+ ```jsonc
109
+ canvas-act { "compositionId":"c_…", "batch":[
110
+ { "action":"frame.create", "args":{ "name":"Worker", "x":0, "y":80, "w":200, "h":110, "fill":"#141a24" } },
111
+ { "action":"canvas.create-node", "args":{ "type":"text", "name":"wl", "text":"CF Worker", "x":14, "y":12, "size":14, "fontWeight":700, "fill":"#e8edf5", "parentId":"<WorkerFrameId>" } },
112
+ { "action": "arrow.create", "args": { "from":"Worker", "to":"HomeDO", "routing":"elbow", "label":"rpc" } }
113
+ ]}
114
+ ```
115
+
116
+ Rules: one box per service (not per file), label every arrow with the call/protocol if non-obvious, keep tiers as aligned rows so dataflow reads in one direction.
117
+
118
+ ## Recipe: ER / schema
119
+
120
+ **Layout:** each entity is a `frame` with a bold title row + a `text` node per field (stack fields at `y += 20`). Relationships are lines between frames with a **cardinality label** (`1`, `N`, `1..*`) near each end.
121
+
122
+ ```jsonc
123
+ canvas-act { "compositionId":"c_…", "batch":[
124
+ { "action":"frame.create", "args":{ "name":"User", "x":0, "y":0, "w":180, "h":120, "fill":"#141a24" } },
125
+ { "action":"canvas.create-node", "args":{ "type":"text", "name":"u-h", "text":"User", "x":12, "y":10, "size":15, "fontWeight":700, "fill":"#fff", "parentId":"<UserFrameId>" } },
126
+ { "action":"canvas.create-node", "args":{ "type":"text", "name":"u-f1", "text":"id PK", "x":12, "y":40, "size":13, "fontWeight":400, "fill":"#aab3c2", "parentId":"<UserFrameId>" } },
127
+ { "action":"canvas.create-node", "args":{ "type":"text", "name":"u-f2", "text":"email", "x":12, "y":60, "size":13, "fontWeight":400, "fill":"#aab3c2", "parentId":"<UserFrameId>" } },
128
+ { "action":"frame.create", "args":{ "name":"Seat", "x":300, "y":0, "w":180, "h":120, "fill":"#141a24" } },
129
+ { "action":"canvas.create-node", "args":{ "type":"text", "name":"s-h", "text":"Seat", "x":12, "y":10, "size":15, "fontWeight":700, "fill":"#fff", "parentId":"<SeatFrameId>" } },
130
+ { "action":"canvas.create-node", "args":{ "type":"line", "name":"u—s", "x":180, "y":40, "w":120, "h":0, "stroke":"#7c8497" } },
131
+ { "action":"canvas.create-node", "args":{ "type":"text", "name":"card1", "text":"1", "x":188, "y":24, "size":12, "fontWeight":700, "fill":"#7c8497" } },
132
+ { "action":"canvas.create-node", "args":{ "type":"text", "name":"cardN", "text":"N", "x":284, "y":24, "size":12, "fontWeight":700, "fill":"#7c8497" } }
133
+ ]}
134
+ ```
135
+
136
+ Rules: PK/FK noted in the field text, one relationship line per FK, cardinality at BOTH ends so the reader knows which side is the "many".
137
+
138
+ ## Recipe: Mind-map
139
+
140
+ **Layout:** one central node (an `ellipse` or pill `rect`), child topics radiating out, each connected by a **curved** branch (an open `vector.create` pen path with `hIn`/`hOut` control points, not a straight line). Place children evenly around the center; second-level topics hang off their parent.
141
+
142
+ ```jsonc
143
+ canvas-act { "compositionId":"c_…", "batch":[
144
+ { "action":"canvas.create-node", "args":{ "type":"ellipse", "name":"core", "x":220, "y":160, "w":160, "h":80, "fill":"#2a1f3a", "stroke":"#7b5cc4" } },
145
+ { "action":"canvas.create-node", "args":{ "type":"text", "name":"coret", "text":"Company Brain", "x":250, "y":190, "size":15, "fontWeight":700, "fill":"#e9defb" } },
146
+ { "action":"canvas.create-node", "args":{ "type":"rect", "name":"c1", "x":480, "y":60, "w":150, "h":48, "fill":"#1b2230", "stroke":"#3a465c", "radius":24 } },
147
+ { "action":"canvas.create-node", "args":{ "type":"text", "name":"c1t", "text":"Org context", "x":500, "y":76, "size":13, "fontWeight":600, "fill":"#e8edf5" } },
148
+ { "action":"vector.create", "args":{ "name":"core→c1", "closed":false, "stroke":"#7b5cc4", "strokeWidth":2,
149
+ "points":[ { "x":382, "y":192, "hOut":{ "x":430, "y":192 } }, { "x":478, "y":92, "hIn":{ "x":430, "y":92 } } ] } }
150
+ ]}
151
+ ```
152
+
153
+ Rules: keep the center visually heaviest, ~4–7 first-level branches (more → it's really a tree, use a frame layout), curve the branches so it reads organic not boxy.
154
+
155
+ ## Recipe: Comparison matrix
156
+
157
+ Perfect for **"X vs Y vs Z"**. **Layout:** a grid of `rect` cells — top row = options, left column = criteria, body cells = the values. Tint the header row/column so the axes pop; fill body cells (green/amber/red) to make the winner obvious at a glance.
158
+
159
+ ```jsonc
160
+ canvas-act { "compositionId":"c_…", "batch":[
161
+ { "action":"canvas.create-node", "args":{ "type":"rect", "name":"h-free", "x":160, "y":0, "w":120, "h":40, "fill":"#222b3a", "stroke":"#3a465c" } },
162
+ { "action":"canvas.create-node", "args":{ "type":"text", "name":"h-freet", "text":"Free", "x":196, "y":12, "size":14, "fontWeight":700, "fill":"#fff" } },
163
+ { "action":"canvas.create-node", "args":{ "type":"rect", "name":"h-pro", "x":280, "y":0, "w":120, "h":40, "fill":"#222b3a", "stroke":"#3a465c" } },
164
+ { "action":"canvas.create-node", "args":{ "type":"text", "name":"h-prot", "text":"Pro", "x":322, "y":12, "size":14, "fontWeight":700, "fill":"#fff" } },
165
+ { "action":"canvas.create-node", "args":{ "type":"rect", "name":"r-agents", "x":0, "y":40, "w":160, "h":40, "fill":"#222b3a", "stroke":"#3a465c" } },
166
+ { "action":"canvas.create-node", "args":{ "type":"text", "name":"r-agentst", "text":"Agents", "x":14, "y":52, "size":13, "fontWeight":600, "fill":"#cfd6e2" } },
167
+ { "action":"canvas.create-node", "args":{ "type":"rect", "name":"cell-free-agents", "x":160, "y":40, "w":120, "h":40, "fill":"#3a2417", "stroke":"#3a465c" } },
168
+ { "action":"canvas.create-node", "args":{ "type":"text", "name":"cell-free-agentst", "text":"1", "x":214, "y":52, "size":13, "fontWeight":600, "fill":"#f0c9a8" } },
169
+ { "action":"canvas.create-node", "args":{ "type":"rect", "name":"cell-pro-agents", "x":280, "y":40, "w":120, "h":40, "fill":"#173a2a", "stroke":"#3a465c" } },
170
+ { "action":"canvas.create-node", "args":{ "type":"text", "name":"cell-pro-agentst", "text":"10", "x":332, "y":52, "size":13, "fontWeight":600, "fill":"#a8f0c9" } }
171
+ ]}
172
+ ```
173
+
174
+ Keep cells a uniform `w`/`h` and snap every cell to the grid (column `x`, row `y`); the alignment is what makes it read as a table, not scattered boxes.
175
+
176
+ ## The viral bit
177
+
178
+ A clean diagram is **instantly screenshot-shareable** in a way a paragraph never is. Every text answer you convert into a tidy flowchart or architecture map is a tiny ad for the canvas — someone drops it in Slack and the reply is "wait, the AI just *drew* that?". So make each one frame-worthy: aligned grid, honest arrows, one clear read direction, a title. The diagram sells the next person on the surface.
179
+
180
+ ## Rules of thumb
181
+
182
+ - **Prose smell test:** about to write 3+ paragraphs about how things connect? Draw it instead.
183
+ - **Pick by the question:** "then" → flowchart, "who/when" → sequence, "what's related" → ER, "which is better" → matrix, "one idea outward" → mind-map.
184
+ - **Skeleton in one `batch`**, then arrows, then labels — capture every returned `id`.
185
+ - **Arrows = `arrow.create {from,to}`** — a first-class arrow that BINDS to the boxes and follows them (`routing:"elbow"` for flowcharts, `label` for edge text). Never hand-draw one as `type:"svg"` with a `marker-end`: that is a static path that does not move with its nodes; always pass `compositionId`; `name` on every create.
186
+ - **Grid or it's a dump:** equal gutters, aligned edges, one read direction, generous whitespace.
187
+ - **Perceive first** (design with `backgroundColor`, place in `gaze`); **re-perceive after** to read the human's ink and revise.
188
+ - **Need an action not in clearly-canvas?** `canvas-catalog { surface:"all" }` — don't invent action names.