pmx-canvas 0.8.2 → 0.9.1

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 (338) hide show
  1. package/.github/extensions/pmx-canvas/runtime.json +1 -1
  2. package/.github/extensions/pmx-canvas/tools.json +601 -22
  3. package/CHANGELOG.md +59 -0
  4. package/Readme.md +131 -532
  5. package/dist/canvas/global.css +2724 -476
  6. package/dist/canvas/index.js +168 -107
  7. package/dist/canvas/mcp-app.html +2899 -596
  8. package/dist/json-render/index.js +20 -20
  9. package/dist/types/client/canvas/BarHint.d.ts +12 -2
  10. package/dist/types/client/canvas/BoardLinkDialog.d.ts +3 -1
  11. package/dist/types/client/canvas/BoardPinButton.d.ts +10 -0
  12. package/dist/types/client/canvas/BoardSwitcher.d.ts +1 -1
  13. package/dist/types/client/canvas/CanvasViewport.d.ts +1 -1
  14. package/dist/types/client/canvas/CommandBar.d.ts +3 -4
  15. package/dist/types/client/canvas/ConnectionBanner.d.ts +2 -1
  16. package/dist/types/client/canvas/ContextChip.d.ts +3 -0
  17. package/dist/types/client/canvas/CrossBoardReferences.d.ts +5 -0
  18. package/dist/types/client/canvas/EdgeLayer.d.ts +14 -3
  19. package/dist/types/client/canvas/EmptyState.d.ts +4 -4
  20. package/dist/types/client/canvas/HomeGraphView.d.ts +2 -0
  21. package/dist/types/client/canvas/HomeMapView.d.ts +1 -0
  22. package/dist/types/client/canvas/HomeReviewView.d.ts +6 -0
  23. package/dist/types/client/canvas/HomeView.d.ts +9 -7
  24. package/dist/types/client/canvas/KnowledgeDialog.d.ts +4 -0
  25. package/dist/types/client/canvas/LifecycleChrome.d.ts +5 -0
  26. package/dist/types/client/canvas/LifecycleFields.d.ts +7 -0
  27. package/dist/types/client/canvas/LifecyclePanel.d.ts +1 -0
  28. package/dist/types/client/canvas/MemoryInspector.d.ts +7 -0
  29. package/dist/types/client/canvas/NearPinLayer.d.ts +14 -0
  30. package/dist/types/client/canvas/NodeContextMark.d.ts +40 -7
  31. package/dist/types/client/canvas/RelationPresetsDialog.d.ts +4 -0
  32. package/dist/types/client/canvas/RelationsPanel.d.ts +4 -0
  33. package/dist/types/client/canvas/SessionPanel.d.ts +2 -0
  34. package/dist/types/client/canvas/canvas-area.d.ts +1 -1
  35. package/dist/types/client/canvas/graph-geometry.d.ts +27 -0
  36. package/dist/types/client/canvas/graph-model.d.ts +37 -0
  37. package/dist/types/client/canvas/memory-layout.d.ts +23 -0
  38. package/dist/types/client/canvas/use-chrome-height.d.ts +2 -0
  39. package/dist/types/client/canvas/use-focus-trap.d.ts +1 -0
  40. package/dist/types/client/canvas/use-memory-graph.d.ts +8 -0
  41. package/dist/types/client/canvas/use-pan-zoom.d.ts +4 -1
  42. package/dist/types/client/icons.d.ts +0 -10
  43. package/dist/types/client/nodes/AxStepControls.d.ts +1 -1
  44. package/dist/types/client/nodes/InlineMarkdownEditor.d.ts +4 -4
  45. package/dist/types/client/nodes/MarkdownNode.d.ts +5 -1
  46. package/dist/types/client/nodes/McpAppNode.d.ts +4 -4
  47. package/dist/types/client/nodes/viewer-runtime-state.d.ts +1 -1
  48. package/dist/types/client/state/boards-store.d.ts +81 -9
  49. package/dist/types/client/state/canvas-store.d.ts +14 -1
  50. package/dist/types/client/state/context-chip-store.d.ts +22 -0
  51. package/dist/types/client/state/context-status-store.d.ts +35 -0
  52. package/dist/types/client/state/human-store.d.ts +2 -1
  53. package/dist/types/client/state/intent-bridge.d.ts +11 -8
  54. package/dist/types/client/state/knowledge-store.d.ts +22 -0
  55. package/dist/types/client/state/near-pin-store.d.ts +44 -1
  56. package/dist/types/client/state/presence-store.d.ts +4 -4
  57. package/dist/types/client/state/presentation.d.ts +28 -0
  58. package/dist/types/client/state/relation-store.d.ts +10 -0
  59. package/dist/types/client/state/session-store.d.ts +41 -2
  60. package/dist/types/client/state/workspace-settings.d.ts +7 -0
  61. package/dist/types/client/types.d.ts +13 -1
  62. package/dist/types/client/utils/keyboard.d.ts +2 -0
  63. package/dist/types/client/utils/time-ago.d.ts +4 -0
  64. package/dist/types/mcp/context-uri-template.d.ts +3 -1
  65. package/dist/types/server/agent-presence.d.ts +10 -3
  66. package/dist/types/server/ax-context.d.ts +1 -1
  67. package/dist/types/server/canvas-db.d.ts +30 -7
  68. package/dist/types/server/canvas-operations.d.ts +24 -2
  69. package/dist/types/server/canvas-provenance.d.ts +22 -2
  70. package/dist/types/server/canvas-serialization.d.ts +2 -0
  71. package/dist/types/server/canvas-state.d.ts +93 -15
  72. package/dist/types/server/canvas-validation.d.ts +1 -1
  73. package/dist/types/server/context-brief.d.ts +94 -6
  74. package/dist/types/server/context-reads.d.ts +33 -7
  75. package/dist/types/server/edit-summary.d.ts +20 -0
  76. package/dist/types/server/index.d.ts +71 -10
  77. package/dist/types/server/knowledge-lifecycle.d.ts +221 -0
  78. package/dist/types/server/lifecycle-status.d.ts +10 -0
  79. package/dist/types/server/memory-graph.d.ts +9 -0
  80. package/dist/types/server/mutation-history.d.ts +2 -0
  81. package/dist/types/server/operations/ops/ax-shared.d.ts +1 -1
  82. package/dist/types/server/operations/ops/boards.d.ts +2 -1
  83. package/dist/types/server/operations/ops/lifecycle.d.ts +2 -0
  84. package/dist/types/server/operations/ops/memory-graph.d.ts +2 -0
  85. package/dist/types/server/operations/ops/nodes.d.ts +5 -0
  86. package/dist/types/server/operations/ops/query.d.ts +23 -0
  87. package/dist/types/server/operations/registry.d.ts +1 -0
  88. package/dist/types/server/placement.d.ts +7 -0
  89. package/dist/types/server/scope-fence.d.ts +2 -1
  90. package/dist/types/server/spatial-analysis.d.ts +6 -3
  91. package/dist/types/server/tour-control.d.ts +32 -0
  92. package/dist/types/server/wiki-links.d.ts +14 -0
  93. package/dist/types/server/workbench-auth.d.ts +2 -0
  94. package/dist/types/shared/agent-context.d.ts +2 -0
  95. package/dist/types/shared/agent-presence.d.ts +15 -12
  96. package/dist/types/shared/auto-arrange.d.ts +1 -0
  97. package/dist/types/shared/boards.d.ts +4 -4
  98. package/dist/types/shared/knowledge-lifecycle.d.ts +41 -0
  99. package/dist/types/shared/knowledge-presets.d.ts +6 -0
  100. package/dist/types/shared/lifecycle-status.d.ts +24 -0
  101. package/dist/types/shared/memory-graph.d.ts +53 -0
  102. package/dist/types/shared/relations.d.ts +68 -0
  103. package/dist/types/shared/semantic-attention.d.ts +2 -0
  104. package/dist/types/shared/tour.d.ts +38 -0
  105. package/dist/types/shared/workspace-settings.d.ts +11 -0
  106. package/docs/RELEASE.md +21 -3
  107. package/docs/adr-001-bun-only-runtime.md +7 -1
  108. package/docs/adr-002-shared-product-separate-runtimes.md +93 -0
  109. package/docs/api-reference.md +109 -0
  110. package/docs/ax-host-adapter-contract.md +1 -1
  111. package/docs/ax-state-contract.md +5 -4
  112. package/docs/cli.md +153 -15
  113. package/docs/demos/pmx-canvas-demo.mp4 +0 -0
  114. package/docs/design/AgentContext.dc.html +3 -3
  115. package/docs/design/BoardPins.dc.html +37 -22
  116. package/docs/design/Categories.dc.html +208 -0
  117. package/docs/design/CategoryEditor.dc.html +33 -0
  118. package/docs/design/Chrome.dc.html +52 -9
  119. package/docs/design/ContextChip.dc.html +224 -0
  120. package/docs/design/ContextChip600.dc.html +136 -0
  121. package/docs/design/EmptyState.dc.html +45 -0
  122. package/docs/design/Flows.dc.html +23 -1
  123. package/docs/design/HeaderMarks.dc.html +183 -0
  124. package/docs/design/Home.dc.html +19 -1
  125. package/docs/design/HomeGraph.dc.html +86 -202
  126. package/docs/design/HomeMap.dc.html +23 -1
  127. package/docs/design/HomeTeam.dc.html +32 -14
  128. package/docs/design/Lifecycle.dc.html +22 -0
  129. package/docs/design/Lifecycle600.dc.html +18 -0
  130. package/docs/design/LifecycleVariants.dc.html +157 -0
  131. package/docs/design/LinkAuthorship.dc.html +139 -0
  132. package/docs/design/LinksChanged.dc.html +203 -0
  133. package/docs/design/LinksOptions.dc.html +137 -0
  134. package/docs/design/LinksOptions600.dc.html +134 -0
  135. package/docs/design/NearPin.dc.html +9 -10
  136. package/docs/design/Pane600.dc.html +4 -3
  137. package/docs/design/Relations.dc.html +3 -2
  138. package/docs/design/Restore.dc.html +152 -0
  139. package/docs/design/SeeChange.dc.html +267 -0
  140. package/docs/design/Uses.dc.html +12 -6
  141. package/docs/design/canvas.json +146 -19
  142. package/docs/design.md +449 -16
  143. package/docs/environment.md +0 -1
  144. package/docs/evals/curation-effect.md +128 -0
  145. package/docs/http-api.md +459 -37
  146. package/docs/mcp.md +146 -18
  147. package/docs/node-types.md +58 -3
  148. package/docs/plans/design-gaps-2026-10-08.md +53 -0
  149. package/docs/plans/plan-009-tech-debt-backlog.md +379 -0
  150. package/docs/plans/plan-016-context-made-visible-wave-1.md +150 -5
  151. package/docs/plans/plan-017-knowledge-categories-and-lifecycle.md +175 -0
  152. package/docs/plans/plan-018-connected-memory-wave-2.md +594 -0
  153. package/docs/plans/plan-019-post-0.9-roadmap.md +198 -0
  154. package/docs/product-context-vision-2026-09.md +17 -1
  155. package/docs/product-vision-2026-09.md +1082 -43
  156. package/docs/product-vision-review-2026-09.md +13 -1
  157. package/docs/screenshots/workbench-live-dark.png +0 -0
  158. package/docs/screenshots/workbench-live-light.png +0 -0
  159. package/docs/sdk.md +62 -2
  160. package/package.json +1 -1
  161. package/plugins/pmx-canvas/com.github.copilot/extensions/pmx-canvas/runtime.json +1 -1
  162. package/plugins/pmx-canvas/plugin.json +1 -1
  163. package/plugins/pmx-canvas/runtime.json +1 -1
  164. package/plugins/pmx-canvas/tools.json +601 -22
  165. package/skills/pmx-canvas/SKILL.md +216 -42
  166. package/skills/pmx-canvas/evals/evals.json +224 -0
  167. package/skills/pmx-canvas/references/full-reference.md +120 -21
  168. package/skills/pmx-canvas/references/github-copilot-app-adapter.md +2 -2
  169. package/skills/pmx-canvas/references/importing-context.md +132 -0
  170. package/skills/pmx-canvas/references/installing-pmx-canvas.md +6 -6
  171. package/skills/pmx-canvas/references/tours-and-recording.md +16 -1
  172. package/skills/pmx-canvas-testing/SKILL.md +20 -0
  173. package/src/cli/agent.ts +2 -0
  174. package/src/cli/commands/ax.ts +12 -0
  175. package/src/cli/commands/boards.ts +88 -11
  176. package/src/cli/commands/edges.ts +28 -0
  177. package/src/cli/commands/groups.ts +7 -0
  178. package/src/cli/commands/nodes.ts +1 -0
  179. package/src/cli/commands/query.ts +34 -2
  180. package/src/cli/commands/record.ts +199 -48
  181. package/src/cli/index.ts +6 -1
  182. package/src/client/App.tsx +177 -70
  183. package/src/client/canvas/AttentionHistory.tsx +0 -2
  184. package/src/client/canvas/BarHint.tsx +40 -2
  185. package/src/client/canvas/BoardCopyDialog.tsx +1 -1
  186. package/src/client/canvas/BoardFolderDialog.tsx +7 -7
  187. package/src/client/canvas/BoardLinkDialog.tsx +138 -33
  188. package/src/client/canvas/BoardPinButton.tsx +33 -0
  189. package/src/client/canvas/BoardSwitcher.tsx +26 -40
  190. package/src/client/canvas/CanvasNode.tsx +360 -237
  191. package/src/client/canvas/CanvasViewport.tsx +45 -7
  192. package/src/client/canvas/CommandBar.tsx +29 -23
  193. package/src/client/canvas/CommandPalette.tsx +5 -12
  194. package/src/client/canvas/ConnectionBanner.tsx +3 -3
  195. package/src/client/canvas/ContextChip.tsx +296 -0
  196. package/src/client/canvas/ContextMenu.tsx +63 -5
  197. package/src/client/canvas/CrossBoardReferences.tsx +60 -0
  198. package/src/client/canvas/EdgeLayer.tsx +339 -76
  199. package/src/client/canvas/EmptyState.tsx +33 -18
  200. package/src/client/canvas/ExpandedNodeOverlay.tsx +72 -40
  201. package/src/client/canvas/ExternalWriters.tsx +57 -42
  202. package/src/client/canvas/HomeGraphView.tsx +942 -0
  203. package/src/client/canvas/HomeMapView.tsx +641 -0
  204. package/src/client/canvas/HomeReviewView.tsx +167 -0
  205. package/src/client/canvas/HomeView.tsx +687 -160
  206. package/src/client/canvas/IntentLayer.tsx +19 -12
  207. package/src/client/canvas/KnowledgeDialog.tsx +488 -0
  208. package/src/client/canvas/LifecycleChrome.tsx +133 -0
  209. package/src/client/canvas/LifecycleFields.tsx +91 -0
  210. package/src/client/canvas/LifecyclePanel.tsx +543 -0
  211. package/src/client/canvas/MemoryInspector.tsx +104 -0
  212. package/src/client/canvas/Minimap.tsx +3 -3
  213. package/src/client/canvas/NearPinLayer.tsx +187 -0
  214. package/src/client/canvas/NodeContextMark.tsx +175 -97
  215. package/src/client/canvas/Presentation.tsx +23 -57
  216. package/src/client/canvas/RelationPresetsDialog.tsx +413 -0
  217. package/src/client/canvas/RelationsPanel.tsx +82 -0
  218. package/src/client/canvas/SelectionBar.tsx +3 -6
  219. package/src/client/canvas/SessionPanel.tsx +90 -50
  220. package/src/client/canvas/SessionReceipt.tsx +311 -39
  221. package/src/client/canvas/ShortcutOverlay.tsx +1 -1
  222. package/src/client/canvas/SnapshotPanel.tsx +27 -36
  223. package/src/client/canvas/ToolRail.tsx +367 -192
  224. package/src/client/canvas/TopBar.tsx +354 -124
  225. package/src/client/canvas/canvas-area.ts +10 -3
  226. package/src/client/canvas/graph-geometry.ts +195 -0
  227. package/src/client/canvas/graph-model.ts +254 -0
  228. package/src/client/canvas/memory-layout.ts +106 -0
  229. package/src/client/canvas/use-chrome-height.ts +20 -0
  230. package/src/client/canvas/use-focus-trap.ts +31 -5
  231. package/src/client/canvas/use-memory-graph.ts +58 -0
  232. package/src/client/canvas/use-node-drag.ts +2 -1
  233. package/src/client/canvas/use-pan-zoom.ts +64 -7
  234. package/src/client/icons.tsx +0 -63
  235. package/src/client/mcp-app/style.css +0 -6
  236. package/src/client/nodes/AxStepControls.tsx +74 -50
  237. package/src/client/nodes/BoardNode.tsx +5 -1
  238. package/src/client/nodes/ContextNode.tsx +18 -11
  239. package/src/client/nodes/ExtAppFrame.tsx +6 -3
  240. package/src/client/nodes/FileNode.tsx +46 -42
  241. package/src/client/nodes/HtmlNode.tsx +32 -0
  242. package/src/client/nodes/ImageNode.tsx +1 -1
  243. package/src/client/nodes/InlineFormatBar.tsx +6 -9
  244. package/src/client/nodes/InlineMarkdownEditor.tsx +56 -17
  245. package/src/client/nodes/MarkdownNode.tsx +377 -109
  246. package/src/client/nodes/McpAppNode.tsx +50 -20
  247. package/src/client/nodes/MdFormatBar.tsx +21 -18
  248. package/src/client/nodes/PromptNode.tsx +1 -1
  249. package/src/client/nodes/ResponseNode.tsx +1 -1
  250. package/src/client/nodes/viewer-runtime-state.ts +54 -22
  251. package/src/client/state/attention-bridge.ts +64 -15
  252. package/src/client/state/boards-store.ts +193 -39
  253. package/src/client/state/canvas-store.ts +99 -12
  254. package/src/client/state/context-chip-store.ts +70 -0
  255. package/src/client/state/context-status-store.ts +53 -0
  256. package/src/client/state/human-store.ts +13 -7
  257. package/src/client/state/intent-bridge.ts +51 -30
  258. package/src/client/state/knowledge-store.ts +43 -0
  259. package/src/client/state/near-pin-store.ts +115 -6
  260. package/src/client/state/presence-store.ts +7 -10
  261. package/src/client/state/presentation.ts +91 -0
  262. package/src/client/state/relation-store.ts +81 -0
  263. package/src/client/state/session-store.ts +144 -18
  264. package/src/client/state/sse-bridge.ts +235 -32
  265. package/src/client/state/workspace-settings.ts +11 -0
  266. package/src/client/theme/global.css +2724 -476
  267. package/src/client/types.ts +12 -0
  268. package/src/client/utils/keyboard.ts +10 -0
  269. package/src/client/utils/time-ago.ts +14 -0
  270. package/src/json-render/renderer/index.tsx +31 -0
  271. package/src/mcp/canvas-app.ts +12 -2
  272. package/src/mcp/context-uri-template.ts +7 -4
  273. package/src/mcp/server.ts +63 -41
  274. package/src/mcp/workbench-app.ts +39 -6
  275. package/src/server/agent-presence.ts +128 -28
  276. package/src/server/ax-context.ts +27 -13
  277. package/src/server/board-export.ts +12 -1
  278. package/src/server/canvas-db.ts +331 -42
  279. package/src/server/canvas-operations.ts +195 -83
  280. package/src/server/canvas-provenance.ts +53 -22
  281. package/src/server/canvas-serialization.ts +2 -0
  282. package/src/server/canvas-state.ts +950 -122
  283. package/src/server/canvas-validation.ts +9 -2
  284. package/src/server/context-brief.ts +345 -38
  285. package/src/server/context-reads.ts +178 -30
  286. package/src/server/demo-state.json +355 -24
  287. package/src/server/edit-summary.ts +74 -0
  288. package/src/server/html-surface.ts +8 -1
  289. package/src/server/index.ts +181 -11
  290. package/src/server/knowledge-lifecycle.ts +304 -0
  291. package/src/server/lifecycle-status.ts +232 -0
  292. package/src/server/memory-graph.ts +166 -0
  293. package/src/server/mutation-history.ts +18 -6
  294. package/src/server/operations/composites.ts +32 -11
  295. package/src/server/operations/http.ts +7 -2
  296. package/src/server/operations/index.ts +4 -0
  297. package/src/server/operations/mcp.ts +26 -1
  298. package/src/server/operations/ops/ax-presence.ts +1 -1
  299. package/src/server/operations/ops/ax-read.ts +57 -6
  300. package/src/server/operations/ops/ax-timeline.ts +28 -2
  301. package/src/server/operations/ops/backup.ts +5 -3
  302. package/src/server/operations/ops/batch.ts +35 -4
  303. package/src/server/operations/ops/boards.ts +188 -47
  304. package/src/server/operations/ops/canvas-wire.ts +31 -1
  305. package/src/server/operations/ops/edges.ts +36 -2
  306. package/src/server/operations/ops/groups.ts +6 -1
  307. package/src/server/operations/ops/lifecycle.ts +262 -0
  308. package/src/server/operations/ops/memory-graph.ts +45 -0
  309. package/src/server/operations/ops/nodes.ts +107 -24
  310. package/src/server/operations/ops/query.ts +281 -68
  311. package/src/server/operations/ops/snapshots.ts +73 -1
  312. package/src/server/operations/ops/validate.ts +5 -1
  313. package/src/server/operations/ops/viewport.ts +97 -3
  314. package/src/server/operations/registry.ts +74 -25
  315. package/src/server/placement.ts +29 -0
  316. package/src/server/scope-fence.ts +78 -6
  317. package/src/server/server.ts +115 -16
  318. package/src/server/spatial-analysis.ts +48 -23
  319. package/src/server/tour-control.ts +82 -0
  320. package/src/server/wiki-links.ts +137 -0
  321. package/src/server/workbench-auth.ts +11 -0
  322. package/src/shared/agent-context.ts +3 -0
  323. package/src/shared/agent-presence.ts +15 -15
  324. package/src/shared/auto-arrange.ts +2 -0
  325. package/src/shared/boards.ts +4 -4
  326. package/src/shared/knowledge-lifecycle.ts +22 -0
  327. package/src/shared/knowledge-presets.ts +80 -0
  328. package/src/shared/lifecycle-status.ts +26 -0
  329. package/src/shared/memory-graph.ts +74 -0
  330. package/src/shared/relations.ts +98 -0
  331. package/src/shared/semantic-attention.ts +15 -1
  332. package/src/shared/tour.ts +23 -5
  333. package/src/shared/workspace-settings.ts +13 -0
  334. package/dist/types/client/canvas/ContextPinBar.d.ts +0 -1
  335. package/dist/types/client/canvas/FocusFieldLayer.d.ts +0 -1
  336. package/dist/types/client/canvas/kind-colors.d.ts +0 -3
  337. package/dist/types/server/agent-context.d.ts +0 -22
  338. package/src/client/canvas/ContextPinBar.tsx +0 -25
@@ -0,0 +1,109 @@
1
+ ## Canvas Types
2
+
3
+ **Node types (18):** `markdown`, `status`, `context`, `ledger`, `trace`, `file`, `diff`, `image`, `html`, `mermaid`, `mcp-app`, `webpage`, `json-render`, `graph`, `group`, `board`, plus internal thread node types `prompt` and `response`
4
+
5
+ **Edge types:** `flow`, `depends-on`, `relation`, `references` — all support labels, styles (solid/dashed/dotted), and animation.
6
+
7
+ ## MCP Server
8
+
9
+ 24 tools: 18 action-discriminated composites (`canvas_import`, `canvas_board`, `canvas_node`, `canvas_render`, `canvas_edge`, `canvas_group`, `canvas_history`, `canvas_view`, `canvas_query`, `canvas_webview`, `canvas_app`, `canvas_snapshot`, `canvas_ax_state`, `canvas_ax_work`, `canvas_ax_gate`, `canvas_ax_timeline`, `canvas_ax_delivery`, `canvas_intent`) plus 6 standalone tools (`canvas_batch`, `canvas_pin_nodes`, `canvas_invoke_command`, `canvas_ax_interaction`, `canvas_ingest_activity`, `canvas_screenshot`). `canvas_import` is the agent half of the human-consented attachment workflow: agents list/read requested imports, submit reviewable Markdown, or report unavailable; they cannot request, cancel, or commit. The 57 legacy single-purpose tools the composites replaced were removed in v0.3.0; v0.4.0 shipped the `canvas_snapshot` composite and removed the 6 deprecated snapshot standalones. Prefer composites for new MCP calls; see `docs/mcp.md` for the authoritative tool list and the legacy-to-composite migration reference.
10
+
11
+ ### Agent-assisted document imports
12
+
13
+ PDF and Office drops retain the original (maximum 20 MiB) as a board-owned attachment. Nothing launches an agent automatically: a human explicitly consents and requests extraction, then reviews the returned sections, references, warnings, and `agentDescription` before committing source-linked Markdown. The agent reads controlled bytes through the returned HTTP download path, or inline base64 only at 2 MiB or below; a remote host may require manual byte transfer. Draft submission may happen while another board is active, but commit requires reopening the captured source board. PMX bundles no converter or OCR and makes no guarantee that a host can read every format, scan, chart, or diagram.
14
+
15
+ Originals remain in SQLite until their board is deleted; snapshots/restores do not discard them, and database backups include them. Static export v1 never includes original bytes. Source-linked Markdown is excluded by default and is controlled by `includeDerivedText`, independently of `includeFiles`; editing the Markdown does not remove its source classification.
16
+
17
+ The `diagram` action of `canvas_app` is a thin preset in `src/server/diagram-presets.ts` that proxies to the hosted [Excalidraw MCP app](https://github.com/excalidraw/excalidraw-mcp) (`https://mcp.excalidraw.com/mcp`). For any other MCP Apps server, use `canvas_app` action `open-mcp-app`.
18
+
19
+ 15 static canvas resources: `canvas://boards`, `canvas://pinned-context`, `canvas://schema`, `canvas://layout`, `canvas://summary`, `canvas://spatial-context`, `canvas://history`, `canvas://code-graph`, `canvas://ax`, `canvas://ax-context`, `canvas://ax-timeline`, `canvas://ax-work`, `canvas://ax-pending-steering`, `canvas://ax-delivery`, `canvas://skills`; two canvas resource templates: `canvas://context{?budget,consumer,since}` and `canvas://graph{?focus,depth}`. Bundled skills additionally register per-skill `canvas://skills/<name>` resources and the `skill://{name}/{+path}` file template.
20
+
21
+ Resource change notifications: the MCP server emits `notifications/resources/updated` when canvas state changes. Pin changes notify `canvas://pinned-context`; all mutations notify `canvas://layout`, `canvas://summary`, `canvas://spatial-context`, `canvas://history`, `canvas://code-graph`, and `canvas://graph`. This enables real-time human→agent collaboration — humans pin nodes in the browser, agents are notified immediately.
22
+
23
+ ### AX Primitives (host-agnostic)
24
+
25
+ Neutral, agent-agnostic agent-experience primitives. The core never imports a host SDK (e.g. `@github/copilot-sdk`); host adapters map onto these HTTP/MCP surfaces. State lives in three partitions:
26
+
27
+ - **Canvas-bound** (`focus`, `work-item`, `approval-gate`, `review-annotation`): live in `PmxAxState`, participate in snapshots + restore, cleared by `canvas_view { action: "clear" }`. Read via `canvas_ax_state { action: "get" }` / `canvas://ax-work`.
28
+ - **Timeline** (`agent-event`, `evidence-item`, `steering-message`): persist in dedicated DB tables for diagnostics/continuity, bounded by retention (500 rows/table), NOT restored by snapshots, NOT cleared by `canvas_view { action: "clear" }`. Read via `canvas_ax_timeline { action: "read" }` / `canvas://ax-timeline`.
29
+ - **Host/session** (`host-capability`): reported by adapters into its own table, exposed for diagnostics, survives `canvas_view { action: "clear" }`. Read via `canvas_ax_state { action: "get" }`.
30
+
31
+ Approval gates implement PMX approvals first (`pending → approved/rejected/held`); host permission hooks are mapped only where low-risk. **Unattended-approval policy** (`src/server/ax-gate-ttl.ts`): every gate carries `expiresAt` (`ttlMs`, default `PMX_CANVAS_GATE_TTL_MS` = 5 min); a 1s sweeper started with the server resolves unanswered gates to `held` (non-approval), records a `policy` agent-event, and re-emits presence; `POST /api/canvas/ax/approval/:id/reopen` (HTTP/SDK only — a human action) restarts the clock. **Scope fence** (`src/server/scope-fence.ts`): `policy.scope = { nodeIds, padding }` makes `executeOperation` refuse agent-originated mutations outside the fence with 403 (`meta.fromWorkbench` exempts the human; batch inner ops are always agent writes, so the fence cannot be keyed on `suppressAutoGhost`); unknown mutating ops are refused under a fence by default — add new layout ops to `checkScopeFence`.
32
+
33
+ - **Agent presence** (`src/server/agent-presence.ts`, shape in `src/shared/agent-presence.ts`): in-memory and TTL-swept like `IntentRegistry`, never persisted. Derived from feeds that already exist — every agent-originated mutation through `executeOperation` (no `x-pmx-workbench` marker) touches its caller as `tooling`; `ax.activity.ingest` kinds `session-start`/`session-end` attach/detach and `tool-start`/`tool-result` drive the phase; `POST /api/canvas/ax/presence` (`canvas_ax_state { action: "set-presence" }`) is the explicit path for `thinking`, cursor, focus. Transport-labelled writes (`api`/`mcp`/`sdk`/`cli`, no `agentId`) are **attributed to the single attached session** so one agent writing through MCP keeps one cursor; identified writers and multi-session boards stay separate; a human-started `browser` session absorbs agent-less writes under any label and takes the writer's name (`HUMAN_STARTED_SESSION_LABEL`); an attach whose label matches an already-attached session twin-merges (one agent, two channels — Copilot's extension + its MCP server) with the channel aliased onto the session. One `agent-presence` SSE frame carries the full snapshot on every change including expiry, and it also carries `activity` — the last 50 agent writes with a `describeWrite` summary (the External Steering feed and the session panel's Update rows). An explicit `attached: false` removes the presence outright (an ended session never lingers as an external writer). **`sessionActive` (any attached presence) gates all agent chrome except presence cursors** — `AgentPresenceLayer` paints every live writer (external ones `is-external`/dashed) so a human always sees where an agent is working; panels/chips/composer still mount on `sessionActive`, and a board with no writers at all stays byte-clean. Contract: `docs/ax-state-contract.md` (Agent presence); design and build plan: `docs/design.md`.
34
+ - **Human presence + user wins** (`src/server/human-presence.ts`, shape in `src/shared/human-presence.ts`): every open workbench tab heartbeats `POST /api/canvas/human-presence` (cursor, name, `grabbingNodeId`); one `human-presence` SSE frame per change. A held node is an **edit lock**: `executeOperation` refuses an agent write to it with 409 until release or the 8 s grab TTL (membership ops — dissolving its group, `group.add` — count as writes to the member), and the client vetoes a pending explicit intent on a grabbed node and records a `yield` timeline event. Human heartbeats are in `PRESENCE_EXEMPT_OPS` — they must never count as agent activity.
35
+ - **Shared undo stack with actors** (`mutation-history.ts`): `executeOperation` tags every recorded entry `human` (workbench marker) or `agent`; `GET /api/canvas/history` exposes `top`. The session panel offers undo only while an agent edit tops the stack and posts steering when the human takes it. SDK writes bypass the registry and default to `agent`.
36
+
37
+ Additional canvas-bound primitives: `elicitation` (request structured human input → respond), `mode-request` (request a plan/execute/autonomous transition → resolve), and a single `policy` singleton (tool/prompt policy: `tools.allowed|excluded|approvalRequired`, `prompt.systemAppend|mode`). All snapshot/restore with the rest of `PmxAxState` and are read via `canvas_ax_state { action: "get" }` / `canvas://ax-work` / `canvas://ax-context`.
38
+
39
+ #### Node interactions (capability-gated)
40
+
41
+ Eligible nodes emit one normalized, zod-validated `PmxAxInteraction` envelope (`{ type, sourceNodeId, payload, sourceSurface }`) that maps onto an AX operation. `applyAxInteraction` (`src/server/ax-interaction.ts`) is the single trust boundary and re-validates every interaction regardless of transport.
42
+
43
+ - **Capabilities:** `DEFAULT_NODE_AX_CAPABILITIES` is the per-node-type ceiling; a node may opt in / narrow via `data.axCapabilities` (`{ enabled, allowed }`), clamped to the ceiling (a node can never escalate). `html`/`html-primitive`, `mcp-app`, and internal `prompt`/`response` are disabled by default.
44
+ - **`sourceSurface` scoping:** sandboxed/opaque-origin iframe surfaces (`html-node`, `mcp-app`, `json-render`) are clamped to their OWN node — caller-supplied `nodeIds` are forced to `[sourceNodeId]`. Trusted surfaces (`native-node`, `adapter`) may target explicit nodeIds. **When adding a new sandboxed surface, add it to the `scoped` predicate** or it silently takes the permissive default.
45
+ - **Transports:** native node controls call `POST /api/canvas/ax/interaction` directly; sandboxed surfaces postMessage a nonce-tagged emit to the parent canvas, which validates source + per-surface nonce + node id before submitting. `html`/`mcp-app` use `window.PMX_AX.emit(type, payload)`; the json-render/graph viewer forwards a spec action named after an AX type (e.g. `on.press → { action: "ax.work.create", params }`).
46
+ - **Commands:** `ax.command.invoke` runs a registry command (`pmx.plan`, `pmx.execute`, `pmx.promote-context`, `pmx.summarize`, `pmx.review`) via `canvas_invoke_command`; unknown names are rejected (400) and a successful call records a `command` agent-event.
47
+ - **Delivery:** steering can be claimed by adapterless MCP clients (`canvas_ax_delivery { action: "claim" }` / `canvas://ax-pending-steering`) and acknowledged (`canvas_ax_delivery { action: "mark" }`); loop-safe (a consumer never receives steering it originated).
48
+
49
+ Interactions request PMX-AX primitives only — never arbitrary shell, tool, MCP, or host execution.
50
+
51
+ #### AX flows (panel and graph)
52
+
53
+ A task flow exists in two interchangeable forms. The `ax-flow` HTML primitive draws it as a panel;
54
+ `ax.flow.materialize` lays the same steps out as native nodes joined by `flow` edges with a
55
+ loop-back rail, each step linked to a work item. It is the only interaction that creates canvas
56
+ nodes, so it is granted to the `html` ceiling alone.
57
+
58
+ - Materialized steps carry `data.axStep` and render native Start/Done/Blocked controls
59
+ (`src/client/nodes/AxStepControls.tsx`) in both the node body and the expanded overlay — the
60
+ flow is drivable without the panel.
61
+ - Work-item status mirrors onto node status chips (`mirrorAxWorkStatusToNodes`), which is what
62
+ makes the in-progress node visible on the board while an agent works.
63
+ - `src/server/ax-flow-loop.ts` advances the loop server-side via `setWorkItemsChangedListener`
64
+ (see architecture rule 8), so it survives a browser reload and keeps running with the tab closed.
65
+ A module-level `advancing` guard prevents re-entrancy.
66
+ - Step geometry and the shared flow shape live in `src/shared/ax-flow.ts` so server and client
67
+ cannot drift.
68
+
69
+ ### Spatial Semantics Layer
70
+
71
+ The canvas exposes spatial intelligence to agents via `canvas://spatial-context`:
72
+ - **Proximity clusters**: Automatically detects nodes grouped together on the canvas
73
+ - **Reading order**: Nodes sorted top-left to bottom-right (how humans read)
74
+ - **Pinned neighborhoods**: For each pinned node, lists nearby unpinned nodes (the human's implicit context)
75
+ - **`canvas://pinned-context`** now includes neighborhood data — nearby unpinned nodes for each pin
76
+
77
+ Use `canvas_query { action: "search" }` to find nodes by title/content keywords instead of parsing the full layout.
78
+
79
+ ### Time Travel (Undo/Redo + History)
80
+
81
+ Every canvas mutation is recorded in an in-memory ring buffer (last 200 operations). Each entry captures forward/inverse closures for clean undo/redo.
82
+
83
+ - **`canvas_history`** (`action: "undo" | "redo"`) — step through history, reversing operations cleanly
84
+ - **`canvas://history`** — human-readable mutation timeline with cursor position
85
+ - **`canvas_snapshot`** (`action: "diff", snapshot`) — compare current canvas vs any saved snapshot (shows added/removed/modified nodes and edges)
86
+ - HTTP: `POST /api/canvas/undo`, `POST /api/canvas/redo`, `GET /api/canvas/history`
87
+
88
+ Design notes:
89
+ - History is session-scoped (in-memory, not persisted to disk)
90
+ - `arrange()` records as a single compound mutation (not N individual moves)
91
+ - Undo/redo emit SSE events so the browser updates immediately
92
+ - The `_suppressRecording` flag prevents undo/redo from creating new history entries
93
+
94
+ ### Code Graph (Auto-Dependency Detection)
95
+
96
+ When file nodes are on the canvas, the system auto-detects import dependencies and creates `depends-on` edges between related files. The code graph updates live when files change.
97
+
98
+ - **`canvas://code-graph`** MCP resource — dependency structure: central files, isolated files, import/imported-by lists
99
+ - HTTP: `GET /api/canvas/code-graph`
100
+ - Supported languages: JS/TS (`import`/`require`), Python (`import`/`from`), Go (`import`), Rust (`mod`/`use crate`)
101
+ - Auto-edges use the `codegraph-` ID prefix and are suppressed from mutation history
102
+ - Recomputation is debounced (300ms) and triggered on file node add/remove and file content change
103
+
104
+ ## Integration Paths
105
+
106
+ 1. **MCP Server** (recommended) — `pmx-canvas --mcp`, auto-starts on first tool call
107
+ 2. **HTTP API** — REST + SSE at `localhost:4313`
108
+ 3. **JavaScript/TypeScript SDK (Bun runtime)** — `import { createCanvas } from 'pmx-canvas'`
109
+ 4. **Agent Skills** — `skills/pmx-canvas/SKILL.md`, `skills/web-artifacts-builder/SKILL.md`, `skills/playwright-cli/SKILL.md`, `skills/pmx-canvas-testing/SKILL.md`, `skills/pmx-canvas-orchestration/SKILL.md` (multi-agent choreography ON the canvas: host executes, canvas is the graph/state/steering surface), plus repo-local agnostic PMX skills such as `doc-coauthoring`, `data-analysis`, `frontend-design`, `web-design-guidelines`, and `json-render-*`
@@ -35,7 +35,7 @@ surface each one binds to.
35
35
  | `ingestActivity(event)` | `POST /api/canvas/ax/activity` · `canvas_ingest_activity` — board auto-reacts | Forwarding the host's tool/session hooks |
36
36
  | `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 |
37
37
  | `mirrorLog(event)` *(optional)* | `GET /api/canvas/ax/timeline` · `canvas://ax-timeline` | Writing AX events into the host's own chat/session log |
38
- | `presence()` | `POST /api/canvas/ax/presence` · `canvas_ax_state { action: "set-presence" }` — or simply `ingestActivity` with `session-start` / `session-end` / `tool-start` / `tool-result` | Calling it from the host's session and tool hooks. Attach saves a pre-session snapshot; detach emits the `agent-session-ended` receipt — detach on shutdown (bounded, best-effort) so the human gets it promptly. If the host knows the model's token usage, report it as `contextUsage: { used, total }` — the top-bar meter then shows the real window instead of the pinned-context estimate |
38
+ | `presence()` | `POST /api/canvas/ax/presence` · `canvas_ax_state { action: "set-presence" }` — or simply `ingestActivity` with `session-start` / `session-end` / `tool-start` / `tool-result` | Calling it from the host's session and tool hooks. Attach saves a pre-session snapshot; detach emits the `agent-session-ended` receipt — detach on shutdown (bounded, best-effort) so the human gets it promptly. If the host knows the model's token usage, report it as `contextUsage: { used, total }` — the context panel then names how many tokens the agent's whole context holds |
39
39
 
40
40
  ### Presence: the cursor works for every adapter
41
41
 
@@ -105,9 +105,10 @@ constants, so they cannot drift); the registry is `src/server/agent-presence.ts`
105
105
  so clients never run their own ticker.
106
106
  - **Transport.** One SSE frame, `agent-presence`, carries the full snapshot on
107
107
  every change, including the last `MAX_ACTIVITY_ENTRIES` agent writes with a
108
- one-line summary. `GET /api/canvas/ax/presence` for the connect-time read;
108
+ one-line summary. An attached presence also carries `session`
109
+ (`{ startedAt, read, created, edited, pinned }`, card ids on the open board
110
+ since it attached, counting every agent there, like the receipt): the agent
111
+ chip's "2 read · 1 edited" and the live lens. A recorded read re-emits the
112
+ frame. `GET /api/canvas/ax/presence` for the connect-time read;
109
113
  `POST /api/canvas/ax/presence` (`canvas_ax_state { action: "set-presence" }`)
110
114
  for explicit updates.
111
- - **Budget.** `used` = estimated tokens of the `pinned-context.get` payload;
112
- `total` = `PMX_CANVAS_CONTEXT_BUDGET_TOKENS` (default
113
- `CONTEXT_BUDGET_DEFAULT_TOKENS`).
package/docs/cli.md CHANGED
@@ -1,5 +1,34 @@
1
1
  # CLI reference
2
2
 
3
+ ## Knowledge lifecycle data
4
+
5
+ `pmx-canvas board knowledge list` reads workspace categories/folders and shared relation presets.
6
+ `pmx-canvas board knowledge category-set '<JSON>'` accepts `{category: {...}}`;
7
+ `pmx-canvas board knowledge category-remove '{"id":"unused-category"}'` deletes an unused category. Explicit folder assignments (even empty folders) refuse deletion and name the folders to reassign or clear first. Unknown IDs are 404; missing/blank IDs are invalid input. No folder settings or inherited policies are silently cleared.
8
+ `board knowledge folder-set '<JSON>'` accepts `{path, categoryId, lifecycleOverride}`.
9
+ `board knowledge relation-preset-set '<JSON>'` accepts `{preset: {id, name, vocabulary}}`;
10
+ `board knowledge relation-preset-remove '{"id":"preset-id"}'` deletes a shared template.
11
+ Vocabulary entries are `{kind, ink, directed}`. These templates are managed in Home;
12
+ editing/deleting one does not rewrite boards. Applying a saved template explicitly copies
13
+ its vocabulary to a selected board. The canvas dropdown only filters existing relation kinds.
14
+ No workspace write opens a board; scope fences refuse agent workspace writes.
15
+ Moving/unfiling a board also checks its stored global scope or writer territory alongside
16
+ the active scope, without opening it. Home or an unfenced board does not bypass that policy.
17
+ `pmx-canvas board lifecycle get|set|review|restore '<JSON>'` uses `id` and the
18
+ [HTTP contract fields](http-api.md#knowledge-lifecycle-data-plan-017-slice-1).
19
+ For example: `pmx-canvas board lifecycle review '{"id":"card-id","outcome":"retain",
20
+ "evidence":"Checked source revision v2","applied":true,"expectedBoardId":"board-id",
21
+ "expectedContentRevision":12}'` (replace 12 with the revision of the card content actually checked).
22
+ Read supports `board`; writes target the open board. For dependencies also send `expectedSources`
23
+ from the checked lifecycle result's `qualification.observations`; stale or unavailable sources refuse
24
+ validation. Qualification includes due reasons, unknown/retired status and separate clocks.
25
+ Retired cards leave active context but remain in direct reads and search, explicitly marked.
26
+
27
+ `edge add` and `edge update` accept `--kind` and `--reason`; update also accepts `--clear-kind`
28
+ and `--clear-reason`. `board vocabulary <board-id> '<JSON-array>'` sets an editable vocabulary
29
+ of `{kind, ink, directed}`. These are semantic relations, independent of edge line type/style.
30
+ Dependency directions and the bounded brief lifecycle snapshot are documented in the HTTP contract.
31
+
3
32
  The CLI is the shell-native way to run and control PMX Canvas. It targets
4
33
  `http://localhost:4313` by default — override with `PMX_CANVAS_URL` or
5
34
  `PMX_CANVAS_PORT` when the server runs elsewhere, or per invocation with the
@@ -34,9 +63,11 @@ The same stops and camera interpolation drive interactive presentation and optio
34
63
  A visual stop editor and carrying tours into static exports/share links are not implemented here.
35
64
 
36
65
  Click **Present** in the top bar, or open `/workbench?present=1` for a chrome-free
37
- embedded/capture view. Right/Down/Space advances, Left/Up goes back, Esc exits.
38
- The camera is local to the viewer; board content continues updating over SSE.
66
+ embedded/capture view (no rail, top bar, minimap or composer). Right/Down/Space
67
+ advances, Left/Up goes back, Esc exits. The presentation camera is local to the
68
+ viewer and never written to the board; board content continues updating over SSE.
39
69
  Stops do not auto-advance. Missing targets show an error and can be skipped.
70
+ With `prefers-reduced-motion: reduce`, every stop and camera move jumps instead of animating.
40
71
 
41
72
  Save this as `tour.json` (replace the IDs with IDs from `pmx-canvas node list`):
42
73
 
@@ -45,6 +76,7 @@ Save this as `tour.json` (replace the IDs with IDs from `pmx-canvas node list`):
45
76
  "stops": [
46
77
  { "target": { "nodeId": "overview-group" }, "duration": 1.5, "padding": 60 },
47
78
  { "target": { "nodeId": "detail-note" }, "duration": 2, "easing": "ease-in-out", "pullback": 0.7 },
79
+ { "target": { "rect": { "x": -400, "y": 200, "width": 1600, "height": 900 } }, "duration": 2 },
48
80
  { "target": { "viewport": { "x": 80, "y": 100, "scale": 0.5 } }, "duration": 1 }
49
81
  ]
50
82
  }
@@ -55,10 +87,11 @@ pmx-canvas tour set --file tour.json
55
87
  pmx-canvas tour get
56
88
  ```
57
89
 
58
- A stop targets either a node ID (including a group ID) or an explicit viewport.
90
+ A stop targets exactly one of: a node ID (including a group ID), a world-space
91
+ `rect` (`x`/`y` is its top-left corner), or an explicit viewport.
59
92
  Viewport translation is screen-space: `screen = world * scale + offset`.
60
93
  `duration` is transition time in seconds (default 1, zero jumps); `padding` is
61
- screen pixels around a target (default 40). Easing is `linear`, `ease-in-out`
94
+ screen pixels around a node or rect target (default 40). Easing is `linear`, `ease-in-out`
62
95
  (default), or `ease-out`. Zoom interpolates logarithmically about the moving
63
96
  world-space centre. `pullback` (0–4, default 0) subtracts a sinusoidal log-zoom
64
97
  offset mid-move without changing endpoints. Tours allow at most 1000 stops.
@@ -68,6 +101,33 @@ the board. A file containing `null` resets the tour: when none is saved, groups
68
101
  are sorted by y, then x, then ID. A saved empty `stops` array deliberately has no
69
102
  stops. SDK: `canvas.setTour(tourOrNull)` / `canvas.getTour()`.
70
103
 
104
+ ### Driving a tour (agents)
105
+
106
+ The server keeps one tour cursor (in memory, not saved), tied to the board it was
107
+ started on; starting a tour on another board replaces it. An agent steps it and
108
+ every presenting viewer follows; a human's arrow keys move the same cursor,
109
+ so `next` always continues from where the audience actually is.
110
+
111
+ ```bash
112
+ pmx-canvas tour go 0 # start presenting at the first stop
113
+ pmx-canvas tour go next # or: previous (clamped at the ends)
114
+ pmx-canvas tour go 2 --no-present # only move viewers already presenting
115
+ pmx-canvas tour exit # leave presentation everywhere
116
+
117
+ # Eased camera move, no tour needed (same fields as a stop)
118
+ pmx-canvas camera move --node <id> --duration 2 --pullback 0.6
119
+ pmx-canvas camera move --rect -400,200,1600,900 --easing ease-out
120
+ pmx-canvas camera move --viewport 80,100,0.5 --duration 0
121
+ ```
122
+
123
+ `tour go` starts presenting in idle workbenches unless `--no-present` is given.
124
+ `camera move` animates every open workbench; outside a presentation its end camera
125
+ becomes the board viewport. Camera moves and tour steps are navigation: they never
126
+ enter undo history, never count as agent writes, and are allowed under a scope fence.
127
+ A deterministic capture (`record --mode deterministic`) ignores both.
128
+ SDK: `canvas.goToTourStop(indexOrStep, { present })`, `canvas.exitTour()`,
129
+ `canvas.moveCamera(stop)`.
130
+
71
131
  ### Optional capture of the same tour
72
132
 
73
133
  `record` is an optional local utility, not a second presentation model. It reads
@@ -83,31 +143,47 @@ pmx-canvas record --mode deterministic --present --fps 30 --resolution 1920x1080
83
143
  pmx-canvas record --mode deterministic --tour-file tour.json --present --output frames
84
144
 
85
145
  # Alternatively, sample the live presentation while agents update the board
86
- pmx-canvas record --duration 10 --present --theme light --output activity.mp4
146
+ pmx-canvas record --duration 10 --present --theme daylight --output activity.mp4
87
147
 
88
148
  # Keep recording until SIGINT (Ctrl+C) or SIGTERM, then encode
89
149
  pmx-canvas record --stop-on-signal --output live.mp4
90
150
  ```
91
151
 
152
+ A board walkthrough end to end: save the `tour.json` above, preview it with
153
+ **Present**, then render it at video quality and record a live pass while an
154
+ agent works:
155
+
156
+ ```bash
157
+ pmx-canvas tour set --file tour.json
158
+ pmx-canvas record --mode deterministic --present --theme midnight --resolution 1920x1080 --fps 30 --output walkthrough.mp4
159
+ pmx-canvas record --duration 20 --present --resolution 1920x1080 --output agent-pass.mp4 &
160
+ pmx-canvas node add --type markdown --title "Findings" --content "Added while recording"
161
+ wait
162
+ ```
163
+
92
164
  Options: `--mode realtime|deterministic` (default realtime), `--resolution WIDTHxHEIGHT`
93
165
  (default 1280x720), `--fps` (1–120, default 30), `--theme`, `--present`,
94
166
  `--duration SECONDS` or `--stop-on-signal` for realtime, `--tour-file FILE`
95
167
  for deterministic mode, `--chrome-path PATH`, and required `--output PATH`.
96
168
  Global `--port` / `--server-url` work here too. Existing output paths are refused.
97
169
 
98
- An `.mp4` output uses ffmpeg/H.264; any other path is a PNG sequence directory.
170
+ An `.mp4` output uses ffmpeg/H.264; any other path is a frame sequence directory
171
+ of `frame-000000.png` files.
99
172
  Frames and `recording.json` are retained at `<output>.frames` even after video
100
- encoding. If ffmpeg is missing, the command clearly reports the PNG fallback
101
- and returns that directory. Encoding failures retain frames and exit nonzero.
173
+ encoding. If ffmpeg is missing, the command clearly reports the frame-sequence
174
+ fallback and returns that directory. Encoding failures retain frames and exit nonzero.
102
175
 
103
176
  Deterministic mode resolves target geometry once and writes
104
177
  `max(1, ceil(duration × fps))` frames per stop, including each endpoint. It sets
105
178
  the camera, waits for two animation frames, checks the applied camera, then
106
179
  captures. Duplicate a target to hold it. This makes **camera timing** deterministic,
107
180
  not animated iframe content, fonts loaded later, network assets, or concurrent
108
- board edits. Realtime mode samples the live board; slow captures repeat frames
109
- to preserve wall-clock speed, with the repeated-frame count in `recording.json`.
110
- Capture has no audio. Chrome and a Bun runtime with WebView support are required.
181
+ board edits. Realtime mode records Chrome's screencast (a frame per paint) and
182
+ writes the newest painted frame on every `--fps` tick while it records, so footage
183
+ keeps wall-clock speed and a stop signal keeps every frame written so far; ticks
184
+ with no new paint repeat the previous frame, counted as `duplicated` in
185
+ `recording.json`. Capture has no audio. Chrome and a Bun runtime with WebView
186
+ support are required; Chrome gets 60 seconds to cold-start.
111
187
  Recording is a local CLI/file operation, not a remote HTTP/MCP file-writing API;
112
188
  HTTP/MCP manage tours and retain their existing screenshot/automation surfaces.
113
189
 
@@ -209,6 +285,17 @@ none keeps 100% with scrolling. [Sizing and readability](node-types.md#mermaid-n
209
285
  `--from-search` / `--to-search` must each resolve to exactly one node — broad
210
286
  queries fail rather than guess. Use the full visible title.
211
287
 
288
+ Background `group create` and `edge add` accept `--destination-board <id>`,
289
+ `--request-id <logical-id>` and `--expected-board <active-id>`. The destination
290
+ does not open in the workbench; `--to-board` on an edge independently selects its
291
+ foreign endpoint. Reuse request IDs only for identical retries. See the
292
+ [creation/retry contract](http-api.md#nodes).
293
+
294
+ `search <query>` accepts `--board-id <id>`, `--folder <path>`, `--scope active|library`
295
+ and `--limit <n>` (`--library` also selects library scope). Board/folder filters
296
+ intersect; folders include descendants, and `--folder ""` selects unfiled boards.
297
+ Filters default omitted scope to library; explicit active scope stays active.
298
+
212
299
  CLI create commands return the created node shape with normalized title,
213
300
  content, and geometry, which makes scripting stacked layouts and batch
214
301
  follow-ups easier.
@@ -282,14 +369,39 @@ node or fit the new ids — auto-placement is board-relative, not camera-relativ
282
369
 
283
370
  ## Boards
284
371
 
372
+ Home has Folders, Map, and Graph views. Folder paths organize boards independently
373
+ of links; dragging a board in Map persists its position in SQLite.
374
+
375
+ Graph is one zoomable Library > Board > Card
376
+ explorer. Library shows neutral, undirected, counted board-pair evidence bundles;
377
+ Board shows internal card relations and external neighbor boards; Card shows exact
378
+ one-hop qualified neighbors, incoming left and outgoing right. Click, Enter or Space
379
+ on a node drills; an edge selects its exact evidence in the existing bottom inspector.
380
+ Back restores the prior scene, camera, query, filters and selection; breadcrumbs go
381
+ up the ownership hierarchy instead. Open board/card is a separate content action.
382
+ Unconnected boards/cards have labelled clickable trays. Search and reveal actions
383
+ expose large sets with explicit displayed/total/filtered/hidden counts. A deterministic
384
+ bounded force solve supplies initial positions. Dragging a node pushes nearby nodes
385
+ and lets connected neighbors respond, then the graph settles around its drop position.
386
+ Link pull stays gentle even for highly connected nodes, with wider spacing between cards.
387
+ Canceled drags restore all displaced nodes. Positions remain local to Graph; live
388
+ updates alone preserve existing anchors. Graph's dock starts collapsed and compact.
389
+ Hover highlights a node's connections without fading the other links.
390
+ Entry and search preserve readable size; the header distinguishes off-screen nodes
391
+ from filtered or not-yet-drawn nodes. Fit view shows the whole drawn extent. Home Map
392
+ (including its 280 px default dock), Folders and server graph focus/depth contracts
393
+ are unchanged.
394
+
285
395
  ```bash
286
396
  pmx-canvas board list # most recently opened first; activeBoardId null = Home
287
397
  pmx-canvas board create "Q4 planning" # created, not opened
288
398
  pmx-canvas board open <board-id> # open the returned ID before writing
289
399
  pmx-canvas board open --home # return the shared workbench to Home
290
400
  pmx-canvas board rename <board-id> "New name"
291
- pmx-canvas board create "Q4 planning" --category Planning
292
- pmx-canvas board category <board-id> "Planning/Quarterly" # nested folders; --clear unfiles it
401
+ pmx-canvas board create "Q4 planning" --folder Planning
402
+ pmx-canvas board folder <board-id> "Planning/Quarterly" # nested folders; --clear unfiles it
403
+ pmx-canvas board pin <board-id> --reason "Q4 rests on it" # join the agent's working set
404
+ pmx-canvas board unpin <board-id>
293
405
  pmx-canvas board from <source-id> "Follow-up" --preview
294
406
  pmx-canvas board from <source-id> "Follow-up" --nodes id1,id2 --readme --structure
295
407
  ```
@@ -297,11 +409,36 @@ pmx-canvas board from <source-id> "Follow-up" --nodes id1,id2 --readme --structu
297
409
  Commands write to the board open in the workbench. `board open` switches the
298
410
  shared visible board, not a private CLI target. Verify its returned
299
411
  `activeBoardId` before writing; another participant can switch it later.
300
- Deletion remains human-only. `board from`
412
+ A pinned board's README and pinned cards reach the agent's brief whichever board is open; it
413
+ is read-only context, never a write target. Deletion remains human-only. `board from`
301
414
  excludes `prompt`, `response`, `trace`, and `mcp-app` cards; selected reusable
302
415
  cards get fresh IDs. `--structure` includes group frames; edges between copied
303
416
  cards are retained automatically. `--readme` carries the designated README. The new board remains inactive and
304
- does not inherit pins, AX state, or mutation history.
417
+ does not inherit pins, AX state, or mutation history. Its `previousBoardId`
418
+ records the source board.
419
+
420
+ ## Connected memory
421
+
422
+ ```bash
423
+ pmx-canvas memory-graph
424
+ pmx-canvas memory-graph --projection boards
425
+ pmx-canvas memory-graph --focus pins --depth 2
426
+ pmx-canvas memory-graph --focus '["board-id","card-id"]' --depth 1
427
+ pmx-canvas edge add --from <source-card-id> --to <target-card-id> --to-board <target-board-id> --type references
428
+ ```
429
+
430
+ Graph focus is a board ID, a JSON qualified key `[boardId,cardId|null]`, or
431
+ `pins`; omit it for the library. Depth is an integer 0–4, default 2, counting
432
+ undirected membership hops. Explicit `--depth 0` is valid; bare `--depth` and
433
+ empty values are rejected. `--projection full|boards` defaults to `full`;
434
+ `boards` returns compact board-only summaries. The projection returns `nodes`, `edges`,
435
+ `unresolvedLinks: [{ source, ref }]`, `focus`, and `depth`; nodes are
436
+ `summaryOnly: true` with summaries capped at 280 characters. It is the same
437
+ projection used by Home, links/backlinks, and brief discovery. Reads mark links
438
+ seen on their owning boards without switching or marking full content read.
439
+ `--to-board` keeps the source on the open board and targets a remote card;
440
+ auto-arrange stays local and static export shows external connection evidence,
441
+ not remote lines.
305
442
 
306
443
  ## Backup and restore
307
444
 
@@ -383,6 +520,7 @@ pmx-canvas ax steer "focus on the failing test first"
383
520
  pmx-canvas ax evidence add --kind test-output --title "unit pass"
384
521
  pmx-canvas ax timeline --limit 50
385
522
  pmx-canvas ax reads --limit 50 # context read log: which context each agent read, pinned delivery
523
+ pmx-canvas ax reads status --board <id> # a board's last agent read, per-node reads, pin metadata
386
524
 
387
525
  # Work items (canvas-bound)
388
526
  pmx-canvas ax work add --title "Wire up auth" --status in-progress node-1
Binary file
@@ -18,7 +18,7 @@ body{margin:0}
18
18
  <div style="display: flex; gap: 40px; align-items: flex-end">
19
19
  <div style="flex: 1">
20
20
  <h1 style="margin: 0; font-size: 28px; font-weight: 600; letter-spacing: -0.015em">What the agent did with context</h1>
21
- <p style="margin: 4px 0 0; font-size: 13px; color: #8ea3bd">Two questions, two colours. Every mark has a glyph and a word, so it reads without the colour, and every mark explains itself on hover.</p>
21
+ <p style="margin: 4px 0 0; font-size: 13px; color: #8ea3bd">Two questions, two colours. Every mark has a glyph and a word, so it reads without the colour, and every mark explains itself on hover. <span style="color: #b9c6d6">Updated 2026-10-08: read, not read and changed show on pinned cards only — unpinned cards carry no read state; the session receipt and the dim-untouched lens say what the agent read. In headers, “by the agent” is the ✦ on the type icon (HeaderMarks).</span></p>
22
22
  </div>
23
23
  <div style="display: flex; gap: 10px">
24
24
  <div style="{{s.rule}} border-color: rgba(75,188,255,0.4)"><span style="{{s.ruleDot}} background: #4BBCFF"></span><span><b style="font-weight: 600; color: #4BBCFF">Blue</b> — what's in context<br><span style="color: #8ea3bd">You or the agent pinned it</span></span></div>
@@ -70,7 +70,7 @@ body{margin:0}
70
70
 
71
71
  <div style="{{sc.node}} left: 360px; top: 172px; border: 1.5px solid #4BBCFF"><div style="position: absolute; left: 0; right: 0; top: 0; height: 2.5px; background: #B388FF"></div><div style="{{sc.head}} background: rgba(75,188,255,0.10)"><span style="{{sc.title}}">SMB is price-sensitive</span><span style="{{sc.read}}"><svg width="12" height="12" viewBox="0 0 24 24" style="{{sc.ic}}"><path d="{{i.pen}}"></path></svg>edited</span><button aria-label="Expand (Enter)" style="width: 22px; height: 22px; border: 0; border-radius: 6px; padding: 0; background: transparent; color: #b9c6d6; display: flex; align-items: center; justify-content: center; flex-shrink: 0"><svg width="13" height="13" viewBox="0 0 24 24" style="fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round"><path d="M14 4h6v6M20 4l-7 7M10 20H4v-6M4 20l7-7"></path></svg></button><span style="{{sc.pin}}"><svg width="10" height="10" viewBox="0 0 24 24" style="fill: none; stroke: currentColor; stroke-width: 2.6; stroke-linecap: round; stroke-linejoin: round"><path d="{{i.pin}}"></path></svg></span></div><div style="{{sc.body}}">finding · edited 14:12 · <span style="color: #B388FF">see change</span></div></div>
72
72
 
73
- <div style="{{sc.node}} left: 640px; top: 172px"><div style="{{sc.head}}"><span style="{{sc.title}}">Competitor pricing</span><span style="{{sc.read}}"><svg width="12" height="12" viewBox="0 0 24 24" style="{{sc.ic}}"><path d="{{i.eye}}"></path></svg>read</span><button aria-label="Expand (Enter)" style="width: 22px; height: 22px; border: 0; border-radius: 6px; padding: 0; background: transparent; color: #b9c6d6; display: flex; align-items: center; justify-content: center; flex-shrink: 0"><svg width="13" height="13" viewBox="0 0 24 24" style="fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round"><path d="M14 4h6v6M20 4l-7 7M10 20H4v-6M4 20l7-7"></path></svg></button><button aria-label="Add to context (P)" style="width: 18px; height: 18px; box-sizing: border-box; border: 1.5px solid #6b7d94; border-radius: 999px; padding: 0; background: transparent; color: #b9c6d6; display: flex; align-items: center; justify-content: center; flex-shrink: 0"><svg width="10" height="10" viewBox="0 0 24 24" style="fill: none; stroke: currentColor; stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round"><path d="M9 4h6l-.8 5.5 2.8 3H7l2.8-3zM12 12.5V20"></path></svg></button></div><div style="{{sc.body}}">webpage · not pinned, read anyway</div></div>
73
+ <div style="{{sc.node}} left: 640px; top: 172px"><div style="{{sc.head}}"><span style="{{sc.title}}">Competitor pricing</span><button aria-label="Expand (Enter)" style="width: 22px; height: 22px; border: 0; border-radius: 6px; padding: 0; background: transparent; color: #b9c6d6; display: flex; align-items: center; justify-content: center; flex-shrink: 0"><svg width="13" height="13" viewBox="0 0 24 24" style="fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round"><path d="M14 4h6v6M20 4l-7 7M10 20H4v-6M4 20l7-7"></path></svg></button><button aria-label="Add to context (P)" style="width: 18px; height: 18px; box-sizing: border-box; border: 1.5px solid #6b7d94; border-radius: 999px; padding: 0; background: transparent; color: #b9c6d6; display: flex; align-items: center; justify-content: center; flex-shrink: 0"><svg width="10" height="10" viewBox="0 0 24 24" style="fill: none; stroke: currentColor; stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round"><path d="M9 4h6l-.8 5.5 2.8 3H7l2.8-3zM12 12.5V20"></path></svg></button></div><div style="{{sc.body}}">webpage · not pinned · read shows in the receipt</div></div>
74
74
 
75
75
  <div style="{{sc.node}} left: 60px; top: 330px; border: 1.5px solid #4BBCFF"><div style="{{sc.head}} background: rgba(75,188,255,0.10)"><span style="{{sc.title}}">Churn by plan</span><span style="{{sc.read}}"><svg width="12" height="12" viewBox="0 0 24 24" style="{{sc.ic}}"><path d="{{i.eye}}"></path></svg>read</span><button aria-label="Expand (Enter)" style="width: 22px; height: 22px; border: 0; border-radius: 6px; padding: 0; background: transparent; color: #b9c6d6; display: flex; align-items: center; justify-content: center; flex-shrink: 0"><svg width="13" height="13" viewBox="0 0 24 24" style="fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round"><path d="M14 4h6v6M20 4l-7 7M10 20H4v-6M4 20l7-7"></path></svg></button><span style="{{sc.pin}} position: relative"><svg width="10" height="10" viewBox="0 0 24 24" style="fill: none; stroke: currentColor; stroke-width: 2.6; stroke-linecap: round; stroke-linejoin: round"><path d="{{i.pin}}"></path></svg><span style="position: absolute; right: -3px; bottom: -3px; width: 9px; height: 9px; border-radius: 999px; background: #B388FF; border: 2px solid #0f1d31"></span></span></div><div style="{{sc.body}}">chart · pinned by Claude</div></div>
76
76
 
@@ -146,7 +146,7 @@ class Component extends DCLogic {
146
146
  var key = [
147
147
  k({ name: 'In context — pinned by you', desc: 'Blue border, tinted header, pin badge.', title: 'Raise Pro to $24?', meta: 'question', pin: true }),
148
148
  k({ name: 'In context — pinned by the agent', desc: 'Same blue, with a violet dot on the pin; hover says why.', title: 'Churn by plan', meta: 'pinned by Claude · 14:04', pin: true, byAgent: true }),
149
- k({ name: 'Read by the agent', desc: 'It loaded this into its context, pinned or not.', title: 'Competitor pricing', meta: 'read 14:11', icon: i.eye, markText: 'read' }),
149
+ k({ name: 'Read by the agent', desc: 'Pinned, and loaded by the agent. Unpinned cards show no read state.', title: 'Competitor pricing', meta: 'read 14:11', pin: true, icon: i.eye, markText: 'read' }),
150
150
  k({ name: 'Pinned, not read yet', desc: 'In context, but the agent hasn’t loaded it since you pinned it.', title: 'Pricing notes', meta: 'pinned 14:18', pin: true, icon: i.eyeOff, markText: 'not read', muted: true }),
151
151
  k({ name: 'Created by the agent', desc: 'Its byline stays until you edit the node.', title: 'Churn flat after last raise', meta: 'created 14:06', icon: i.spark, markText: 'by Claude' }),
152
152
  k({ name: 'Edited by the agent', desc: 'Violet bar for the session; “see change” opens the diff and undo.', title: 'SMB is price-sensitive', meta: 'edited 14:12 · see change', bar: true, icon: i.pen, markText: 'edited' }),