pmx-canvas 0.1.4 → 0.1.6
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 +129 -0
- package/Readme.md +325 -68
- package/dist/types/server/canvas-schema.d.ts +2 -0
- package/dist/types/server/image-source.d.ts +3 -0
- package/dist/types/server/index.d.ts +1 -0
- package/package.json +1 -1
- package/skills/pmx-canvas/SKILL.md +179 -12
- package/src/cli/agent.ts +75 -7
- package/src/cli/index.ts +3 -1
- package/src/json-render/server.ts +24 -0
- package/src/mcp/server.ts +15 -5
- package/src/server/canvas-operations.ts +3 -11
- package/src/server/canvas-schema.ts +53 -1
- package/src/server/image-source.ts +206 -0
- package/src/server/server.ts +17 -5
package/Readme.md
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
# pmx-canvas
|
|
2
2
|
|
|
3
|
-
A
|
|
3
|
+
**A shared thinking surface for humans and coding agents.** Drop files, plans,
|
|
4
|
+
status, charts, fetched web pages, and hand-drawn diagrams onto the same
|
|
5
|
+
infinite 2D canvas; pin what matters; let the agent read your spatial curation
|
|
6
|
+
as structured context. Drive it from a CLI, the Model Context Protocol, an
|
|
7
|
+
HTTP API, or a Bun-based TypeScript SDK — whichever fits how your agent runs.
|
|
4
8
|
|
|
5
9
|
<p align="center">
|
|
6
10
|
<img src="docs/screenshots/welcome-dark.png" alt="Empty canvas — dark theme" width="49%" />
|
|
@@ -12,9 +16,35 @@ A spatial canvas workbench for coding agents. Infinite 2D canvas with nodes, edg
|
|
|
12
16
|
<img src="docs/screenshots/demo-workbench-light.png" alt="Structured workbench demo — light theme" width="49%" />
|
|
13
17
|
</p>
|
|
14
18
|
|
|
15
|
-
PMX Canvas is a spatial
|
|
19
|
+
PMX Canvas is a **collaborative spatial workspace** that humans and agents share in real time. It works in both directions:
|
|
16
20
|
|
|
17
|
-
**
|
|
21
|
+
- **Human-first.** You open the canvas, drop in files, sketch a plan, group what belongs together, pin what matters. The agent watches the curation update live and uses it to ground its next action — no prompt engineering, no copy-paste.
|
|
22
|
+
- **Agent-first.** You ask the agent to gather data from sources (logs, files, search results, dashboards, web pages), and it lays the findings out as nodes and edges. You step in, rearrange, edit, prune, and steer where the analysis goes next.
|
|
23
|
+
|
|
24
|
+
### What it's for
|
|
25
|
+
|
|
26
|
+
pmx-canvas drives any work that benefits from making **context, relations, and provenance explicit**. The canvas turns work that is normally scattered across chat history, tabs, files, and dashboards into something with explicit context (pinned nodes), explicit relations (edges, groups, proximity), and explicit provenance (which side added which piece). Whatever data either the human or the agent pulls in — files, fetched web pages, screenshots, log excerpts, structured panels, charts, hand-drawn diagrams, bundled web artifacts — lives on the same surface and is reachable from both sides.
|
|
27
|
+
|
|
28
|
+
**The canvas is agnostic about what you do with it.** The reach of the workspace is the union of pmx-canvas's own node types and **whatever your agent's harness already has access to** — MCP servers, MCP apps, shell commands and CLIs, files in the working directory, web-fetch tools, anything else its toolbelt exposes. The canvas itself doesn't care where the data came from; it just needs the agent (or you) to drop it on the surface as the right node type. To make that concrete:
|
|
29
|
+
|
|
30
|
+
- A **Jira MCP** turns the canvas into a triage board — tickets land as `markdown` nodes you can group by status and pin the in-flight ones.
|
|
31
|
+
- A **database MCP** turns it into an exploratory query workbench — each query result becomes a `json-render` table or `graph` node next to the `markdown` node holding the SQL.
|
|
32
|
+
- An **Excalidraw MCP app** turns it into a sketch surface — diagrams open as `mcp-app` nodes you can resize and annotate.
|
|
33
|
+
- A **shell-driven agent** with `gh` + `kubectl` in its harness turns it into an ops board — open issues become markdown, pod statuses become `status` nodes, the relationships you care about become edges.
|
|
34
|
+
- **Plain file reads** in the agent's working directory turn it into a code-context map — `file` nodes for source, `markdown` nodes for the agent's notes, all live-watched.
|
|
35
|
+
- A **custom MCP or CLI** for your data source turns it into whatever shape that data fits — without pmx-canvas knowing anything about your domain.
|
|
36
|
+
|
|
37
|
+
Common use cases — non-exhaustive, mix and match as the work shifts:
|
|
38
|
+
|
|
39
|
+
- **Idea generation** — capture divergent thoughts spatially without losing them
|
|
40
|
+
- **Validation** — test a claim against supporting and refuting evidence
|
|
41
|
+
- **Research** — gather, organize, and compare sources from anywhere
|
|
42
|
+
- **Analysis** — make sense of accumulated material, surface patterns
|
|
43
|
+
- **Mind mapping** — relationships, hierarchies, and structure spatially
|
|
44
|
+
|
|
45
|
+
…plus anything else the combination of the canvas and your agent's toolbelt — MCP servers, MCP apps, CLIs, file access, web fetch — makes possible.
|
|
46
|
+
|
|
47
|
+
**Spatial arrangement is communication.** When a human drags three file nodes next to a bug report, the agent knows they're related. When the agent drops 12 webpage nodes from a research session, the human can immediately group, prune, and pin the ones worth keeping. The agent reads spatial state via `canvas://pinned-context`, `canvas://spatial-context`, and the SSE event stream; the human reads the same state through the rendered browser.
|
|
18
48
|
|
|
19
49
|
## Prerequisites
|
|
20
50
|
|
|
@@ -22,18 +52,113 @@ PMX Canvas is a spatial thinking surface for coding agents and the humans workin
|
|
|
22
52
|
|
|
23
53
|
The published SDK entrypoint is Bun-first: `import { createCanvas } from 'pmx-canvas'` is supported in Bun, while Node.js consumers should use the CLI, MCP server, or HTTP API instead.
|
|
24
54
|
|
|
55
|
+
## Scope
|
|
56
|
+
|
|
57
|
+
- **Single-machine, today.** One canvas runs per `bunx pmx-canvas` instance, on
|
|
58
|
+
one machine. There is no built-in multi-user auth or presence — collaboration
|
|
59
|
+
means human↔agent on the same machine, plus any other browser tab/agent
|
|
60
|
+
pointed at the same `localhost:4313`. To share a canvas across machines, commit
|
|
61
|
+
`.pmx-canvas/state.json` to your repo and pull it on the other side.
|
|
62
|
+
- **What leaves your machine.** The core canvas runs entirely on `localhost`.
|
|
63
|
+
Network egress only happens for explicit, opt-in flows: `webpage` nodes
|
|
64
|
+
fetch the URL you give them; `mcp-app` / `canvas_add_diagram` calls go to
|
|
65
|
+
whatever MCP server URL you configure (the Excalidraw preset uses
|
|
66
|
+
`https://mcp.excalidraw.com/mcp`); `bunx` itself reads the npm registry on
|
|
67
|
+
first install. Nothing else phones home.
|
|
68
|
+
- **State auto-saves** to `.pmx-canvas/state.json` (debounced ~500 ms after each
|
|
69
|
+
mutation). Closing the browser tab keeps everything — only `Ctrl-C` (or
|
|
70
|
+
`pmx-canvas serve stop`) on the server actually stops the canvas. Pins,
|
|
71
|
+
positions, and node content survive both. Snapshots live under
|
|
72
|
+
`.pmx-canvas/snapshots/`.
|
|
73
|
+
|
|
25
74
|
## Quick start
|
|
26
75
|
|
|
27
|
-
|
|
76
|
+
There are two paths into pmx-canvas, and they work together. Pick whichever
|
|
77
|
+
matches who is starting the session — you can hand off to the other side at any
|
|
78
|
+
point because both halves drive the same canvas.
|
|
79
|
+
|
|
80
|
+
### Easiest: install the `pmx-canvas` agent skill (recommended)
|
|
81
|
+
|
|
82
|
+
The fastest way to get going is to install the main `pmx-canvas` agent skill
|
|
83
|
+
into your agent of choice. The skill teaches the agent how to install the
|
|
84
|
+
package, start the server, and drive every node type, group, snapshot, and
|
|
85
|
+
search the canvas exposes. You don't have to install the rest of the bundled
|
|
86
|
+
skills (`web-artifacts-builder`, `pmx-canvas-testing`, `playwright-cli`, the
|
|
87
|
+
`json-render-*` family, etc.) — once the canvas is running, the agent can read
|
|
88
|
+
`canvas://skills` and pull in companion skills as the work demands.
|
|
89
|
+
|
|
90
|
+
Three install paths, in order of how universal they are:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
# 1. GitHub CLI extension. `gh skill` is the official Agent Skills extension
|
|
94
|
+
# for the GitHub CLI — it knows where each harness keeps its skills tree
|
|
95
|
+
# and copies the SKILL.md and assets into the right place. Requires
|
|
96
|
+
# `gh` >= 2.90. See https://cli.github.com/manual/gh_skill_install.
|
|
97
|
+
gh skill install pskoett/pmx-canvas pmx-canvas
|
|
98
|
+
|
|
99
|
+
# 2. Agent Skills CLI. `npx skills` is the runtime-agnostic installer for
|
|
100
|
+
# skills that follow the Agent Skills specification
|
|
101
|
+
# (https://agentskills.io/specification). It works for any agent harness
|
|
102
|
+
# that reads from a per-user or per-project skills directory.
|
|
103
|
+
npx skills add pskoett/pmx-canvas/skills/pmx-canvas
|
|
104
|
+
|
|
105
|
+
# 3. Manual clone + copy. Works everywhere; you pick where the skill lands.
|
|
106
|
+
git clone https://github.com/pskoett/pmx-canvas.git
|
|
107
|
+
cp -r pmx-canvas/skills/pmx-canvas <your-agent-skills-dir>
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
For path 3, point at whichever directory your agent harness reads. Common
|
|
111
|
+
defaults — check your harness docs if it isn't here:
|
|
112
|
+
|
|
113
|
+
| Harness | Skills directory |
|
|
114
|
+
|---------|------------------|
|
|
115
|
+
| Claude Code | `.claude/skills/` (project) or `~/.claude/skills/` (user-wide) |
|
|
116
|
+
| GitHub Copilot CLI | `.github/skills/`, `.claude/skills/`, or `.agents/skills/` (project); `~/.copilot/skills/`, `~/.claude/skills/`, or `~/.agents/skills/` (user-wide). [docs](https://docs.github.com/en/copilot/how-tos/copilot-cli/customize-copilot/add-skills) |
|
|
117
|
+
| Cross-harness convention | `.agents/skills/` (project) — followed by an increasing number of harnesses, see the [Agent Skills specification](https://agentskills.io/specification) |
|
|
118
|
+
| Other / unsure | check your harness's docs for the canonical skills directory |
|
|
119
|
+
|
|
120
|
+
After install, point your agent at the skill and try the **minimum-viable
|
|
121
|
+
prompt**:
|
|
122
|
+
|
|
123
|
+
> *"Use the `pmx-canvas` skill to start the canvas, then add this repo's
|
|
124
|
+
> `Readme.md` and the top three source files as `file` nodes. Auto-arrange
|
|
125
|
+
> them and pin two."*
|
|
126
|
+
|
|
127
|
+
You should see the browser open and four nodes appear inside ~10 seconds. If
|
|
128
|
+
that works, the skill, the canvas, and the agent are all wired up.
|
|
129
|
+
|
|
130
|
+
If your agent isn't MCP-capable yet, wire it up first — see
|
|
131
|
+
[Connect your agent (MCP)](#connect-your-agent-mcp) for the JSON snippet that
|
|
132
|
+
turns `bunx pmx-canvas --mcp` into a stdio MCP server your harness can connect
|
|
133
|
+
to. The skill assumes the agent can call MCP tools. From there
|
|
134
|
+
work up to richer prompts — the [Example](#example-pull-data-in-build-something-out)
|
|
135
|
+
section below has a fuller flow.
|
|
136
|
+
|
|
137
|
+
For a richer install (the full bundle as a plugin marketplace, mirroring the
|
|
138
|
+
pattern in [`pskoett-ai-skills`](https://github.com/pskoett/pskoett-ai-skills)),
|
|
139
|
+
see [Agent skills](#agent-skills) below.
|
|
140
|
+
|
|
141
|
+
### Run it directly (no agent required)
|
|
142
|
+
|
|
143
|
+
You don't need an agent to use pmx-canvas — the workbench, CLI, and HTTP API
|
|
144
|
+
are first-class on their own.
|
|
145
|
+
|
|
146
|
+
#### Install from npm
|
|
28
147
|
|
|
29
148
|
```bash
|
|
30
149
|
bunx pmx-canvas # Start canvas, open browser
|
|
31
|
-
bunx pmx-canvas serve --daemon --no-open --wait-ms=20000
|
|
32
150
|
bunx pmx-canvas --demo # Start with sample nodes
|
|
33
|
-
bunx pmx-canvas --
|
|
151
|
+
bunx pmx-canvas --no-open # Headless (good for daemons / CI)
|
|
152
|
+
bunx pmx-canvas --mcp # Run as MCP server (stdio)
|
|
153
|
+
bunx pmx-canvas --help # All commands
|
|
154
|
+
bunx pmx-canvas serve --daemon --no-open --wait-ms=20000 # Detached background mode
|
|
34
155
|
```
|
|
35
156
|
|
|
36
|
-
|
|
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
|
|
37
162
|
|
|
38
163
|
```bash
|
|
39
164
|
git clone https://github.com/pskoett/pmx-canvas.git
|
|
@@ -42,26 +167,20 @@ bun install
|
|
|
42
167
|
bun run build
|
|
43
168
|
bun run dev # Start + open browser
|
|
44
169
|
bun run dev:demo # Start with sample nodes
|
|
45
|
-
bun run dev:portless # Start at https://pmx.localhost/workbench (requires global portless)
|
|
46
170
|
```
|
|
47
171
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
For local development only, you can give the canvas a stable hostname with
|
|
51
|
-
[Portless](https://github.com/vercel-labs/portless):
|
|
172
|
+
For a stable local hostname, install [Portless](https://github.com/vercel-labs/portless)
|
|
173
|
+
first **and then** run the portless variant:
|
|
52
174
|
|
|
53
175
|
```bash
|
|
54
176
|
npm install -g portless
|
|
55
|
-
bun run dev:portless
|
|
177
|
+
bun run dev:portless # https://pmx.localhost/workbench
|
|
56
178
|
```
|
|
57
179
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
This is intentionally a repo-local developer workflow. The published
|
|
61
|
-
`bunx pmx-canvas` path still defaults to plain loopback and does not depend on
|
|
62
|
-
Portless being installed.
|
|
180
|
+
The published `bunx pmx-canvas` path defaults to plain loopback and does **not**
|
|
181
|
+
depend on Portless.
|
|
63
182
|
|
|
64
|
-
|
|
183
|
+
#### Test the unpublished CLI from a repo checkout
|
|
65
184
|
|
|
66
185
|
If you want to exercise the real package before publishing, link the repo locally:
|
|
67
186
|
|
|
@@ -81,10 +200,17 @@ For one-off local runs without linking, `bun run src/cli/index.ts ...` works too
|
|
|
81
200
|
|
|
82
201
|
### Recommended ways to drive the canvas
|
|
83
202
|
|
|
84
|
-
|
|
85
|
-
- **MCP** for agents that already speak the Model Context Protocol
|
|
203
|
+
Once the canvas is up, two control surfaces are first-class:
|
|
86
204
|
|
|
87
|
-
|
|
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 resources, including the bundled-skill index at `canvas://skills`.
|
|
208
|
+
|
|
209
|
+
Both paths cover core canvas work. A few advanced capabilities (live resource
|
|
210
|
+
subscriptions, `canvas_diff`) remain MCP-only. The HTTP API and the
|
|
211
|
+
[Bun SDK](#javascripttypescript-sdk-bun-runtime) are also available for programmatic use.
|
|
212
|
+
|
|
213
|
+
#### Connect your agent (MCP)
|
|
88
214
|
|
|
89
215
|
Add to your agent's MCP config:
|
|
90
216
|
|
|
@@ -99,17 +225,99 @@ Add to your agent's MCP config:
|
|
|
99
225
|
}
|
|
100
226
|
```
|
|
101
227
|
|
|
102
|
-
The canvas auto-starts on first tool call. Works with
|
|
228
|
+
The canvas auto-starts on first tool call. Works with any MCP-capable agent
|
|
229
|
+
harness — pmx-canvas does not depend on a specific coding agent.
|
|
230
|
+
|
|
231
|
+
For developer flows on the `pmx-canvas` repo itself (release process,
|
|
232
|
+
contribution gates, etc.) see [`AGENTS.md`](AGENTS.md) and
|
|
233
|
+
[`docs/RELEASE.md`](docs/RELEASE.md).
|
|
234
|
+
|
|
235
|
+
## Example: pull data in, build something out
|
|
236
|
+
|
|
237
|
+
The canvas is most useful when it's *not* empty. The pattern is the same
|
|
238
|
+
across every use case: gather data from whatever surfaces the human or the
|
|
239
|
+
agent has access to, lay it out using whichever node types fit, then
|
|
240
|
+
collaborate on the result.
|
|
241
|
+
|
|
242
|
+
A research / analysis example against a release-planning workflow:
|
|
243
|
+
|
|
244
|
+
> *"Read the latest release notes from `CHANGELOG.md`, the open issues from
|
|
245
|
+
> our GitHub repo, last week's deploy logs, and the pricing page from
|
|
246
|
+
> example.com. Put each one on the canvas as the right node type — markdown
|
|
247
|
+
> for the changelog, file nodes for the local files, status nodes for the
|
|
248
|
+
> deploy events, a webpage node for the URL — then build me a json-render
|
|
249
|
+
> dashboard and a chart that summarize what shipped, what broke, and what's
|
|
250
|
+
> still open."*
|
|
251
|
+
|
|
252
|
+
The same shape works for any use case. *Idea generation:* "give me twelve
|
|
253
|
+
angles on X, drop each as a markdown node, arrange in a flow layout."
|
|
254
|
+
*Validation:* "for the claim in the pinned node, place supporting and
|
|
255
|
+
refuting sources beside it as webpage and file nodes." *Mind mapping:*
|
|
256
|
+
"build a tree of the concepts in [topic] — central concept top-center,
|
|
257
|
+
major branches as groups, sub-concepts inside each group connected with
|
|
258
|
+
depends-on edges."
|
|
259
|
+
|
|
260
|
+
[`skills/pmx-canvas/SKILL.md`](skills/pmx-canvas/SKILL.md) has step-by-step
|
|
261
|
+
recipes for these and other patterns under *Workflow Patterns*. New
|
|
262
|
+
patterns become viable whenever you add an MCP server or MCP app — the
|
|
263
|
+
canvas surface stays the same, the things you can put on it grow.
|
|
264
|
+
|
|
265
|
+
What the agent does, end to end:
|
|
266
|
+
|
|
267
|
+
1. Reads each source via the tools your harness already provides (filesystem,
|
|
268
|
+
web fetch, GitHub API, log readers — pmx-canvas does not impose data
|
|
269
|
+
sources; bring your own).
|
|
270
|
+
2. Calls the canvas to drop each finding on the workbench:
|
|
271
|
+
- `markdown` for narrative notes and AI-summarized text
|
|
272
|
+
- `file` for live-watching local source files
|
|
273
|
+
- `webpage` for fetched web pages with cached extracted text
|
|
274
|
+
- `image` for screenshots and exported diagrams
|
|
275
|
+
- `status` / `ledger` / `trace` for structured runtime/evaluation state
|
|
276
|
+
- `json-render` for inline structured UI (dashboards, tables, forms) — see
|
|
277
|
+
[Json-render nodes](#json-render-nodes)
|
|
278
|
+
- `graph` for line / bar / pie / radar / stacked / composed charts — see
|
|
279
|
+
[the schema reference](#schema-driven-discovery)
|
|
280
|
+
- `mcp-app` (Excalidraw and other MCP App servers) for hand-drawn diagrams
|
|
281
|
+
- `web-artifact` for full bundled React/Tailwind interactive surfaces — see
|
|
282
|
+
[Web artifacts](#web-artifacts)
|
|
283
|
+
- `group` to bound related nodes into a frame
|
|
284
|
+
- `edge` to connect findings (`flow`, `depends-on`, `relation`,
|
|
285
|
+
`references`) so the relationships are first-class, not implicit
|
|
286
|
+
3. You step into the canvas, rearrange, prune, group, and **pin** the nodes
|
|
287
|
+
that matter.
|
|
288
|
+
4. The agent reads `canvas://pinned-context` and `canvas://spatial-context`
|
|
289
|
+
and uses your curation to ground the next round of analysis or build.
|
|
290
|
+
|
|
291
|
+
This loop works for investigations, architecture sketches, research surveys,
|
|
292
|
+
release planning, dashboards, post-mortems, lecture notes — anywhere the gap
|
|
293
|
+
between "I have the data somewhere" and "I have a coherent picture" is
|
|
294
|
+
currently blocking your thinking.
|
|
103
295
|
|
|
104
296
|
## How it works
|
|
105
297
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
298
|
+
The same simple loop runs in both directions, regardless of what the work
|
|
299
|
+
actually is:
|
|
300
|
+
|
|
301
|
+
1. **Either side adds material** to the canvas. The agent uses any tool its
|
|
302
|
+
harness exposes (file reads, web fetch, an attached MCP server, an MCP
|
|
303
|
+
app, the canvas's own tools) and lays the result out as the right node
|
|
304
|
+
type. The human drops files, drags nodes around, types markdown.
|
|
305
|
+
2. **The human curates spatial structure** — they group, position, draw
|
|
306
|
+
edges, and pin what matters. Curation is communication: proximity means
|
|
307
|
+
relatedness, pinning means "agent, focus here."
|
|
308
|
+
3. **The agent reads that structure as machine-readable context.**
|
|
309
|
+
`canvas://pinned-context` returns the pinned nodes plus their nearby
|
|
310
|
+
neighbors. `canvas://spatial-context` returns proximity clusters,
|
|
311
|
+
reading order, and pinned neighborhoods. SSE notifies the agent the
|
|
312
|
+
moment any of it changes.
|
|
313
|
+
4. **The agent acts on that context** using whatever tools are at its
|
|
314
|
+
disposal — `bunx pmx-canvas`'s 38 MCP tools, plus every other MCP your
|
|
315
|
+
harness has connected. Each new MCP expands what the loop can do without
|
|
316
|
+
changing the loop.
|
|
317
|
+
|
|
318
|
+
The canvas's job is to keep that loop honest: spatial state stays explicit,
|
|
319
|
+
provenance stays attributable to the side that made it, and both sides see
|
|
320
|
+
the same workspace via different surfaces.
|
|
113
321
|
|
|
114
322
|
## Features
|
|
115
323
|
|
|
@@ -255,12 +463,16 @@ canvas_add_json_render_node({
|
|
|
255
463
|
root: 'card',
|
|
256
464
|
elements: {
|
|
257
465
|
card: { type: 'Card', props: { title: 'Deploy' }, children: ['status'] },
|
|
258
|
-
status: { type: 'Badge', props: { variant: '
|
|
466
|
+
status: { type: 'Badge', props: { variant: 'default', text: 'Healthy' } },
|
|
259
467
|
},
|
|
260
468
|
},
|
|
261
469
|
});
|
|
262
470
|
```
|
|
263
471
|
|
|
472
|
+
`Badge` uses shadcn variants: `default`, `secondary`, `destructive`, and `outline`.
|
|
473
|
+
Older saved specs using `label` or status variants such as `success`/`warning` are
|
|
474
|
+
normalized during validation for compatibility.
|
|
475
|
+
|
|
264
476
|
Use `canvas_describe_schema` / `canvas_validate_spec` to introspect the component catalog before
|
|
265
477
|
building a spec -- see [Schema-driven discovery](#schema-driven-discovery).
|
|
266
478
|
|
|
@@ -373,6 +585,13 @@ json-render component catalog, and node-type examples so an agent can introspect
|
|
|
373
585
|
The CLI's `node schema` / `validate spec` subcommands surface the same data from the terminal,
|
|
374
586
|
which is strictly better than guessing flags or payloads.
|
|
375
587
|
|
|
588
|
+
MCP node creation uses dedicated tools for structured node families. Read
|
|
589
|
+
`mcp.nodeTypeRouting` from `canvas_describe_schema` / `canvas://schema` when in doubt:
|
|
590
|
+
`json-render` -> `canvas_add_json_render_node`, `graph` -> `canvas_add_graph_node`,
|
|
591
|
+
`web-artifact` -> `canvas_build_web_artifact`, `external-app` -> `canvas_open_mcp_app`,
|
|
592
|
+
and `group` -> `canvas_create_group`. Basic nodes such as `markdown`, `status`, `file`,
|
|
593
|
+
`image`, and `webpage` use `canvas_add_node`.
|
|
594
|
+
|
|
376
595
|
### Persistence
|
|
377
596
|
|
|
378
597
|
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.
|
|
@@ -465,18 +684,28 @@ effectively:
|
|
|
465
684
|
|
|
466
685
|
| Skill | Purpose |
|
|
467
686
|
|-------|---------|
|
|
468
|
-
| [`pmx-canvas`](skills/pmx-canvas/SKILL.md) | Core canvas workflows
|
|
687
|
+
| [`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. |
|
|
688
|
+
| [`web-artifacts-builder`](skills/web-artifacts-builder/SKILL.md) | Build single-file React/Tailwind artifacts and drop them on the canvas as embedded nodes |
|
|
689
|
+
| [`json-render-core`](skills/json-render-core/SKILL.md) | Drive the `@json-render/core` runtime — the spec format, parsing, and validation |
|
|
690
|
+
| [`json-render-react`](skills/json-render-react/SKILL.md) | Render json-render specs into React using the runtime |
|
|
691
|
+
| [`json-render-shadcn`](skills/json-render-shadcn/SKILL.md) | The shadcn/ui component catalog — Card, Stack, Button, Form fields, Tables |
|
|
692
|
+
| [`json-render-mcp`](skills/json-render-mcp/SKILL.md) | Expose a json-render spec as a `ui://` MCP resource |
|
|
693
|
+
| [`json-render-codegen`](skills/json-render-codegen/SKILL.md) | Generate json-render specs from prompts / structured input |
|
|
694
|
+
| [`json-render-ink`](skills/json-render-ink/SKILL.md) | Render json-render specs to the terminal via Ink |
|
|
469
695
|
| [`pmx-canvas-testing`](skills/pmx-canvas-testing/SKILL.md) | Testing patterns against the running canvas |
|
|
470
|
-
| [`web-artifacts-builder`](skills/web-artifacts-builder/SKILL.md) | Build single-file React/Tailwind artifacts for the canvas |
|
|
471
696
|
| [`playwright-cli`](skills/playwright-cli/SKILL.md) | Browser automation recipes for canvas + arbitrary pages |
|
|
472
|
-
| [`json-render-*`](skills/) | Drive the `@json-render/*` catalog (core, react, shadcn, mcp, codegen, ink) |
|
|
473
697
|
| [`frontend-design`](skills/frontend-design/SKILL.md), [`web-design-guidelines`](skills/web-design-guidelines/SKILL.md) | Design-quality rules for agent-generated UI |
|
|
474
698
|
| [`doc-coauthoring`](skills/doc-coauthoring/SKILL.md) | Structured doc-writing flow |
|
|
475
699
|
| [`data-analysis`](skills/data-analysis/SKILL.md) | Data exploration patterns |
|
|
476
|
-
| [`published-consumer-e2e`](skills/published-consumer-e2e/SKILL.md) | Smoke-test the published `bunx pmx-canvas` path |
|
|
477
700
|
|
|
478
|
-
|
|
479
|
-
|
|
701
|
+
(`published-consumer-e2e` exists in `skills/` for maintainer use — it smoke-tests the
|
|
702
|
+
published `bunx` path against a clean temp consumer — but it isn't a user-facing skill.)
|
|
703
|
+
|
|
704
|
+
You only need to install [`pmx-canvas`](skills/pmx-canvas/SKILL.md) up front (see the
|
|
705
|
+
[Quick start](#quick-start)) — once the canvas is running, the agent can read
|
|
706
|
+
`canvas://skills` to discover the rest and pull them in as the work demands. The core skill
|
|
707
|
+
also references the companion skills directly so the agent knows when each one is the right
|
|
708
|
+
tool.
|
|
480
709
|
|
|
481
710
|
## Integration
|
|
482
711
|
|
|
@@ -494,7 +723,7 @@ layout validation, graph/json-render nodes, group control, snapshots, and search
|
|
|
494
723
|
|
|
495
724
|
### MCP server
|
|
496
725
|
|
|
497
|
-
38 tools +
|
|
726
|
+
38 tools + 8 resources. Zero config for any MCP-capable agent.
|
|
498
727
|
|
|
499
728
|
<details>
|
|
500
729
|
<summary>MCP tools</summary>
|
|
@@ -553,7 +782,8 @@ layout validation, graph/json-render nodes, group control, snapshots, and search
|
|
|
553
782
|
| `canvas://summary` | Compact overview: counts, pinned titles, viewport |
|
|
554
783
|
| `canvas://spatial-context` | Proximity clusters, reading order, pinned neighborhoods |
|
|
555
784
|
| `canvas://history` | Mutation history timeline with undo/redo position |
|
|
556
|
-
| `canvas://code-graph` | Auto-detected file dependency graph |
|
|
785
|
+
| `canvas://code-graph` | Auto-detected file dependency graph (JS/TS, Python, Go, Rust) |
|
|
786
|
+
| `canvas://skills` | Index of bundled agent skills + per-skill content at `canvas://skills/<name>` |
|
|
557
787
|
|
|
558
788
|
</details>
|
|
559
789
|
|
|
@@ -741,6 +971,7 @@ pmx-canvas node add --help --type webpage --json
|
|
|
741
971
|
pmx-canvas external-app add --kind excalidraw --title "Diagram"
|
|
742
972
|
pmx-canvas node add --type graph --graph-type bar --data-file ./metrics.json --x-key label --y-key value
|
|
743
973
|
pmx-canvas node add --type graph --graph-type bar --data '[{"x":"a","y":1}]' --x-key x --y-key y
|
|
974
|
+
pmx-canvas graph add --graph-type bar --data '[{"x":"a","y":1}]' --x-key x --y-key y # Alias for graph nodes
|
|
744
975
|
pmx-canvas node schema --type json-render --component Table --summary
|
|
745
976
|
pmx-canvas edge add --from-search "DVT O3 — GitOps" --to-search "deep work trend" --type relation
|
|
746
977
|
pmx-canvas batch --file ./canvas-ops.json
|
|
@@ -767,22 +998,68 @@ Use the CLI when you want:
|
|
|
767
998
|
The CLI create commands return the created node shape with normalized title/content and geometry,
|
|
768
999
|
which makes scripting stacked layouts and batch follow-up operations easier.
|
|
769
1000
|
|
|
1001
|
+
For graph nodes, `node add --type graph` is the canonical CLI form. `graph add`
|
|
1002
|
+
is a convenience alias that uses the same flags and server endpoint.
|
|
1003
|
+
|
|
1004
|
+
Graph height flags are split by target: `--node-height` / `--nodeHeight` control
|
|
1005
|
+
the canvas node frame, while `--chart-height` controls the chart content inside
|
|
1006
|
+
the node. CLI `--height` is still accepted as a frame-height compatibility alias.
|
|
1007
|
+
For MCP/HTTP payloads, use `nodeHeight` for the frame and `height` for chart content.
|
|
1008
|
+
|
|
770
1009
|
## Agent compatibility
|
|
771
1010
|
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
|
776
|
-
|
|
777
|
-
|
|
|
778
|
-
|
|
|
1011
|
+
pmx-canvas is harness-agnostic. Any agent that can spawn an MCP stdio server,
|
|
1012
|
+
make HTTP requests, or invoke a CLI can drive the canvas.
|
|
1013
|
+
|
|
1014
|
+
| Capability | Path | Config |
|
|
1015
|
+
|------------|------|--------|
|
|
1016
|
+
| MCP-capable agent | MCP stdio server | `"command": "bunx", "args": ["pmx-canvas", "--mcp"]` |
|
|
1017
|
+
| Shell-driven agent | CLI | `bunx pmx-canvas …` (see [Recommended ways to drive the canvas](#recommended-ways-to-drive-the-canvas)) |
|
|
1018
|
+
| HTTP-only environment | REST + SSE | `fetch()` / `curl` at `http://localhost:4313/api/canvas/...` |
|
|
1019
|
+
| Bun runtime | TypeScript SDK | `import { createCanvas } from 'pmx-canvas'` |
|
|
1020
|
+
|
|
1021
|
+
## Known limitations
|
|
1022
|
+
|
|
1023
|
+
These are real things you'll hit and they aren't your fault — work around
|
|
1024
|
+
them rather than chase them as bugs.
|
|
1025
|
+
|
|
1026
|
+
- **Single-machine, no built-in multi-user auth.** See
|
|
1027
|
+
[Scope](#scope) above. Sharing a canvas
|
|
1028
|
+
across machines today means committing `.pmx-canvas/state.json`.
|
|
1029
|
+
- **Excalidraw / external `mcp-app` flakes:** grouped Excalidraw element IDs
|
|
1030
|
+
can change after edits, so an agent that builds a diagram in two passes
|
|
1031
|
+
should capture every element ID immediately after `canvas_add_diagram`
|
|
1032
|
+
returns. Editing while another tool call is in flight occasionally drops
|
|
1033
|
+
the in-progress edit.
|
|
1034
|
+
- **External MCP apps are transport-based over MCP.** `canvas_open_mcp_app`
|
|
1035
|
+
requires `toolName` plus a `transport` object for the external MCP server.
|
|
1036
|
+
For the built-in Excalidraw preset, use `canvas_add_diagram`; the CLI's
|
|
1037
|
+
`external-app add --kind excalidraw` is a higher-level convenience wrapper.
|
|
1038
|
+
- **Web-artifact build timeouts on cold installs.** The first
|
|
1039
|
+
`canvas_build_web_artifact` call in a fresh workspace runs `pnpm install`
|
|
1040
|
+
for ~30 dependencies. On constrained machines or slow networks, the
|
|
1041
|
+
default timeout can fire before the install completes — bump
|
|
1042
|
+
`--timeout-ms` (CLI) or `timeoutMs` (MCP/SDK) on first use, or
|
|
1043
|
+
pre-warm with `bunx pmx-canvas web-artifact build --title warmup
|
|
1044
|
+
--app-tsx 'export default () => null'`.
|
|
1045
|
+
- **Webpage-fetch failure modes.** Sites that require auth, render purely
|
|
1046
|
+
client-side without server HTML, or block headless fetches will store
|
|
1047
|
+
with empty extracted text. The node still works as a URL bookmark; the
|
|
1048
|
+
agent's view of the content will be the URL only.
|
|
1049
|
+
- **Image cloud-on-demand stalls (macOS).** Images stored in iCloud Drive
|
|
1050
|
+
/ OneDrive that aren't downloaded locally are detected up-front and
|
|
1051
|
+
rejected with a clear error rather than freezing the server. Download
|
|
1052
|
+
the file locally first.
|
|
1053
|
+
- **`prompt` and `response` node types are internal.** They surface in
|
|
1054
|
+
`canvas://layout` for thread rendering but aren't created via the public
|
|
1055
|
+
`canvas_add_node` API.
|
|
779
1056
|
|
|
780
1057
|
## Architecture
|
|
781
1058
|
|
|
782
1059
|
```
|
|
783
|
-
Agent (
|
|
1060
|
+
Agent harness (any MCP-capable client, CLI consumer, or HTTP caller)
|
|
784
1061
|
|
|
|
785
|
-
|-- MCP Server ---- 38 tools +
|
|
1062
|
+
|-- MCP Server ---- 38 tools + 8 resources + change notifications
|
|
786
1063
|
|-- Bun SDK ------- createCanvas()
|
|
787
1064
|
|-- HTTP API ------ REST + SSE at localhost:4313
|
|
788
1065
|
|
|
|
@@ -837,26 +1114,6 @@ from the durable eval in [docs/evals/e2e-cli-coverage.md](docs/evals/e2e-cli-cov
|
|
|
837
1114
|
parseable JSON, node creation, graph `--data`, web-artifact failure handling, Excalidraw external
|
|
838
1115
|
apps, `focus --no-pan`, arrange/validate, and status subtype reporting.
|
|
839
1116
|
|
|
840
|
-
## Release
|
|
841
|
-
|
|
842
|
-
Use this sequence before publishing a new version:
|
|
843
|
-
|
|
844
|
-
```bash
|
|
845
|
-
bun install --frozen-lockfile
|
|
846
|
-
bun run release:check
|
|
847
|
-
bun run test:e2e-cli
|
|
848
|
-
bun run release:smoke
|
|
849
|
-
bun run pack:dry-run
|
|
850
|
-
```
|
|
851
|
-
|
|
852
|
-
Then publish the version currently in `package.json`:
|
|
853
|
-
|
|
854
|
-
```bash
|
|
855
|
-
bun publish
|
|
856
|
-
```
|
|
857
|
-
|
|
858
|
-
If this is the first release from your machine, run `bunx npm login` once so Bun can reuse your npm credentials.
|
|
859
|
-
|
|
860
1117
|
### Project structure
|
|
861
1118
|
|
|
862
1119
|
```
|
|
@@ -12,6 +12,7 @@ export interface CanvasCreateTypeSchema {
|
|
|
12
12
|
kind: 'node' | 'virtual-node';
|
|
13
13
|
description: string;
|
|
14
14
|
endpoint: string;
|
|
15
|
+
mcpTool?: string;
|
|
15
16
|
fields: CanvasCreateField[];
|
|
16
17
|
example: Record<string, unknown>;
|
|
17
18
|
notes?: string[];
|
|
@@ -39,6 +40,7 @@ export declare function describeCanvasSchema(): {
|
|
|
39
40
|
mcp: {
|
|
40
41
|
tools: string[];
|
|
41
42
|
resources: string[];
|
|
43
|
+
nodeTypeRouting: Record<string, string>;
|
|
42
44
|
};
|
|
43
45
|
};
|
|
44
46
|
export declare function validateStructuredCanvasPayload(input: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pmx-canvas",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"description": "Spatial canvas workbench for coding agents — infinite 2D canvas with agent-native CLI, MCP integration, nodes, edges, file watching, and snapshots",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/server/index.ts",
|