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
@@ -834,6 +834,230 @@
834
834
  "type": "output_check"
835
835
  }
836
836
  ]
837
+ },
838
+ {
839
+ "id": 36,
840
+ "name": "folder-cli-without-removed-category",
841
+ "prompt": "In a verified disposable workspace, use the CLI to create Release notes under Engineering/Canvas, move it to Engineering/Release, then unfile it without opening it. An old script uses board create --category Engineering/Canvas. Check that obsolete command as a negative control; do not silently accept it or create a knowledge category instead. Leave the active board and its cards alone.",
842
+ "expected_output": "Executes board create \"Release notes\" --folder Engineering/Canvas, captures the returned board ID, uses board folder <id> Engineering/Release and board folder <id> --clear. Reads the library after each step to verify folder and stable identity/content. In the disposable target, --category exits nonzero with the removal diagnostic and creates no board. No board open or category-set substitute occurs; activeBoardId and the original board layout remain unchanged.",
843
+ "assertions": [
844
+ {
845
+ "name": "uses-current-folder-commands",
846
+ "description": "CLI trace uses --folder on create, the returned ID with positional board folder, and --clear to unfile; successful command results are required, not merely suggested commands",
847
+ "type": "output_check"
848
+ },
849
+ {
850
+ "name": "verifies-folder-and-identity",
851
+ "description": "Library reads show Engineering/Canvas, then Engineering/Release, then an empty folder on the same board ID without losing its content",
852
+ "type": "output_check"
853
+ },
854
+ {
855
+ "name": "rejects-obsolete-category-control",
856
+ "description": "The isolated --category control exits nonzero with 'The --category flag was removed.' and leaves the library count unchanged; no category-set is used to simulate filing",
857
+ "type": "output_check"
858
+ },
859
+ {
860
+ "name": "does-not-navigate-to-file",
861
+ "description": "Before/after reads show unchanged activeBoardId and active layout; the trace contains no board open to perform filing",
862
+ "type": "output_check"
863
+ }
864
+ ]
865
+ },
866
+ {
867
+ "id": 37,
868
+ "name": "whole-library-map-versus-full-content-delivery",
869
+ "prompt": "On a disposable library, board A is active and inactive board B has pinned Markdown cards Target and Unread control. Target's decisive sentence is beyond character 280. Show the whole-board connection map, then use the actual Target text to answer its question without opening B. Use one stable consumer. After a human edits Target, refresh just that card. Do map summaries prove you read both cards in full?",
870
+ "expected_output": "Reads a whole-library graph with projection boards and omitted focus for orientation, then resolves B/Target and explicitly gets its full content with canvas_node {action:get, id, board:B, full:true}. Uses the sentence beyond the summary in its answer. Captures read status before and after graph/full deliveries, checks Target's delivered content revision, then fully rereads Target after the edit. Does not mark Unread control fully read from a graph/compact summary or confuse complete link delivery with full-content delivery. Active A remains unchanged.",
871
+ "assertions": [
872
+ {
873
+ "name": "requests-board-map-not-content-dump",
874
+ "description": "Trace requests canvas_query graph with projection boards and no focus (or equivalent memory-graph API), and observes board-qualified summaryOnly results rather than using a full layout as the map",
875
+ "type": "output_check"
876
+ },
877
+ {
878
+ "name": "fetches-and-uses-full-qualified-target",
879
+ "description": "Trace gets the resolved B/Target with full:true (or equivalent tracked full-node API); the answer uses its seeded sentence beyond 280 characters and read-status evidence records that delivered revision",
880
+ "type": "output_check"
881
+ },
882
+ {
883
+ "name": "refreshes-only-observed-stale-content",
884
+ "description": "After the human edit, a new full Target delivery advances its recorded read revision; status deltas show the unread control received no full-content read from map/compact discovery alone",
885
+ "type": "output_check"
886
+ },
887
+ {
888
+ "name": "preserves-active-board-and-read-boundaries",
889
+ "description": "Before/after activeBoardId and A layout match, no open/write occurs, and full-read claims are backed by deliveries rather than summaryOnly or link-seen state",
890
+ "type": "output_check"
891
+ }
892
+ ]
893
+ },
894
+ {
895
+ "id": 38,
896
+ "name": "durable-background-create-replay",
897
+ "prompt": "In an isolated workspace, keep A active while populating inactive B with two static Markdown cards, a group containing them, and a references edge. Use durable request IDs per creation and batch named references. Simulate a lost response after a committed prefix, retry, and restart the disposable daemon before retrying again. With the harness, edit one created card and delete the other on B, return to A, then replay the original requests. Do not recreate deleted work or undo later edits.",
898
+ "expected_output": "Uses destinationBoardId:B and stable per-operation requestId inside each batch operation's args, resolving group/edge named references. Replays identical inputs after partial completion and restart and compares original receipts/IDs. Later edit/deletion controls are harness-owned, not unsupported background CRUD. Replay returns original receipts without duplicating, overwriting or resurrecting objects. Qualified reads show B's intended surviving state and unchanged A activeBoardId/layout/viewport throughout agent background writes.",
899
+ "assertions": [
900
+ {
901
+ "name": "targets-each-static-creation",
902
+ "description": "Batch trace puts destinationBoardId and distinct logical requestId in node/group/edge args, uses valid named references, and verifies group membership and qualified edge endpoints on B",
903
+ "type": "output_check"
904
+ },
905
+ {
906
+ "name": "replays-prefix-and-restart-durably",
907
+ "description": "Evidence includes a committed prefix with lost response, identical retry after it and after a real isolated daemon restart, stable returned IDs/receipts and no duplicate nodes/groups/edges",
908
+ "type": "output_check"
909
+ },
910
+ {
911
+ "name": "replay-is-not-reapplication",
912
+ "description": "After harness edit/deletion and original-input replay, qualified reads retain the later edit and deleted-card absence even though original creation receipts are returned",
913
+ "type": "output_check"
914
+ },
915
+ {
916
+ "name": "keeps-background-work-off-active-board",
917
+ "description": "Before/after reads around agent creation/replays show A stays active with identical layout/viewport; no agent board open, active update/remove, runtime creation or background intent is used",
918
+ "type": "output_check"
919
+ }
920
+ ]
921
+ },
922
+ {
923
+ "id": 39,
924
+ "name": "background-create-conflicts-and-stale-active-guard",
925
+ "prompt": "In a disposable workspace with A active and B inactive, create a static note on B with requestId logical-note and expectedBoardId A. Test reusing logical-note with changed content and with destination A. Then have the harness switch the active board to C and send a new creation for B using stale expectedBoardId A. Do not force it through. Finally create a genuinely separate identical note with a fresh request ID after checking C. Also test a background file-node creation as an unsupported control.",
926
+ "expected_output": "Observes conflicts on changed-input and changed-destination reuse without mutating either destination. Stale expectedBoardId guards the actual active board, not B: the new request is refused after the switch to C. Rereads active identity before using expectedBoardId C with a fresh logical ID for the intentional duplicate. Unsupported background file creation fails without side effects. No clearing guards, board switching or blind retries to defeat rejection; C stays active.",
927
+ "assertions": [
928
+ {
929
+ "name": "changed-request-conflicts-without-writes",
930
+ "description": "Actual changed-content and changed-destination requests using logical-note fail with conflicts, and destination reads prove original content/counts are unchanged",
931
+ "type": "output_check"
932
+ },
933
+ {
934
+ "name": "stale-guard-requires-reread",
935
+ "description": "After the harness switch, expectedBoardId A is refused with no creation on B; trace rereads C before any fresh write and does not remove the guard or substitute B as the active identity",
936
+ "type": "output_check"
937
+ },
938
+ {
939
+ "name": "new-operation-gets-new-identity",
940
+ "description": "The intentional identical creation uses a new requestId and expectedBoardId C, returns a distinct node ID on B and leaves C active with unchanged layout",
941
+ "type": "output_check"
942
+ },
943
+ {
944
+ "name": "unsupported-background-control-has-no-effect",
945
+ "description": "A file-node creation with destinationBoardId B fails as unsupported and qualified reads show no new file or active-board side effect; no active-board fallback is attempted",
946
+ "type": "output_check"
947
+ }
948
+ ]
949
+ },
950
+ {
951
+ "id": 40,
952
+ "name": "board-qualified-native-relations",
953
+ "prompt": "In a disposable library A is active, and A and B both contain a card with ID shared. The harness has given A/shared, A/Navigation and B/shared explicit durable lifecycle policies and validated their current content. From A/shared add a depends-on edge to B/shared with reason 'Capacity requires measured throughput'. Add an ordinary references edge from A/Navigation to the same remote source. Read the qualified graph, change B/shared with the harness, and check which dependents become review-due. Keep A active and do not replace the edge with a board portal.",
954
+ "expected_output": "Resolves the two board identities and uses canvas_edge add with from:shared, to:shared, toBoardId:B, type:depends-on for dependent to prerequisite, preserving reason. Uses a references edge for Navigation. Reads graph and lifecycle qualifications with explicit board identities: the dependency is remote, not a self-loop on A. With explicit durable lifecycle policies in the fixture, the source change makes the dependent due but not the ordinary-reference control. Reads do not open B or mutate its source.",
955
+ "assertions": [
956
+ {
957
+ "name": "writes-qualified-remote-edge",
958
+ "description": "Actual edge add uses A/shared as source and toBoardId B with target shared; graph endpoints are distinct qualified keys, not bare-ID self-loops or board portal nodes",
959
+ "type": "output_check"
960
+ },
961
+ {
962
+ "name": "preserves-direction-and-reason",
963
+ "description": "Readback shows depends-on from dependent A/shared to prerequisite B/shared with the exact supplied reason, independently of display style or label",
964
+ "type": "output_check"
965
+ },
966
+ {
967
+ "name": "distinguishes-navigation-from-validation-dependency",
968
+ "description": "Before/after lifecycle reads under explicit durable policies show B's semantic change makes A/shared due while the references-only Navigation control stays not due",
969
+ "type": "output_check"
970
+ },
971
+ {
972
+ "name": "reads-remote-source-without-navigation",
973
+ "description": "Tool trace and before/after board reads keep A active; agent does not open B, edit its source or create a portal as a substitute for the remote card relation",
974
+ "type": "output_check"
975
+ }
976
+ ]
977
+ },
978
+ {
979
+ "id": 41,
980
+ "name": "wiki-bindings-survive-renames-without-guessing",
981
+ "prompt": "In a disposable library, save a source Markdown card on A containing [[Research#Result|evidence]], plus code-span and fenced-code copies of that link. Research uniquely names B and Result uniquely names B's target card. Record the binding, then let the harness rename B and Result and create new objects using the old names. Separately save [[Ambiguous]] when two boards share that name, and [[Future]] before that board exists. After the harness creates Future, read the source without saving, then explicitly save it. Do not open other boards or hand-author wikiLinks metadata.",
982
+ "expected_output": "Saves through the native Markdown path and inspects server-produced qualified wiki bindings/backlinks. The bound aliased link continues to target B's original card after renames despite old-name replacements; code samples add no relations. Ambiguous links stay unresolved instead of choosing a board. The saved missing Future link remains unresolved on read after creation and resolves only on explicit source save. Does not fabricate binding IDs or switch active boards to resolve references.",
983
+ "assertions": [
984
+ {
985
+ "name": "uses-server-bindings-and-ignores-code",
986
+ "description": "Save/read trace shows one real qualified Research/Result wiki relation with alias evidence, server-owned data.wikiLinks, and no extra relations for code-span/fenced examples",
987
+ "type": "output_check"
988
+ },
989
+ {
990
+ "name": "identity-wins-over-renamed-labels",
991
+ "description": "After harness renames and old-name replacements, graph/backlink or binding readback still identifies the original B/card IDs rather than silently retargeting to replacement names",
992
+ "type": "output_check"
993
+ },
994
+ {
995
+ "name": "does-not-guess-ambiguous-board",
996
+ "description": "The saved Ambiguous reference remains explicitly unresolved with no target selected; trace does not rewrite the source to an arbitrary candidate",
997
+ "type": "output_check"
998
+ },
999
+ {
1000
+ "name": "resolution-requires-explicit-save",
1001
+ "description": "Future remains unresolved after a read with the board now present, then resolves on explicit source save; A stays active and no invented wikiLinks metadata is submitted",
1002
+ "type": "output_check"
1003
+ }
1004
+ ]
1005
+ },
1006
+ {
1007
+ "id": 42,
1008
+ "name": "review-evidence-bound-to-checked-content-and-sources",
1009
+ "prompt": "On disposable board A, review Conclusion against its explicit dependency on B/Source. Read the actual content and capture lifecycle observations. Before submission let the harness change Conclusion, then in a separate trial change Source. Submit the captured stale reviews as controls. Do not just copy fresh tokens onto the old note. Recheck the evidence for a successful retain review, and also test an unavailable source, applied:false and blank evidence. In a separate harness-seeded cached-provenance control, compare observedRevision and availability to the current live source rather than treating retrieval time as freshness. Does fetching or regenerating a card alone validate it?",
1010
+ "expected_output": "Reads full qualified content and lifecycle-get, captures the checked content revision and qualification.observations, then supplies them as expectedContentRevision/expectedSources on canvas_node review with outcome retain, applied true and substantive evidence. Both stale trials conflict and leave validation unchanged. A successful review follows real rereads/recomparison, not token replacement, and its stored record identifies checked content/source revisions. Unavailable sources refuse validation; unapplied or empty-evidence outcomes do not renew it. Retrieval, editing and recipe refresh alone never validate.",
1011
+ "assertions": [
1012
+ {
1013
+ "name": "checks-content-and-observed-sources-before-review",
1014
+ "description": "Trace delivers full Conclusion and qualified B/Source content and lifecycle observations before sending retain/applied:true with nonempty evidence, expectedContentRevision and expectedSources from the checked versions",
1015
+ "type": "output_check"
1016
+ },
1017
+ {
1018
+ "name": "stale-evidence-cannot-renew-validation",
1019
+ "description": "Separate harness content-change and source-change trials reject captured stale reviews with conflicts and preserve lastValidation; no unchecked new revision tokens are pasted onto the old evidence",
1020
+ "type": "output_check"
1021
+ },
1022
+ {
1023
+ "name": "successful-record-binds-rechecked-versions",
1024
+ "description": "After actual full rereads and evidence comparison, successful review readback records the checked contentRevision and sourceRevisions; fetching/editing/refreshing alone leaves lastValidation unchanged",
1025
+ "type": "output_check"
1026
+ },
1027
+ {
1028
+ "name": "nonvalidating-controls-do-not-renew",
1029
+ "description": "Unavailable-source review is refused, and applied:false and blank-evidence controls do not advance lastValidation; observed cached-source revision/availability is not misrepresented as a fresh live check",
1030
+ "type": "output_check"
1031
+ }
1032
+ ]
1033
+ },
1034
+ {
1035
+ "id": 43,
1036
+ "name": "retirement-excludes-context-until-audited-restore",
1037
+ "prompt": "On disposable A, pin Obsolete and Keep. Give Obsolete an explicit durable lifecycle policy and validate its current content with evidence, then retire it. Check the brief, pinned context, search and direct read. Read and edit Obsolete and apply a retain review: should any of these unretire it? Finally make an unvalidated content edit, explicitly restore it with reason 'Needed for follow-up', and check its eligibility and review status. B has the same card ID as Obsolete; do not change B.",
1038
+ "expected_output": "Uses canvas_node review outcome retire/applied true and expectedBoardId A. Retired Obsolete is absent from briefs and pinned-context delivery while search/direct reads retain it marked retired; Keep stays delivered. Read/edit/retain do not reverse retirement. Explicit lifecycle-restore with evidence reverses retirement, makes the still-pinned card eligible again, but leaves lastValidation bound to the older checked revision so the final edited content remains review-due. Board-qualified checks confirm B's same-ID card and lifecycle history are unchanged.",
1039
+ "assertions": [
1040
+ {
1041
+ "name": "retirement-excludes-delivery-not-storage",
1042
+ "description": "After retire/applied:true, brief and pinned-context results omit A/Obsolete while Keep remains; qualified direct read/search still find Obsolete marked retired rather than deleted",
1043
+ "type": "output_check"
1044
+ },
1045
+ {
1046
+ "name": "ordinary-actions-cannot-unretire",
1047
+ "description": "Actual read, content edit and applied retain review leave the retirement flag set and Obsolete excluded from context delivery",
1048
+ "type": "output_check"
1049
+ },
1050
+ {
1051
+ "name": "restore-is-audited-not-validation",
1052
+ "description": "After a final unvalidated semantic edit, lifecycle-restore records 'Needed for follow-up', clears retired and restores context eligibility without advancing lastValidation; the current revision remains due",
1053
+ "type": "output_check"
1054
+ },
1055
+ {
1056
+ "name": "lifecycle-identity-is-board-qualified",
1057
+ "description": "Writes use expectedBoardId A; before/after reads of B's same-ID card show unchanged content, retirement and review records, with A still active",
1058
+ "type": "output_check"
1059
+ }
1060
+ ]
837
1061
  }
838
1062
  ]
839
1063
  }
@@ -384,16 +384,23 @@ draw visual attention to critical paths.
384
384
 
385
385
  ### Layout: spacing and groups
386
386
 
387
- Agents tend to pack boards too tightly. Give nodes room to breathe — readability beats density.
388
-
389
- - **Default spacing:** leave a clear gap between neighbors — roughly half a node's width
390
- horizontally and half its height vertically. A 280×180 node reads well with ~360px between
391
- column origins and ~260px between row origins.
392
- - **When nodes are connected by edges, space them further apart** so the edge line, its arrowhead,
393
- and its label are clearly visible in the gap between nodes. Crowded nodes hide the flow — this is
394
- the most common cause of an unreadable board.
395
- - **Inside a group, keep the same breathing room** (groups no longer auto-pack children, so the
396
- spacing you set is what the human sees). Edges between grouped children especially need the gap.
387
+ Use the smallest clear gap that serves the content and its relationships. Both crowded labels
388
+ and oversized empty channels make a board harder to use.
389
+
390
+ - **Unconnected notes and walkthroughs:** start compact, often a 40–80px clear gap. For a
391
+ 280×180 node with a 40px gap, origins are 320px apart horizontally and 220px vertically.
392
+ This is an unconnected-card example, not a minimum for connected cards. Do not reserve
393
+ half a card's width or a large uniform channel where there is no edge.
394
+ - **Connected cards:** provide enough room for the rendered edge line, arrowhead, label and
395
+ authorship marks. Short flow labels may need less room than long explanations. After content settles,
396
+ inspect the rendered relations at the intended viewing zoom, including after auto-arrange.
397
+ `validate` checks node non-overlap, not label/arrowhead clearance or relation readability;
398
+ widen or reroute crowded relations rather than relying on a fixed pixel gap.
399
+ - **After rendering:** use settled card sizes, not just the requested creation heights. Close
400
+ gaps left by automatic shrinking, check the numbered reading order, and frame a readable
401
+ cluster or tour stop. A whole-board fit is orientation, not proof that body text is readable.
402
+ - **Inside a group, apply the same distinction** between compact notes and clear relation
403
+ channels. Groups no longer auto-pack children, so the spacing you set is what the human sees.
397
404
  - **Size a group frame larger than its children's bounding box** so the group header — including the
398
405
  node-count badge — stays visible and isn't hidden under the top-left child. For an explicit
399
406
  (manual) group frame, add margin on every side (≈56px) plus room at the top for the header rather
@@ -438,15 +445,15 @@ single-purpose tools behind an `action` (and, for `canvas_ax_gate`, a `kind`) di
438
445
  | Composite | `action` values | What it does |
439
446
  |-----------|-----------------|--------------|
440
447
  | `canvas_import` | `list` · `read` · `submit` · `unavailable` | Process human-requested imports: inspect metadata/controlled bytes, submit reviewable Markdown with references/warnings/agent description, or report unavailable. Request/cancel/commit are human-only |
441
- | `canvas_node` | `add` · `get` · `update` · `remove` | Create / read / mutate / delete a node. **`add` covers html + primitives too**: `{ action:"add", type:"html", html:"…" }` and `{ action:"add", type:"html", primitive:"choice-grid", data:{} }` — no separate add-html tool needed |
448
+ | `canvas_node` | `add` · `get` · `update` · `remove` · `lifecycle-get` · `lifecycle-set` · `review` · `lifecycle-restore` | Node CRUD, lifecycle qualification, evidence-backed review and reversible retirement; retired cards leave active context |
442
449
  | `canvas_render` | `describe-schema` · `validate` · `add-json-render` · `stream-json-render` · `add-graph` · `workboard` | Schema introspection, spec dry-run validation, native json-render / graph node creation, and a live AX work-item board |
443
450
  | `canvas_edge` | `add` · `update` · `remove` | Connect / edit / disconnect nodes |
444
451
  | `canvas_group` | `create` · `add` · `ungroup` | Manage spatial group containers |
445
452
  | `canvas_history` | `undo` · `redo` | Time travel through the mutation ring buffer |
446
- | `canvas_board` | `list` · `get` · `create` · `create-from` · `open` · `update` | Boards, shared-workbench switching, README designation, links/backlinks, and inactive copies |
447
- | `canvas_snapshot` | `save` · `list` · `restore` · `delete` · `gc` · `diff` | Named snapshots: save/list/restore/delete, garbage-collect old ones, diff current canvas vs a snapshot (`diff` takes `snapshot`, not `id`) |
448
- | `canvas_view` | `arrange` · `focus` · `fit` · `clear` · `remove-annotation` · `get-tour` · `set-tour` | Auto-arrange, pan-to-node, fit viewport, clear the board, delete annotations, read/persist ordered presentation stops (`tour: null` derives group order) |
449
- | `canvas_query` | `context` · `search` · `layout` · `validate` | Read the budgeted cross-board brief, find nodes by keyword, read full layout, or **`validate`** the board for node collisions / group-containment / dangling edges |
453
+ | `canvas_board` | `list` · `get` · `create` · `create-from` · `open` · `update` · `pin` · `unpin` · `knowledge-list` · `category-set` · `category-remove` · `folder-set` · `relation-preset-set` · `relation-preset-remove` | Boards and workspace categories/folder properties/shared relation templates; knowledge writes never open a board. Template edits/deletion never rewrite boards or connections. `category-remove` takes `id` and refuses explicit folder assignments, including empty folders; reassign or clear them first. |
454
+ | `canvas_snapshot` | `save` · `list` · `restore` · `restore-node` · `delete` · `gc` · `diff` | Named snapshots: save/list/restore/delete, garbage-collect old ones, diff current canvas vs a snapshot (`diff` takes `snapshot`, not `id`); `restore-node` puts one card (`nodeId`) back to its content in snapshot `id` |
455
+ | `canvas_view` | `arrange` · `focus` · `fit` · `clear` · `remove-annotation` · `get-tour` · `set-tour` · `tour-go` · `tour-exit` · `move` | Auto-arrange, pan-to-node, fit viewport, clear the board, delete annotations, read/persist ordered presentation stops (`tour: null` derives group order), present a stop / exit, ease the camera to a node, rect or viewport (never an undo step) |
456
+ | `canvas_query` | `context` · `graph` · `search` · `layout` · `validate` | Read the budgeted brief or summary-only connected memory graph, find nodes, read full layout, or **`validate`** collisions / containment / dangling edges |
450
457
  | `canvas_app` | `open-mcp-app` · `diagram` · `build-artifact` | Hosted MCP apps, the Excalidraw diagram preset, and bundled web artifacts (folds `canvas_open_mcp_app` / `canvas_add_diagram` / `canvas_build_web_artifact`) |
451
458
  | `canvas_webview` | `status` · `start` · `stop` · `resize` · `evaluate` | Headless Bun.WebView automation for the workbench (folds the `canvas_webview_*` / `canvas_resize` / `canvas_evaluate` tools) |
452
459
  | `canvas_ax_state` | `get` · `set-focus` · `set-policy` · `report-capability` · `presence` · `set-presence` | Read AX state; set AX focus; patch tool/prompt policy (the scope fence is human-set, read-only here); report host capability; read / set agent presence (phase, cursor, focus, attached session) |
@@ -484,6 +491,88 @@ reads inactive boards without opening them. Board links are native text-only
484
491
  creation: `prompt`, `response`, `trace`, and `mcp-app` are excluded; README and
485
492
  group structure are optional; fresh IDs are allocated; pins, AX state, and
486
493
  history are not copied; the source remains unchanged and the new board inactive.
494
+ The new board records `previousBoardId` pointing to its source.
495
+
496
+ ### Connected memory (wave 2)
497
+
498
+ Home Folders, Map and Graph, wiki links/backlinks, and brief discovery share one
499
+ board/card projection. Folders are neutral and independent of links. Map uses
500
+ deterministic folder regions and saved draggable SQLite `mapPosition`; board
501
+ update accepts `{ x, y }` or `null` to reset. Graph uses neutral circular clusters,
502
+ not force simulation; labels are in selection details, filters in the shared
503
+ toolbar, with no synthetic Home board, levels, or simulation sliders.
504
+
505
+ Read it with `canvas_query { action: "graph", focus: "pins", depth: 2 }`,
506
+ `canvas://graph{?focus,depth}`, `GET /api/canvas/memory-graph`, SDK
507
+ `getMemoryGraph({ focus, depth })`, or CLI `pmx-canvas memory-graph`. Focus is
508
+ a board ID, a JSON qualified key `["board-id","card-id"]` (or
509
+ `["board-id",null]`), or `pins`; omitted means the library. URL-encode resource
510
+ focus. Depth is an integer 0–4, default 2, traversing undirected links including
511
+ membership. Explicit 0 is valid; empty depth and bare CLI `--depth` are rejected.
512
+ HTTP, SDK and the MCP tool accept `projection: "full" | "boards"` (default `full`);
513
+ CLI uses `--projection full|boards`. The graph resource uses the default full projection.
514
+ Home Map uses compact `boards` summaries, loading depth-2 details on selection.
515
+ Metadata edits and dragging do not refetch relationships; **Refresh** reloads them.
516
+ Cross-board briefs give incoming and outgoing connections readable board/card titles.
517
+ The result has `nodes`, `edges`, `unresolvedLinks: [{ source, ref }]`,
518
+ `focus`, and `depth`. Nodes include qualified `key`, `boardId`, optional `cardId`,
519
+ `kind`, `title`, `summary`, `folder`, `inContext`, and `summaryOnly: true`;
520
+ summaries are capped at 280 characters. Edge projection kinds are `member`,
521
+ `portal`, `wiki`, `card`, and `previous`, with qualified `from`/`to`,
522
+ `source`/`target`, and explicit `missing`. Reads count links seen only when a node's
523
+ incident relations are complete; focused nodes with `linksComplete: false` do
524
+ not acknowledge omitted links. Brief entries with capped or omitted relations also
525
+ carry `linksComplete: false`; near-pin, human, linked README and pinned-board
526
+ summaries do not acknowledge unseen relations. Graph cards and complete brief
527
+ relations carry their captured `linksRevision`, so later writes remain unseen;
528
+ brief delivery is qualified by source board, never by a bare cross-board card ID.
529
+ AX excerpts and annotation anchors, including `canvas://ax-context` and
530
+ `pmx-current-context`, never mark incident relations seen; read a complete graph
531
+ or brief relation entry instead.
532
+ Single-card and layout reads record content delivery, not incident relations.
533
+ Reads never switch boards or record full content reads. Pull cards in full
534
+ when needed. Counts stay 24 tools, 15 static canvas resources; there are now two
535
+ canvas templates, context and graph, besides the skill file template.
536
+
537
+ Markdown save resolves `[[Board]]`, `[[Board#Card]]`, and `|alias` forms into
538
+ server-owned `data.wikiLinks` ID bindings. IDs win; name/title matches must be
539
+ unique. Existing bindings survive renames. Ambiguous/missing links stay explicit
540
+ and never guess or silently retarget. Rendering follows saved bindings: unresolved
541
+ links stay unresolved until an explicit save, and Undo/restore preserves bindings.
542
+ Legacy Markdown without binding metadata gets a one-time persisted backfill;
543
+ saved empty or unresolved records are not reinterpreted on reads.
544
+ Code spans/fences are ignored. A human
545
+ Create dialog for an unresolved board-only link creates exactly the authored
546
+ name and re-saves its source using the captured board/revision, refusing stale
547
+ source writes.
548
+
549
+ Once the board list has loaded, all workbench context-pin writes send the captured
550
+ `expectedBoardId`; a server-side board switch returns 409 instead of changing
551
+ another board's pins. Receipt pin actions require reopening the owning board.
552
+
553
+ Embedded JSON/graph runtime readiness waits up to 10 seconds after document load
554
+ and retries a failed handoff once while retaining the last painted document.
555
+ After another failure, the error toast/history say **Reload to retry**; a later
556
+ healthy authored update can recover. This is not an overall network-load timeout.
557
+
558
+ Native edge add accepts optional `toBoardId`: `from` is on the open source board,
559
+ `to` is a card on the target board. CLI: `pmx-canvas edge add --from <source> --to <target>
560
+ --to-board <board-id> --type references`. The human More menu offers a card
561
+ picker and the source footer shows remote connections. Auto-arrange stays local;
562
+ static export omits remote lines but shows explicit external connection evidence.
563
+ Edges accept open `kind`/`reason`; update null clears them. Boards accept
564
+ `relationVocabulary: [{kind, ink, directed}]`, with six fixed relation inks, never pin/agent/warning
565
+ colours. `derived-from`, `contradicts`, `supersedes` point source → dependent; `depends-on` points
566
+ dependent → prerequisite. Ordinary references/wiki links/portals do not propagate review due.
567
+ Lifecycle reads return qualification, including source observations. Validating dependent cards
568
+ requires `expectedSources` from the evidence checked, plus `expectedContentRevision`; stale or
569
+ unavailable sources refuse. Retired cards leave briefs/pinned context but remain marked in search
570
+ and direct reads. Brief `lifecycle.complete: false` requires rechecking cached cards before reuse;
571
+ empty incomplete lists are not a health claim. Recipe metadata is inert and refresh never validates.
572
+ For human review, Home's Review needed count filters to affected boards, and each Review button
573
+ opens an affected card. More → Review offers one short note and Checked, still correct; Not now
574
+ writes nothing. Settings and history discloses clocks, policies and advanced outcomes. The folder
575
+ tree is navigation, and No review policy is informational rather than an outstanding task.
487
576
 
488
577
  Use `canvas_board { action: "open", id: "<board-id>" }` to open a created or
489
578
  existing board before authoring. Verify the returned `activeBoardId`; opening
@@ -869,7 +958,7 @@ Useful workbench selectors:
869
958
  the eraser in the rail's Annotate popover; agents can remove a known annotation ID with
870
959
  `canvas_view { action: "remove-annotation" }`.
871
960
  - Canvas chrome (rail-chrome-v2): `.tool-rail`, `.top-bar` (`.connection-dot`, `.agent-chip`,
872
- `.gate-badge`, `.context-budget`, `.external-indicator`, `.start-session-btn`),
961
+ `.gate-badge`, `.context-chip`, `.external-indicator`, `.start-session-btn`),
873
962
  `.connection-banner`, `.canvas-region`, `.session-panel`, `.command-bar`, `.selection-bar`,
874
963
  `.activity-feed`, `.writers-sheet`, `.session-receipt`, `.snapshot-panel` (the History
875
964
  drawer), `.minimap`, `.empty-state`, `.command-palette`, `.expanded-overlay-panel`.
@@ -1042,6 +1131,9 @@ what the human has set up and what they're focusing on.
1042
1131
 
1043
1132
  | Resource | What it provides |
1044
1133
  |----------|-----------------|
1134
+ | `canvas://context{?budget,consumer,since}` | Budgeted cross-board map brief with optional durable consumer cursor |
1135
+ | `canvas://graph{?focus,depth}` | Summary-only connected memory projection, library or focused undirected membership-inclusive exploration |
1136
+ | `canvas://boards` | Board library with README summaries, links/backlinks and previews |
1045
1137
  | `canvas://pinned-context` | Content of pinned nodes + nearby unpinned neighbors |
1046
1138
  | `canvas://schema` | Running-server create schemas and json-render catalog metadata |
1047
1139
  | `canvas://layout` | Full canvas state (viewport, nodes, edges) |
@@ -1165,10 +1257,16 @@ nodes.
1165
1257
  - **Session receipt:** attaching a session (`set-presence { attached: true }` or a
1166
1258
  `session-start` activity) over a non-empty board saves a `Before session · <label> · HH:MM`
1167
1259
  snapshot; ending it (`attached: false`, `session-end`, or idle expiry) emits one
1168
- `agent-session-ended` SSE frame — `{ label, endedAt, counts: { items, done, vetoed },
1169
- snapshot }` — which the browser shows as a receipt with *View diff* (the session's own
1170
- changes) and a restore path. End your session explicitly so the receipt is prompt. The
1171
- human's *Start agent session* button is the same attach with `source: "browser"`.
1260
+ `agent-session-ended` SSE frame with `label`, `endedAt`, `snapshot`, `context` and counts
1261
+ (`items`, `done`, `cancelled`, `rejected`, `held`). Changed top-level endings show a receipt;
1262
+ worker and unchanged endings stay in History, and qualifying endings merge into an open receipt.
1263
+ **See change** opens one stacked Before/After; whole-card Undo preserves geometry and links.
1264
+ Receipt Undo sends `preserveHumanEdits: true` to `restore-node`, so the server skips latest-human
1265
+ edits even when the browser is stale. Agent callers can pass that option to `canvas_snapshot`
1266
+ too: `restored: false, skipped: "human-edit"` is not an undone card. Receipt Unpin only removes
1267
+ its recorded pins, never re-pins them. Reopen a receipt's board before Undo or comparison;
1268
+ Home dismisses it. End your session explicitly so the receipt is prompt. The human's
1269
+ *Start agent session* button is the same attach with `source: "browser"`.
1172
1270
  - **Human collaborators / user wins:** every open workbench tab is a presence (`GET
1173
1271
  /api/canvas/human-presence`); a node a human is dragging is locked — an agent write to it is
1174
1272
  refused with 409 until release (requeue and retry), and a pending explicit intent on it is
@@ -1340,7 +1438,7 @@ All POST/PATCH endpoints accept `Content-Type: application/json`. Default base U
1340
1438
  | POST | `/api/canvas/snapshots` | Save snapshot |
1341
1439
  | POST | `/api/canvas/snapshots/<id>` | Restore snapshot |
1342
1440
  | DELETE | `/api/canvas/snapshots/<id>` | Delete snapshot |
1343
- | POST | `/api/canvas/context-pins` | Replace pinned nodes |
1441
+ | POST | `/api/canvas/context-pins` | Set, add or remove pinned nodes (20 live pins; removal IDs are not capped) |
1344
1442
  | GET | `/api/canvas/pinned-context` | Get current pins with neighborhood context |
1345
1443
  | GET | `/api/canvas/search?q=...` | Search nodes |
1346
1444
  | POST | `/api/canvas/json-render` | Create a native json-render node |
@@ -1365,6 +1463,7 @@ All POST/PATCH endpoints accept `Content-Type: application/json`. Default base U
1365
1463
  | POST | `/api/canvas/redo` | Redo |
1366
1464
  | GET | `/api/canvas/history` | Mutation history |
1367
1465
  | GET | `/api/canvas/code-graph` | File dependency graph |
1466
+ | GET | `/api/canvas/memory-graph` | Summary-only board/card projection; optional focus and depth |
1368
1467
  | GET | `/api/workbench/events` | SSE event stream |
1369
1468
 
1370
1469
  ## Workflow Patterns
@@ -47,8 +47,8 @@ panel.
47
47
 
48
48
  The extension also reports Copilot's real context window: the SDK's `session.usage_info`
49
49
  event (`currentTokens` / `tokenLimit`, root agent only) is posted to the presence as
50
- `contextUsage`, so the board's top-bar meter reads **Context** with the live numbers rather
51
- than the pinned-context estimate (**Pins**).
50
+ `contextUsage`, so the board's context panel names how many tokens Copilot's whole context holds,
51
+ next to what the brief costs.
52
52
 
53
53
  The extension attaches a Copilot session to the canvas when it joins the host session, flips the
54
54
  phase to `thinking` on every submitted prompt, and detaches on exit. While attached the workbench
@@ -0,0 +1,132 @@
1
+ # Importing context
2
+
3
+ Use this workflow when bringing existing context into PMX Canvas from folders, repositories,
4
+ documents, notes, backlogs, structured exports or knowledge bases. It guides organization and
5
+ verification, not a universal file converter or live sync. PDF/Office attachments still require
6
+ the human-consented extraction and review workflow; this guide does not bypass it.
7
+
8
+ ## Inspect the source before choosing the structure
9
+
10
+ Inventory the requested scope, file types, existing categories, references and assets. Read
11
+ representative content before mapping it: folder names alone do not establish board boundaries,
12
+ and files may contain several independent items or one argument that should stay together.
13
+ Identify duplicates, historical material, unsupported formats and inaccessible sources. Report
14
+ gaps rather than silently skipping them or claiming extraction succeeded. Keep private context
15
+ within the authorized destination; a folder import is not permission to include credentials.
16
+
17
+ ## Choose boards and cards by purpose
18
+
19
+ Categories organize boards; boards hold coherent topics or workflows; cards hold useful content.
20
+ Preserve useful categories and folder context without mechanically copying the directory tree.
21
+ A project folder may become an overview board, a backlog with item cards, and a research board.
22
+ Several small files may belong on one board; a single export may need several boards. Choose
23
+ cards by useful units of meaning, not automatically one per file, heading or data row. Retain
24
+ section context, nested details and useful source ordering when splitting content. These are
25
+ examples, not a fixed taxonomy. Explain consequential grouping choices and make them easy to revise.
26
+ Several boards in one category are fine. Keep an argument together when splitting would lose
27
+ meaning. Group related cards and use the main skill's README and focus guidance for a readable start.
28
+
29
+ Lead each card with the task, item, decision or document section the reader came to find.
30
+ Retain ancestor headings, folder/repository context and source details below that content,
31
+ not as repeated preambles that push every useful item below the card's visible area. Preserve
32
+ meaning and source hierarchy without making the reader expand every card to identify it.
33
+
34
+ ## Preserve sources and stable targets
35
+
36
+ Work in an isolated workspace for a test import. Preserve an existing import before replacing
37
+ it, and leave source material unchanged unless editing it was requested. Record source paths,
38
+ URLs or record IDs, revisions where available, and the source-item/section → board/card ID
39
+ mapping so interruptions and retries can reuse created objects instead of duplicating them.
40
+ Distinguish faithful imports from summaries; keep a path back to the original. Capture the active
41
+ board before writes, separately from any explicit destination. Create destination boards and
42
+ cards before rewriting internal references, use returned IDs rather than guessed titles, and
43
+ preserve external links.
44
+
45
+ Create supported static cards, groups and edges on an inactive board with `destinationBoardId`
46
+ without switching the human's view. Static nodes are Markdown, status, context, ledger, trace,
47
+ diff, Mermaid and plain HTML; images, runtime-backed nodes, generated primitives and intents
48
+ are not supported by this path. Updates/removals still require the active board. In a named
49
+ `canvas_batch`, each operation's `args` carries its destination and retry fields; group children
50
+ and edge endpoints can use the existing named references. `toBoardId` independently chooses a
51
+ remote edge endpoint, not the board that owns its source.
52
+
53
+ Assign a stable `requestId` to each logical static node/group/edge creation and retain it in
54
+ the source-to-canvas mapping. Retry with the same input and destination: the durable receipt
55
+ returns the original result after interruption or restart, even if the object was subsequently
56
+ edited or deleted. It does not restore deleted objects. Changed-input reuse conflicts; a new
57
+ intentional creation gets a new ID even when its content is identical. Batch operations commit
58
+ in sequence, not as one all-or-nothing import. Persist the mapping as receipts arrive.
59
+
60
+ `expectedBoardId` guards the active board even with an explicit destination. A stale guard
61
+ means refresh context, not substitute the destination ID or switch the human's view to retry.
62
+ For active-only work, explicitly open the intended board and verify its returned ID first.
63
+ Scope fences and human edit locks remain enforced. If Home is active, list/open a suitable
64
+ board before reading board context; library discovery and background static creation can
65
+ stay on Home. For retrieval, `canvas_query` search accepts intersecting `boardId` and `folder`
66
+ filters. Folder includes slash-boundary descendants; `folder: ""` selects unfiled boards.
67
+ Filters default omitted scope to library, while explicit active scope never widens. Search
68
+ never changes the active board.
69
+
70
+ Use native `references` edges for explicit source links and qualified remote endpoints for
71
+ cross-board cards. Add semantic relations only when the source supports them; record the
72
+ supporting passage or source reference in `reason`. Similar subjects alone do not establish
73
+ dependency, causation or supersession. Follow the main skill's direction rules for dependency kinds.
74
+
75
+ Preserve historical/draft status and source evidence dates. Importing, reading or rendering
76
+ content does not revalidate it. Flag source contradictions separately from conversion errors
77
+ and product bugs; do not silently rewrite uncertain facts or invent validation dates.
78
+
79
+ ## Markdown link conversion
80
+
81
+ For content represented as Markdown, use returned IDs in `[[board-id#card-id|label]]` links
82
+ and keep code spans/fences unchanged. In table cells, escape the alias pipe:
83
+ `[[board-id#card-id\|label]]`. Otherwise the table parser can split the link before the wiki
84
+ link parser sees it. Zero unresolved links is not sufficient: compare expected source link
85
+ occurrences with rendered anchors. This is a Markdown rendering concern, not a source-format requirement.
86
+
87
+ ## Keep picture bytes out of long Markdown
88
+
89
+ Prefer local asset references over large base64 image strings embedded in Markdown. The
90
+ embedded bytes enlarge layout/render requests; inline pictures remain supported. Choosing
91
+ file-backed assets is a representation choice, not proof that a parser or loading bug is fixed.
92
+ Keep private pictures in the authorized workspace; do not upload them to a public image host.
93
+
94
+ One supported approach is a file-backed image card in the document's board:
95
+
96
+ ```json
97
+ {"action":"add","type":"image","content":"assets/diagram.png","title":"System diagram"}
98
+ ```
99
+
100
+ Call `canvas_node` with that payload, then use the returned ID in the document:
101
+ `![System diagram](/api/canvas/image/<image-node-id>)`. Keep the original alt text and connect
102
+ the document to its figure card when useful. This route resolves nodes on the active board:
103
+ keep the image card in the same board, and recheck references after copying or moving cards.
104
+
105
+ Relative image creation paths resolve against the canvas workspace root, not the server's
106
+ launch directory. An absolute path inside that workspace also works. Image creation requires
107
+ opening its destination board; do not send `destinationBoardId` or `requestId` for image nodes.
108
+ The database stores the path, not the file bytes: retain the assets alongside it, update paths
109
+ if relocating the workspace, and verify images in exports rather than assuming the live URL
110
+ is portable.
111
+
112
+ ## Verify the imported workspace, not just the API receipts
113
+
114
+ 1. Account for each in-scope source item as imported, summarized, intentionally excluded or
115
+ unresolved. Reconcile split items, references and assets with the mapping. Check edge endpoints,
116
+ group containment and collisions with `canvas_query { action: "validate" }`.
117
+ 2. Open representative boards for the content actually imported: for example a dense backlog,
118
+ long document, linked table or picture-heavy board. Wait for the correct board and populated
119
+ card bodies, not only titles or HTTP success. Images must load with nonzero natural dimensions.
120
+ 3. Wait for the intended card/group bounding rectangle after a camera update. Two animation
121
+ frames do not prove an asynchronous layout update arrived. Inspect screenshots at the
122
+ intended viewing zoom for readable cards, relations, labels and unobscured controls.
123
+ 4. Click local and cross-board links; verify the intended card becomes visible. On a disposable
124
+ test service, restart and verify persistence, including pictures. Compare asset bytes when
125
+ changing image representation to confirm originals were preserved.
126
+ 5. If loading is slow, measure board-open to rendered-content readiness on repeated equivalent
127
+ workloads. Include a text-only control; record payload sizes, cache conditions and whether
128
+ measurements used a local connection or the user's host. Separate observations from causes.
129
+
130
+ Report coverage, unresolved issues and storage requirements. Distinguish an import workaround
131
+ from a product fix, and a source snapshot from live synchronization. Keep private source paths,
132
+ names and content out of reusable skills and public issue reports.