pmx-canvas 0.2.7 → 0.3.0
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 +110 -1
- package/Readme.md +13 -11
- package/dist/json-render/index.css +1 -1
- package/dist/types/mcp/canvas-access.d.ts +0 -7
- package/dist/types/server/ax-state-manager.d.ts +3 -2
- package/dist/types/server/bundled-skills.d.ts +3 -3
- package/dist/types/server/canvas-state.d.ts +2 -0
- package/dist/types/server/ext-app-lookup.d.ts +1 -3
- package/dist/types/server/operations/composites.d.ts +29 -23
- package/dist/types/server/operations/http.d.ts +2 -1
- package/dist/types/shared/ax-intent.d.ts +1 -1
- package/docs/RELEASE.md +23 -8
- package/docs/ax-host-adapter-contract.md +7 -7
- package/docs/ax-state-contract.md +7 -6
- package/docs/bun-webview-integration.md +5 -5
- package/docs/cli.md +1 -1
- package/docs/http-api.md +7 -3
- package/docs/mcp.md +121 -100
- package/docs/node-types.md +45 -35
- package/docs/plans/plan-006-mcp-tool-consolidation.md +3 -1
- package/docs/plans/plan-008-registry-finish.md +2 -0
- package/docs/plans/plan-009-tech-debt-backlog.md +51 -0
- package/docs/screenshot.png +0 -0
- package/docs/tech-debt-assessment-2026-06.md +1 -1
- package/docs/tech-debt-assessment-2026-07.md +135 -0
- package/package.json +1 -1
- package/skills/data-analysis/SKILL.md +3 -3
- package/skills/frontend-design/SKILL.md +3 -2
- package/skills/json-render-mcp/SKILL.md +4 -3
- package/skills/playwright-cli/SKILL.md +1 -1
- package/skills/pmx-canvas/SKILL.md +9 -6
- package/skills/pmx-canvas/evals/evals.json +2 -2
- package/skills/pmx-canvas/references/ax-html-control-surface.md +3 -1
- package/skills/pmx-canvas/references/excalidraw-diagram-authoring.md +2 -2
- package/skills/pmx-canvas/references/full-reference.md +48 -53
- package/skills/pmx-canvas/references/html-primitives.md +3 -3
- package/skills/tufte-viz/SKILL.md +5 -4
- package/skills/web-artifacts-builder/SKILL.md +4 -4
- package/src/mcp/canvas-access.ts +4 -99
- package/src/mcp/server.ts +74 -201
- package/src/server/ax-state-manager.ts +3 -2
- package/src/server/bundled-skills.ts +3 -3
- package/src/server/canvas-schema.ts +46 -29
- package/src/server/canvas-state.ts +5 -0
- package/src/server/code-graph.ts +1 -1
- package/src/server/ext-app-lookup.ts +1 -8
- package/src/server/index.ts +1 -1
- package/src/server/intent-registry.ts +1 -1
- package/src/server/operations/composites.ts +39 -39
- package/src/server/operations/http.ts +3 -2
- package/src/server/operations/mcp.ts +7 -6
- package/src/server/operations/ops/app.ts +4 -4
- package/src/server/operations/ops/nodes.ts +5 -5
- package/src/server/operations/ops/query.ts +19 -8
- package/src/server/operations/ops/snapshots.ts +6 -6
- package/src/server/server.ts +30 -2
- package/src/shared/ax-intent.ts +1 -1
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Shared body reader: preserves the parsed JSON value as-is (object, array,
|
|
3
3
|
* or primitive) — per-op `readInput` decides what to do with non-object
|
|
4
|
-
* bodies; the shared reader never coerces.
|
|
4
|
+
* bodies; the shared reader never coerces. A non-empty body that fails to
|
|
5
|
+
* parse is a 400 (OperationError), never a silent empty input.
|
|
5
6
|
*/
|
|
6
7
|
export declare function readJsonValue(req: Request): Promise<unknown>;
|
|
7
8
|
export declare function dispatchOperationRoute(req: Request, url: URL): Promise<Response | null>;
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* agent is ABOUT to make (create / move / connect / remove / edit) so the canvas
|
|
6
6
|
* can paint a faint placeholder before the real mutation lands. Like a
|
|
7
7
|
* multiplayer cursor, it auto-expires, is count-capped, and never enters
|
|
8
|
-
* `
|
|
8
|
+
* `canvas_query` (`layout` action), `state.json`, or snapshots.
|
|
9
9
|
*
|
|
10
10
|
* This module is import-shared by the server (IntentRegistry + the intent ops)
|
|
11
11
|
* and the client (intent-store + IntentLayer); it must stay free of any
|
package/docs/RELEASE.md
CHANGED
|
@@ -46,14 +46,18 @@ and exercises the CLI flows from
|
|
|
46
46
|
|
|
47
47
|
## Versioning
|
|
48
48
|
|
|
49
|
-
Semantic versioning
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
49
|
+
Semantic versioning, in 0.x semver honestly (see `docs/api-stability.md`).
|
|
50
|
+
We are pre-1.0, so minor versions — not just major — are the breaking-change
|
|
51
|
+
boundary:
|
|
52
|
+
|
|
53
|
+
- Patch (`0.x.y → 0.x.y+1`): bug fixes, hardening, internal cleanups,
|
|
54
|
+
additive CLI flags / MCP fields with backwards-compat fallbacks. Never
|
|
55
|
+
breaks a public surface.
|
|
56
|
+
- Minor (`0.x → 0.x+1`): documented breaking changes are allowed only here
|
|
57
|
+
(e.g. the 0.2 → 0.3 removal of the 57 deprecated legacy single-purpose MCP
|
|
58
|
+
tools in favor of their composite replacements). Every breaking change in
|
|
59
|
+
a minor needs a `### Breaking` CHANGELOG entry naming the replacement —
|
|
60
|
+
see the release-blocker gate below.
|
|
57
61
|
- Major (`0.x → 1.0`): production-stability commitment.
|
|
58
62
|
|
|
59
63
|
CLAUDE.md rule #5 (CanvasStateManager / PmxCanvas SDK / HTTP / MCP
|
|
@@ -70,6 +74,11 @@ Each release section uses these subheadings:
|
|
|
70
74
|
command/flag, SDK export, JSON shape).
|
|
71
75
|
- **Changed** — behavior changes that aren't strictly bug fixes
|
|
72
76
|
(response shape additions, schema cleanups, stricter validation).
|
|
77
|
+
- **Breaking** — removed or incompatibly changed public surface (see
|
|
78
|
+
`docs/api-stability.md`). Required at minor version boundaries whenever a
|
|
79
|
+
public surface breaks; must name the replacement.
|
|
80
|
+
- **Deprecated** — public surface marked for removal in a future minor,
|
|
81
|
+
per the `docs/api-stability.md` deprecation policy.
|
|
73
82
|
- **Fixed** — bug fixes.
|
|
74
83
|
- **Internal** — refactors, test additions, docs that don't affect
|
|
75
84
|
the public surface.
|
|
@@ -78,6 +87,12 @@ Don't ship a release without a CHANGELOG entry. The GitHub release
|
|
|
78
87
|
notes file (`/tmp/pmx-canvas-vX.Y.Z-release-notes.md` by convention)
|
|
79
88
|
expands on the CHANGELOG with examples and migration notes.
|
|
80
89
|
|
|
90
|
+
**Release-blocker gate:** a breaking change without a `### Breaking`
|
|
91
|
+
CHANGELOG entry blocks the release (`docs/api-stability.md`). Check the
|
|
92
|
+
diff against the previous tag for removed/renamed public surface — MCP
|
|
93
|
+
tool names, HTTP routes, SDK exports, CLI flags — before tagging; if
|
|
94
|
+
anything broke and isn't named under `### Breaking`, add the entry first.
|
|
95
|
+
|
|
81
96
|
## Tag → publish
|
|
82
97
|
|
|
83
98
|
The publish workflow ([`/.github/workflows/publish.yml`](../.github/workflows/publish.yml))
|
|
@@ -20,9 +20,9 @@ surface each one binds to.
|
|
|
20
20
|
| Adapter method | PMX surface (owned) | Harness-owned part |
|
|
21
21
|
| --- | --- | --- |
|
|
22
22
|
| `pullContext()` | `GET /api/canvas/ax/context?consumer=<id>` · `canvas://ax-context` — full board **plus** a compact `delivery` lead block | When/where to inject it into the model's turn |
|
|
23
|
-
| `deliverSteer()` | `GET /api/canvas/ax/delivery/pending?consumer=<id>` · `
|
|
23
|
+
| `deliverSteer()` | `GET /api/canvas/ax/delivery/pending?consumer=<id>` · `canvas_ax_delivery { action: "claim" }` → act → `POST …/delivery/<id>/mark` · `canvas_ax_delivery { action: "mark" }` | Calling the host's native send/wake |
|
|
24
24
|
| `ingestActivity(event)` | `POST /api/canvas/ax/activity` · `canvas_ingest_activity` — board auto-reacts | Forwarding the host's tool/session hooks |
|
|
25
|
-
| `awaitGate(id)` | `GET /api/canvas/ax/{approval\|elicitation\|mode}/<id>?waitMs=` · `
|
|
25
|
+
| `awaitGate(id)` | `GET /api/canvas/ax/{approval\|elicitation\|mode}/<id>?waitMs=` · `canvas_ax_gate { kind: "approval"\|"elicitation"\|"mode", action: "await" }` | Optionally surfacing a native modal; the agent must await PMX |
|
|
26
26
|
| `mirrorLog(event)` *(optional)* | `GET /api/canvas/ax/timeline` · `canvas://ax-timeline` | Writing AX events into the host's own chat/session log |
|
|
27
27
|
|
|
28
28
|
## Steering is gated, not pushed (#54)
|
|
@@ -37,8 +37,8 @@ message; it does **not** wake the agent. It reaches the next turn only when:
|
|
|
37
37
|
2. **A human message fires the turn.** A sandbox button click cannot itself create a
|
|
38
38
|
new agent turn (an app-platform constraint). Any human prompt triggers the injection.
|
|
39
39
|
3. **The agent acts, then acks.** Injected `pendingSteering` / `pendingActivity` is
|
|
40
|
-
*to-do*, not narration: act on it, then `
|
|
41
|
-
(or resolve the work item / gate). Until acked, steering re-injects every gated turn.
|
|
40
|
+
*to-do*, not narration: act on it, then `canvas_ax_delivery { action: "mark" }`
|
|
41
|
+
the steering (or resolve the work item / gate). Until acked, steering re-injects every gated turn.
|
|
42
42
|
|
|
43
43
|
The `delivery` lead block (`GET /api/canvas/ax/context?consumer=<id>`) is the
|
|
44
44
|
robustness hedge: it's compact and sits above the full dump, so an adapter can inject
|
|
@@ -69,9 +69,9 @@ turn"), never imply it interrupts the agent now.
|
|
|
69
69
|
tool becomes a blocked work item + a review finding + evidence without the agent
|
|
70
70
|
remembering to push it. Reactions are kind-driven and overridable per call.
|
|
71
71
|
- **Blocking gates (gates that actually gate).** Before, an approval gate was inert
|
|
72
|
-
data the agent had to poll. With `
|
|
73
|
-
long-poll), the agent requests a gate then *blocks* until the
|
|
74
|
-
the browser — real human-in-the-loop control on any harness.
|
|
72
|
+
data the agent had to poll. With `canvas_ax_gate { kind: "approval", action: "await" }`
|
|
73
|
+
(and the `?waitMs` HTTP long-poll), the agent requests a gate then *blocks* until the
|
|
74
|
+
human resolves it in the browser — real human-in-the-loop control on any harness.
|
|
75
75
|
|
|
76
76
|
## What stays harness-owned
|
|
77
77
|
|
|
@@ -6,7 +6,7 @@ snapshot-vs-audit boundary; it is the documented module boundary for
|
|
|
6
6
|
`AxStateManager` (`src/server/ax-state-manager.ts`), which `CanvasStateManager`
|
|
7
7
|
holds and delegates to.
|
|
8
8
|
|
|
9
|
-
| Partition | Members | Storage | Snapshotted | Cleared by `
|
|
9
|
+
| Partition | Members | Storage | Snapshotted | Cleared by `canvas_view { action: "clear" }` | Cleared by `restore` |
|
|
10
10
|
|-----------|---------|---------|:-----------:|:-------------------------:|:--------------------:|
|
|
11
11
|
| **Canvas-bound** | `focus`, `workItems`, `approvalGates`, `reviewAnnotations`, `elicitations`, `modeRequests`, `policy` | in-memory `_axState` + one JSON blob in the `ax_state` table | ✅ | ✅ | ✅ (replaced by the snapshot's AX) |
|
|
12
12
|
| **Timeline (audit-only)** | `agent-event`, `evidence-item`, `steering-message` | `ax_events` / `ax_evidence` / `ax_steering` tables, 500-row retention, sequential ids | ❌ | ❌ | ❌ |
|
|
@@ -15,14 +15,15 @@ holds and delegates to.
|
|
|
15
15
|
**Rules.** Canvas-bound state travels with the canvas (snapshot / restore / clear);
|
|
16
16
|
timeline and host data are diagnostic and survive all three. Timeline rows are
|
|
17
17
|
append-only, retention-bounded (`AX_TIMELINE_RETENTION = 500` per table), and
|
|
18
|
-
read via `
|
|
19
|
-
row is reported by adapters and read via `
|
|
18
|
+
read via `canvas_ax_timeline { action: "read" }` / `canvas://ax-timeline`. The
|
|
19
|
+
host-capability row is reported by adapters and read via `canvas_ax_state {
|
|
20
|
+
action: "get" }`.
|
|
20
21
|
|
|
21
22
|
## Read surfaces
|
|
22
23
|
|
|
23
|
-
- **Canvas-bound:** `
|
|
24
|
-
- **Timeline:** `
|
|
25
|
-
- **Host:** `
|
|
24
|
+
- **Canvas-bound:** `canvas_ax_state { action: "get" }`, `canvas://ax`, `canvas://ax-context`, `canvas://ax-work`
|
|
25
|
+
- **Timeline:** `canvas_ax_timeline { action: "read" }`, `canvas://ax-timeline`, `canvas://ax-pending-steering`, `canvas://ax-delivery`
|
|
26
|
+
- **Host:** `canvas_ax_state { action: "get" }`
|
|
26
27
|
|
|
27
28
|
## Node-deletion semantics (soft-orphan + audit)
|
|
28
29
|
|
|
@@ -144,11 +144,11 @@ These flags are intentionally automation-only. They do **not** imply a visible B
|
|
|
144
144
|
|
|
145
145
|
Implemented in [`src/mcp/server.ts`](../src/mcp/server.ts):
|
|
146
146
|
|
|
147
|
-
- `
|
|
148
|
-
- `
|
|
149
|
-
- `
|
|
150
|
-
- `
|
|
151
|
-
- `
|
|
147
|
+
- `canvas_webview { action: "status" }`
|
|
148
|
+
- `canvas_webview { action: "start" }`
|
|
149
|
+
- `canvas_webview { action: "stop" }`
|
|
150
|
+
- `canvas_webview { action: "evaluate" }`
|
|
151
|
+
- `canvas_webview { action: "resize" }`
|
|
152
152
|
- `canvas_screenshot`
|
|
153
153
|
|
|
154
154
|
Current MCP behavior:
|
package/docs/cli.md
CHANGED
|
@@ -217,7 +217,7 @@ take a screenshot when the drawn form matters.
|
|
|
217
217
|
|
|
218
218
|
Humans draw with the pen toolbar button and remove marks with the eraser button.
|
|
219
219
|
If an agent already knows the annotation ID from context, it can remove it through
|
|
220
|
-
MCP with `
|
|
220
|
+
MCP with `canvas_view { action: "remove-annotation", id }`.
|
|
221
221
|
|
|
222
222
|
## When to reach for the CLI
|
|
223
223
|
|
package/docs/http-api.md
CHANGED
|
@@ -3,14 +3,18 @@
|
|
|
3
3
|
REST endpoints for all canvas operations + an SSE event stream. Works from
|
|
4
4
|
any language. Default base URL: `http://localhost:4313`.
|
|
5
5
|
|
|
6
|
+
A non-empty request body that is not valid JSON returns
|
|
7
|
+
`400 { "ok": false, "error": "Malformed JSON body." }` on every route; empty
|
|
8
|
+
bodies are treated as an empty request.
|
|
9
|
+
|
|
6
10
|
## Canvas state
|
|
7
11
|
|
|
8
12
|
```bash
|
|
9
13
|
# Get canvas state
|
|
10
14
|
curl http://localhost:4313/api/canvas/state
|
|
11
15
|
|
|
12
|
-
# Search nodes
|
|
13
|
-
curl "http://localhost:4313/api/canvas/search?q=auth"
|
|
16
|
+
# Search nodes (optional limit= caps the result count)
|
|
17
|
+
curl "http://localhost:4313/api/canvas/search?q=auth&limit=10"
|
|
14
18
|
|
|
15
19
|
# Validate the current layout
|
|
16
20
|
curl http://localhost:4313/api/canvas/validate
|
|
@@ -133,7 +137,7 @@ Host-agnostic agent-experience primitives across three state partitions.
|
|
|
133
137
|
Canvas-bound state (work items, approval gates, review annotations) rides
|
|
134
138
|
canvas snapshots; timeline state (events, evidence, steering) persists for
|
|
135
139
|
diagnostics but is retention-bounded and not restored by snapshots; the host
|
|
136
|
-
capability is reported by adapters and survives `
|
|
140
|
+
capability is reported by adapters and survives `canvas_view { action: "clear" }`.
|
|
137
141
|
|
|
138
142
|
```bash
|
|
139
143
|
# Timeline — record a normalized agent-event
|
package/docs/mcp.md
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
# MCP reference
|
|
2
2
|
|
|
3
|
-
PMX Canvas ships an MCP stdio server with **
|
|
3
|
+
PMX Canvas ships an MCP stdio server with **27 tools** + **14 core resources**,
|
|
4
4
|
plus per-skill resources at `canvas://skills/<name>`. The server emits
|
|
5
5
|
`notifications/resources/updated` when canvas state changes — humans pin
|
|
6
6
|
nodes in the browser, agents are notified immediately.
|
|
7
7
|
|
|
8
|
-
> **Consolidation in
|
|
9
|
-
>
|
|
10
|
-
>
|
|
11
|
-
>
|
|
12
|
-
>
|
|
13
|
-
>
|
|
14
|
-
>
|
|
8
|
+
> **Consolidation completed in v0.3.0 (plan-006/008).** The MCP surface shrank
|
|
9
|
+
> from 84 tools to 27: 15 action-discriminated **composites** (recommended —
|
|
10
|
+
> see below) plus 12 standalone tools. The 57 legacy single-purpose tools that
|
|
11
|
+
> the composites replaced were removed in v0.3.0 per
|
|
12
|
+
> [`api-stability.md`](api-stability.md); their descriptions carried
|
|
13
|
+
> `Deprecated:` prefixes for one minor before removal. The 6 snapshot tools
|
|
14
|
+
> remain registered as deprecated standalones — they fold into a
|
|
15
|
+
> `canvas_snapshot` composite in v0.4 (see [Standalone tools](#standalone-tools)
|
|
16
|
+
> below). **Prefer the composites.**
|
|
15
17
|
|
|
16
18
|
## Connect
|
|
17
19
|
|
|
@@ -35,15 +37,15 @@ The canvas auto-starts on first tool call.
|
|
|
35
37
|
Action-discriminated tools that consolidate the single-purpose tools. Each maps
|
|
36
38
|
its `action` to the same operation the legacy tool used, so results are identical.
|
|
37
39
|
|
|
38
|
-
| Composite | `action` values |
|
|
40
|
+
| Composite | `action` values | Replaced (removed in v0.3.0) |
|
|
39
41
|
|-----------|-----------------|----------|
|
|
40
42
|
| `canvas_node` | `add` · `get` · `update` · `remove` | `canvas_add_node`, `canvas_get_node`, `canvas_update_node`, `canvas_remove_node`, `canvas_add_html_node` (`add` + `type:"html"`), `canvas_add_html_primitive` (`add` + `type:"html"`, `primitive:"<kind>"`), `canvas_refresh_webpage_node` (`update` + `refresh:true`) |
|
|
41
43
|
| `canvas_render` | `describe-schema` · `validate` · `add-json-render` · `stream-json-render` · `add-graph` | `canvas_describe_schema`, `canvas_validate_spec`, `canvas_add_json_render_node`, `canvas_stream_json_render_node`, `canvas_add_graph_node` |
|
|
42
44
|
| `canvas_edge` | `add` · `remove` | `canvas_add_edge`, `canvas_remove_edge` |
|
|
43
45
|
| `canvas_group` | `create` · `add` · `ungroup` | `canvas_create_group`, `canvas_group_nodes`, `canvas_ungroup` |
|
|
44
46
|
| `canvas_history` | `undo` · `redo` | `canvas_undo`, `canvas_redo` |
|
|
45
|
-
| `canvas_view` | `arrange` · `focus` · `fit` · `clear` | `canvas_arrange`, `canvas_focus_node`, `canvas_fit_view`, `canvas_clear` |
|
|
46
|
-
| `canvas_query` | `search` · `layout` | `canvas_search`, `canvas_get_layout` |
|
|
47
|
+
| `canvas_view` | `arrange` · `focus` · `fit` · `clear` · `remove-annotation` | `canvas_arrange`, `canvas_focus_node`, `canvas_fit_view`, `canvas_clear`, `canvas_remove_annotation` |
|
|
48
|
+
| `canvas_query` | `search` · `layout` · `validate` | `canvas_search`, `canvas_get_layout`, `canvas_validate` |
|
|
47
49
|
| `canvas_webview` | `status` · `start` · `stop` · `resize` · `evaluate` | `canvas_webview_status`, `canvas_webview_start`, `canvas_webview_stop`, `canvas_resize`, `canvas_evaluate` |
|
|
48
50
|
| `canvas_app` | `open-mcp-app` · `diagram` · `build-artifact` | `canvas_open_mcp_app`, `canvas_add_diagram`, `canvas_build_web_artifact` |
|
|
49
51
|
| `canvas_ax_state` | `get` · `set-focus` · `set-policy` · `report-capability` | `canvas_get_ax`, `canvas_set_ax_focus`, `canvas_set_ax_policy`, `canvas_report_host_capability` |
|
|
@@ -64,7 +66,7 @@ veto it — before the mutation lands.
|
|
|
64
66
|
- `clear` — abandon/dissolve it explicitly. Normal linked mutations settle automatically.
|
|
65
67
|
|
|
66
68
|
Intents are **ephemeral presence**: never persisted, never snapshotted, never in
|
|
67
|
-
`
|
|
69
|
+
`canvas_query { action: "layout" }`, and auto-expiring. They ride their own SSE channel
|
|
68
70
|
(`ax-intent` / `ax-intent-clear`) and replay to reconnecting browsers while still
|
|
69
71
|
live. Best practice — narrate your next move: `signal` → mutate with the returned
|
|
70
72
|
`intent.id` as `intentId`. A vetoed or expired linked mutation is rejected, and a
|
|
@@ -87,86 +89,105 @@ tools). `canvas_screenshot` also stays standalone — it returns a binary image
|
|
|
87
89
|
the composite/registry JSON wire shape does not model. (Wave 5 folded
|
|
88
90
|
`canvas_refresh_webpage_node` → `canvas_node { action: "update", refresh: true }` after
|
|
89
91
|
fixing `node.update`'s `formatResult` to surface a FAILED refresh as `isError` +
|
|
90
|
-
`{ ok:false, error }` instead of masking it as a false `{ ok:true }`.)
|
|
91
|
-
fold
|
|
92
|
+
`{ ok:false, error }` instead of masking it as a false `{ ok:true }`.) The 6
|
|
93
|
+
snapshot tools are the one deferred fold: a `canvas_snapshot` composite is
|
|
94
|
+
planned for v0.4 (the name collides with the legacy `canvas_snapshot` save
|
|
95
|
+
tool, and [`api-stability.md`](api-stability.md) requires deprecating a tool
|
|
96
|
+
for one minor before removing it) — they stay registered as deprecated
|
|
97
|
+
standalones until then.
|
|
92
98
|
|
|
93
|
-
##
|
|
99
|
+
## Standalone tools
|
|
100
|
+
|
|
101
|
+
12 tools that intentionally stay outside the composites — either because
|
|
102
|
+
folding them would hurt (distinct callers, binary payloads, trust-boundary or
|
|
103
|
+
execution-intent semantics), or because they're mid-deprecation pending a
|
|
104
|
+
v0.4 composite. See [Migration reference](#migration-reference) below for the
|
|
105
|
+
57 tools these composites replaced.
|
|
94
106
|
|
|
95
107
|
| Tool | Description |
|
|
96
108
|
|------|-------------|
|
|
97
|
-
| `
|
|
98
|
-
| `
|
|
99
|
-
| `
|
|
100
|
-
| `canvas_add_diagram` | Hand-drawn diagram via the hosted Excalidraw MCP App (preset alias for `canvas_open_mcp_app`) |
|
|
101
|
-
| `canvas_open_mcp_app` | Open any [MCP Apps](https://modelcontextprotocol.io/docs/extensions/apps) server's `ui://` resource as an iframe node |
|
|
102
|
-
| `canvas_describe_schema` | Describe the running server's create schemas, examples, json-render catalog, and HTML primitive catalog |
|
|
103
|
-
| `canvas_validate_spec` | Validate a json-render spec, graph payload, or HTML primitive payload without creating a node |
|
|
104
|
-
| `canvas_refresh_webpage_node` | **Deprecated** → `canvas_node { action: "update", refresh: true }`. Re-fetch and update a webpage node from its stored URL |
|
|
105
|
-
| `canvas_add_json_render_node` | Create a native json-render node from a validated spec |
|
|
106
|
-
| `canvas_stream_json_render_node` | Progressively build a json-render node from SpecStream JSON-Patch ops (live/streaming panels) |
|
|
107
|
-
| `canvas_add_graph_node` | Create a native graph node (line, bar, pie, area, scatter, radar, stacked-bar, composed, sparkline, dot-plot, bullet, slopegraph) |
|
|
108
|
-
| `canvas_build_web_artifact` | Build a bundled HTML artifact and open it on the canvas |
|
|
109
|
-
|
|
110
|
-
`canvas_add_html_node` accepts optional `summary`, `agentSummary`, `embeddedNodeIds`, and
|
|
111
|
-
`embeddedUrls`. PMX also derives a bounded text summary from visible HTML, so rich HTML nodes stay
|
|
112
|
-
searchable and readable in pinned/spatial context.
|
|
113
|
-
| `canvas_update_node` | Update content, position, size, collapsed state |
|
|
114
|
-
| `canvas_remove_node` | Remove a node and its edges |
|
|
115
|
-
| `canvas_get_layout` | Get full canvas state |
|
|
116
|
-
| `canvas_get_node` | Get a single node by ID |
|
|
117
|
-
| `canvas_remove_annotation` | Remove a human-drawn annotation by ID |
|
|
118
|
-
| `canvas_add_edge` | Connect two nodes |
|
|
119
|
-
| `canvas_remove_edge` | Remove a connection |
|
|
120
|
-
| `canvas_arrange` | Auto-arrange (grid/column/flow) |
|
|
121
|
-
| `canvas_validate` | Validate collisions, containment, and missing edge endpoints |
|
|
122
|
-
| `canvas_focus_node` | Pan viewport to a node; use CLI `focus --no-pan` when you only need to select/raise |
|
|
123
|
-
| `canvas_fit_view` | Fit the canvas viewport to all nodes or a selected subset |
|
|
124
|
-
| `canvas_get_ax` | Read the PMX AX state (focus, work items, approvals, review annotations, host capability) plus pinned/focused context |
|
|
125
|
-
| `canvas_set_ax_focus` | Set the host-agnostic AX focus node set; adapters can pass a source such as `codex` |
|
|
126
|
-
| `canvas_record_ax_event` | Record a normalized timeline `agent-event` (prompt/assistant-message/tool-start/tool-result/failure/approval/steering) |
|
|
127
|
-
| `canvas_send_steering` | Record a `steering-message`: a user instruction from the surface to the active agent session |
|
|
128
|
-
| `canvas_get_ax_timeline` | Read the bounded AX timeline (events, evidence, steering) plus counts |
|
|
129
|
-
| `canvas_add_work_item` | Add a canvas-bound `work-item` (visible task/plan/status tied to nodes) |
|
|
130
|
-
| `canvas_update_work_item` | Update a work item's title/status/detail/nodeIds by ID |
|
|
131
|
-
| `canvas_request_approval` | Request human approval via an `approval-gate` (pending) before a high-impact action |
|
|
132
|
-
| `canvas_resolve_approval` | Resolve a pending approval gate (`approved`/`rejected`) |
|
|
133
|
-
| `canvas_add_evidence` | Record an `evidence-item` on the timeline (logs/tool-result/screenshot/file/diff/test-output) |
|
|
134
|
-
| `canvas_add_review_annotation` | Add a canvas-bound `review-annotation` (comment/finding) anchored to a node, file, or region |
|
|
135
|
-
| `canvas_report_host_capability` | Report a host/session `host-capability` for diagnostics |
|
|
109
|
+
| `canvas_batch` | Run a batch of canvas operations with `$ref` support |
|
|
110
|
+
| `canvas_pin_nodes` | Pin nodes to include in agent context |
|
|
111
|
+
| `canvas_invoke_command` | Invoke a registry command (`pmx.plan`, `pmx.execute`, `pmx.promote-context`, `pmx.summarize`, `pmx.review`); records a `command` agent-event, unknown names rejected |
|
|
136
112
|
| `canvas_ax_interaction` | Submit one capability-gated AX interaction envelope (`{ type, sourceNodeId, payload }`) that maps onto an AX operation; the server re-validates and clamps sandboxed surfaces to their own node |
|
|
137
|
-
| `canvas_claim_ax_delivery` | Claim undelivered steering messages for an adapterless consumer (loop-safe — never returns steering the consumer originated) |
|
|
138
|
-
| `canvas_mark_ax_delivery` | Mark a steering message delivered for a consumer |
|
|
139
|
-
| `canvas_request_elicitation` | Request structured human input via a canvas-bound `elicitation` (pending) |
|
|
140
|
-
| `canvas_respond_elicitation` | Respond to / resolve a pending elicitation |
|
|
141
|
-
| `canvas_request_mode` | Request a workflow `mode-request` transition (plan/execute/autonomous) |
|
|
142
|
-
| `canvas_resolve_mode` | Resolve a pending mode request |
|
|
143
113
|
| `canvas_ingest_activity` | Ingest a harness-forwarded agent activity (tool/session event); the board auto-reacts with kind-driven, overridable defaults (failure → work item + review + evidence; `tool-result`+success → evidence). Makes AX bidirectional |
|
|
144
|
-
| `canvas_await_approval` | Block until an approval gate resolves (human approves/rejects in the browser) or the timeout elapses (`timeoutMs` 0 = immediate read). Gates that actually gate |
|
|
145
|
-
| `canvas_await_elicitation` | Block until an elicitation is answered or the timeout elapses |
|
|
146
|
-
| `canvas_await_mode` | Block until a mode request resolves or the timeout elapses |
|
|
147
|
-
| `canvas_invoke_command` | Invoke a registry command (`pmx.plan`, `pmx.execute`, `pmx.promote-context`, `pmx.summarize`, `pmx.review`); records a `command` agent-event, unknown names rejected |
|
|
148
|
-
| `canvas_set_ax_policy` | Patch the canvas-bound tool/prompt policy (`tools.allowed\|excluded\|approvalRequired`, `prompt.systemAppend\|mode`); patches merge and are normalized |
|
|
149
|
-
| `canvas_pin_nodes` | Pin nodes to include in agent context |
|
|
150
|
-
| `canvas_clear` | Clear all nodes and edges |
|
|
151
|
-
| `canvas_snapshot` | Save current canvas as a named snapshot |
|
|
152
|
-
| `canvas_list_snapshots` | List saved snapshots, bounded to the newest 20 by default |
|
|
153
|
-
| `canvas_gc_snapshots` | Delete old snapshots while keeping the newest N |
|
|
154
|
-
| `canvas_restore` | Restore canvas from a saved snapshot |
|
|
155
|
-
| `canvas_delete_snapshot` | Delete a saved snapshot |
|
|
156
|
-
| `canvas_search` | Find nodes by title/content keywords |
|
|
157
|
-
| `canvas_undo` | Undo the last canvas mutation |
|
|
158
|
-
| `canvas_redo` | Redo the last undone mutation |
|
|
159
|
-
| `canvas_diff` | Compare current canvas vs a saved snapshot |
|
|
160
|
-
| `canvas_create_group` | Create a group containing specified nodes |
|
|
161
|
-
| `canvas_group_nodes` | Add nodes to an existing group |
|
|
162
|
-
| `canvas_ungroup` | Release all children from a group |
|
|
163
|
-
| `canvas_batch` | Run a batch of canvas operations with `$ref` support |
|
|
164
|
-
| `canvas_webview_status` | Get Bun.WebView automation status for the workbench |
|
|
165
|
-
| `canvas_webview_start` | Start or replace the Bun.WebView automation session |
|
|
166
|
-
| `canvas_webview_stop` | Stop the active Bun.WebView automation session |
|
|
167
|
-
| `canvas_evaluate` | Evaluate JavaScript in the active workbench automation session |
|
|
168
|
-
| `canvas_resize` | Resize the active workbench automation viewport |
|
|
169
114
|
| `canvas_screenshot` | Capture a screenshot from the active workbench automation session |
|
|
115
|
+
| `canvas_snapshot` | **Deprecated** → folds into the `canvas_snapshot` composite in v0.4 (actions `save\|list\|restore\|delete\|gc\|diff`). Save current canvas as a named snapshot |
|
|
116
|
+
| `canvas_list_snapshots` | **Deprecated** → folds into the `canvas_snapshot` composite in v0.4 (actions `save\|list\|restore\|delete\|gc\|diff`). List saved snapshots, bounded to the newest 20 by default |
|
|
117
|
+
| `canvas_restore` | **Deprecated** → folds into the `canvas_snapshot` composite in v0.4 (actions `save\|list\|restore\|delete\|gc\|diff`). Restore canvas from a saved snapshot |
|
|
118
|
+
| `canvas_delete_snapshot` | **Deprecated** → folds into the `canvas_snapshot` composite in v0.4 (actions `save\|list\|restore\|delete\|gc\|diff`). Delete a saved snapshot |
|
|
119
|
+
| `canvas_gc_snapshots` | **Deprecated** → folds into the `canvas_snapshot` composite in v0.4 (actions `save\|list\|restore\|delete\|gc\|diff`). Delete old snapshots while keeping the newest N |
|
|
120
|
+
| `canvas_diff` | **Deprecated** → folds into the `canvas_snapshot` composite in v0.4 (actions `save\|list\|restore\|delete\|gc\|diff`). Compare current canvas vs a saved snapshot |
|
|
121
|
+
|
|
122
|
+
`canvas_node { action: "add", type: "html" }` accepts optional `summary`, `agentSummary`,
|
|
123
|
+
`embeddedNodeIds`, and `embeddedUrls`. PMX also derives a bounded text summary from visible
|
|
124
|
+
HTML, so rich HTML nodes stay searchable and readable in pinned/spatial context.
|
|
125
|
+
|
|
126
|
+
## Migration reference
|
|
127
|
+
|
|
128
|
+
The 57 legacy single-purpose tools below were removed in v0.3.0. Each row is
|
|
129
|
+
the composite call that replaces it — kept as a lookup table for anyone
|
|
130
|
+
migrating an older integration.
|
|
131
|
+
|
|
132
|
+
| Removed tool | Composite replacement |
|
|
133
|
+
|------|-------------|
|
|
134
|
+
| `canvas_add_node` | `canvas_node { action: "add" }` |
|
|
135
|
+
| `canvas_get_node` | `canvas_node { action: "get" }` |
|
|
136
|
+
| `canvas_update_node` | `canvas_node { action: "update" }` |
|
|
137
|
+
| `canvas_remove_node` | `canvas_node { action: "remove" }` |
|
|
138
|
+
| `canvas_add_html_node` | `canvas_node { action: "add", type: "html" }` |
|
|
139
|
+
| `canvas_add_html_primitive` | `canvas_node { action: "add", type: "html", primitive: "<kind>" }` |
|
|
140
|
+
| `canvas_refresh_webpage_node` | `canvas_node { action: "update", refresh: true }` |
|
|
141
|
+
| `canvas_describe_schema` | `canvas_render { action: "describe-schema" }` |
|
|
142
|
+
| `canvas_validate_spec` | `canvas_render { action: "validate" }` |
|
|
143
|
+
| `canvas_add_json_render_node` | `canvas_render { action: "add-json-render" }` |
|
|
144
|
+
| `canvas_stream_json_render_node` | `canvas_render { action: "stream-json-render" }` |
|
|
145
|
+
| `canvas_add_graph_node` | `canvas_render { action: "add-graph" }` |
|
|
146
|
+
| `canvas_add_edge` | `canvas_edge { action: "add" }` |
|
|
147
|
+
| `canvas_remove_edge` | `canvas_edge { action: "remove" }` |
|
|
148
|
+
| `canvas_create_group` | `canvas_group { action: "create" }` |
|
|
149
|
+
| `canvas_group_nodes` | `canvas_group { action: "add" }` |
|
|
150
|
+
| `canvas_ungroup` | `canvas_group { action: "ungroup" }` |
|
|
151
|
+
| `canvas_undo` | `canvas_history { action: "undo" }` |
|
|
152
|
+
| `canvas_redo` | `canvas_history { action: "redo" }` |
|
|
153
|
+
| `canvas_arrange` | `canvas_view { action: "arrange" }` |
|
|
154
|
+
| `canvas_focus_node` | `canvas_view { action: "focus" }` |
|
|
155
|
+
| `canvas_fit_view` | `canvas_view { action: "fit" }` |
|
|
156
|
+
| `canvas_clear` | `canvas_view { action: "clear" }` |
|
|
157
|
+
| `canvas_remove_annotation` | `canvas_view { action: "remove-annotation" }` |
|
|
158
|
+
| `canvas_search` | `canvas_query { action: "search" }` |
|
|
159
|
+
| `canvas_get_layout` | `canvas_query { action: "layout" }` |
|
|
160
|
+
| `canvas_validate` | `canvas_query { action: "validate" }` |
|
|
161
|
+
| `canvas_open_mcp_app` | `canvas_app { action: "open-mcp-app" }` |
|
|
162
|
+
| `canvas_add_diagram` | `canvas_app { action: "diagram" }` |
|
|
163
|
+
| `canvas_build_web_artifact` | `canvas_app { action: "build-artifact" }` |
|
|
164
|
+
| `canvas_webview_status` | `canvas_webview { action: "status" }` |
|
|
165
|
+
| `canvas_webview_start` | `canvas_webview { action: "start" }` |
|
|
166
|
+
| `canvas_webview_stop` | `canvas_webview { action: "stop" }` |
|
|
167
|
+
| `canvas_resize` | `canvas_webview { action: "resize" }` |
|
|
168
|
+
| `canvas_evaluate` | `canvas_webview { action: "evaluate" }` |
|
|
169
|
+
| `canvas_get_ax` | `canvas_ax_state { action: "get" }` |
|
|
170
|
+
| `canvas_set_ax_focus` | `canvas_ax_state { action: "set-focus" }` |
|
|
171
|
+
| `canvas_set_ax_policy` | `canvas_ax_state { action: "set-policy" }` |
|
|
172
|
+
| `canvas_report_host_capability` | `canvas_ax_state { action: "report-capability" }` |
|
|
173
|
+
| `canvas_add_work_item` | `canvas_ax_work { action: "add" }` |
|
|
174
|
+
| `canvas_update_work_item` | `canvas_ax_work { action: "update" }` |
|
|
175
|
+
| `canvas_add_review_annotation` | `canvas_ax_work { action: "annotate" }` |
|
|
176
|
+
| `canvas_request_approval` | `canvas_ax_gate { kind: "approval", action: "request" }` |
|
|
177
|
+
| `canvas_resolve_approval` | `canvas_ax_gate { kind: "approval", action: "resolve" }` |
|
|
178
|
+
| `canvas_await_approval` | `canvas_ax_gate { kind: "approval", action: "await" }` |
|
|
179
|
+
| `canvas_request_elicitation` | `canvas_ax_gate { kind: "elicitation", action: "request" }` |
|
|
180
|
+
| `canvas_respond_elicitation` | `canvas_ax_gate { kind: "elicitation", action: "resolve" }` |
|
|
181
|
+
| `canvas_await_elicitation` | `canvas_ax_gate { kind: "elicitation", action: "await" }` |
|
|
182
|
+
| `canvas_request_mode` | `canvas_ax_gate { kind: "mode", action: "request" }` |
|
|
183
|
+
| `canvas_resolve_mode` | `canvas_ax_gate { kind: "mode", action: "resolve" }` |
|
|
184
|
+
| `canvas_await_mode` | `canvas_ax_gate { kind: "mode", action: "await" }` |
|
|
185
|
+
| `canvas_get_ax_timeline` | `canvas_ax_timeline { action: "read" }` |
|
|
186
|
+
| `canvas_record_ax_event` | `canvas_ax_timeline { action: "record-event" }` |
|
|
187
|
+
| `canvas_add_evidence` | `canvas_ax_timeline { action: "add-evidence" }` |
|
|
188
|
+
| `canvas_send_steering` | `canvas_ax_timeline { action: "send-steering" }` |
|
|
189
|
+
| `canvas_claim_ax_delivery` | `canvas_ax_delivery { action: "claim" }` |
|
|
190
|
+
| `canvas_mark_ax_delivery` | `canvas_ax_delivery { action: "mark" }` |
|
|
170
191
|
|
|
171
192
|
## Resources
|
|
172
193
|
|
|
@@ -255,27 +276,27 @@ raw stroke geometry or visual shape.
|
|
|
255
276
|
|
|
256
277
|
Annotations are a browser-visible markup layer. Use the pen toolbar button to
|
|
257
278
|
draw and the eraser toolbar button to remove an annotation again; agents can also
|
|
258
|
-
remove a known annotation ID with `
|
|
279
|
+
remove a known annotation ID with `canvas_view { action: "remove-annotation", id }`.
|
|
259
280
|
|
|
260
281
|
Use WebView automation when an agent needs to actually see annotations as drawn.
|
|
261
|
-
For example, inspect `.annotation-layer path` with `
|
|
262
|
-
`canvas_screenshot` to distinguish an arrow from a line, circle, or highlight.
|
|
282
|
+
For example, inspect `.annotation-layer path` with `canvas_webview { action: "evaluate" }`
|
|
283
|
+
or capture a `canvas_screenshot` to distinguish an arrow from a line, circle, or highlight.
|
|
263
284
|
|
|
264
285
|
## Node-type routing
|
|
265
286
|
|
|
266
|
-
MCP node creation uses dedicated
|
|
267
|
-
`mcp.nodeTypeRouting` from `
|
|
268
|
-
in doubt:
|
|
269
|
-
|
|
270
|
-
- `json-render` → `
|
|
271
|
-
- `graph` → `
|
|
272
|
-
- `html-primitive` → `canvas_node { action: "add", type: "html", primitive: "<kind>" }`
|
|
273
|
-
- `html` → `canvas_node { action: "add", type: "html" }`
|
|
274
|
-
- `web-artifact` → `
|
|
275
|
-
- `mcp-app` → `
|
|
276
|
-
- `group` → `
|
|
287
|
+
MCP node creation uses dedicated composite actions for structured node
|
|
288
|
+
families. Read `mcp.nodeTypeRouting` from `canvas_render { action:
|
|
289
|
+
"describe-schema" }` / `canvas://schema` when in doubt:
|
|
290
|
+
|
|
291
|
+
- `json-render` → `canvas_render { action: "add-json-render" }`
|
|
292
|
+
- `graph` → `canvas_render { action: "add-graph" }`
|
|
293
|
+
- `html-primitive` → `canvas_node { action: "add", type: "html", primitive: "<kind>" }`
|
|
294
|
+
- `html` → `canvas_node { action: "add", type: "html" }`
|
|
295
|
+
- `web-artifact` → `canvas_app { action: "build-artifact" }`
|
|
296
|
+
- `mcp-app` → `canvas_app { action: "open-mcp-app" }`
|
|
297
|
+
- `group` → `canvas_group { action: "create" }`
|
|
277
298
|
- Basic nodes (`markdown`, `status`, `file`, `image`, `webpage`) →
|
|
278
|
-
`
|
|
299
|
+
`canvas_node { action: "add" }`
|
|
279
300
|
|
|
280
301
|
## CLI/MCP alignment
|
|
281
302
|
|