pmx-canvas 0.1.22 → 0.1.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/.github/extensions/pmx-canvas/extension.mjs +591 -0
  2. package/CHANGELOG.md +140 -0
  3. package/Readme.md +40 -8
  4. package/dist/canvas/global.css +36 -3
  5. package/dist/canvas/index.js +54 -54
  6. package/dist/types/client/nodes/ExtAppFrame.d.ts +1 -0
  7. package/dist/types/client/nodes/iframe-document-url.d.ts +8 -0
  8. package/dist/types/client/state/intent-bridge.d.ts +4 -0
  9. package/dist/types/client/types.d.ts +1 -0
  10. package/dist/types/json-render/catalog.d.ts +1 -1
  11. package/dist/types/mcp/canvas-access.d.ts +9 -0
  12. package/dist/types/server/ax-context.d.ts +3 -0
  13. package/dist/types/server/ax-state.d.ts +43 -0
  14. package/dist/types/server/canvas-db.d.ts +38 -0
  15. package/dist/types/server/canvas-state.d.ts +36 -16
  16. package/dist/types/server/index.d.ts +6 -0
  17. package/dist/types/server/mutation-history.d.ts +1 -1
  18. package/docs/cli.md +13 -0
  19. package/docs/http-api.md +24 -0
  20. package/docs/mcp.md +20 -2
  21. package/docs/plans/plan-004-pmx-ax-primitives.md +463 -0
  22. package/docs/screenshot.png +0 -0
  23. package/docs/sdk.md +5 -0
  24. package/package.json +3 -2
  25. package/skills/pmx-canvas/SKILL.md +22 -4
  26. package/skills/pmx-canvas/references/codex-app-adapter.md +107 -0
  27. package/skills/pmx-canvas/references/github-copilot-app-adapter.md +111 -0
  28. package/src/cli/agent.ts +34 -0
  29. package/src/cli/index.ts +2 -1
  30. package/src/client/App.tsx +2 -0
  31. package/src/client/canvas/CanvasNode.tsx +7 -0
  32. package/src/client/canvas/CommandPalette.tsx +2 -1
  33. package/src/client/canvas/use-node-drag.ts +29 -7
  34. package/src/client/canvas/use-node-resize.ts +27 -7
  35. package/src/client/nodes/ExtAppFrame.tsx +51 -10
  36. package/src/client/nodes/HtmlNode.tsx +5 -2
  37. package/src/client/nodes/iframe-document-url.ts +58 -0
  38. package/src/client/state/intent-bridge.ts +8 -0
  39. package/src/client/state/sse-bridge.ts +2 -2
  40. package/src/client/theme/global.css +36 -3
  41. package/src/client/types.ts +1 -0
  42. package/src/mcp/canvas-access.ts +38 -0
  43. package/src/mcp/server.ts +113 -4
  44. package/src/server/ax-context.ts +38 -0
  45. package/src/server/ax-state.ts +130 -0
  46. package/src/server/canvas-db.ts +745 -0
  47. package/src/server/canvas-operations.ts +80 -1
  48. package/src/server/canvas-schema.ts +3 -3
  49. package/src/server/canvas-state.ts +390 -50
  50. package/src/server/canvas-validation.ts +6 -0
  51. package/src/server/index.ts +18 -0
  52. package/src/server/mutation-history.ts +1 -0
  53. package/src/server/server.ts +197 -11
@@ -0,0 +1,463 @@
1
+ ---
2
+ title: PMX AX Primitives and Copilot Adapter Plan
3
+ status: draft
4
+ date: 2026-06-02
5
+ ---
6
+
7
+ # PMX AX Primitives and Copilot Adapter Plan
8
+
9
+ ## Summary
10
+
11
+ PMX Canvas should own the agent-experience primitives as core PMX concepts, not
12
+ as GitHub Copilot concepts. GitHub Copilot becomes the first native host
13
+ adapter: it renders the existing PMX workbench in a Copilot canvas and maps
14
+ Copilot SDK features onto the neutral PMX AX contract.
15
+
16
+ This plan keeps PMX Canvas agent-agnostic and backward-compatible while adding:
17
+
18
+ - core AX state and serializers
19
+ - HTTP, SDK, MCP, and CLI surfaces for the AX primitives
20
+ - a committed `.github/extensions/pmx-canvas/` Copilot canvas adapter
21
+ - CLI support to scaffold/install the same adapter in other PMX Canvas projects
22
+
23
+ Codex is intentionally out of scope for this pass, but the core contract should
24
+ make a later Codex adapter straightforward.
25
+
26
+ Implementation should proceed in vertical slices: each primitive lands across
27
+ state, persistence, HTTP, SDK, MCP, CLI, docs, and tests before moving to the
28
+ next primitive group. This avoids half-wired surfaces and keeps the existing PMX
29
+ "one operation, all access paths" rule intact.
30
+
31
+ ## Interview Decisions
32
+
33
+ - First pass surfaces: core model, HTTP, SDK, MCP, CLI, and GitHub Copilot
34
+ adapter.
35
+ - Out of scope: Codex adapter. Copilot should be a real adapter for the
36
+ existing PMX Canvas experience, not a demo-only scaffold.
37
+ - Compatibility: preserve existing APIs and state formats; add optional AX
38
+ fields/endpoints/tables in a backward-compatible way.
39
+ - Persistence: AX state lives inside the existing `.pmx-canvas/canvas.db`
40
+ persistence model alongside nodes, edges, context pins, annotations, and
41
+ snapshots.
42
+ - Copilot distribution: commit a project extension under
43
+ `.github/extensions/pmx-canvas/` and add CLI support to scaffold/install that
44
+ adapter for other projects later.
45
+
46
+ ## Core AX Primitive Contract
47
+
48
+ | PMX AX primitive | Core meaning | Persistence/snapshot semantics | First adapter mapping |
49
+ |---|---|---|---|
50
+ | `canvas-surface` | A live PMX workbench surface with nodes, edges, viewport, annotations, pins, and snapshots. | Existing canvas state and snapshots. | Copilot `createCanvas().open()` returns the running `/workbench` URL. |
51
+ | `pinned-context` | Human-curated node set plus bounded agent-readable summaries and neighborhoods. | Existing context pin state and snapshots. | Copilot hooks return it as `additionalContext`; MCP keeps `canvas://pinned-context`. |
52
+ | `focus` | Current node or node set the human/agent wants attention on. | Canvas-bound state; snapshot with canvas. | Copilot canvas action/HTTP/CLI can focus without requiring app-specific state. |
53
+ | `agent-action` | Normalized operation request against PMX state. | Operation request/result is timeline state; effects persist through target primitive. | Copilot canvas actions/tools proxy to PMX HTTP/SDK/MCP operations. |
54
+ | `steering-message` | User instruction emitted from the PMX surface to the active agent session. | Timeline state; persisted in DB but not restored by snapshots. | Copilot adapter maps it to `session.send()` or `sendAndWait()`. |
55
+ | `approval-gate` | A PMX-owned request for human approval/rejection before a high-impact AX action. | Canvas-bound state while pending/resolved; snapshot with canvas. | Copilot adapter exposes approval UI/actions and may map safe cases to SDK permission hooks. |
56
+ | `work-item` | Visible task/plan/status primitive tied to nodes or agent work. | Canvas-bound state; snapshot with canvas. | Existing status/markdown nodes can render it; adapters can update it through AX APIs. |
57
+ | `evidence-item` | Inspectable artifact such as logs, tool result, screenshot, file, diff, or test output. | Timeline state; persisted in DB with retention, not restored by snapshots. | Copilot session/tool events become evidence nodes/items. |
58
+ | `review-annotation` | Human or agent comment/finding anchored to a node/file/region. | Canvas-bound state; snapshot with canvas. | PMX annotations/nodes remain source of truth; Copilot can render and update them. |
59
+ | `agent-event` | Normalized timeline event for prompts, assistant messages, tool starts/results, failures, approvals, and steering. | Timeline state; persisted in DB with retention, not restored by snapshots. | Copilot `session.on(...)` events are normalized into PMX AX events. |
60
+ | `host-capability` | What the current host can do: canvas, hooks, tools, session messaging, permissions, files, UI prompts. | Session/host state; persisted only when useful for diagnostics. | Copilot `session.capabilities` maps to neutral capability flags. |
61
+
62
+ ### State partitions
63
+
64
+ - **Canvas-bound AX state:** `focus`, `work-item`, `approval-gate`,
65
+ `review-annotation`, and existing pins. These participate in canvas
66
+ snapshots and restore.
67
+ - **Timeline AX state:** `agent-event`, `evidence-item`, `agent-action`
68
+ records, and `steering-message`. These persist in the PMX DB for diagnostics
69
+ and continuity but are not restored by canvas snapshots.
70
+ - **Host/session AX state:** `host-capability`. This is reported by adapters
71
+ and exposed for diagnostics, but it should not make core depend on any host.
72
+
73
+ ## Architecture
74
+
75
+ ### Make the change easy first
76
+
77
+ Add a small core AX module before wiring endpoints:
78
+
79
+ - `src/server/ax-state.ts`
80
+ - AX primitive types
81
+ - normalizers and validation helpers
82
+ - context/export serializers
83
+ - event/action/evidence/approval/work-item helpers
84
+
85
+ This avoids scattering AX-specific object shapes across `canvas-state.ts`,
86
+ `server.ts`, `index.ts`, `mcp/server.ts`, and `cli/agent.ts`.
87
+
88
+ ### Vertical slice sequencing
89
+
90
+ Use primitive groups as the unit of implementation:
91
+
92
+ 1. AX context and focus: reuse existing pins and prove context export across
93
+ HTTP, SDK, MCP, CLI, and Copilot hook injection.
94
+ 2. Steering and agent events: prove adapter-to-session messaging and timeline
95
+ recording without changing canvas rendering.
96
+ 3. Work items and approvals: add user-visible collaboration state and approval
97
+ enforcement for AX actions that explicitly opt into approval.
98
+ 4. Evidence and review annotations: add richer diagnostics and review surfaces.
99
+ 5. Host capabilities and adapter polish: expose what each host can support and
100
+ improve native Copilot ergonomics.
101
+
102
+ Each group should be complete across all applicable access paths before the
103
+ next group starts.
104
+
105
+ ### Server-authoritative state
106
+
107
+ `CanvasStateManager` remains the source of truth. AX state should be loaded,
108
+ mutated, snapshotted, restored, and notified through the same server-side path
109
+ as canvas nodes and context pins.
110
+
111
+ ### Adapter boundary
112
+
113
+ Core must not import `@github/copilot-sdk`. The Copilot adapter lives under
114
+ `.github/extensions/pmx-canvas/extension.mjs` and talks to PMX Canvas through
115
+ HTTP plus normal Copilot SDK APIs.
116
+
117
+ The adapter should:
118
+
119
+ 1. discover a running PMX Canvas server through an explicit contract
120
+ 2. open the existing `/workbench` URL in a Copilot canvas
121
+ 3. expose Copilot canvas actions that proxy PMX AX and canvas operations
122
+ 4. inject PMX pinned/AX context on prompt submission
123
+ 5. map session events and steering messages to PMX AX events/evidence
124
+
125
+ The discovery contract should be implemented before adapter features:
126
+
127
+ 1. use adapter input or environment (`PMX_CANVAS_URL` / `PMX_CANVAS_PORT`) when
128
+ provided
129
+ 2. probe the repo default loopback server (`127.0.0.1:4313`) and any configured
130
+ port
131
+ 3. read PMX daemon metadata under `.pmx-canvas/` when available
132
+ 4. fail with a visible `session.log()` diagnostic and an actionable canvas error
133
+ instead of opening a blank iframe
134
+
135
+ ## Affected Files/Areas
136
+
137
+ ### Core state and persistence
138
+
139
+ - `src/server/ax-state.ts` - new core AX primitive model and serializers
140
+ - `src/server/canvas-state.ts` - own AX state, persistence integration,
141
+ notifications, snapshots, restore, clear
142
+ - `src/server/canvas-db.ts` - add migration-safe AX tables or JSON state row
143
+ and snapshot persistence
144
+ - `src/server/canvas-serialization.ts` and/or `src/server/agent-context.ts` -
145
+ reuse existing pinned-context summaries in the AX context export
146
+
147
+ ### Core operations and SDK
148
+
149
+ - `src/server/canvas-operations.ts` - add shared operation helpers for AX
150
+ mutations
151
+ - `src/server/index.ts` - add `PmxCanvas` SDK methods for AX state, context,
152
+ actions, approvals, evidence, events, work items, capabilities, and steering
153
+ - `src/mcp/canvas-access.ts` - add local/remote access methods for AX APIs
154
+
155
+ ### HTTP and SSE
156
+
157
+ - `src/server/server.ts` - add routes such as:
158
+ - `GET /api/canvas/ax`
159
+ - `PATCH /api/canvas/ax`
160
+ - `GET /api/canvas/ax/context`
161
+ - `POST /api/canvas/ax/action`
162
+ - `POST /api/canvas/ax/event`
163
+ - `POST /api/canvas/ax/evidence`
164
+ - `POST /api/canvas/ax/approval`
165
+ - `POST /api/canvas/ax/steer`
166
+ - emit `ax-state-changed` / `ax-event-created` SSE events where useful
167
+ - keep existing `/api/canvas/context-pins` and `/api/canvas/pinned-context`
168
+ stable; AX context should build on them
169
+
170
+ ### MCP
171
+
172
+ - `src/mcp/server.ts`
173
+ - add AX resource(s), likely `canvas://ax` and `canvas://ax-context`
174
+ - add tools such as `canvas_get_ax`, `canvas_update_ax`,
175
+ `canvas_record_ax_event`, `canvas_add_evidence`,
176
+ `canvas_request_approval`, and `canvas_send_steering`
177
+ - update resource notifications for AX changes
178
+
179
+ ### CLI
180
+
181
+ - `src/cli/index.ts` - add top-level command group routing, likely `ax`
182
+ and/or `copilot`
183
+ - `src/cli/agent.ts` - add agent-native JSON commands:
184
+ - `pmx-canvas ax status`
185
+ - `pmx-canvas ax context`
186
+ - `pmx-canvas ax event add`
187
+ - `pmx-canvas ax evidence add`
188
+ - `pmx-canvas ax approval request|resolve`
189
+ - `pmx-canvas ax work add|update|list`
190
+ - `pmx-canvas copilot install-extension`
191
+
192
+ ### Copilot adapter
193
+
194
+ - `.github/extensions/pmx-canvas/extension.mjs`
195
+ - register a canvas through `joinSession({ canvases: [...] })`
196
+ - use `createCanvas` from `@github/copilot-sdk/extension`
197
+ - bind a loopback-safe workbench URL from the PMX server
198
+ - expose action handlers for PMX operations
199
+ - add `onUserPromptSubmitted` and `onSessionStart` hooks for AX context
200
+ - subscribe to session events and record normalized AX events/evidence
201
+ - use `session.log()`, never `console.log()`
202
+ - a bundled extension template path in the published package, for example
203
+ `src/cli/templates/copilot-extension/pmx-canvas/extension.mjs` or an
204
+ equivalent package-included location
205
+
206
+ ### Client/browser
207
+
208
+ - `src/client/types.ts` - add client-side AX types if the workbench needs to
209
+ render AX state directly
210
+ - `src/client/state/sse-bridge.ts` - consume AX SSE events if browser UI
211
+ should react live
212
+ - Existing workbench UI should stay intact; Copilot embeds it rather than
213
+ reimplementing the canvas renderer.
214
+
215
+ ### Docs and package contents
216
+
217
+ - `Readme.md`
218
+ - `docs/http-api.md`
219
+ - `docs/sdk.md`
220
+ - `docs/mcp.md`
221
+ - `docs/cli.md`
222
+ - `skills/pmx-canvas/SKILL.md`
223
+ - `package.json` - include the Copilot extension template in published package
224
+ files if the current package configuration would otherwise omit it
225
+
226
+ ## Implementation Checklist
227
+
228
+ ### Phase 0: Adapter/API spike and scaffolding
229
+
230
+ - [x] Re-check the local `create-canvas` skill and Copilot SDK docs/types before
231
+ writing the extension entrypoint.
232
+ - [x] Use `extensions_manage scaffold` for the project extension baseline, then
233
+ edit it into `.github/extensions/pmx-canvas/extension.mjs`.
234
+ - [x] Define the PMX server discovery contract for the adapter.
235
+ - [x] Add or choose a package-included extension template path for CLI
236
+ installation.
237
+
238
+ ### Phase 1: AX context and focus vertical slice
239
+
240
+ - [x] Define `src/server/ax-state.ts` with primitive types, normalizers, and
241
+ context/focus serializers.
242
+ - [x] Add canvas-bound AX focus state to `CanvasStateManager` without changing
243
+ existing node, edge, annotation, pin, or snapshot behavior.
244
+ - [x] Persist focus state in SQLite using additive schema changes only.
245
+ - [x] Snapshot and restore canvas-bound AX focus state.
246
+ - [x] Add HTTP endpoints and SSE events for AX context/focus.
247
+ - [x] Add `PmxCanvas` SDK methods for AX context/focus.
248
+ - [x] Add `CanvasAccess` local/remote methods for AX context/focus.
249
+ - [x] Add MCP resources/tools and resource notifications for AX context/focus.
250
+ - [x] Add CLI `ax context` and `ax focus` commands.
251
+ - [x] Make the Copilot adapter open the live PMX workbench and inject AX context
252
+ from prompt hooks.
253
+
254
+ ### Phase 2: Steering and agent-event vertical slice
255
+
256
+ - [ ] Add timeline persistence for steering messages and agent events with a
257
+ retention policy.
258
+ - [ ] Add HTTP/SDK/MCP/CLI operations for recording and reading AX timeline
259
+ events.
260
+ - [ ] Add Copilot adapter steering actions that call `session.send()` only from
261
+ explicit user/action flows.
262
+ - [ ] Subscribe to useful Copilot session events and record normalized
263
+ `agent-event` entries.
264
+
265
+ ### Phase 3: Work items and approval gates vertical slice
266
+
267
+ - [ ] Add canvas-bound work-item and approval-gate state.
268
+ - [ ] Persist and snapshot work items and approval gates.
269
+ - [ ] Add HTTP/SDK/MCP/CLI operations for work-item and approval lifecycle.
270
+ - [ ] Enforce approvals for AX actions explicitly marked as requiring approval;
271
+ existing non-AX canvas endpoints remain unchanged.
272
+ - [ ] Add Copilot adapter UI/actions for approval request and resolution.
273
+
274
+ ### Phase 4: Evidence, review annotations, and host capabilities
275
+
276
+ - [ ] Add timeline evidence-item persistence and retention.
277
+ - [ ] Add review-annotation state or map the AX shape onto existing annotations
278
+ where possible.
279
+ - [ ] Add host-capability reporting across HTTP/SDK/MCP/CLI.
280
+ - [ ] Record Copilot tool/session evidence where low-risk and useful.
281
+
282
+ ### Phase 5: Docs, template install, and verification
283
+
284
+ - [ ] Add `pmx-canvas copilot install-extension` or equivalent scaffold command.
285
+ - [ ] Ensure the extension template is included in published package contents.
286
+ - [ ] Update docs and the pmx-canvas skill to describe AX primitives and the
287
+ Copilot adapter.
288
+ - [ ] Add parity/static tests for state persistence, HTTP, SDK, MCP, CLI,
289
+ adapter scaffold behavior, and no Copilot imports in core.
290
+ - [ ] Run the repo-standard verification ladder after implementation.
291
+
292
+ ## Success Criteria
293
+
294
+ - PMX Canvas core can represent and persist AX primitives without any GitHub
295
+ Copilot dependency.
296
+ - Existing PMX Canvas behavior remains backward-compatible: current HTTP, MCP,
297
+ CLI, SDK, browser, snapshots, and pinned-context flows keep working.
298
+ - HTTP, SDK, MCP, and CLI expose the same AX primitives consistently.
299
+ - The GitHub Copilot app can open PMX Canvas natively through a project canvas
300
+ extension and render the existing workbench.
301
+ - The Copilot adapter can:
302
+ - inject PMX AX/pinned context on prompt submission
303
+ - proxy core canvas/AX actions
304
+ - update pins/basic canvas state
305
+ - send steering instructions to the agent session
306
+ - record useful Copilot session/tool events as AX events/evidence
307
+ - Canvas-bound AX state is included in snapshots; timeline AX state persists in
308
+ the PMX DB but is not restored by snapshots.
309
+ - Codex is not implemented, but no core type or persistence decision prevents a
310
+ later Codex adapter.
311
+
312
+ ## Risk Assessment
313
+
314
+ | Risk | Impact | Mitigation |
315
+ |---|---|---|
316
+ | AX model becomes Copilot-shaped instead of PMX-shaped. | Future Codex/MCP/HTTP reuse becomes expensive. | Keep all Copilot imports and names out of core; use neutral PMX primitives and adapter mapping only. |
317
+ | Persistence changes break existing `.pmx-canvas/canvas.db` files. | Existing users lose or corrupt canvas state. | Add new tables/rows with `CREATE TABLE IF NOT EXISTS`; keep current tables and existing payload shapes stable. |
318
+ | Duplicating pinned-context logic creates drift. | Different agents receive different context. | Reuse `agent-context.ts` and existing pinned-context summaries for AX context export. |
319
+ | Copilot adapter tries to reimplement the workbench UI. | Large fragile UI duplicate. | Embed the existing `/workbench` URL and use adapter code only for SDK hooks/actions/session events. |
320
+ | Extension process cannot run Bun/PMX server in some environments. | Copilot canvas opens without a backend. | Prefer discovering an existing PMX server; add explicit startup diagnostics and clear error states. Use loopback URLs only. |
321
+ | `session.send()` from hooks causes loops. | Adapter can recursively prompt the agent. | Do not call `session.send()` synchronously from prompt hooks; steering actions should be user/action initiated. |
322
+ | MCP/CLI/SDK parity drifts. | Agents see different capabilities by host. | Follow the existing repo rule: new operation lands in state manager, SDK, HTTP, MCP, and CLI together. |
323
+ | SQLite schema changes assume migrations that do not exist. | Older DBs fail to load. | Use additive tables/columns only unless a real migration path is added; do not bump schema version without a tested migrator. |
324
+ | AX timeline grows without bounds. | DB size and context export become noisy. | Add a retention/query limit policy for timeline primitives; context export should include bounded summaries only. |
325
+
326
+ ## Test Strategy
327
+
328
+ ### Unit tests
329
+
330
+ - `tests/unit/canvas-state.test.ts`
331
+ - AX state persists and reloads
332
+ - AX state is included in snapshots and restored
333
+ - clearing canvas handles AX state according to the chosen semantics
334
+ - `tests/unit/server-api.test.ts`
335
+ - HTTP AX endpoints return stable JSON
336
+ - AX context reuses pinned node summaries
337
+ - SSE emits AX events when AX state changes
338
+ - `tests/unit/pmx-canvas-sdk.test.ts`
339
+ - `PmxCanvas` exposes AX methods and mutates core state correctly
340
+ - `tests/unit/mcp-server.test.ts`
341
+ - MCP lists AX resources/tools
342
+ - MCP tools can read/update AX state
343
+ - resource notifications include AX changes
344
+ - `tests/unit/cli-node.test.ts` or a new CLI test file
345
+ - `pmx-canvas ax ...` commands return JSON and fail loudly on invalid input
346
+ - `pmx-canvas copilot install-extension --dry-run` previews the target path
347
+ - Static/parity tests
348
+ - no core/server/shared files import `@github/copilot-sdk`
349
+ - every committed AX operation has SDK, HTTP, MCP, and CLI coverage or an
350
+ explicit documented exception
351
+ - the Copilot extension template is included in the package file list
352
+
353
+ ### Adapter tests
354
+
355
+ - Add a focused test around the generated Copilot extension file/template:
356
+ - extension file exists at `.github/extensions/pmx-canvas/extension.mjs`
357
+ - it imports only `@github/copilot-sdk/extension` and Node built-ins
358
+ - it contains no `console.log`
359
+ - declared canvas/actions avoid reserved `canvas.*` action names
360
+ - server discovery failures produce visible adapter diagnostics
361
+
362
+ Full runtime Copilot SDK execution may not be practical in normal Bun tests, so
363
+ the minimum automated test should verify the scaffold/template and the PMX HTTP
364
+ contract it relies on.
365
+
366
+ ### Integration/e2e
367
+
368
+ - Existing web canvas Playwright test after client changes.
369
+ - HTTP smoke:
370
+ - start PMX server
371
+ - add nodes
372
+ - pin nodes
373
+ - read `/api/canvas/ax/context`
374
+ - invoke an AX event/evidence/approval mutation
375
+ - Snapshot smoke:
376
+ - create canvas-bound AX state
377
+ - save snapshot
378
+ - mutate AX state
379
+ - restore snapshot
380
+ - confirm canvas-bound AX state restored and timeline state remains bounded
381
+ - MCP smoke:
382
+ - start MCP server
383
+ - list AX resources/tools
384
+ - read AX context
385
+
386
+ ## Validation and Diagnostics
387
+
388
+ - Build/typecheck must catch shared type drift:
389
+ - `bun run typecheck`
390
+ - `bun run build`
391
+ - Unit tests should cover the changed surfaces:
392
+ - `bun test tests/unit/canvas-state.test.ts tests/unit/server-api.test.ts tests/unit/pmx-canvas-sdk.test.ts tests/unit/mcp-server.test.ts tests/unit/cli-node.test.ts`
393
+ - If client code changes, run the canvas bundle build and browser tests per repo
394
+ guidance.
395
+ - For manual Copilot adapter validation:
396
+ - reload extensions
397
+ - verify `pmx-canvas` appears in canvas capabilities
398
+ - open the Copilot canvas
399
+ - confirm the PMX workbench loads
400
+ - pin a node and confirm the next prompt receives AX context
401
+ - invoke a basic adapter action and confirm PMX state changes
402
+
403
+ Diagnostics expectations:
404
+
405
+ - Extension failures should be visible through `extensions_manage inspect`.
406
+ - Adapter should use `session.log()` for user-visible errors.
407
+ - HTTP/CLI/MCP failures should include actionable errors, not silent no-ops.
408
+
409
+ ## Knowledge Map
410
+
411
+ | Step | Knowledge Source | Confidence |
412
+ |---|---|---|
413
+ | Define neutral AX primitives | Prompt/context from interview plus existing PMX pinned-context architecture | High |
414
+ | Persist AX state in core | Codebase: `canvas-state.ts`, `canvas-db.ts`, tests/helpers persistence patterns | High |
415
+ | Expose HTTP/SDK/MCP/CLI surfaces | Codebase: existing 1:1 operation pattern in `server.ts`, `index.ts`, `mcp/server.ts`, `cli/agent.ts` | High |
416
+ | Build Copilot canvas adapter | Reachable SDK docs: `create-canvas` skill, `extensions.md`, `agent-author.md`, `canvas.d.ts`, `session.d.ts`; verify again in Phase 0 | High |
417
+ | Inject context in Copilot | Reachable SDK docs: `onUserPromptSubmitted` and `additionalContext` | High |
418
+ | Programmatic steering in Copilot | Reachable SDK docs: `session.send()` / `sendAndWait()` and gotchas | High |
419
+ | Runtime validation inside actual GitHub Copilot app | Host tooling available through extension management and canvas tools; runtime still requires manual inspection | Medium |
420
+ | Codex adapter | Out of scope; future host-specific docs needed | Not planned |
421
+
422
+ ## Open Questions
423
+
424
+ - [ ] Should `canvas_clear` remove timeline AX events/evidence, or only
425
+ canvas-bound AX state? This can proceed with the conservative default:
426
+ clear canvas-bound state and keep timeline history subject to retention.
427
+ - [ ] Should `approval-gate` integrate deeply with Copilot permission hooks in
428
+ this first pass or only expose PMX approvals through adapter UI/actions?
429
+ This can proceed by implementing PMX approvals first and mapping
430
+ permission hooks only where low-risk.
431
+
432
+ ## Rejected Alternatives
433
+
434
+ ### Put Copilot SDK concepts directly in PMX core
435
+
436
+ Rejected because PMX Canvas must remain usable by any agent. Core should expose
437
+ neutral AX concepts; Copilot translates them to SDK hooks, canvases, tools, and
438
+ session events.
439
+
440
+ ### Store AX in `.pmx-canvas/ax.json`
441
+
442
+ Rejected by interview decision. AX should persist with existing PMX Canvas state
443
+ in SQLite and snapshots, so project state remains coherent.
444
+
445
+ ### Rebuild the PMX workbench UI inside the Copilot extension
446
+
447
+ Rejected because the existing PMX browser app already implements full canvas
448
+ functionality. The adapter should embed and bridge it rather than fork the UI.
449
+
450
+ ## Refinement Notes
451
+
452
+ ### Draft pass
453
+
454
+ Initial plan aligns the broad implementation with existing repo rules: state is
455
+ server-authoritative, MCP tools map to SDK/HTTP/state operations, and the
456
+ Copilot adapter is isolated from core.
457
+
458
+ ### Fresh-eyes pass 1
459
+
460
+ Refined the plan from a breadth-first implementation into phased vertical
461
+ slices, split canvas-bound AX state from timeline AX state, made server
462
+ discovery and template packaging explicit, added static/parity tests, and
463
+ resolved the snapshot-vs-timeline contradiction before implementation.
Binary file
package/docs/sdk.md CHANGED
@@ -83,6 +83,11 @@ await canvas.runBatch([
83
83
  canvas.arrange('grid');
84
84
  console.log(canvas.validate());
85
85
  console.log(canvas.getLayout());
86
+
87
+ // AX context for host adapters
88
+ canvas.setAxFocus({ nodeIds: [n1], source: 'sdk' });
89
+ console.log(canvas.getAxState());
90
+ console.log(canvas.getAxContext());
86
91
  ```
87
92
 
88
93
  ## WebView automation
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pmx-canvas",
3
- "version": "0.1.22",
3
+ "version": "0.1.24",
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",
@@ -19,6 +19,7 @@
19
19
  "src/",
20
20
  "skills/",
21
21
  "docs/",
22
+ ".github/extensions/pmx-canvas/",
22
23
  "dist/canvas/",
23
24
  "dist/json-render/",
24
25
  "dist/types/",
@@ -106,6 +107,6 @@
106
107
  },
107
108
  "homepage": "https://github.com/pskoett/pmx-canvas#readme",
108
109
  "engines": {
109
- "bun": ">=1.3.12"
110
+ "bun": ">=1.3.14"
110
111
  }
111
112
  }
@@ -65,6 +65,16 @@ If this skill is installed before the `pmx-canvas` command exists, install the p
65
65
  `references/installing-pmx-canvas.md` for local development, npm/global install, and MCP config
66
66
  options.
67
67
 
68
+ ## Adapter References
69
+
70
+ PMX Canvas core is host-agnostic. When a host-specific adapter is available, read the matching
71
+ reference before using adapter-native features:
72
+
73
+ - `references/github-copilot-app-adapter.md` — GitHub Copilot app project extension, native canvas
74
+ panel, AX context injection, and live-test checklist.
75
+ - `references/codex-app-adapter.md` — Codex app native Browser + MCP adapter, AX context reading,
76
+ focus labeling, and live-test checklist.
77
+
68
78
  The canvas auto-starts on first MCP tool call when running in MCP mode (`pmx-canvas --mcp`).
69
79
  For manual start:
70
80
 
@@ -156,6 +166,8 @@ pmx-canvas web-artifact build --title "Dashboard" --app-file ./App.tsx --deps re
156
166
  pmx-canvas node list --type web-artifact --summary
157
167
  pmx-canvas node list --type external-app --summary
158
168
  pmx-canvas pin --list
169
+ pmx-canvas ax context
170
+ pmx-canvas ax focus <node-id>
159
171
  pmx-canvas snapshot save --name "before-refactor"
160
172
  pmx-canvas code-graph
161
173
  pmx-canvas spatial
@@ -175,6 +187,8 @@ pmx-canvas spatial
175
187
  `"DVT O3"` can be ambiguous; prefer the full visible title such as `"DVT O3 — GitOps"`.
176
188
  - `search`, `layout`, `status`, `arrange`, `focus` — inspect and navigate the canvas. Prefer
177
189
  `focus --no-pan` when you only need to select/raise a node without hijacking the human's camera.
190
+ - `ax status|context|focus` — inspect the host-agnostic AX layer; `ax context`
191
+ combines pinned context and AX focus for adapter prompt injection.
178
192
  - `fit [id ...]` — set the server viewport to fit the whole canvas or selected nodes before screenshots or whole-board review
179
193
  - `screenshot --output <path>` — top-level shortcut for `webview screenshot`; supports `--format png|jpeg|webp` and `--quality`
180
194
  - `json-render --schema|--examples` — inspect the json-render component catalog with `--component`/`--field` filters; same data as `node schema --type json-render` in a more direct shape
@@ -960,12 +974,16 @@ When the human wants to explore a different approach without losing current work
960
974
 
961
975
  ## Persistence
962
976
 
963
- Canvas state auto-saves to `.pmx-canvas/state.json` on every mutation (debounced 500ms). State
964
- loads automatically on server start. The file is git-committable — spatial knowledge
977
+ Canvas state auto-saves to `.pmx-canvas/canvas.db` on every mutation (debounced 500ms). State
978
+ loads automatically on server start. The SQLite DB is git-committable — spatial knowledge
965
979
  persists across sessions.
966
980
 
967
- Snapshots save to `.pmx-canvas/snapshots/`. Web artifacts land in `.pmx-canvas/artifacts/`.
968
- Legacy `.pmx-canvas.json` and `.pmx-canvas-snapshots/` are auto-migrated on first boot.
981
+ Snapshots, context pins, and large node blobs are stored in the same DB. Web artifacts land in
982
+ `.pmx-canvas/artifacts/`. Legacy JSON state, snapshot, and blob files are auto-imported into
983
+ SQLite and renamed to `.bak` on first boot.
984
+
985
+ Stop the server or flush/close the SDK before committing `canvas.db`; shutdown checkpoints SQLite
986
+ WAL data into the DB file.
969
987
 
970
988
  ## Real-Time Collaboration
971
989
 
@@ -0,0 +1,107 @@
1
+ # Codex App Adapter
2
+
3
+ Use this reference when PMX Canvas is running natively in the Codex app. The adapter is intentionally
4
+ thin: PMX Canvas remains the state owner, Codex uses MCP for agent operations/context, and the Codex
5
+ in-app Browser renders the live PMX workbench.
6
+
7
+ ## Adapter Identity
8
+
9
+ - Host: Codex app
10
+ - Visual surface: Codex in-app Browser opened to the PMX `/workbench` URL
11
+ - Agent surface: PMX Canvas MCP server (`pmx-canvas --mcp`)
12
+ - Fallback surface: PMX Canvas CLI for manual scripts when MCP is unavailable
13
+ - AX source label: `codex`
14
+
15
+ This is not a separate PMX renderer and does not require a Codex extension API. Codex already has
16
+ the two native surfaces PMX needs: MCP resources/tools for the agent, and the in-app Browser for the
17
+ human-visible canvas. Prefer MCP over the CLI for Codex-native use because MCP exposes structured
18
+ tools, resources, and `canvas://ax-context`; use the CLI only as a fallback or for shell scripts.
19
+
20
+ ## What The Adapter Does
21
+
22
+ - Opens the live PMX workbench in the Codex in-app Browser.
23
+ - Uses MCP tools/resources for all agent-side operations.
24
+ - Reads `canvas://ax-context` or `canvas_get_ax` for pinned and focused context.
25
+ - Sets AX focus through `canvas_set_ax_focus` with `source: "codex"` when the focus change comes
26
+ from Codex-hosted steering.
27
+ - Keeps all persistent PMX state in `.pmx-canvas/canvas.db`; Codex does not own canvas state.
28
+
29
+ ## Setup
30
+
31
+ Use MCP as the primary Codex adapter path.
32
+
33
+ Add the PMX MCP server to the Codex workspace config:
34
+
35
+ ```json
36
+ {
37
+ "mcpServers": {
38
+ "canvas": {
39
+ "command": "bunx",
40
+ "args": ["pmx-canvas", "--mcp"]
41
+ }
42
+ }
43
+ }
44
+ ```
45
+
46
+ For local repo development, use the source entrypoint instead:
47
+
48
+ ```json
49
+ {
50
+ "mcpServers": {
51
+ "canvas": {
52
+ "command": "bun",
53
+ "args": ["run", "src/mcp/server.ts"]
54
+ }
55
+ }
56
+ }
57
+ ```
58
+
59
+ The MCP server auto-starts the HTTP workbench on first tool call. Open the returned workbench URL
60
+ in the Codex in-app Browser, usually `http://127.0.0.1:4313/workbench` or
61
+ `http://localhost:4313/workbench`.
62
+
63
+ ## Codex-Native Workflow
64
+
65
+ 1. Start or connect to the PMX MCP server.
66
+ 2. Open `/workbench` in the Codex in-app Browser.
67
+ 3. Use the browser canvas for human spatial curation: pin nodes, move nodes, group nodes, and
68
+ inspect rendered artifacts.
69
+ 4. Use MCP tools for agent operations: create/update nodes, pin nodes, read layout, and read AX
70
+ context.
71
+ 5. When Codex wants to mark the current attention target, call:
72
+
73
+ ```json
74
+ {
75
+ "nodeIds": ["node-123"],
76
+ "source": "codex"
77
+ }
78
+ ```
79
+
80
+ against `canvas_set_ax_focus`.
81
+
82
+ ## Context Contract
83
+
84
+ Codex agents should treat PMX AX context as host-native working context:
85
+
86
+ - `canvas://pinned-context` is the explicit human-curated node set.
87
+ - `canvas://ax-context` combines pins, focus, and surface metadata.
88
+ - `canvas_get_ax` returns both persisted AX state and agent-ready context.
89
+ - Focus is a current attention target, not a command to ignore the rest of the repository.
90
+
91
+ ## Live-Test Checklist
92
+
93
+ 1. Confirm the PMX MCP server is configured for the workspace.
94
+ 2. Call `canvas_get_ax` and confirm it returns `ok: true`.
95
+ 3. Open `http://127.0.0.1:4313/workbench` in the Codex in-app Browser.
96
+ 4. Add or reuse a node, then pin it from the browser or with `canvas_pin_nodes`.
97
+ 5. Read `canvas://ax-context` and confirm the pinned node appears.
98
+ 6. Call `canvas_set_ax_focus` with `source: "codex"` and a real node ID.
99
+ 7. Read `canvas_get_ax` again and confirm `state.focus.source` is `codex`.
100
+ 8. Refresh the browser and confirm the workbench still shows the same state.
101
+
102
+ ## Adapter Boundary
103
+
104
+ Do not add Codex-specific APIs to PMX Canvas core. Core owns neutral AX primitives; Codex maps them
105
+ through MCP and the in-app Browser. If Codex later exposes a dedicated extension or prompt-injection
106
+ hook, implement that as a separate adapter layer that reads the same `/api/canvas/ax/context` or
107
+ `canvas://ax-context` contract.