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.
- package/CHANGELOG.md +94 -0
- package/Readme.md +108 -1058
- package/dist/canvas/global.css +141 -0
- package/dist/canvas/index.js +129 -79
- package/dist/json-render/index.css +1 -1
- package/dist/types/client/nodes/HtmlNode.d.ts +5 -0
- package/dist/types/client/state/canvas-store.d.ts +5 -1
- package/dist/types/client/state/intent-bridge.d.ts +3 -1
- package/dist/types/client/types.d.ts +2 -2
- package/dist/types/json-render/catalog.d.ts +1 -1
- package/dist/types/mcp/canvas-access.d.ts +7 -1
- package/dist/types/server/agent-context.d.ts +1 -0
- package/dist/types/server/canvas-operations.d.ts +4 -2
- package/dist/types/server/canvas-provenance.d.ts +1 -1
- package/dist/types/server/canvas-serialization.d.ts +3 -0
- package/dist/types/server/canvas-state.d.ts +51 -4
- package/dist/types/server/demo.d.ts +5 -0
- package/dist/types/server/index.d.ts +13 -3
- package/dist/types/server/web-artifacts.d.ts +18 -0
- package/dist/types/shared/canvas-node-kind.d.ts +5 -0
- package/package.json +1 -1
- package/skills/pmx-canvas/SKILL.md +43 -0
- package/skills/pmx-canvas-testing/SKILL.md +17 -0
- package/src/cli/agent.ts +52 -5
- package/src/cli/index.ts +2 -23
- package/src/client/canvas/AttentionHistory.tsx +14 -1
- package/src/client/canvas/CanvasNode.tsx +1 -1
- package/src/client/canvas/CanvasViewport.tsx +3 -0
- package/src/client/canvas/DockedNode.tsx +110 -12
- package/src/client/canvas/ExpandedNodeOverlay.tsx +5 -0
- package/src/client/canvas/Minimap.tsx +1 -0
- package/src/client/icons.tsx +1 -0
- package/src/client/nodes/HtmlNode.tsx +151 -0
- package/src/client/state/canvas-store.ts +24 -2
- package/src/client/state/intent-bridge.ts +4 -3
- package/src/client/state/sse-bridge.ts +1 -0
- package/src/client/theme/global.css +141 -0
- package/src/client/types.ts +3 -0
- package/src/mcp/canvas-access.ts +34 -7
- package/src/mcp/server.ts +178 -25
- package/src/server/agent-context.ts +50 -3
- package/src/server/canvas-operations.ts +20 -3
- package/src/server/canvas-provenance.ts +2 -1
- package/src/server/canvas-serialization.ts +38 -13
- package/src/server/canvas-state.ts +305 -34
- package/src/server/demo.ts +792 -0
- package/src/server/index.ts +33 -3
- package/src/server/server.ts +74 -13
- package/src/server/web-artifacts.ts +116 -3
- 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
|
|
4
|
-
status, charts, fetched web pages, and hand-drawn
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
###
|
|
28
|
+
### 01 / Curate
|
|
25
29
|
|
|
26
|
-
|
|
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
|
-
|
|
35
|
+
### 02 / Mix any data source
|
|
29
36
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
-
|
|
34
|
-
|
|
35
|
-
|
|
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
|
-
|
|
44
|
+
### 03 / Control your context
|
|
38
45
|
|
|
39
|
-
|
|
40
|
-
-
|
|
41
|
-
|
|
42
|
-
|
|
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-paste — pin 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
|
-
|
|
51
|
+
### 04 / Save
|
|
46
52
|
|
|
47
|
-
|
|
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
|
-
|
|
59
|
+
### 05 / Any agent
|
|
50
60
|
|
|
51
|
-
- [
|
|
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
|
-
|
|
67
|
+
## Prerequisites
|
|
54
68
|
|
|
55
|
-
|
|
69
|
+
- [Bun](https://bun.sh) >= 1.3.12
|
|
56
70
|
|
|
57
|
-
|
|
58
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
200
|
-
|
|
201
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
-
###
|
|
108
|
+
### Install the agent skill (recommended)
|
|
499
109
|
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
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
|
-
|
|
510
|
-
|
|
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
|
-
|
|
987
|
-
|
|
118
|
+
# 2. Agent Skills CLI (runtime-agnostic)
|
|
119
|
+
npx skills add pskoett/pmx-canvas/skills/pmx-canvas
|
|
988
120
|
|
|
989
|
-
|
|
990
|
-
pmx-canvas
|
|
991
|
-
pmx-canvas
|
|
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
|
-
|
|
1025
|
-
|
|
1026
|
-
-
|
|
1027
|
-
|
|
1028
|
-
-
|
|
1029
|
-
-
|
|
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
|
-
|
|
1036
|
-
is a convenience alias that uses the same flags and server endpoint.
|
|
133
|
+
## Documentation
|
|
1037
134
|
|
|
1038
|
-
|
|
1039
|
-
the
|
|
1040
|
-
|
|
1041
|
-
|
|
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
|
-
##
|
|
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
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
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
|
|
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
|
|
165
|
+
- **MCP:** [@modelcontextprotocol/sdk](https://github.com/modelcontextprotocol/typescript-sdk) (stdio)
|
|
1088
166
|
|
|
1089
167
|
## Development
|
|
1090
168
|
|
|
1091
169
|
```bash
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
bun
|
|
1095
|
-
bun run
|
|
1096
|
-
bun run dev
|
|
1097
|
-
bun run dev:
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
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
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
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
|
|
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`)
|