pmx-canvas 0.1.18 → 0.1.19
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/CHANGELOG.md +54 -0
- package/dist/types/server/canvas-state.d.ts +2 -0
- package/docs/RELEASE.md +153 -0
- package/docs/bun-webview-integration.md +296 -0
- package/docs/cli.md +140 -0
- package/docs/evals/e2e-cli-coverage.md +61 -0
- package/docs/http-api.md +191 -0
- package/docs/mcp.md +135 -0
- package/docs/node-types.md +244 -0
- package/docs/plans/.gitkeep +0 -0
- package/docs/plans/plan-001-semantic-watch-mvp.md +335 -0
- package/docs/plans/plan-002-human-attention-layer-design-spec.md +679 -0
- package/docs/plans/plan-003-human-attention-layer-implementation-plan.md +572 -0
- package/docs/reactive-canvas-proposal.md +578 -0
- package/docs/release-review-0.1.0.md +38 -0
- package/docs/screenshot.png +0 -0
- package/docs/screenshots/demo-workbench-dark.png +0 -0
- package/docs/screenshots/demo-workbench-light.png +0 -0
- package/docs/screenshots/welcome-dark.png +0 -0
- package/docs/screenshots/welcome-light.png +0 -0
- package/docs/sdk.md +92 -0
- package/package.json +2 -1
- package/src/cli/agent.ts +17 -0
- package/src/mcp/canvas-access.ts +2 -0
- package/src/mcp/server.ts +2 -0
- package/src/server/canvas-state.ts +18 -5
- package/src/server/server.ts +2 -0
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: eval-20260424-001
|
|
3
|
+
pattern-key: pmx-canvas.cli-e2e-fresh-workspace
|
|
4
|
+
source: pmx-canvas-0.1.2-e2e-cli-coverage-report
|
|
5
|
+
promoted-rule: "Fresh-workspace CLI coverage must verify node creation, parseable JSON, web-artifact failure behavior, external apps, arrange/validate, and focus no-pan before release."
|
|
6
|
+
promoted-to: package.json test:e2e-cli
|
|
7
|
+
created: 2026-04-24
|
|
8
|
+
last-run: 2026-04-25
|
|
9
|
+
last-result: pass
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# PMX Canvas CLI E2E Coverage Eval
|
|
13
|
+
|
|
14
|
+
## What This Tests
|
|
15
|
+
|
|
16
|
+
Prevents regressions in the published-agent CLI flows that caused the 0.1.2 E2E report failures.
|
|
17
|
+
|
|
18
|
+
## Precondition
|
|
19
|
+
|
|
20
|
+
- Bun is installed.
|
|
21
|
+
- The repo has been built with `bun run build` when client/browser assets changed.
|
|
22
|
+
- Network is available for the hosted Excalidraw MCP preset and web-artifact dependency install.
|
|
23
|
+
- Port `4567` is free, or `PMX_CANVAS_E2E_PORT` is set to a free port.
|
|
24
|
+
|
|
25
|
+
## Verification Method
|
|
26
|
+
|
|
27
|
+
Command check:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
bun run test:e2e-cli
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
The command runs `scripts/e2e-cli-coverage.sh`, which creates a fresh temp workspace, starts the local PMX Canvas CLI server, and verifies:
|
|
34
|
+
|
|
35
|
+
- `layout` and `node list` emit JSON parseable by Python's `json` module.
|
|
36
|
+
- Core node types can be created through the CLI, including two webpage input paths.
|
|
37
|
+
- Graph nodes accept `--data` as an alias for `--data-json`.
|
|
38
|
+
- All graph variants create successfully: line, bar, pie, area, scatter, radar, stacked-bar, composed.
|
|
39
|
+
- Simple and dashboard-shaped json-render specs create successfully.
|
|
40
|
+
- Generic `node add --type mcp-app` is rejected with guidance.
|
|
41
|
+
- `external-app add --kind excalidraw` creates a tool-backed app node.
|
|
42
|
+
- Broken web-artifact builds return `ok: false`, exit non-zero, and do not create a node.
|
|
43
|
+
- One successful web-artifact build emits a substantial bundled React/Recharts app, opens a node, and browser-verifies the real app content renders in the iframe.
|
|
44
|
+
- `focus --no-pan` selects without viewport panning.
|
|
45
|
+
- `arrange --layout grid` and `validate` agree on a valid layout.
|
|
46
|
+
- Search can find artifact nodes and `status` reports expected graph/json-render/web-artifact counts.
|
|
47
|
+
|
|
48
|
+
## Expected Result
|
|
49
|
+
|
|
50
|
+
**Pass:** `PMX Canvas CLI E2E coverage passed` and exit code 0.
|
|
51
|
+
|
|
52
|
+
**Fail:** Any command exits non-zero, JSON parsing fails, an assertion fails, or the server does not become healthy.
|
|
53
|
+
|
|
54
|
+
## Recovery Action
|
|
55
|
+
|
|
56
|
+
If this eval fails:
|
|
57
|
+
|
|
58
|
+
1. Re-run with `PMX_CANVAS_E2E_KEEP_WORKDIR=1 bun run test:e2e-cli` to preserve the temp workspace.
|
|
59
|
+
2. Inspect the preserved `.pmx-canvas/` state and `pmx-canvas.log` printed by the script.
|
|
60
|
+
3. Fix the failing CLI/server path and add or update the narrower unit regression.
|
|
61
|
+
4. Re-run `bun run test:e2e-cli`, then `bun run test:all` before release.
|
package/docs/http-api.md
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
# HTTP API reference
|
|
2
|
+
|
|
3
|
+
REST endpoints for all canvas operations + an SSE event stream. Works from
|
|
4
|
+
any language. Default base URL: `http://localhost:4313`.
|
|
5
|
+
|
|
6
|
+
## Canvas state
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
# Get canvas state
|
|
10
|
+
curl http://localhost:4313/api/canvas/state
|
|
11
|
+
|
|
12
|
+
# Search nodes
|
|
13
|
+
curl "http://localhost:4313/api/canvas/search?q=auth"
|
|
14
|
+
|
|
15
|
+
# Validate the current layout
|
|
16
|
+
curl http://localhost:4313/api/canvas/validate
|
|
17
|
+
|
|
18
|
+
# Inspect running-server schemas
|
|
19
|
+
curl http://localhost:4313/api/canvas/schema
|
|
20
|
+
|
|
21
|
+
# Validate a json-render spec without creating a node
|
|
22
|
+
curl -X POST http://localhost:4313/api/canvas/schema/validate \
|
|
23
|
+
-H "Content-Type: application/json" \
|
|
24
|
+
-d '{"type":"json-render","spec":{"root":"card","elements":{"card":{"type":"Card","props":{"title":"Preview"},"children":[]}}}}'
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Nodes
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
# Add a node
|
|
31
|
+
curl -X POST http://localhost:4313/api/canvas/node \
|
|
32
|
+
-H "Content-Type: application/json" \
|
|
33
|
+
-d '{"type":"markdown","title":"Hello","content":"# World"}'
|
|
34
|
+
|
|
35
|
+
# Add an html node (sandboxed iframe)
|
|
36
|
+
curl -X POST http://localhost:4313/api/canvas/node \
|
|
37
|
+
-H "Content-Type: application/json" \
|
|
38
|
+
-d '{"type":"html","title":"Chart","html":"<canvas id=\"c\"></canvas><script src=\"https://cdn.jsdelivr.net/npm/chart.js\"></script><script>/* ... */</script>"}'
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Edges
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
# Add an edge
|
|
45
|
+
curl -X POST http://localhost:4313/api/canvas/edge \
|
|
46
|
+
-H "Content-Type: application/json" \
|
|
47
|
+
-d '{"from":"node-1","to":"node-2","type":"flow","label":"next"}'
|
|
48
|
+
|
|
49
|
+
# Add an edge by unique search match instead of explicit IDs
|
|
50
|
+
curl -X POST http://localhost:4313/api/canvas/edge \
|
|
51
|
+
-H "Content-Type: application/json" \
|
|
52
|
+
-d '{"fromSearch":"DVT O3 — GitOps","toSearch":"deep work trend","type":"relation"}'
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Search-based edge creation is intentionally strict: `fromSearch` and
|
|
56
|
+
`toSearch` must each resolve to exactly one node. Broad queries that match
|
|
57
|
+
multiple nodes fail; use the full visible title.
|
|
58
|
+
|
|
59
|
+
## Annotations
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
# Add a freehand annotation. The default/currentColor stroke follows the active theme.
|
|
63
|
+
curl -X POST http://localhost:4313/api/canvas/annotation \
|
|
64
|
+
-H "Content-Type: application/json" \
|
|
65
|
+
-d '{"points":[{"x":100,"y":120},{"x":220,"y":120}],"color":"currentColor","width":4}'
|
|
66
|
+
|
|
67
|
+
# Remove an annotation
|
|
68
|
+
curl -X DELETE http://localhost:4313/api/canvas/annotation/ann-123
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Agent-readable context reports annotation IDs, targets, and bounds. Use WebView
|
|
72
|
+
inspection or screenshots when the drawn shape matters.
|
|
73
|
+
|
|
74
|
+
## Pins
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
# Pin nodes for agent context
|
|
78
|
+
curl -X POST http://localhost:4313/api/canvas/context-pins \
|
|
79
|
+
-H "Content-Type: application/json" \
|
|
80
|
+
-d '{"nodeIds":["node-1","node-2"]}'
|
|
81
|
+
|
|
82
|
+
# Get pinned context
|
|
83
|
+
curl http://localhost:4313/api/canvas/pinned-context
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Diagrams (Excalidraw preset)
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
curl -X POST http://localhost:4313/api/canvas/diagram \
|
|
90
|
+
-H "Content-Type: application/json" \
|
|
91
|
+
-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"}'
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## SSE event stream
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
curl -N http://localhost:4313/api/workbench/events
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
The browser, the CLI `watch` command, and the MCP resource notifications
|
|
101
|
+
all consume this stream. Auto-reconnect with exponential backoff.
|
|
102
|
+
|
|
103
|
+
## Time travel
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
curl -X POST http://localhost:4313/api/canvas/undo
|
|
107
|
+
curl -X POST http://localhost:4313/api/canvas/redo
|
|
108
|
+
curl http://localhost:4313/api/canvas/history
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## WebView automation
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
# Start WebView automation
|
|
115
|
+
curl -X POST http://localhost:4313/api/workbench/webview/start \
|
|
116
|
+
-H "Content-Type: application/json" \
|
|
117
|
+
-d '{"backend":"chrome","width":1280,"height":800}'
|
|
118
|
+
|
|
119
|
+
# Evaluate JS in the active WebView session
|
|
120
|
+
curl -X POST http://localhost:4313/api/workbench/webview/evaluate \
|
|
121
|
+
-H "Content-Type: application/json" \
|
|
122
|
+
-d '{"expression":"document.title"}'
|
|
123
|
+
|
|
124
|
+
# Resize the active WebView session
|
|
125
|
+
curl -X POST http://localhost:4313/api/workbench/webview/resize \
|
|
126
|
+
-H "Content-Type: application/json" \
|
|
127
|
+
-d '{"width":1440,"height":900}'
|
|
128
|
+
|
|
129
|
+
# Capture a screenshot
|
|
130
|
+
curl -X POST http://localhost:4313/api/workbench/webview/screenshot \
|
|
131
|
+
-H "Content-Type: application/json" \
|
|
132
|
+
-d '{"format":"png"}' \
|
|
133
|
+
--output canvas.png
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Batch operations
|
|
137
|
+
|
|
138
|
+
Build a canvas in one shot. Earlier results can be referenced from later
|
|
139
|
+
operations via `$assigned-name.field`.
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
curl -X POST http://localhost:4313/api/canvas/batch \
|
|
143
|
+
-H "Content-Type: application/json" \
|
|
144
|
+
-d '{"operations":[{"op":"node.add","assign":"a","args":{"type":"markdown","title":"A"}},{"op":"group.create","args":{"title":"Frame","childIds":["$a.id"]}}]}'
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Supported operations:
|
|
148
|
+
|
|
149
|
+
- `node.add`, `node.update`
|
|
150
|
+
- `graph.add`
|
|
151
|
+
- `edge.add`
|
|
152
|
+
- `group.create`, `group.add`, `group.remove`
|
|
153
|
+
- `pin.set`, `pin.add`, `pin.remove`
|
|
154
|
+
- `snapshot.save`
|
|
155
|
+
- `arrange`
|
|
156
|
+
|
|
157
|
+
`node.add` supports `type: "webpage"` inside batch. The batch itself still
|
|
158
|
+
succeeds when the webpage node is created but the fetch fails; the
|
|
159
|
+
per-operation result includes `fetch: { ok, error? }` plus a top-level
|
|
160
|
+
`error` field for the fetch problem.
|
|
161
|
+
|
|
162
|
+
Example with assignments:
|
|
163
|
+
|
|
164
|
+
```json
|
|
165
|
+
{
|
|
166
|
+
"operations": [
|
|
167
|
+
{
|
|
168
|
+
"op": "graph.add",
|
|
169
|
+
"assign": "wins",
|
|
170
|
+
"args": {
|
|
171
|
+
"title": "Major wins",
|
|
172
|
+
"graphType": "bar",
|
|
173
|
+
"data": [
|
|
174
|
+
{ "label": "Docs", "value": 5 },
|
|
175
|
+
{ "label": "Tests", "value": 8 }
|
|
176
|
+
],
|
|
177
|
+
"xKey": "label",
|
|
178
|
+
"yKey": "value"
|
|
179
|
+
}
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
"op": "group.create",
|
|
183
|
+
"assign": "frame",
|
|
184
|
+
"args": {
|
|
185
|
+
"title": "Quarterly graphs",
|
|
186
|
+
"childIds": ["$wins.id"]
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
]
|
|
190
|
+
}
|
|
191
|
+
```
|
package/docs/mcp.md
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# MCP reference
|
|
2
|
+
|
|
3
|
+
PMX Canvas ships an MCP stdio server with **41 tools** + **8 core resources**,
|
|
4
|
+
plus per-skill resources at `canvas://skills/<name>`. The server emits
|
|
5
|
+
`notifications/resources/updated` when canvas state changes — humans pin
|
|
6
|
+
nodes in the browser, agents are notified immediately.
|
|
7
|
+
|
|
8
|
+
## Connect
|
|
9
|
+
|
|
10
|
+
Add to your agent's MCP config:
|
|
11
|
+
|
|
12
|
+
```json
|
|
13
|
+
{
|
|
14
|
+
"mcpServers": {
|
|
15
|
+
"canvas": {
|
|
16
|
+
"command": "bunx",
|
|
17
|
+
"args": ["pmx-canvas", "--mcp"]
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
The canvas auto-starts on first tool call.
|
|
24
|
+
|
|
25
|
+
## Tools
|
|
26
|
+
|
|
27
|
+
| Tool | Description |
|
|
28
|
+
|------|-------------|
|
|
29
|
+
| `canvas_add_node` | Add a node (markdown, status, context, file, webpage, html, etc.) |
|
|
30
|
+
| `canvas_add_html_node` | Create an `html` node from a self-contained HTML/JS document (sandboxed iframe) |
|
|
31
|
+
| `canvas_add_diagram` | Hand-drawn diagram via the hosted Excalidraw MCP App (preset alias for `canvas_open_mcp_app`) |
|
|
32
|
+
| `canvas_open_mcp_app` | Open any [MCP Apps](https://modelcontextprotocol.io/docs/extensions/apps) server's `ui://` resource as an iframe node |
|
|
33
|
+
| `canvas_describe_schema` | Describe the running server's create schemas, examples, and json-render catalog |
|
|
34
|
+
| `canvas_validate_spec` | Validate a json-render spec or graph payload without creating a node |
|
|
35
|
+
| `canvas_refresh_webpage_node` | Re-fetch and update a webpage node from its stored URL |
|
|
36
|
+
| `canvas_add_json_render_node` | Create a native json-render node from a validated spec |
|
|
37
|
+
| `canvas_add_graph_node` | Create a native graph node (line, bar, pie, area, scatter, radar, stacked-bar, composed) |
|
|
38
|
+
| `canvas_build_web_artifact` | Build a bundled HTML artifact and open it on the canvas |
|
|
39
|
+
| `canvas_update_node` | Update content, position, size, collapsed state |
|
|
40
|
+
| `canvas_remove_node` | Remove a node and its edges |
|
|
41
|
+
| `canvas_get_layout` | Get full canvas state |
|
|
42
|
+
| `canvas_get_node` | Get a single node by ID |
|
|
43
|
+
| `canvas_remove_annotation` | Remove a human-drawn annotation by ID |
|
|
44
|
+
| `canvas_add_edge` | Connect two nodes |
|
|
45
|
+
| `canvas_remove_edge` | Remove a connection |
|
|
46
|
+
| `canvas_arrange` | Auto-arrange (grid/column/flow) |
|
|
47
|
+
| `canvas_validate` | Validate collisions, containment, and missing edge endpoints |
|
|
48
|
+
| `canvas_focus_node` | Pan viewport to a node; use CLI `focus --no-pan` when you only need to select/raise |
|
|
49
|
+
| `canvas_pin_nodes` | Pin nodes to include in agent context |
|
|
50
|
+
| `canvas_clear` | Clear all nodes and edges |
|
|
51
|
+
| `canvas_snapshot` | Save current canvas as a named snapshot |
|
|
52
|
+
| `canvas_list_snapshots` | List saved snapshots, bounded to the newest 20 by default |
|
|
53
|
+
| `canvas_gc_snapshots` | Delete old snapshots while keeping the newest N |
|
|
54
|
+
| `canvas_restore` | Restore canvas from a saved snapshot |
|
|
55
|
+
| `canvas_delete_snapshot` | Delete a saved snapshot |
|
|
56
|
+
| `canvas_search` | Find nodes by title/content keywords |
|
|
57
|
+
| `canvas_undo` | Undo the last canvas mutation |
|
|
58
|
+
| `canvas_redo` | Redo the last undone mutation |
|
|
59
|
+
| `canvas_diff` | Compare current canvas vs a saved snapshot |
|
|
60
|
+
| `canvas_create_group` | Create a group containing specified nodes |
|
|
61
|
+
| `canvas_group_nodes` | Add nodes to an existing group |
|
|
62
|
+
| `canvas_ungroup` | Release all children from a group |
|
|
63
|
+
| `canvas_batch` | Run a batch of canvas operations with `$ref` support |
|
|
64
|
+
| `canvas_webview_status` | Get Bun.WebView automation status for the workbench |
|
|
65
|
+
| `canvas_webview_start` | Start or replace the Bun.WebView automation session |
|
|
66
|
+
| `canvas_webview_stop` | Stop the active Bun.WebView automation session |
|
|
67
|
+
| `canvas_evaluate` | Evaluate JavaScript in the active workbench automation session |
|
|
68
|
+
| `canvas_resize` | Resize the active workbench automation viewport |
|
|
69
|
+
| `canvas_screenshot` | Capture a screenshot from the active workbench automation session |
|
|
70
|
+
|
|
71
|
+
## Resources
|
|
72
|
+
|
|
73
|
+
Individual bundled skills are also readable at `canvas://skills/<name>`.
|
|
74
|
+
|
|
75
|
+
| Resource | Description |
|
|
76
|
+
|----------|-------------|
|
|
77
|
+
| `canvas://pinned-context` | Content of pinned nodes + nearby unpinned neighbors |
|
|
78
|
+
| `canvas://schema` | Running-server create schemas and json-render catalog metadata |
|
|
79
|
+
| `canvas://layout` | Full canvas state (all nodes, edges, viewport) |
|
|
80
|
+
| `canvas://summary` | Compact overview: counts, pinned titles, viewport |
|
|
81
|
+
| `canvas://spatial-context` | Proximity clusters, reading order, pinned neighborhoods |
|
|
82
|
+
| `canvas://history` | Mutation history timeline with undo/redo position |
|
|
83
|
+
| `canvas://code-graph` | Auto-detected file dependency graph (JS/TS, Python, Go, Rust) |
|
|
84
|
+
| `canvas://skills` | Index of bundled agent skills + per-skill content at `canvas://skills/<name>` |
|
|
85
|
+
|
|
86
|
+
## Change notifications
|
|
87
|
+
|
|
88
|
+
The MCP server emits `notifications/resources/updated` whenever canvas state
|
|
89
|
+
changes:
|
|
90
|
+
|
|
91
|
+
- Pin changes notify `canvas://pinned-context`
|
|
92
|
+
- All mutations notify `canvas://layout`, `canvas://summary`,
|
|
93
|
+
`canvas://spatial-context`, `canvas://history`, and `canvas://code-graph`
|
|
94
|
+
|
|
95
|
+
This closes the human-to-agent loop: spatial curation in the browser becomes
|
|
96
|
+
an immediate signal in the agent's context.
|
|
97
|
+
|
|
98
|
+
## Annotation Visibility
|
|
99
|
+
|
|
100
|
+
Human-drawn canvas annotations are rendered as browser SVG ink. MCP resources
|
|
101
|
+
keep annotation context compact: agents see annotation counts, bounds, and target
|
|
102
|
+
summaries such as the node or empty canvas region that was marked, but not the
|
|
103
|
+
raw stroke geometry or visual shape.
|
|
104
|
+
|
|
105
|
+
Annotations are a browser-visible markup layer. Use the pen toolbar button to
|
|
106
|
+
draw and the eraser toolbar button to remove an annotation again; agents can also
|
|
107
|
+
remove a known annotation ID with `canvas_remove_annotation`.
|
|
108
|
+
|
|
109
|
+
Use WebView automation when an agent needs to actually see annotations as drawn.
|
|
110
|
+
For example, inspect `.annotation-layer path` with `canvas_evaluate` or capture a
|
|
111
|
+
`canvas_screenshot` to distinguish an arrow from a line, circle, or highlight.
|
|
112
|
+
|
|
113
|
+
## Node-type routing
|
|
114
|
+
|
|
115
|
+
MCP node creation uses dedicated tools for structured node families. Read
|
|
116
|
+
`mcp.nodeTypeRouting` from `canvas_describe_schema` / `canvas://schema` when
|
|
117
|
+
in doubt:
|
|
118
|
+
|
|
119
|
+
- `json-render` → `canvas_add_json_render_node`
|
|
120
|
+
- `graph` → `canvas_add_graph_node`
|
|
121
|
+
- `html` → `canvas_add_html_node`
|
|
122
|
+
- `web-artifact` → `canvas_build_web_artifact`
|
|
123
|
+
- `mcp-app` → `canvas_open_mcp_app`
|
|
124
|
+
- `group` → `canvas_create_group`
|
|
125
|
+
- Basic nodes (`markdown`, `status`, `file`, `image`, `webpage`) →
|
|
126
|
+
`canvas_add_node`
|
|
127
|
+
|
|
128
|
+
## CLI/MCP alignment
|
|
129
|
+
|
|
130
|
+
CLI and MCP are kept aligned for the main canvas operations: node and edge
|
|
131
|
+
creation, graph/json-render/html nodes, web artifacts, external apps, groups,
|
|
132
|
+
batch builds, layout validation, snapshots, search, focus, pins, undo/redo,
|
|
133
|
+
semantic watch streams, WebView automation, and daemon/server control where
|
|
134
|
+
it applies. A few agent-native capabilities — resource subscriptions and
|
|
135
|
+
`canvas_diff` — remain MCP-only.
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
# Node types
|
|
2
|
+
|
|
3
|
+
Canvas nodes are typed. Each type has a dedicated renderer, schema, and (for
|
|
4
|
+
structured types) a dedicated MCP tool. This page is the user-facing reference
|
|
5
|
+
for what each type is for and how to create one. For tool/HTTP/SDK signatures,
|
|
6
|
+
see [MCP tools](mcp.md), [HTTP API](http-api.md), and [SDK](sdk.md).
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
| Type | Purpose |
|
|
11
|
+
|------|---------|
|
|
12
|
+
| `markdown` | Rich markdown with rendered preview |
|
|
13
|
+
| `status` | Compact status indicator (phase, message, elapsed time) |
|
|
14
|
+
| `context` | Context cards, token usage, workspace grounding |
|
|
15
|
+
| `ledger` | Execution ledger summary |
|
|
16
|
+
| `trace` | Agent trace pills (tool calls, subagent activity) |
|
|
17
|
+
| `file` | Live file viewer with auto-update on disk changes |
|
|
18
|
+
| `image` | Image viewer (file paths, data URIs, URLs) |
|
|
19
|
+
| `webpage` | Persisted webpage snapshot with stored URL, extracted text, refresh |
|
|
20
|
+
| `mcp-app` | Tool-backed hosted MCP App iframes (Excalidraw, etc.) |
|
|
21
|
+
| `json-render` | Structured UI from JSON specs (cards, tables, forms) |
|
|
22
|
+
| `graph` | Charts (line, bar, pie, area, scatter, radar, stacked-bar, composed) |
|
|
23
|
+
| `html` | Self-contained HTML/JS in a sandboxed iframe |
|
|
24
|
+
| `web-artifact` | Bundled React/Tailwind artifact (full single-file app) |
|
|
25
|
+
| `group` | Spatial container/frame around other nodes |
|
|
26
|
+
|
|
27
|
+
Thread node types `prompt` and `response` exist internally for agent
|
|
28
|
+
conversation rendering and are not created through public APIs.
|
|
29
|
+
|
|
30
|
+
## Choosing the right visual tier
|
|
31
|
+
|
|
32
|
+
Three rendering tiers cover increasing levels of complexity. Pick the lowest
|
|
33
|
+
that fits the work — each step adds capability and bundle weight.
|
|
34
|
+
|
|
35
|
+
| Tier | Type | Use when | Bundle weight |
|
|
36
|
+
|------|------|----------|---------------|
|
|
37
|
+
| 1 | `json-render` | You can describe the UI as a spec (forms, tables, dashboards from a component catalog) | None — runtime already loaded |
|
|
38
|
+
| 2 | `html` | You have/can write self-contained HTML+JS (Chart.js, D3, custom widgets, interactive demos) | None — sandboxed iframe |
|
|
39
|
+
| 3 | `web-artifact` | You need a full React/Tailwind app with shadcn components, routing, or shared state | Build step |
|
|
40
|
+
|
|
41
|
+
## File nodes
|
|
42
|
+
|
|
43
|
+
File nodes display project files with line numbers and language detection.
|
|
44
|
+
When an agent edits a file through its normal tools, the canvas node updates
|
|
45
|
+
automatically via `fs.watch()`.
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
canvas_add_node({ type: 'file', content: 'src/server/index.ts' })
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Image nodes
|
|
52
|
+
|
|
53
|
+
Image nodes display local paths, remote URLs, and data URIs. File-backed and
|
|
54
|
+
HTTP(S)-backed images preserve provenance so agents can tell where evidence
|
|
55
|
+
came from. Nodes can carry validation status or warnings.
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
canvas_add_node({
|
|
59
|
+
type: 'image',
|
|
60
|
+
content: 'artifacts/dashboard.png',
|
|
61
|
+
data: {
|
|
62
|
+
validationStatus: 'passed',
|
|
63
|
+
validationMessage: 'Screenshot matches the requested dashboard state.',
|
|
64
|
+
},
|
|
65
|
+
})
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Webpage nodes
|
|
69
|
+
|
|
70
|
+
Webpage nodes store the source URL on the node, fetch the page server-side,
|
|
71
|
+
and cache extracted text for search, pins, and agent context. Saved canvases
|
|
72
|
+
keep enough information for an agent to refresh the node from the original
|
|
73
|
+
URL later.
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
canvas_add_node({ type: 'webpage', url: 'https://example.com/docs' })
|
|
77
|
+
canvas_refresh_webpage_node({ id: 'node-abc123' })
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## MCP App nodes
|
|
81
|
+
|
|
82
|
+
`mcp-app` nodes embed other MCP servers' UI resources (`ui://...`) directly
|
|
83
|
+
on the canvas as sandboxed iframes. Any server implementing the
|
|
84
|
+
[MCP Apps extension](https://modelcontextprotocol.io/docs/extensions/apps)
|
|
85
|
+
can be opened with `canvas_open_mcp_app`.
|
|
86
|
+
|
|
87
|
+
Generic `pmx-canvas node add --type mcp-app` is intentionally rejected —
|
|
88
|
+
these nodes need tool/session metadata. Use `canvas_open_mcp_app` (or the
|
|
89
|
+
`canvas_add_diagram` Excalidraw preset) instead.
|
|
90
|
+
|
|
91
|
+
### Excalidraw preset (hand-drawn diagrams)
|
|
92
|
+
|
|
93
|
+
[Excalidraw](https://github.com/excalidraw/excalidraw-mcp) ships a hosted MCP
|
|
94
|
+
server at `https://mcp.excalidraw.com/mcp`. PMX Canvas exposes a one-call
|
|
95
|
+
preset:
|
|
96
|
+
|
|
97
|
+
```ts
|
|
98
|
+
canvas_add_diagram({
|
|
99
|
+
elements: [
|
|
100
|
+
{ type: 'rectangle', id: 'a', x: 80, y: 120, width: 180, height: 80,
|
|
101
|
+
roundness: { type: 3 }, backgroundColor: '#a5d8ff', fillStyle: 'solid',
|
|
102
|
+
label: { text: 'Agent', fontSize: 18 } },
|
|
103
|
+
{ type: 'rectangle', id: 'b', x: 380, y: 120, width: 180, height: 80,
|
|
104
|
+
roundness: { type: 3 }, backgroundColor: '#d0bfff', fillStyle: 'solid',
|
|
105
|
+
label: { text: 'PMX Canvas', fontSize: 18 } },
|
|
106
|
+
{ type: 'arrow', id: 'a1', x: 260, y: 160, width: 120, height: 0,
|
|
107
|
+
startBinding: { elementId: 'a' }, endBinding: { elementId: 'b' },
|
|
108
|
+
label: { text: 'adds nodes' } },
|
|
109
|
+
],
|
|
110
|
+
title: 'Agent → Canvas',
|
|
111
|
+
});
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
For any other MCP App, call `canvas_open_mcp_app` directly with the server's
|
|
115
|
+
transport, tool name, and arguments.
|
|
116
|
+
|
|
117
|
+
## json-render nodes
|
|
118
|
+
|
|
119
|
+
`json-render` nodes turn structured JSON specs into rendered UI panels
|
|
120
|
+
(dashboards, tables, forms, cards) without writing HTML. PMX Canvas ships the
|
|
121
|
+
[`@json-render/*`](https://www.npmjs.com/package/@json-render/core) runtime
|
|
122
|
+
and component catalog (core + react + shadcn).
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
canvas_add_json_render_node({
|
|
126
|
+
title: 'Deploy status',
|
|
127
|
+
spec: {
|
|
128
|
+
root: 'card',
|
|
129
|
+
elements: {
|
|
130
|
+
card: { type: 'Card', props: { title: 'Deploy' }, children: ['status'] },
|
|
131
|
+
status: { type: 'Badge', props: { variant: 'default', text: 'Healthy' } },
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
});
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
`Badge` uses shadcn variants: `default`, `secondary`, `destructive`,
|
|
138
|
+
`outline`. Older saved specs using `label` or status variants such as
|
|
139
|
+
`success`/`warning` are normalized during validation.
|
|
140
|
+
|
|
141
|
+
Use `canvas_describe_schema` / `canvas_validate_spec` to introspect the
|
|
142
|
+
component catalog before building a spec.
|
|
143
|
+
|
|
144
|
+
## HTML nodes
|
|
145
|
+
|
|
146
|
+
`html` nodes render a self-contained HTML/JS document in a sandboxed iframe.
|
|
147
|
+
They sit between `json-render` (no custom JS) and `web-artifact` (full bundled
|
|
148
|
+
React app) — perfect for Chart.js, D3, custom widgets, and any HTML you can
|
|
149
|
+
write or paste.
|
|
150
|
+
|
|
151
|
+
The sandbox runs with `allow-scripts` only — no same-origin access, no
|
|
152
|
+
top-level navigation, no form submission. Inline `<script>` and CDN
|
|
153
|
+
`<script src>` both work. The canvas auto-injects its theme tokens
|
|
154
|
+
(`--c-*` and `--color-*` aliases) into the iframe `<head>` so artifacts can
|
|
155
|
+
match the active theme.
|
|
156
|
+
|
|
157
|
+
```ts
|
|
158
|
+
canvas_add_html_node({
|
|
159
|
+
title: 'Cost projection',
|
|
160
|
+
html: '<canvas id="c"></canvas><script src="https://cdn.jsdelivr.net/npm/chart.js"></script><script>...</script>',
|
|
161
|
+
})
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
A fragment without `<html>`/`<head>` is wrapped in a full document
|
|
165
|
+
automatically. Default size is 720×640.
|
|
166
|
+
|
|
167
|
+
## Web artifacts
|
|
168
|
+
|
|
169
|
+
A **web artifact** is a single-file, fully bundled HTML app (React + Tailwind
|
|
170
|
+
+ shadcn) the agent builds from TSX source. Use it when the work calls for a
|
|
171
|
+
real interactive app — charts, forms, mini-dashboards — beyond what a static
|
|
172
|
+
node or `html` snippet can express.
|
|
173
|
+
|
|
174
|
+
`canvas_build_web_artifact` takes source strings (`App.tsx`, optional
|
|
175
|
+
`index.css`, `main.tsx`, `index.html`, plus extra files), runs the bundled
|
|
176
|
+
web-artifacts-builder scripts, writes the self-contained HTML to
|
|
177
|
+
`.pmx-canvas/artifacts/<slug>.html`, and (by default) opens it in the canvas.
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
pmx-canvas web-artifact build --title "Dashboard" --app-file ./App.tsx --deps recharts --include-logs
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
The scaffold includes `recharts`. Pass `--deps name,name2` for additional
|
|
184
|
+
package dependencies. Failed or empty CLI bundles print `ok: false`, exit
|
|
185
|
+
non-zero, and do not create a canvas node.
|
|
186
|
+
|
|
187
|
+
The matching agent skill is at
|
|
188
|
+
[`skills/web-artifacts-builder/SKILL.md`](../skills/web-artifacts-builder/SKILL.md).
|
|
189
|
+
|
|
190
|
+
## Groups
|
|
191
|
+
|
|
192
|
+
Groups are spatial containers that visually contain other nodes. They render
|
|
193
|
+
as dashed-border frames with a title bar and optional accent color.
|
|
194
|
+
|
|
195
|
+
- Select 2+ nodes and click "Group" in the selection bar
|
|
196
|
+
- Right-click a group to ungroup
|
|
197
|
+
- Collapsing a group hides children and shows a summary
|
|
198
|
+
- By default, group creation preserves the children's current positions and
|
|
199
|
+
expands the frame around them
|
|
200
|
+
- Pass `childLayout` to auto-pack children (`grid`, `column`, `flow`)
|
|
201
|
+
- Pass explicit `x`, `y`, `width`, and `height` to create a manual frame and
|
|
202
|
+
lay children out inside it
|
|
203
|
+
|
|
204
|
+
```ts
|
|
205
|
+
canvas_create_group({ title: 'Auth Module', childIds: ['node-1', 'node-2'], color: '#4a9eff' })
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## Edge types
|
|
209
|
+
|
|
210
|
+
All edges support labels, styles (solid/dashed/dotted), and animation.
|
|
211
|
+
|
|
212
|
+
| Type | Use case |
|
|
213
|
+
|------|----------|
|
|
214
|
+
| `flow` | Sequential steps, data flow |
|
|
215
|
+
| `depends-on` | Dependencies between tasks |
|
|
216
|
+
| `relation` | General relationships |
|
|
217
|
+
| `references` | Cross-references, evidence links |
|
|
218
|
+
|
|
219
|
+
## Schema-driven discovery
|
|
220
|
+
|
|
221
|
+
Agents don't have to guess node shapes. The running server exposes its create
|
|
222
|
+
schemas, json-render component catalog, and node-type examples:
|
|
223
|
+
|
|
224
|
+
- `canvas_describe_schema` / `GET /api/canvas/schema` — list all node-create
|
|
225
|
+
schemas, required fields, json-render components, and sample payloads
|
|
226
|
+
- `canvas_validate_spec` / `POST /api/canvas/schema/validate` — validate a
|
|
227
|
+
json-render spec or graph payload **without** creating a node
|
|
228
|
+
- `canvas_validate` / `GET /api/canvas/validate` — validate the current
|
|
229
|
+
layout for collisions, containment, and missing edge endpoints
|
|
230
|
+
- `canvas://schema` — the same data as an MCP resource
|
|
231
|
+
|
|
232
|
+
The CLI's `node schema` / `validate spec` subcommands surface the same data
|
|
233
|
+
from the terminal.
|
|
234
|
+
|
|
235
|
+
MCP node creation uses dedicated tools for structured node families. Read
|
|
236
|
+
`mcp.nodeTypeRouting` from `canvas_describe_schema` when in doubt:
|
|
237
|
+
`json-render` → `canvas_add_json_render_node`,
|
|
238
|
+
`graph` → `canvas_add_graph_node`,
|
|
239
|
+
`html` → `canvas_add_html_node`,
|
|
240
|
+
`web-artifact` → `canvas_build_web_artifact`,
|
|
241
|
+
`mcp-app` → `canvas_open_mcp_app`,
|
|
242
|
+
`group` → `canvas_create_group`.
|
|
243
|
+
Basic nodes (`markdown`, `status`, `file`, `image`, `webpage`) use
|
|
244
|
+
`canvas_add_node`.
|
|
File without changes
|