beehaven 0.8.29 → 0.8.34
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/dist/agent-attribution.js +20 -2
- package/dist/agent-scope.js +55 -10
- package/dist/agent-state.js +44 -0
- package/dist/agents-md-text.js +64 -0
- package/dist/browser-login.js +14 -4
- package/dist/build-channel.js +2 -2
- package/dist/claude-bridge.js +12 -9
- package/dist/clearly.js +4 -3
- package/dist/cli-state.js +45 -3
- package/dist/cli.js +82 -53
- package/dist/commands/agent-skills.js +12 -1
- package/dist/commands/agent.js +235 -28
- package/dist/commands/agents-md.js +118 -0
- package/dist/commands/daemon-cmd.js +2 -0
- package/dist/commands/help.js +21 -0
- package/dist/commands/self-update.js +32 -5
- package/dist/commands/workspace.js +22 -6
- package/dist/daemon-client.js +10 -6
- package/dist/daemon-entry.js +1 -0
- package/dist/daemon-process.js +125 -0
- package/dist/daemon.js +131 -62
- package/dist/dashboard.js +118 -6
- package/dist/ipc-auth.js +3 -1
- package/dist/ipc-client.js +7 -6
- package/dist/ipc-path.js +92 -0
- package/dist/ipc-server.js +33 -33
- package/dist/npm-update.js +138 -0
- package/dist/session-binding.js +135 -0
- package/dist/session-target.js +91 -0
- package/dist/setup-service.js +9 -4
- package/dist/verb-surface.js +1 -0
- package/dist/watcher.js +9 -23
- package/dist/windows-hide.js +77 -0
- package/package.json +2 -2
- package/scripts/sync-skills.mjs +6 -0
- package/skills/agent-doodle-space/SKILL.md +1 -1
- package/skills/agent-home/SKILL.md +1 -1
- package/skills/brand-identity/SKILL.md +22 -5
- package/skills/clearly-agent/SKILL.md +38 -14
- package/skills/clearly-canvas/SKILL.md +31 -5
- package/skills/clearly-canvas/authoring.md +41 -12
- package/skills/clearly-canvas/example.mjs +72 -69
- package/skills/clearly-docs/SKILL.md +151 -0
- package/skills/clearly-init/SKILL.md +135 -0
- package/skills/clearly-workflows/SKILL.md +90 -0
- package/skills/clearly-workspace/SKILL.md +1 -1
- package/skills/codebase-map/SKILL.md +1 -1
- package/skills/design-craft/SKILL.md +9 -6
- package/skills/index.json +45 -10
- package/skills/layout-systems/SKILL.md +14 -11
- package/skills/pair-on-canvas/SKILL.md +1 -1
- package/skills/sticker-pack/SKILL.md +132 -0
- package/skills/visualize/SKILL.md +188 -0
package/skills/index.json
CHANGED
|
@@ -17,21 +17,21 @@
|
|
|
17
17
|
"project-plans.md",
|
|
18
18
|
"review.mjs"
|
|
19
19
|
],
|
|
20
|
-
"sha": "
|
|
20
|
+
"sha": "e23e25bd46b02d9c"
|
|
21
21
|
},
|
|
22
22
|
{
|
|
23
23
|
"name": "agent-home",
|
|
24
24
|
"files": [
|
|
25
25
|
"SKILL.md"
|
|
26
26
|
],
|
|
27
|
-
"sha": "
|
|
27
|
+
"sha": "e1d18e7518ff4b65"
|
|
28
28
|
},
|
|
29
29
|
{
|
|
30
30
|
"name": "agent-doodle-space",
|
|
31
31
|
"files": [
|
|
32
32
|
"SKILL.md"
|
|
33
33
|
],
|
|
34
|
-
"sha": "
|
|
34
|
+
"sha": "1e1911e6d8784476"
|
|
35
35
|
},
|
|
36
36
|
{
|
|
37
37
|
"name": "design-craft",
|
|
@@ -39,35 +39,35 @@
|
|
|
39
39
|
"SKILL.md",
|
|
40
40
|
"references.md"
|
|
41
41
|
],
|
|
42
|
-
"sha": "
|
|
42
|
+
"sha": "d11f0c45c93c9dea"
|
|
43
43
|
},
|
|
44
44
|
{
|
|
45
45
|
"name": "layout-systems",
|
|
46
46
|
"files": [
|
|
47
47
|
"SKILL.md"
|
|
48
48
|
],
|
|
49
|
-
"sha": "
|
|
49
|
+
"sha": "27151a50e3bdb27a"
|
|
50
50
|
},
|
|
51
51
|
{
|
|
52
52
|
"name": "brand-identity",
|
|
53
53
|
"files": [
|
|
54
54
|
"SKILL.md"
|
|
55
55
|
],
|
|
56
|
-
"sha": "
|
|
56
|
+
"sha": "366139b11ff11b58"
|
|
57
57
|
},
|
|
58
58
|
{
|
|
59
59
|
"name": "pair-on-canvas",
|
|
60
60
|
"files": [
|
|
61
61
|
"SKILL.md"
|
|
62
62
|
],
|
|
63
|
-
"sha": "
|
|
63
|
+
"sha": "1d79147baa8c232d"
|
|
64
64
|
},
|
|
65
65
|
{
|
|
66
66
|
"name": "codebase-map",
|
|
67
67
|
"files": [
|
|
68
68
|
"SKILL.md"
|
|
69
69
|
],
|
|
70
|
-
"sha": "
|
|
70
|
+
"sha": "4a4af2229b68827d"
|
|
71
71
|
},
|
|
72
72
|
{
|
|
73
73
|
"name": "clearly-workspace",
|
|
@@ -75,13 +75,48 @@
|
|
|
75
75
|
"SKILL.md",
|
|
76
76
|
"survey.mjs"
|
|
77
77
|
],
|
|
78
|
-
"sha": "
|
|
78
|
+
"sha": "3a3e6fa6e3cf8717"
|
|
79
79
|
},
|
|
80
80
|
{
|
|
81
81
|
"name": "clearly-agent",
|
|
82
82
|
"files": [
|
|
83
83
|
"SKILL.md"
|
|
84
84
|
],
|
|
85
|
-
"sha": "
|
|
85
|
+
"sha": "11505106cb1dd287"
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"name": "visualize",
|
|
89
|
+
"files": [
|
|
90
|
+
"SKILL.md"
|
|
91
|
+
],
|
|
92
|
+
"sha": "88bb6e94fb37c337"
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"name": "sticker-pack",
|
|
96
|
+
"files": [
|
|
97
|
+
"SKILL.md"
|
|
98
|
+
],
|
|
99
|
+
"sha": "74af254817a134d6"
|
|
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": "b9622f21173bab0d"
|
|
86
121
|
}
|
|
87
122
|
]
|
|
@@ -47,7 +47,7 @@ that lost one. If you have four items, ask whether one is really a different thi
|
|
|
47
47
|
```
|
|
48
48
|
margin 8–10% of the short edge (1080 → 88–108; A3 → 280–350)
|
|
49
49
|
display 12–20% of the HEIGHT (1350 → 160–270px), weight 700–900, tracking −3 to −6,
|
|
50
|
-
lineHeight
|
|
50
|
+
lineHeight "92%"–"100%"
|
|
51
51
|
supporting 2–3% of height credits, date, venue — deliberately small
|
|
52
52
|
```
|
|
53
53
|
|
|
@@ -105,7 +105,7 @@ content column ≤ 1200 even though the slide is 1920
|
|
|
105
105
|
## Landing page / hero — 1440 wide (design), content max 1200
|
|
106
106
|
|
|
107
107
|
```
|
|
108
|
-
margin 96 · headline 64–88 (tracking −2, lineHeight
|
|
108
|
+
margin 96 · headline 64–88 (tracking −2, lineHeight "105%") · sub 20–24 muted, w ≤ 640
|
|
109
109
|
CTA 48–56 tall, 24–32 horizontal padding · section spacing 96–160 vertical
|
|
110
110
|
```
|
|
111
111
|
|
|
@@ -124,7 +124,7 @@ CTA 48–56 tall, 24–32 horizontal padding · section spacing 96–160 vertica
|
|
|
124
124
|
|
|
125
125
|
```
|
|
126
126
|
margin: outer 10%, inner (gutter side) 12–14% — asymmetric, because the binding eats it
|
|
127
|
-
columns 2–3 for A4 body · measure 45–75ch · body 10–11pt (≈42–46px at 300dpi), lineHeight
|
|
127
|
+
columns 2–3 for A4 body · measure 45–75ch · body 10–11pt (≈42–46px at 300dpi), lineHeight "145%"
|
|
128
128
|
```
|
|
129
129
|
|
|
130
130
|
- **Asymmetric margins are the mark of real editorial.** Equal margins all round read as a
|
|
@@ -141,9 +141,9 @@ columns 2–3 for A4 body · measure 45–75ch · body 10–11pt (≈42–46px a
|
|
|
141
141
|
## Cards, tables and dense UI
|
|
142
142
|
|
|
143
143
|
- **Card padding 24–32, radius 10–16, gap between cards ≥ 2× padding.**
|
|
144
|
-
-
|
|
145
|
-
|
|
146
|
-
|
|
144
|
+
- **Cards are filled frames.** Parent labels, icons and controls to the card; use auto
|
|
145
|
+
layout for its content. Build rows and grids from these cards, with deliberate
|
|
146
|
+
Hug/Fill/Fixed sizing. Reserve rectangles for decorative shapes, swatches and rules.
|
|
147
147
|
- **In tables, align numbers RIGHT and use tabular figures.** Left-aligned numbers of
|
|
148
148
|
different lengths cannot be compared, which is the only reason the table exists.
|
|
149
149
|
- **Zebra striping OR rules, never both.** Ideally neither — space is enough at ≥12px row padding.
|
|
@@ -153,10 +153,13 @@ columns 2–3 for A4 body · measure 45–75ch · body 10–11pt (≈42–46px a
|
|
|
153
153
|
## Building it on the canvas
|
|
154
154
|
|
|
155
155
|
```jsonc
|
|
156
|
-
// ONE batch.
|
|
157
|
-
{"action":"frame.create","args":{"
|
|
158
|
-
{"action":"canvas.create-node","args":{"name":"
|
|
159
|
-
"
|
|
156
|
+
// ONE batch. A content stack owns its fill and children; the layout computes positions.
|
|
157
|
+
{"action":"frame.create","args":{"id":"card","name":"Feature card","w":360,"h":200,"fill":"#FFFFFF"}}
|
|
158
|
+
{"action":"canvas.create-node","args":{"name":"Feature title","type":"text","parentId":"card",
|
|
159
|
+
"w":312,"text":"Make room for the idea","size":28,"fontWeight":600,"lineHeight":"auto"}}
|
|
160
|
+
{"action":"canvas.create-node","args":{"name":"Feature detail","type":"text","parentId":"card",
|
|
161
|
+
"w":312,"text":"Keep every layer ready for the next edit.","size":16,"lineHeight":"145%"}}
|
|
162
|
+
{"action":"canvas.auto-layout","args":{"id":"card","direction":"v","gap":16,"padding":24,"sizingH":"fixed","sizingV":"hug"}}
|
|
160
163
|
```
|
|
161
164
|
|
|
162
165
|
- ⚠ **Omit `h` on text** — it hugs its wrapped content. Pin `h` only when a later element's
|
|
@@ -180,5 +183,5 @@ columns 2–3 for A4 body · measure 45–75ch · body 10–11pt (≈42–46px a
|
|
|
180
183
|
| Deck | too many words; title states the topic instead of the argument; full-width text |
|
|
181
184
|
| Landing | subhead runs full width; two competing CTAs; sections evenly spaced |
|
|
182
185
|
| Editorial | symmetric margins; no baseline grid; unbroken columns |
|
|
183
|
-
| Cards |
|
|
186
|
+
| Cards | background and contents lack a shared frame; layout breaks when copy grows |
|
|
184
187
|
| **All** | **an exact 50/50 split, and four type sizes where three would do** |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: pair-on-canvas
|
|
3
|
-
description: Use a Clearly canvas as mission control for a coding task — read the spec the human placed on the board, do the work in the repo, and report progress, diffs, and next steps back as cards they steer by inking. Load this when the user says "work the task on my canvas", "take this from the board", "what's on my Clearly canvas", "pick up the spec", "let's pair on the canvas", or whenever a human is directing your coding work spatially instead of in a chat thread.
|
|
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. Use a Clearly canvas as mission control for a coding task — read the spec the human placed on the board, do the work in the repo, and report progress, diffs, and next steps back as cards they steer by inking. Load this when the user says "work the task on my canvas", "take this from the board", "what's on my Clearly canvas", "pick up the spec", "let's pair on the canvas", or whenever a human is directing your coding work spatially instead of in a chat thread.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
> **⚠ CANVAS WORK GOES THROUGH THE CLI, NOT AN MCP TOOL.** Anything written
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sticker-pack
|
|
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. 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: 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. 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.
|