pmx-canvas 0.1.14 → 0.1.15

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 (50) hide show
  1. package/CHANGELOG.md +94 -0
  2. package/Readme.md +108 -1058
  3. package/dist/canvas/global.css +141 -0
  4. package/dist/canvas/index.js +129 -79
  5. package/dist/json-render/index.css +1 -1
  6. package/dist/types/client/nodes/HtmlNode.d.ts +5 -0
  7. package/dist/types/client/state/canvas-store.d.ts +5 -1
  8. package/dist/types/client/state/intent-bridge.d.ts +3 -1
  9. package/dist/types/client/types.d.ts +2 -2
  10. package/dist/types/json-render/catalog.d.ts +1 -1
  11. package/dist/types/mcp/canvas-access.d.ts +7 -1
  12. package/dist/types/server/agent-context.d.ts +1 -0
  13. package/dist/types/server/canvas-operations.d.ts +4 -2
  14. package/dist/types/server/canvas-provenance.d.ts +1 -1
  15. package/dist/types/server/canvas-serialization.d.ts +3 -0
  16. package/dist/types/server/canvas-state.d.ts +51 -4
  17. package/dist/types/server/demo.d.ts +5 -0
  18. package/dist/types/server/index.d.ts +13 -3
  19. package/dist/types/server/web-artifacts.d.ts +18 -0
  20. package/dist/types/shared/canvas-node-kind.d.ts +5 -0
  21. package/package.json +1 -1
  22. package/skills/pmx-canvas/SKILL.md +43 -0
  23. package/skills/pmx-canvas-testing/SKILL.md +17 -0
  24. package/src/cli/agent.ts +52 -5
  25. package/src/cli/index.ts +2 -23
  26. package/src/client/canvas/AttentionHistory.tsx +14 -1
  27. package/src/client/canvas/CanvasNode.tsx +1 -1
  28. package/src/client/canvas/CanvasViewport.tsx +3 -0
  29. package/src/client/canvas/DockedNode.tsx +110 -12
  30. package/src/client/canvas/ExpandedNodeOverlay.tsx +5 -0
  31. package/src/client/canvas/Minimap.tsx +1 -0
  32. package/src/client/icons.tsx +1 -0
  33. package/src/client/nodes/HtmlNode.tsx +151 -0
  34. package/src/client/state/canvas-store.ts +24 -2
  35. package/src/client/state/intent-bridge.ts +4 -3
  36. package/src/client/state/sse-bridge.ts +1 -0
  37. package/src/client/theme/global.css +141 -0
  38. package/src/client/types.ts +3 -0
  39. package/src/mcp/canvas-access.ts +34 -7
  40. package/src/mcp/server.ts +178 -25
  41. package/src/server/agent-context.ts +50 -3
  42. package/src/server/canvas-operations.ts +20 -3
  43. package/src/server/canvas-provenance.ts +2 -1
  44. package/src/server/canvas-serialization.ts +38 -13
  45. package/src/server/canvas-state.ts +305 -34
  46. package/src/server/demo.ts +792 -0
  47. package/src/server/index.ts +33 -3
  48. package/src/server/server.ts +74 -13
  49. package/src/server/web-artifacts.ts +116 -3
  50. package/src/shared/canvas-node-kind.ts +14 -0
package/Readme.md CHANGED
@@ -1,10 +1,11 @@
1
1
  # pmx-canvas
2
2
 
3
- **A shared thinking surface for humans and coding agents.** Drop files, plans,
4
- status, charts, fetched web pages, and hand-drawn diagrams onto the same
5
- infinite 2D canvas; pin what matters; let the agent read your spatial curation
6
- as structured context. Drive it from a CLI, the Model Context Protocol, an
7
- HTTP API, or a Bun-based TypeScript SDK whichever fits how your agent runs.
3
+ **A moldable canvas for agent-assisted thinking.** An infinite 2D surface
4
+ where files, plans, status, charts, fetched web pages, and hand-drawn
5
+ diagrams live side by side. Every node carries its own renderer; agents
6
+ (and you) build new views in the middle of a session, not as a separate
7
+ tooling project. Pin what matters and the agent reads your spatial
8
+ curation as structured context.
8
9
 
9
10
  <p align="center">
10
11
  <img src="docs/screenshots/welcome-dark.png" alt="Empty canvas — dark theme" width="49%" />
@@ -16,202 +17,78 @@ HTTP API, or a Bun-based TypeScript SDK — whichever fits how your agent runs.
16
17
  <img src="docs/screenshots/demo-workbench-light.png" alt="Structured workbench demo — light theme" width="49%" />
17
18
  </p>
18
19
 
19
- PMX Canvas is a **collaborative spatial workspace** that humans and agents share in real time. It works in both directions:
20
+ PMX Canvas is a collaborative spatial workspace that humans and agents share
21
+ in real time. Either side adds material; the human curates spatial structure
22
+ (grouping, positioning, pinning); the agent reads that curation through
23
+ `canvas://pinned-context` and acts on it. Spatial arrangement is
24
+ communication — proximity means relatedness, pinning means *focus here*.
20
25
 
21
- - **Human-first.** You open the canvas, drop in files, sketch a plan, group what belongs together, pin what matters. The agent watches the curation update live and uses it to ground its next action — no prompt engineering, no copy-paste.
22
- - **Agent-first.** You ask the agent to gather data from sources (logs, files, search results, dashboards, web pages), and it lays the findings out as nodes and edges. You step in, rearrange, edit, prune, and steer where the analysis goes next.
26
+ ## Main features
23
27
 
24
- ### What it's for
28
+ ### 01 / Curate
25
29
 
26
- pmx-canvas drives any work that benefits from making **context, relations, and provenance explicit**. The canvas turns work that is normally scattered across chat history, tabs, files, and dashboards into something with explicit context (pinned nodes), explicit relations (edges, groups, proximity), and explicit provenance (which side added which piece). Whatever data either the human or the agent pulls in — files, fetched web pages, screenshots, log excerpts, structured panels, charts, hand-drawn diagrams, bundled web artifacts — lives on the same surface and is reachable from both sides.
30
+ Drag, group, arrange, and **pin** nodes spatially. Curation is the channel
31
+ from human intent to agent context — the agent reads `canvas://pinned-context`
32
+ and `canvas://spatial-context` (proximity clusters, reading order, pinned
33
+ neighborhoods) and uses your layout to ground its next action.
27
34
 
28
- **The canvas is agnostic about what you do with it.** The reach of the workspace is the union of pmx-canvas's own node types and **whatever your agent's harness already has access to** — MCP servers, MCP apps, shell commands and CLIs, files in the working directory, web-fetch tools, anything else its toolbelt exposes. The canvas itself doesn't care where the data came from; it just needs the agent (or you) to drop it on the surface as the right node type. To make that concrete:
35
+ ### 02 / Mix any data source
29
36
 
30
- - An **Atlassian MCP** or **GitHub MCP/CLI** turns the canvas into a triage board — tickets or issues land as `markdown` nodes you can group by status and pin the in-flight ones.
31
- - A **database MCP** turns it into an exploratory query workbench each query result becomes a `json-render` table or `graph` node next to the `markdown` node holding the SQL.
32
- - An **Excalidraw MCP app** turns it into a sketch surface diagrams open as `mcp-app` nodes you can resize and annotate.
33
- - A **shell-driven agent** with `gh` + `kubectl` in its harness turns it into an ops board — open issues become markdown, pod statuses become `status` nodes, the relationships you care about become edges.
34
- - **Plain file reads** in the agent's working directory turn it into a code-context map — `file` nodes for source, `markdown` nodes for the agent's notes, all live-watched.
35
- - A **custom MCP or CLI** for your data source turns it into whatever shape that data fits — without pmx-canvas knowing anything about your domain.
37
+ Files, web pages, screenshots, structured panels, charts, hand-drawn
38
+ diagrams, embedded MCP Apps, and bundled web artifacts all live on the same
39
+ surface. The reach of the canvas is the union of its
40
+ [built-in node types](docs/node-types.md) and **whatever your agent's harness
41
+ already has access to** MCP servers, CLIs, file reads, web fetch, anything
42
+ on its toolbelt.
36
43
 
37
- Common use cases non-exhaustive, mix and match as the work shifts:
44
+ ### 03 / Control your context
38
45
 
39
- - **Idea generation** capture divergent thoughts spatially without losing them
40
- - **Validation** test a claim against supporting and refuting evidence
41
- - **Research** gather, organize, and compare sources from anywhere
42
- - **Analysis** — make sense of accumulated material, surface patterns
43
- - **Mind mapping** — relationships, hierarchies, and structure spatially
46
+ Pinning is an explicit, low-noise control over what the agent sees next. No
47
+ prompt engineering, no copy-pastepin a node in the browser and the MCP
48
+ server fires a `notifications/resources/updated` event the agent's harness
49
+ picks up immediately.
44
50
 
45
- …plus anything else the combination of the canvas and your agent's toolbelt — MCP servers, MCP apps, CLIs, file access, web fetch — makes possible.
51
+ ### 04 / Save
46
52
 
47
- **Spatial arrangement is communication.** When a human drags three file nodes next to a bug report, the agent knows they're related. When the agent drops 12 webpage nodes from a research session, the human can immediately group, prune, and pin the ones worth keeping. The agent reads spatial state via `canvas://pinned-context`, `canvas://spatial-context`, and the SSE event stream; the human reads the same state through the rendered browser.
53
+ Spatial state auto-saves to `.pmx-canvas/state.json` (debounced ~500 ms)
54
+ git-committable, shareable across machines, and survives both browser
55
+ refresh and server restart. Named [snapshots](docs/mcp.md#tools), full
56
+ undo/redo, and an auto-detected code graph (JS/TS, Python, Go, Rust) make
57
+ the canvas durable rather than throwaway.
48
58
 
49
- ## Prerequisites
59
+ ### 05 / Any agent
50
60
 
51
- - [Bun](https://bun.sh) >= 1.3.12
61
+ Harness-agnostic. Drive the canvas from [MCP](docs/mcp.md) (40 tools,
62
+ 8 resources, change notifications), the [CLI](docs/cli.md), the
63
+ [HTTP API](docs/http-api.md), or the [Bun SDK](docs/sdk.md). Works with
64
+ Claude Code, GitHub Copilot CLI, Codex, Cursor, Windsurf, or any agent
65
+ that can spawn an MCP stdio server, call a CLI, or hit an HTTP endpoint.
52
66
 
53
- The published SDK entrypoint is Bun-first: `import { createCanvas } from 'pmx-canvas'` is supported in Bun, while Node.js consumers should use the CLI, MCP server, or HTTP API instead.
67
+ ## Prerequisites
54
68
 
55
- ## Scope
69
+ - [Bun](https://bun.sh) >= 1.3.12
56
70
 
57
- - **Single-machine, today.** One canvas runs per `bunx pmx-canvas` instance, on
58
- one machine. There is no built-in multi-user auth or presence — collaboration
59
- means human↔agent on the same machine, plus any other browser tab/agent
60
- pointed at the same `localhost:4313`. To share a canvas across machines, commit
61
- `.pmx-canvas/state.json` to your repo and pull it on the other side.
62
- - **What leaves your machine.** The core canvas runs entirely on `localhost`.
63
- Network egress only happens for explicit, opt-in flows: `webpage` nodes
64
- fetch the URL you give them; `mcp-app` / `canvas_add_diagram` calls go to
65
- whatever MCP server URL you configure (the Excalidraw preset uses
66
- `https://mcp.excalidraw.com/mcp`); `bunx` itself reads the npm registry on
67
- first install. Nothing else phones home.
68
- - **State auto-saves** to `.pmx-canvas/state.json` (debounced ~500 ms after each
69
- mutation). Closing the browser tab keeps everything — only `Ctrl-C` (or
70
- `pmx-canvas serve stop`) on the server actually stops the canvas. Pins,
71
- positions, and node content survive both. Snapshots live under
72
- `.pmx-canvas/snapshots/`.
71
+ The published SDK entrypoint is Bun-first. Node.js consumers should use the
72
+ CLI, MCP server, or HTTP API.
73
73
 
74
74
  ## Quick start
75
75
 
76
- There are two paths into pmx-canvas, and they work together. Pick whichever
77
- matches who is starting the session — you can hand off to the other side at any
78
- point because both halves drive the same canvas.
79
-
80
- ### Easiest: install the `pmx-canvas` agent skill (recommended)
81
-
82
- The fastest way to get going is to install the main `pmx-canvas` agent skill
83
- into your agent of choice. The skill teaches the agent how to install the
84
- package, start the server, and drive every node type, group, snapshot, and
85
- search the canvas exposes. You don't have to install the rest of the bundled
86
- skills (`web-artifacts-builder`, `pmx-canvas-testing`, `playwright-cli`, the
87
- `json-render-*` family, etc.) — once the canvas is running, the agent can read
88
- `canvas://skills` and pull in companion skills as the work demands.
89
-
90
- Three install paths, in order of how universal they are:
91
-
92
- ```bash
93
- # 1. GitHub CLI extension. `gh skill` is the official Agent Skills extension
94
- # for the GitHub CLI — it knows where each harness keeps its skills tree
95
- # and copies the SKILL.md and assets into the right place. Requires
96
- # `gh` >= 2.90. See https://cli.github.com/manual/gh_skill_install.
97
- gh skill install pskoett/pmx-canvas pmx-canvas
98
-
99
- # 2. Agent Skills CLI. `npx skills` is the runtime-agnostic installer for
100
- # skills that follow the Agent Skills specification
101
- # (https://agentskills.io/specification). It works for any agent harness
102
- # that reads from a per-user or per-project skills directory.
103
- npx skills add pskoett/pmx-canvas/skills/pmx-canvas
104
-
105
- # 3. Manual clone + copy. Works everywhere; you pick where the skill lands.
106
- git clone https://github.com/pskoett/pmx-canvas.git
107
- cp -r pmx-canvas/skills/pmx-canvas <your-agent-skills-dir>
108
- ```
109
-
110
- For path 3, point at whichever directory your agent harness reads. Common
111
- defaults — check your harness docs if it isn't here:
112
-
113
- | Harness | Skills directory |
114
- |---------|------------------|
115
- | Claude Code | `.claude/skills/` (project) or `~/.claude/skills/` (user-wide) |
116
- | GitHub Copilot CLI | `.github/skills/`, `.claude/skills/`, or `.agents/skills/` (project); `~/.copilot/skills/`, `~/.claude/skills/`, or `~/.agents/skills/` (user-wide). [docs](https://docs.github.com/en/copilot/how-tos/copilot-cli/customize-copilot/add-skills) |
117
- | Cross-harness convention | `.agents/skills/` (project) — followed by an increasing number of harnesses, see the [Agent Skills specification](https://agentskills.io/specification) |
118
- | Other / unsure | check your harness's docs for the canonical skills directory |
119
-
120
- After install, point your agent at the skill and try the **minimum-viable
121
- prompt**:
122
-
123
- > *"Use the `pmx-canvas` skill to start the canvas, then add this repo's
124
- > `Readme.md` and the top three source files as `file` nodes. Auto-arrange
125
- > them and pin two."*
126
-
127
- You should see the browser open and four nodes appear inside ~10 seconds. If
128
- that works, the skill, the canvas, and the agent are all wired up.
129
-
130
- If your agent isn't MCP-capable yet, wire it up first — see
131
- [Connect your agent (MCP)](#connect-your-agent-mcp) for the JSON snippet that
132
- turns `bunx pmx-canvas --mcp` into a stdio MCP server your harness can connect
133
- to. The skill assumes the agent can call MCP tools. From there
134
- work up to richer prompts — the [Example](#example-pull-data-in-build-something-out)
135
- section below has a fuller flow.
136
-
137
- For a richer install (the full bundle as a plugin marketplace, mirroring the
138
- pattern in [`pskoett-ai-skills`](https://github.com/pskoett/pskoett-ai-skills)),
139
- see [Agent skills](#agent-skills) below.
140
-
141
- ### Run it directly (no agent required)
142
-
143
- You don't need an agent to use pmx-canvas — the workbench, CLI, and HTTP API
144
- are first-class on their own.
145
-
146
- #### Install from npm
76
+ ### Run the canvas
147
77
 
148
78
  ```bash
149
79
  bunx pmx-canvas # Start canvas, open browser
150
- bunx pmx-canvas --demo # Start with sample nodes
80
+ bunx pmx-canvas --demo # Start with the project-tour demo board
151
81
  bunx pmx-canvas --no-open # Headless (good for daemons / CI)
152
82
  bunx pmx-canvas --mcp # Run as MCP server (stdio)
153
83
  bunx pmx-canvas --help # All commands
154
- bunx pmx-canvas serve --daemon --no-open --wait-ms=20000 # Detached background mode
155
- ```
156
-
157
- The canvas opens at `http://localhost:4313`. Try `bunx pmx-canvas --demo`
158
- first — you'll see three nodes connected by two edges; that confirms the
159
- canvas server, the browser bundle, and the SSE event stream are all wired up.
160
-
161
- #### Install from source
162
-
163
- ```bash
164
- git clone https://github.com/pskoett/pmx-canvas.git
165
- cd pmx-canvas
166
- bun install
167
- bun run build
168
- bun run dev # Start + open browser
169
- bun run dev:demo # Start with sample nodes
170
- ```
171
-
172
- For a stable local hostname, install [Portless](https://github.com/vercel-labs/portless)
173
- first **and then** run the portless variant:
174
-
175
- ```bash
176
- npm install -g portless
177
- bun run dev:portless # https://pmx.localhost/workbench
178
- ```
179
-
180
- The published `bunx pmx-canvas` path defaults to plain loopback and does **not**
181
- depend on Portless.
182
-
183
- #### Test the unpublished CLI from a repo checkout
184
-
185
- If you want to exercise the real package before publishing, link the repo locally:
186
-
187
- ```bash
188
- git clone https://github.com/pskoett/pmx-canvas.git
189
- cd pmx-canvas
190
- bun install
191
- bun run build
192
- bun link
193
-
194
- # Then from any shell:
195
- pmx-canvas --help
196
- pmx-canvas --no-open
197
84
  ```
198
85
 
199
- For one-off local runs without linking, `bun run src/cli/index.ts ...` works too.
200
-
201
- ### Recommended ways to drive the canvas
86
+ The canvas opens at `http://localhost:4313`. Try `--demo` first it seeds a
87
+ project tour with grouped markdown, status, file, image, webpage,
88
+ json-render, graph, html, Excalidraw diagram, and MCP App nodes connected by
89
+ labeled edges.
202
90
 
203
- Once the canvas is up, pick the control surface that fits your agent or script:
204
-
205
- - **CLI** for local use, scripting, automation, and terminal-native agents.
206
- - **MCP** for agents that already speak the Model Context Protocol — 38 tools +
207
- 8 core resources, including the bundled-skill index at `canvas://skills`.
208
- - **HTTP API** for REST/SSE clients in any language.
209
- - **Bun SDK** for TypeScript code running on Bun.
210
-
211
- The CLI and MCP cover normal canvas work; the reference sections below show
212
- the exact commands, tools, and payloads.
213
-
214
- #### Connect your agent (MCP)
91
+ ### Connect your agent (MCP)
215
92
 
216
93
  Add to your agent's MCP config:
217
94
 
@@ -226,916 +103,89 @@ Add to your agent's MCP config:
226
103
  }
227
104
  ```
228
105
 
229
- The canvas auto-starts on first tool call. Works with any MCP-capable agent
230
- harness — pmx-canvas does not depend on a specific coding agent.
231
-
232
- For developer flows on the `pmx-canvas` repo itself (release process,
233
- contribution gates, etc.) see [`AGENTS.md`](AGENTS.md) and
234
- [`docs/RELEASE.md`](docs/RELEASE.md).
235
-
236
- ## Example: pull data in, build something out
237
-
238
- The canvas is most useful when it's *not* empty. The pattern is the same
239
- across every use case: gather data from whatever surfaces the human or the
240
- agent has access to, lay it out using whichever node types fit, then
241
- collaborate on the result.
242
-
243
- A research / analysis example against a release-planning workflow:
244
-
245
- > *"Read the latest release notes from `CHANGELOG.md`, the open issues from
246
- > our GitHub repo, last week's deploy logs, and the pricing page from
247
- > example.com. Put each one on the canvas as the right node type — markdown
248
- > for the changelog, file nodes for the local files, status nodes for the
249
- > deploy events, a webpage node for the URL — then build me a json-render
250
- > dashboard and a chart that summarize what shipped, what broke, and what's
251
- > still open."*
252
-
253
- The same shape works for any use case. *Idea generation:* "give me twelve
254
- angles on X, drop each as a markdown node, arrange in a flow layout."
255
- *Validation:* "for the claim in the pinned node, place supporting and
256
- refuting sources beside it as webpage and file nodes." *Mind mapping:*
257
- "build a tree of the concepts in [topic] — central concept top-center,
258
- major branches as groups, sub-concepts inside each group connected with
259
- depends-on edges."
260
-
261
- [`skills/pmx-canvas/SKILL.md`](skills/pmx-canvas/SKILL.md) has step-by-step
262
- recipes for these and other patterns under *Workflow Patterns*. New
263
- patterns become viable whenever you add an MCP server or MCP app — the
264
- canvas surface stays the same, the things you can put on it grow.
265
-
266
- What the agent does, end to end:
267
-
268
- 1. Reads each source via the tools your harness already provides (filesystem,
269
- web fetch, GitHub API, log readers — pmx-canvas does not impose data
270
- sources; bring your own).
271
- 2. Calls the canvas to drop each finding on the workbench:
272
- - `markdown` for narrative notes and AI-summarized text
273
- - `file` for live-watching local source files
274
- - `webpage` for fetched web pages with cached extracted text
275
- - `image` for screenshots and exported diagrams
276
- - `status` / `ledger` / `trace` for structured runtime/evaluation state
277
- - `json-render` for inline structured UI (dashboards, tables, forms) — see
278
- [Json-render nodes](#json-render-nodes)
279
- - `graph` for line / bar / pie / radar / stacked / composed charts — see
280
- [the schema reference](#schema-driven-discovery)
281
- - `mcp-app` (Excalidraw and other MCP App servers) for hand-drawn diagrams
282
- - `web-artifact` for full bundled React/Tailwind interactive surfaces — see
283
- [Web artifacts](#web-artifacts)
284
- - `group` to bound related nodes into a frame
285
- - `edge` to connect findings (`flow`, `depends-on`, `relation`,
286
- `references`) so the relationships are first-class, not implicit
287
- 3. You step into the canvas, rearrange, prune, group, and **pin** the nodes
288
- that matter.
289
- 4. The agent reads `canvas://pinned-context` and `canvas://spatial-context`
290
- and uses your curation to ground the next round of analysis or build.
291
-
292
- This loop works for investigations, architecture sketches, research surveys,
293
- release planning, dashboards, post-mortems, lecture notes — anywhere the gap
294
- between "I have the data somewhere" and "I have a coherent picture" is
295
- currently blocking your thinking.
296
-
297
- ## How it works
298
-
299
- The same simple loop runs in both directions, regardless of what the work
300
- actually is:
301
-
302
- 1. **Either side adds material** to the canvas. The agent uses any tool its
303
- harness exposes (file reads, web fetch, an attached MCP server, an MCP
304
- app, the canvas's own tools) and lays the result out as the right node
305
- type. The human drops files, drags nodes around, types markdown.
306
- 2. **The human curates spatial structure** — they group, position, draw
307
- edges, and pin what matters. Curation is communication: proximity means
308
- relatedness, pinning means "agent, focus here."
309
- 3. **The agent reads that structure as machine-readable context.**
310
- `canvas://pinned-context` returns the pinned nodes plus their nearby
311
- neighbors. `canvas://spatial-context` returns proximity clusters,
312
- reading order, and pinned neighborhoods. SSE notifies the agent the
313
- moment any of it changes.
314
- 4. **The agent acts on that context** using whatever tools are at its
315
- disposal — `bunx pmx-canvas`'s 38 MCP tools, plus every other MCP your
316
- harness has connected. Each new MCP expands what the loop can do without
317
- changing the loop.
318
-
319
- The canvas's job is to keep that loop honest: spatial state stays explicit,
320
- provenance stays attributable to the side that made it, and both sides see
321
- the same workspace via different surfaces.
322
-
323
- ## Features
324
-
325
- ### Canvas
326
-
327
- - Infinite 2D canvas with pan, zoom, and scroll
328
- - Minimap with click-to-navigate
329
- - Auto-arrange layouts (grid, column, flow)
330
- - Multi-select with selection bar actions
331
- - Snap-to-alignment guides while dragging nodes
332
- - Keyboard shortcuts (Cmd+0 reset, Cmd+/- zoom, Tab cycle, Esc deselect)
333
- - Command palette (Cmd+K) -- search nodes and actions
334
- - In-UI shortcut overlay -- press `?` for the full cheatsheet
335
- - Context menu on right-click
336
- - Docked panels -- pin nodes to left/right HUD
337
- - Expanded view -- click to expand any node to full-screen overlay
338
- - Inline markdown editor with format bar for rich in-place editing
339
- - Attention toasts + history -- surface agent mutations the human didn't initiate
340
- - Layout validation -- detect collisions, containment breaches, and missing edge endpoints
341
- - Themes: dark (default), light, high-contrast
342
- - Persistence: auto-saves to `.pmx-canvas/state.json`, restores on restart
343
-
344
- ### Node types
345
-
346
- | Type | Description |
347
- |------|-------------|
348
- | `markdown` | Rich markdown with rendered preview |
349
- | `status` | Compact status indicator (phase, message, elapsed time) |
350
- | `context` | Context cards, token usage, workspace grounding |
351
- | `ledger` | Execution ledger summary |
352
- | `trace` | Agent trace pills (tool calls, subagent activity) |
353
- | `file` | Live file viewer with auto-update on disk changes |
354
- | `image` | Image viewer (file paths, data URIs, URLs) |
355
- | `webpage` | Persisted webpage snapshot with stored URL, extracted text, and refresh support |
356
- | `mcp-app` | Tool-backed hosted MCP app iframes (Excalidraw, web artifacts, etc.) -- see [MCP app nodes](#mcp-app-nodes) |
357
- | `json-render` | Structured UI from JSON specs |
358
- | `graph` | Line, bar, pie, area, scatter, radar, stacked-bar, and composed charts |
359
- | `group` | Spatial container/frame that contains other nodes |
360
-
361
- Thread node types `prompt` and `response` are used internally for agent conversation
362
- rendering and are not created directly through the public APIs.
363
-
364
- ### Edge types
365
-
366
- All edges support labels, styles (solid/dashed/dotted), and animation.
367
-
368
- | Type | Use case |
369
- |------|----------|
370
- | `flow` | Sequential steps, data flow |
371
- | `depends-on` | Dependencies between tasks |
372
- | `relation` | General relationships |
373
- | `references` | Cross-references, evidence links |
374
-
375
- ### File nodes
376
-
377
- File nodes display project files with line numbers and language detection. When an agent edits a file through its normal tools, the canvas node updates automatically via `fs.watch()`.
378
-
379
- ```typescript
380
- canvas_add_node({ type: 'file', content: 'src/server/index.ts' })
381
- ```
382
-
383
- ### Image nodes
384
-
385
- Image nodes display local paths, remote URLs, and data URIs. File-backed and
386
- HTTP(S)-backed images preserve provenance so agents can tell where evidence
387
- came from, and nodes can carry validation status or warnings when an agent is
388
- using screenshots as proof.
389
-
390
- ```typescript
391
- canvas_add_node({
392
- type: 'image',
393
- content: 'artifacts/dashboard.png',
394
- data: {
395
- validationStatus: 'passed',
396
- validationMessage: 'Screenshot matches the requested dashboard state.',
397
- },
398
- })
399
- ```
400
-
401
- ### Webpage nodes
402
-
403
- Webpage nodes store the source URL on the node, fetch the page server-side, and cache extracted text for search, pins, and agent context. Saved canvases keep enough information for an agent to come back later and refresh the node from the original URL.
404
-
405
- ```typescript
406
- canvas_add_node({ type: 'webpage', url: 'https://example.com/docs' }) // content still works, but url is canonical
407
- canvas_refresh_webpage_node({ id: 'node-abc123' })
408
- ```
409
-
410
- ### MCP app nodes
411
-
412
- `mcp-app` nodes embed other MCP servers' UI resources (`ui://...`) directly on the canvas as
413
- sandboxed iframes. Any server that implements the [MCP Apps extension](https://modelcontextprotocol.io/docs/extensions/apps)
414
- can be opened as a node with `canvas_open_mcp_app`.
415
-
416
- Generic `pmx-canvas node add --type mcp-app` is intentionally rejected because these nodes need
417
- tool/session metadata. Use `pmx-canvas web-artifact build` for bundled React artifacts or
418
- `pmx-canvas external-app add --kind excalidraw` for the Excalidraw preset.
419
-
420
- #### Recommended: Excalidraw (hand-drawn diagrams)
421
-
422
- [Excalidraw](https://github.com/excalidraw/excalidraw-mcp) ships a hosted MCP server at
423
- `https://mcp.excalidraw.com/mcp` that renders hand-drawn diagrams with streaming draw-on
424
- animations and fullscreen editing. It is a strong example of an MCP App that fits naturally
425
- inside PMX Canvas: the app opens as a node, can be moved and pinned like any other node, and
426
- supports fullscreen editing when you want to expand it into a larger workspace.
427
-
428
- PMX Canvas ships a preset so an agent can open an Excalidraw diagram in one call, without wiring
429
- the transport by hand:
430
-
431
- ```bash
432
- pmx-canvas external-app add --kind excalidraw --title "Agent to Canvas"
433
- ```
434
-
435
- ```typescript
436
- canvas_add_diagram({
437
- elements: [
438
- { type: 'rectangle', id: 'a', x: 80, y: 120, width: 180, height: 80,
439
- roundness: { type: 3 }, backgroundColor: '#a5d8ff', fillStyle: 'solid',
440
- label: { text: 'Agent', fontSize: 18 } },
441
- { type: 'rectangle', id: 'b', x: 380, y: 120, width: 180, height: 80,
442
- roundness: { type: 3 }, backgroundColor: '#d0bfff', fillStyle: 'solid',
443
- label: { text: 'PMX Canvas', fontSize: 18 } },
444
- { type: 'arrow', id: 'a1', x: 260, y: 160, width: 120, height: 0,
445
- startBinding: { elementId: 'a' }, endBinding: { elementId: 'b' },
446
- label: { text: 'adds nodes' } },
447
- ],
448
- title: 'Agent → Canvas',
449
- });
450
- ```
451
-
452
- Under the hood this is just a thin alias for `canvas_open_mcp_app` with the Excalidraw transport
453
- preset. You can use the hosted Excalidraw server directly, or point the same flow at a local
454
- `excalidraw-mcp` instance if you prefer running the app yourself. For any other MCP app, use
455
- `canvas_open_mcp_app` directly:
456
-
457
- ```typescript
458
- canvas_open_mcp_app({
459
- transport: { type: 'http', url: 'https://mcp.excalidraw.com/mcp' },
460
- toolName: 'create_view',
461
- serverName: 'Excalidraw',
462
- toolArguments: { elements: '[ ... ]' },
463
- });
464
- ```
465
-
466
- The canvas runs the tool against the remote MCP server, renders the returned `ui://` resource in
467
- a sandboxed iframe node, and keeps the resource's CSP + permission hints intact. Resize, drag,
468
- and pin the node like any other canvas node. Edits made in expanded/fullscreen mode are persisted
469
- back into the node model context and replayed when the iframe remounts.
470
-
471
- ### Json-render nodes
472
-
473
- `json-render` nodes turn structured JSON specs into rendered UI panels (dashboards, tables, forms,
474
- cards) without writing HTML. PMX Canvas ships the [`@json-render/*`](https://www.npmjs.com/package/@json-render/core)
475
- runtime and component catalog (core + react + shadcn), so agents can describe an interface as a
476
- spec and render it inline on the canvas.
477
-
478
- ```typescript
479
- canvas_add_json_render_node({
480
- title: 'Deploy status',
481
- spec: {
482
- root: 'card',
483
- elements: {
484
- card: { type: 'Card', props: { title: 'Deploy' }, children: ['status'] },
485
- status: { type: 'Badge', props: { variant: 'default', text: 'Healthy' } },
486
- },
487
- },
488
- });
489
- ```
490
-
491
- `Badge` uses shadcn variants: `default`, `secondary`, `destructive`, and `outline`.
492
- Older saved specs using `label` or status variants such as `success`/`warning` are
493
- normalized during validation for compatibility.
494
-
495
- Use `canvas_describe_schema` / `canvas_validate_spec` to introspect the component catalog before
496
- building a spec -- see [Schema-driven discovery](#schema-driven-discovery).
106
+ The canvas auto-starts on first tool call.
497
107
 
498
- ### Web artifacts
108
+ ### Install the agent skill (recommended)
499
109
 
500
- A **web artifact** is a single-file, fully bundled HTML app (React + Tailwind + shadcn) that an
501
- agent builds from TSX source and drops onto the canvas as an embedded node. Useful when you want
502
- a real interactive UI -- charts, forms, mini-dashboards -- instead of a static node.
503
-
504
- `canvas_build_web_artifact` takes source strings (`App.tsx`, optional `index.css`, `main.tsx`,
505
- `index.html`, plus extra files), runs the bundled web-artifacts-builder scripts, writes the
506
- self-contained HTML to `.pmx-canvas/artifacts/<slug>.html`, and (by default) opens it in the canvas.
110
+ The fastest way to get a working canvas is to install the `pmx-canvas` agent
111
+ skill. It teaches the agent how to install the package, start the server, and
112
+ drive every node type, group, snapshot, and search the canvas exposes.
507
113
 
508
114
  ```bash
509
- pmx-canvas node add --type web-artifact --title "Dashboard" --app-file ./App.tsx
510
- pmx-canvas web-artifact build --title "Dashboard" --app-file ./App.tsx --deps recharts --include-logs
511
- ```
512
-
513
- The scaffold includes `recharts` for chart-heavy artifacts. Pass `--deps name,name2` for any
514
- additional package dependencies before bundling. Failed or empty CLI bundles print `ok: false`,
515
- exit non-zero, and do not create a canvas node.
516
-
517
- The matching agent skill is at [skills/web-artifacts-builder/SKILL.md](skills/web-artifacts-builder/SKILL.md).
518
-
519
- ### Groups
520
-
521
- Groups are spatial containers that visually contain other nodes. They render as dashed-border frames with a title bar and optional accent color.
522
-
523
- - Select 2+ nodes and click "Group" in the selection bar
524
- - Right-click a group to ungroup
525
- - Collapsing a group hides children and shows a summary
526
- - By default, group creation preserves the children's current positions and expands the frame around them
527
- - Pass `childLayout` to auto-pack children (`grid`, `column`, `flow`)
528
- - Pass explicit `x`, `y`, `width`, and `height` to create a manual frame and lay children out inside it
529
-
530
- ```typescript
531
- canvas_create_group({ title: 'Auth Module', childIds: ['node-1', 'node-2'], color: '#4a9eff' })
532
- ```
533
-
534
- ### Batch operations
535
-
536
- Batch mode lets you build a canvas in one shot and reference earlier results from later operations.
537
-
538
- - HTTP: `POST /api/canvas/batch`
539
- - CLI: `pmx-canvas batch --file ./canvas-ops.json`
540
- - MCP: `canvas_batch`
541
- - SDK: `await canvas.runBatch([...])`
542
-
543
- Supported operations:
544
-
545
- - `node.add`
546
- - `node.update`
547
- - `graph.add`
548
- - `edge.add`
549
- - `group.create`
550
- - `group.add`
551
- - `group.remove`
552
- - `pin.set`, `pin.add`, `pin.remove`
553
- - `snapshot.save`
554
- - `arrange`
555
-
556
- `node.add` also supports `type: "webpage"` inside batch. The batch itself still succeeds when the
557
- webpage node is created but the fetch fails; the per-operation result includes `fetch: { ok, error? }`
558
- plus a top-level `error` field for the fetch problem.
559
-
560
- Example:
561
-
562
- ```json
563
- {
564
- "operations": [
565
- {
566
- "op": "graph.add",
567
- "assign": "wins",
568
- "args": {
569
- "title": "Major wins",
570
- "graphType": "bar",
571
- "data": [
572
- { "label": "Docs", "value": 5 },
573
- { "label": "Tests", "value": 8 }
574
- ],
575
- "xKey": "label",
576
- "yKey": "value"
577
- }
578
- },
579
- {
580
- "op": "group.create",
581
- "assign": "frame",
582
- "args": {
583
- "title": "Quarterly graphs",
584
- "childIds": ["$wins.id"]
585
- }
586
- }
587
- ]
588
- }
589
- ```
590
-
591
- ### Schema-driven discovery
592
-
593
- Agents don't have to guess node shapes. The running server exposes its own create schemas,
594
- json-render component catalog, and node-type examples so an agent can introspect before building.
595
-
596
- - `canvas_describe_schema` / `GET /api/canvas/schema` -- list all node-create schemas, required
597
- fields, json-render components, and sample payloads
598
- - `canvas_validate_spec` / `POST /api/canvas/schema/validate` -- validate a json-render spec or
599
- graph payload **without** creating a node
600
- - `canvas_validate` / `GET /api/canvas/validate` -- validate the current layout for collisions,
601
- containment, and missing edge endpoints
602
- - `canvas://schema` -- the same schema data as an MCP resource
603
-
604
- The CLI's `node schema` / `validate spec` subcommands surface the same data from the terminal,
605
- which is strictly better than guessing flags or payloads.
606
-
607
- MCP node creation uses dedicated tools for structured node families. Read
608
- `mcp.nodeTypeRouting` from `canvas_describe_schema` / `canvas://schema` when in doubt:
609
- `json-render` -> `canvas_add_json_render_node`, `graph` -> `canvas_add_graph_node`,
610
- `web-artifact` -> `canvas_build_web_artifact`, `external-app` -> `canvas_open_mcp_app`,
611
- and `group` -> `canvas_create_group`. Basic nodes such as `markdown`, `status`, `file`,
612
- `image`, and `webpage` use `canvas_add_node`.
613
-
614
- ### Persistence
615
-
616
- Canvas state auto-saves to `.pmx-canvas/state.json` in the workspace root on every mutation (debounced). The file is git-committable -- spatial knowledge persists across sessions and can be shared with a team. Everything the canvas generates (state, snapshots, web artifacts, daemon log/pid) is consolidated under `.pmx-canvas/`. Legacy `.pmx-canvas.json` and `.pmx-canvas-snapshots/` are migrated to the new layout automatically on first boot.
617
-
618
- Configuration env vars:
619
-
620
- - `PMX_CANVAS_STATE_FILE` -- override the persistence path
621
- - `PMX_WEB_CANVAS_PORT` -- server-side default port (server may fall back to another port if taken)
622
- - `PMX_CANVAS_PORT` -- CLI client-side default target port
623
- - `PMX_CANVAS_THEME` -- default theme (`dark`, `light`, `high-contrast`)
624
- - `PMX_CANVAS_DISABLE_BROWSER_OPEN=1` -- skip auto-opening a browser (useful in CI)
625
-
626
- ### Snapshots
627
-
628
- Named checkpoints of the entire canvas state. Save before a refactor, restore if the approach fails, switch between workstreams.
629
-
630
- ```typescript
631
- canvas_snapshot({ name: 'before refactor' })
632
- canvas_restore({ id: 'snap-abc123' })
633
- ```
634
-
635
- Stored in `.pmx-canvas/snapshots/`. Toolbar button opens a panel to save, browse, restore, and delete.
636
-
637
- ### Spatial semantics
638
-
639
- The canvas understands spatial arrangement and exposes it to agents:
640
-
641
- - **`canvas://spatial-context`** -- proximity clusters, reading order, pinned neighborhoods
642
- - **`canvas://pinned-context`** -- includes nearby unpinned nodes for each pin (the human's implicit context)
643
- - **`canvas_search`** -- find nodes by title/content keywords
644
-
645
- ### Time travel
646
-
647
- Every mutation is recorded with undo/redo support (last 200 operations):
648
-
649
- - **`canvas_undo`** / **`canvas_redo`** -- step through history
650
- - **`canvas://history`** -- readable mutation timeline
651
- - **`canvas_diff`** -- compare current state vs any saved snapshot
652
-
653
- ### Code graph
654
-
655
- File nodes automatically detect import dependencies between each other. Add file nodes and watch `depends-on` edges appear as the system parses `import`/`require`/`from` statements across JS/TS, Python, Go, and Rust.
656
-
657
- - **`canvas://code-graph`** -- dependency structure: central files, isolated files, import chains
658
- - Auto-edges update live when files change on disk
659
-
660
- ### Real-time sync
661
-
662
- - SSE push: server broadcasts all changes to connected browsers instantly
663
- - Bidirectional: browser interactions (drag, resize, pin) sync back to server
664
- - Auto-reconnect with exponential backoff
665
- - MCP resource change notifications close the human-to-agent loop
666
-
667
- ### Semantic watch
668
-
669
- `pmx-canvas watch` consumes the SSE stream and emits compact semantic deltas
670
- for agents that need low-token updates instead of full layout snapshots. It
671
- filters noise from harmless moves and reports meaningful events such as pins,
672
- node additions/removals, group changes, edge connections, and moves that
673
- change spatial clustering.
674
-
675
- ```bash
676
- pmx-canvas watch --events context-pin,move-end
677
- pmx-canvas watch --json --events context-pin --max-events 1
678
- ```
679
-
680
- ### WebView automation
681
-
682
- Agents can drive a headless Bun.WebView (Chromium or WebKit) pointed at their own workbench,
683
- so they can screenshot, inspect, and script the live canvas without spawning a user-visible
684
- browser.
685
-
686
- - **Why**: let an agent verify its own UI state (what does the canvas actually look like right now?),
687
- capture screenshots for PR reviews, or script interactions in tests
688
- - **Controls**: `canvas_webview_start` / `_stop` / `_status` to manage the session,
689
- `canvas_evaluate` to run JS in the page, `canvas_resize` to change viewport,
690
- `canvas_screenshot` for PNG/JPEG/WebP captures
691
- - **Backends**: WebKit on macOS by default; Chrome/Chromium elsewhere (override with `--backend`)
692
- - **Mirrored surfaces**: CLI (`pmx-canvas webview ...`), HTTP (`/api/workbench/webview/*`),
693
- SDK (`canvas.startAutomationWebView()` / `evaluateAutomationWebView()` / `screenshotAutomationWebView()`)
694
-
695
- ```bash
696
- pmx-canvas --webview-automation # start canvas + headless WebView session
697
- pmx-canvas webview screenshot --output ./canvas.png
698
- ```
699
-
700
- ### Daemon mode
701
-
702
- Run the canvas as a detached background process with pid/log tracking instead of holding a
703
- terminal:
704
-
705
- ```bash
706
- pmx-canvas serve --daemon --no-open # start detached, wait for health
707
- pmx-canvas serve status # inspect health + pid state
708
- pmx-canvas serve stop # stop the daemon for this port/pid file
709
- ```
710
-
711
- ## Agent skills
712
-
713
- Installing `pmx-canvas` also ships a library of reusable agent skills under the package's
714
- `skills/` directory that teach your agent how to use the canvas and adjacent capabilities
715
- effectively:
716
-
717
- | Skill | Purpose |
718
- |-------|---------|
719
- | [`pmx-canvas`](skills/pmx-canvas/SKILL.md) | **Core canvas workflows** — when to create which node type, how to pin for context, batch builds. Start here. |
720
- | [`web-artifacts-builder`](skills/web-artifacts-builder/SKILL.md) | Build single-file React/Tailwind artifacts and drop them on the canvas as embedded nodes |
721
- | [`json-render-core`](skills/json-render-core/SKILL.md) | Drive the `@json-render/core` runtime — the spec format, parsing, and validation |
722
- | [`json-render-react`](skills/json-render-react/SKILL.md) | Render json-render specs into React using the runtime |
723
- | [`json-render-shadcn`](skills/json-render-shadcn/SKILL.md) | The shadcn/ui component catalog — Card, Stack, Button, Form fields, Tables |
724
- | [`json-render-mcp`](skills/json-render-mcp/SKILL.md) | Expose a json-render spec as a `ui://` MCP resource |
725
- | [`json-render-codegen`](skills/json-render-codegen/SKILL.md) | Generate json-render specs from prompts / structured input |
726
- | [`json-render-ink`](skills/json-render-ink/SKILL.md) | Render json-render specs to the terminal via Ink |
727
- | [`pmx-canvas-testing`](skills/pmx-canvas-testing/SKILL.md) | Testing patterns against the running canvas |
728
- | [`playwright-cli`](skills/playwright-cli/SKILL.md) | Browser automation recipes for canvas + arbitrary pages |
729
- | [`frontend-design`](skills/frontend-design/SKILL.md), [`web-design-guidelines`](skills/web-design-guidelines/SKILL.md) | Design-quality rules for agent-generated UI |
730
- | [`doc-coauthoring`](skills/doc-coauthoring/SKILL.md) | Structured doc-writing flow |
731
- | [`data-analysis`](skills/data-analysis/SKILL.md) | Data exploration patterns |
732
-
733
- (`published-consumer-e2e` exists in `skills/` for maintainer use — it smoke-tests the
734
- published `bunx` path against a clean temp consumer — but it isn't a user-facing skill.)
735
-
736
- You only need to install [`pmx-canvas`](skills/pmx-canvas/SKILL.md) up front (see the
737
- [Quick start](#quick-start)) — once the canvas is running, the agent can read
738
- `canvas://skills` to discover the rest and pull them in as the work demands. The core skill
739
- also references the companion skills directly so the agent knows when each one is the right
740
- tool.
741
-
742
- ## Integration
743
-
744
- ### CLI and MCP alignment
745
-
746
- CLI and MCP are kept aligned for the main canvas operations: node and edge
747
- creation, graph/json-render nodes, web artifacts, external apps, groups,
748
- batch builds, layout validation, snapshots, search, focus, pins, undo/redo,
749
- semantic watch streams, WebView automation, and daemon/server control where
750
- it applies. A few agent-native capabilities, such as resource subscriptions
751
- and `canvas_diff`, remain MCP-only.
752
-
753
- ### MCP server
754
-
755
- 38 tools + 8 core resources, plus per-skill resources under `canvas://skills/<name>`.
756
- Zero config for any MCP-capable agent.
757
-
758
- <details>
759
- <summary>MCP tools</summary>
760
-
761
- | Tool | Description |
762
- |------|-------------|
763
- | `canvas_add_node` | Add a node (markdown, status, context, file, webpage, etc.) |
764
- | `canvas_add_diagram` | Draw a hand-drawn diagram via the hosted Excalidraw MCP app (preset alias for `canvas_open_mcp_app`) |
765
- | `canvas_open_mcp_app` | Open any [MCP Apps](https://modelcontextprotocol.io/docs/extensions/apps) server's `ui://` resource as an iframe node |
766
- | `canvas_describe_schema` | Describe the running server's create schemas, examples, and json-render catalog |
767
- | `canvas_validate_spec` | Validate a json-render spec or graph payload without creating a node |
768
- | `canvas_refresh_webpage_node` | Re-fetch and update a webpage node from its stored URL |
769
- | `canvas_add_json_render_node` | Create a native json-render node from a validated spec |
770
- | `canvas_add_graph_node` | Create a native graph node (line, bar, pie, area, scatter, radar, stacked-bar, composed) |
771
- | `canvas_build_web_artifact` | Build a bundled HTML artifact and open it on the canvas |
772
- | `canvas_update_node` | Update content, position, size, collapsed state |
773
- | `canvas_remove_node` | Remove a node and its edges |
774
- | `canvas_get_layout` | Get full canvas state |
775
- | `canvas_get_node` | Get a single node by ID |
776
- | `canvas_add_edge` | Connect two nodes |
777
- | `canvas_remove_edge` | Remove a connection |
778
- | `canvas_arrange` | Auto-arrange (grid/column/flow) |
779
- | `canvas_validate` | Validate collisions, containment, and missing edge endpoints |
780
- | `canvas_focus_node` | Pan viewport to a node; use CLI `focus --no-pan` when you only need to select/raise |
781
- | `canvas_pin_nodes` | Pin nodes to include in agent context |
782
- | `canvas_clear` | Clear all nodes and edges |
783
- | `canvas_snapshot` | Save current canvas as a named snapshot |
784
- | `canvas_list_snapshots` | List saved snapshots |
785
- | `canvas_restore` | Restore canvas from a saved snapshot |
786
- | `canvas_delete_snapshot` | Delete a saved snapshot |
787
- | `canvas_search` | Find nodes by title/content keywords |
788
- | `canvas_undo` | Undo the last canvas mutation |
789
- | `canvas_redo` | Redo the last undone mutation |
790
- | `canvas_diff` | Compare current canvas vs a saved snapshot |
791
- | `canvas_create_group` | Create a group containing specified nodes |
792
- | `canvas_group_nodes` | Add nodes to an existing group |
793
- | `canvas_ungroup` | Release all children from a group |
794
- | `canvas_batch` | Run a batch of canvas operations with `$ref` support |
795
- | `canvas_webview_status` | Get Bun.WebView automation status for the workbench |
796
- | `canvas_webview_start` | Start or replace the Bun.WebView automation session |
797
- | `canvas_webview_stop` | Stop the active Bun.WebView automation session |
798
- | `canvas_evaluate` | Evaluate JavaScript in the active workbench automation session |
799
- | `canvas_resize` | Resize the active workbench automation viewport |
800
- | `canvas_screenshot` | Capture a screenshot from the active workbench automation session |
801
-
802
- </details>
803
-
804
- <details>
805
- <summary>MCP resources</summary>
806
-
807
- The table lists the core resources. Individual bundled skills are also readable
808
- at `canvas://skills/<name>`.
809
-
810
- | Resource | Description |
811
- |----------|-------------|
812
- | `canvas://pinned-context` | Content of pinned nodes + nearby unpinned neighbors |
813
- | `canvas://schema` | Running-server create schemas and json-render catalog metadata |
814
- | `canvas://layout` | Full canvas state (all nodes, edges, viewport) |
815
- | `canvas://summary` | Compact overview: counts, pinned titles, viewport |
816
- | `canvas://spatial-context` | Proximity clusters, reading order, pinned neighborhoods |
817
- | `canvas://history` | Mutation history timeline with undo/redo position |
818
- | `canvas://code-graph` | Auto-detected file dependency graph (JS/TS, Python, Go, Rust) |
819
- | `canvas://skills` | Index of bundled agent skills + per-skill content at `canvas://skills/<name>` |
820
-
821
- </details>
822
-
823
- The MCP server emits `notifications/resources/updated` when canvas state changes, enabling real-time human-to-agent collaboration.
824
-
825
- ### HTTP API
826
-
827
- REST endpoints for all canvas operations + SSE event stream. Works from any language.
828
-
829
- ```bash
830
- # Get canvas state
831
- curl http://localhost:4313/api/canvas/state
832
-
833
- # Add a node
834
- curl -X POST http://localhost:4313/api/canvas/node \
835
- -H "Content-Type: application/json" \
836
- -d '{"type":"markdown","title":"Hello","content":"# World"}'
837
-
838
- # Add an edge
839
- curl -X POST http://localhost:4313/api/canvas/edge \
840
- -H "Content-Type: application/json" \
841
- -d '{"from":"node-1","to":"node-2","type":"flow","label":"next"}'
842
-
843
- # Add an edge by unique search match instead of explicit IDs
844
- curl -X POST http://localhost:4313/api/canvas/edge \
845
- -H "Content-Type: application/json" \
846
- -d '{"fromSearch":"DVT O3 — GitOps","toSearch":"deep work trend","type":"relation"}'
847
-
848
- # Pin nodes for agent context
849
- curl -X POST http://localhost:4313/api/canvas/context-pins \
850
- -H "Content-Type: application/json" \
851
- -d '{"nodeIds":["node-1","node-2"]}'
852
-
853
- # Get pinned context
854
- curl http://localhost:4313/api/canvas/pinned-context
855
-
856
- # Draw a hand-drawn diagram via the Excalidraw MCP app preset
857
- curl -X POST http://localhost:4313/api/canvas/diagram \
858
- -H "Content-Type: application/json" \
859
- -d '{"elements":[{"type":"rectangle","id":"r1","x":60,"y":60,"width":180,"height":80,"roundness":{"type":3},"backgroundColor":"#a5d8ff","fillStyle":"solid","label":{"text":"Hello","fontSize":18}}],"title":"Diagram"}'
860
-
861
- # SSE event stream
862
- curl -N http://localhost:4313/api/workbench/events
863
-
864
- # Start WebView automation
865
- curl -X POST http://localhost:4313/api/workbench/webview/start \
866
- -H "Content-Type: application/json" \
867
- -d '{"backend":"chrome","width":1280,"height":800}'
868
-
869
- # Evaluate JS in the active WebView session
870
- curl -X POST http://localhost:4313/api/workbench/webview/evaluate \
871
- -H "Content-Type: application/json" \
872
- -d '{"expression":"document.title"}'
873
-
874
- # Resize the active WebView session
875
- curl -X POST http://localhost:4313/api/workbench/webview/resize \
876
- -H "Content-Type: application/json" \
877
- -d '{"width":1440,"height":900}'
878
-
879
- # Capture a screenshot
880
- curl -X POST http://localhost:4313/api/workbench/webview/screenshot \
881
- -H "Content-Type: application/json" \
882
- -d '{"format":"png"}' \
883
- --output canvas.png
884
-
885
- # Search nodes
886
- curl "http://localhost:4313/api/canvas/search?q=auth"
887
-
888
- # Run a batch build
889
- curl -X POST http://localhost:4313/api/canvas/batch \
890
- -H "Content-Type: application/json" \
891
- -d '{"operations":[{"op":"node.add","assign":"a","args":{"type":"markdown","title":"A"}},{"op":"group.create","args":{"title":"Frame","childIds":["$a.id"]}}]}'
892
-
893
- # Validate the current layout
894
- curl http://localhost:4313/api/canvas/validate
895
-
896
- # Inspect running-server schemas
897
- curl http://localhost:4313/api/canvas/schema
898
-
899
- # Validate a json-render spec without creating a node
900
- curl -X POST http://localhost:4313/api/canvas/schema/validate \
901
- -H "Content-Type: application/json" \
902
- -d '{"type":"json-render","spec":{"root":"card","elements":{"card":{"type":"Card","props":{"title":"Preview"},"children":[]}}}}'
903
-
904
- # Undo / redo
905
- curl -X POST http://localhost:4313/api/canvas/undo
906
- curl -X POST http://localhost:4313/api/canvas/redo
907
- ```
908
-
909
- Search-based edge creation is intentionally strict: `fromSearch` and `toSearch` must each resolve
910
- to exactly one node. Broad queries such as `"DVT O3"` may fail if multiple nodes match; use the
911
- full visible title instead.
912
-
913
- ### JavaScript/TypeScript SDK (Bun runtime)
914
-
915
- ```typescript
916
- import { createCanvas } from 'pmx-canvas';
917
-
918
- const canvas = createCanvas({ port: 4313 });
919
- await canvas.start({ open: true });
920
-
921
- // Add nodes
922
- const n1 = canvas.addNode({ type: 'markdown', title: 'Plan', content: '# Step 1\nDo the thing.' });
923
- const n2 = canvas.addNode({ type: 'status', title: 'Build', content: 'passing' });
924
- const n3 = canvas.addNode({ type: 'file', content: 'src/index.ts' });
925
-
926
- // Connect them
927
- canvas.addEdge({ from: n1, to: n2, type: 'flow' });
928
-
929
- // Group related nodes
930
- canvas.createGroup({ title: 'Build Pipeline', childIds: [n1, n2] });
931
-
932
- // Draw a hand-drawn diagram via the Excalidraw MCP-app preset
933
- await canvas.addDiagram({
934
- elements: [
935
- { type: 'rectangle', id: 'r1', x: 80, y: 80, width: 160, height: 60,
936
- roundness: { type: 3 }, backgroundColor: '#a5d8ff', fillStyle: 'solid',
937
- label: { text: 'Agent' } },
938
- ],
939
- title: 'Quick sketch',
940
- });
941
-
942
- // Batch-build a graph and group around it
943
- await canvas.runBatch([
944
- {
945
- op: 'graph.add',
946
- assign: 'graph',
947
- args: {
948
- title: 'Major wins',
949
- graphType: 'bar',
950
- data: [
951
- { label: 'Docs', value: 5 },
952
- { label: 'Tests', value: 8 },
953
- ],
954
- xKey: 'label',
955
- yKey: 'value',
956
- },
957
- },
958
- {
959
- op: 'group.create',
960
- args: {
961
- title: 'Quarterly graphs',
962
- childIds: ['$graph.id'],
963
- },
964
- },
965
- ]);
966
-
967
- // Arrange and inspect
968
- canvas.arrange('grid');
969
- console.log(canvas.validate());
970
- console.log(canvas.getLayout());
971
-
972
- // Optional WebView automation
973
- const webview = await canvas.startAutomationWebView({ backend: 'chrome', width: 1280, height: 800 });
974
- console.log(webview.active);
975
- console.log(await canvas.evaluateAutomationWebView('document.title'));
976
- await canvas.resizeAutomationWebView(1440, 900);
977
- const screenshot = await canvas.screenshotAutomationWebView({ format: 'png' });
978
- console.log(screenshot.byteLength);
979
- await canvas.stopAutomationWebView();
980
- ```
981
-
982
- ### CLI
983
-
984
- The CLI is the equally recommended shell-native way to run and control PMX Canvas.
115
+ # 1. GitHub CLI extension (gh >= 2.90)
116
+ gh skill install pskoett/pmx-canvas pmx-canvas
985
117
 
986
- The CLI targets `http://localhost:4313` by default. Override with `PMX_CANVAS_URL` or
987
- `PMX_CANVAS_PORT` when the server runs elsewhere.
118
+ # 2. Agent Skills CLI (runtime-agnostic)
119
+ npx skills add pskoett/pmx-canvas/skills/pmx-canvas
988
120
 
989
- ```bash
990
- pmx-canvas # Start canvas, open browser
991
- pmx-canvas --demo # Start with sample nodes
992
- pmx-canvas --port=8080 # Custom port
993
- pmx-canvas --no-open # Headless (for agents)
994
- pmx-canvas serve --daemon --no-open # Start a detached daemon and wait for health
995
- pmx-canvas serve status # Inspect daemon health + pid state
996
- pmx-canvas serve stop # Stop the daemon for this port/pid file
997
- pmx-canvas --theme=light # Light theme (dark, light, high-contrast)
998
- pmx-canvas --mcp # Run as MCP server (stdio)
999
- pmx-canvas --webview-automation # Start headless Bun.WebView session
1000
- pmx-canvas open # Open the current workbench in a browser
1001
- pmx-canvas node add --type webpage --url https://example.com/docs
1002
- pmx-canvas node add --type web-artifact --title "Dashboard" --app-file ./App.tsx
1003
- pmx-canvas node add --help --type webpage --json
1004
- pmx-canvas external-app add --kind excalidraw --title "Diagram"
1005
- pmx-canvas node add --type graph --graph-type bar --data-file ./metrics.json --x-key label --y-key value
1006
- pmx-canvas node add --type graph --graph-type bar --data '[{"x":"a","y":1}]' --x-key x --y-key y
1007
- pmx-canvas graph add --graph-type bar --data '[{"x":"a","y":1}]' --x-key x --y-key y # Alias for graph nodes
1008
- pmx-canvas node schema --type json-render --component Table --summary
1009
- pmx-canvas edge add --from-search "DVT O3 — GitOps" --to-search "deep work trend" --type relation
1010
- pmx-canvas batch --file ./canvas-ops.json
1011
- pmx-canvas validate
1012
- pmx-canvas watch --events context-pin,move-end
1013
- pmx-canvas focus <node-id> --no-pan
1014
- pmx-canvas validate spec --type json-render --spec-file ./dashboard.json --summary
1015
- pmx-canvas web-artifact build --title "Dashboard" --app-file ./App.tsx --deps recharts --include-logs
1016
- pmx-canvas webview status # Show WebView automation status
1017
- pmx-canvas webview start --backend chrome --width 1440 --height 900
1018
- pmx-canvas webview evaluate --expression "document.title"
1019
- pmx-canvas webview resize --width 1280 --height 800
1020
- pmx-canvas webview screenshot --output ./canvas.png
1021
- pmx-canvas webview stop
121
+ # 3. Manual clone + copy
122
+ git clone https://github.com/pskoett/pmx-canvas.git
123
+ cp -r pmx-canvas/skills/pmx-canvas <your-agent-skills-dir>
1022
124
  ```
1023
125
 
1024
- Use the CLI when you want:
1025
-
1026
- - direct terminal control without MCP wiring
1027
- - shell scripts and CI-friendly automation
1028
- - schema-driven discovery from the running server instead of guessing flags or payloads
1029
- - local debugging of canvas, webview, and screenshot flows
1030
- - a control surface that covers normal canvas work without MCP wiring
1031
-
1032
- The CLI create commands return the created node shape with normalized title/content and geometry,
1033
- which makes scripting stacked layouts and batch follow-up operations easier.
126
+ Common harness skill directories: `.claude/skills/` (Claude Code),
127
+ `.github/skills/` or `.copilot/skills/` (Copilot CLI),
128
+ `.agents/skills/` (cross-harness convention). Once the canvas is running,
129
+ the agent can read `canvas://skills` and pull in companion skills
130
+ (`web-artifacts-builder`, `json-render-*`, `pmx-canvas-testing`,
131
+ `playwright-cli`, etc.) as the work demands.
1034
132
 
1035
- For graph nodes, `node add --type graph` is the canonical CLI form. `graph add`
1036
- is a convenience alias that uses the same flags and server endpoint.
133
+ ## Documentation
1037
134
 
1038
- Graph height flags are split by target: `--node-height` / `--nodeHeight` control
1039
- the canvas node frame, while `--chart-height` controls the chart content inside
1040
- the node. CLI `--height` is still accepted as a frame-height compatibility alias.
1041
- For MCP/HTTP payloads, use `nodeHeight` for the frame and `height` for chart content.
135
+ - **[Node types](docs/node-types.md)** every node type, edge types, and
136
+ the three-tier visual matrix (json-render html web-artifact)
137
+ - **[CLI reference](docs/cli.md)** full command surface, daemon mode,
138
+ watch streams, WebView automation
139
+ - **[MCP reference](docs/mcp.md)** — 40 tools, 8 resources, change
140
+ notifications, node-type routing
141
+ - **[HTTP API](docs/http-api.md)** — REST endpoints, SSE, batch operations
142
+ - **[Bun SDK](docs/sdk.md)** — `createCanvas()` for TypeScript on Bun
143
+ - **[Release process](docs/RELEASE.md)** — maintainer-only
1042
144
 
1043
- ## Agent compatibility
1044
-
1045
- pmx-canvas is harness-agnostic. Any agent that can spawn an MCP stdio server,
1046
- make HTTP requests, or invoke a CLI can drive the canvas.
1047
-
1048
- | Capability | Path | Config |
1049
- |------------|------|--------|
1050
- | MCP-capable agent | MCP stdio server | `"command": "bunx", "args": ["pmx-canvas", "--mcp"]` |
1051
- | Shell-driven agent | CLI | `bunx pmx-canvas …` (see [Recommended ways to drive the canvas](#recommended-ways-to-drive-the-canvas)) |
1052
- | HTTP-only environment | REST + SSE | `fetch()` / `curl` at `http://localhost:4313/api/canvas/...` |
1053
- | Bun runtime | TypeScript SDK | `import { createCanvas } from 'pmx-canvas'` |
145
+ ## Scope
1054
146
 
1055
- ## Architecture
1056
-
1057
- ```
1058
- Agent harness (any MCP-capable client, CLI consumer, or HTTP caller)
1059
- |
1060
- |-- MCP Server ---- 38 tools + 8 core resources + per-skill resources + change notifications
1061
- |-- Bun SDK ------- createCanvas()
1062
- |-- HTTP API ------ REST + SSE at localhost:4313
1063
- |
1064
- v
1065
- Bun.serve HTTP + SSE Server
1066
- | CanvasStateManager (authoritative state)
1067
- | Context pins (human curates -> agent notified)
1068
- | File watcher (fs.watch -> live node updates)
1069
- | Code graph (auto-detected dependencies)
1070
- | Persistence (.pmx-canvas/state.json)
1071
- | Snapshots (.pmx-canvas/snapshots/)
1072
- |
1073
- v
1074
- Browser (Preact SPA at /workbench)
1075
- Pan/zoom canvas with nodes + edges + minimap
1076
- @preact/signals reactive state
1077
- SSE bridge for real-time updates
1078
- Theme toggle (dark/light/high-contrast)
1079
- ```
147
+ - **Single-machine, today.** One canvas per `bunx pmx-canvas` instance, on
148
+ one machine. No built-in multi-user auth or presence — collaboration means
149
+ human ↔ agent on the same machine, plus any other browser tab/agent
150
+ pointed at the same `localhost:4313`. To share across machines, commit
151
+ `.pmx-canvas/state.json`.
152
+ - **What leaves your machine.** The core canvas runs entirely on
153
+ `localhost`. Network egress only happens for explicit, opt-in flows:
154
+ `webpage` nodes fetch the URL you give them; `mcp-app` /
155
+ `canvas_add_diagram` calls go to whatever MCP server URL you configure
156
+ (the Excalidraw preset uses `https://mcp.excalidraw.com/mcp`); `bunx`
157
+ itself reads the npm registry on first install. Nothing else phones home.
1080
158
 
1081
159
  ## Tech stack
1082
160
 
1083
161
  - **Runtime:** [Bun](https://bun.sh)
1084
162
  - **UI:** [Preact](https://preactjs.com) + [@preact/signals](https://github.com/preactjs/signals)
1085
- - **Styling:** CSS custom properties for the main canvas UI, plus a Tailwind-based build for the json-render viewer bundle
163
+ - **Styling:** CSS custom properties + Tailwind (json-render bundle only)
1086
164
  - **Server:** Bun.serve (HTTP + SSE)
1087
- - **MCP:** [@modelcontextprotocol/sdk](https://github.com/modelcontextprotocol/typescript-sdk) (stdio transport)
165
+ - **MCP:** [@modelcontextprotocol/sdk](https://github.com/modelcontextprotocol/typescript-sdk) (stdio)
1088
166
 
1089
167
  ## Development
1090
168
 
1091
169
  ```bash
1092
- bun install # Install dependencies
1093
- bun run build # Build client SPA -> dist/canvas/
1094
- bun run dev # Start server + open browser
1095
- bun run dev:demo # Start with sample nodes
1096
- bun run dev:portless # Start at https://pmx.localhost/workbench
1097
- bun run dev:portless:demo # Same, with demo nodes
1098
- ```
1099
-
1100
- ### Testing
1101
-
1102
- ```bash
1103
- bun run test # Unit tests
1104
- bun run test:coverage # Unit tests with text summary + coverage/lcov.info
1105
- bun run test:e2e # Playwright end-to-end tests
1106
- bun run test:e2e-cli # Fresh-workspace CLI coverage eval
1107
- bun run test:all # Unit tests + browser smoke
170
+ git clone https://github.com/pskoett/pmx-canvas.git
171
+ cd pmx-canvas
172
+ bun install
173
+ bun run build
174
+ bun run dev # Start + open browser
175
+ bun run dev:demo # Start with the demo board
176
+ bun run test # Unit tests
177
+ bun run test:e2e # Playwright end-to-end tests
178
+ bun run test:all # Unit tests + browser smoke
1108
179
  ```
1109
180
 
1110
- `bun run test:e2e-cli` starts a local server in a fresh temp workspace and verifies the CLI flows
1111
- from the durable eval in [docs/evals/e2e-cli-coverage.md](docs/evals/e2e-cli-coverage.md):
1112
- parseable JSON, node creation, graph `--data`, web-artifact failure handling, Excalidraw external
1113
- apps, `focus --no-pan`, arrange/validate, and status subtype reporting.
1114
-
1115
- ### Project structure
1116
-
1117
- ```
1118
- src/
1119
- server/ # HTTP/SSE server, state management
1120
- index.ts # PmxCanvas class, createCanvas() export
1121
- server.ts # Bun.serve HTTP + SSE, REST endpoints
1122
- canvas-state.ts # CanvasStateManager (authoritative state)
1123
- client/ # Preact SPA (served at /workbench)
1124
- App.tsx # Root component
1125
- canvas/ # Viewport, nodes, edges, minimap
1126
- nodes/ # Node type renderers
1127
- state/ # State management (canvas-store, sse-bridge)
1128
- cli/
1129
- index.ts # CLI entry point
1130
- mcp/
1131
- server.ts # MCP server (tools + resources)
1132
- dist/
1133
- canvas/ # Built client SPA
1134
- ```
181
+ For developer flows on the `pmx-canvas` repo itself (release process,
182
+ contribution gates, agent-skill mirroring) see
183
+ [`AGENTS.md`](AGENTS.md) and [`docs/RELEASE.md`](docs/RELEASE.md).
1135
184
 
1136
185
  ## Contributing
1137
186
 
1138
- Contributions are welcome. Please open an issue first to discuss what you'd like to change.
187
+ Contributions welcome. Please open an issue first to discuss what you'd like
188
+ to change.
1139
189
 
1140
190
  1. Fork the repo
1141
191
  2. Create a feature branch (`git checkout -b feature/my-change`)