pmx-canvas 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (341) 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 +66 -0
  4. package/Readme.md +131 -532
  5. package/dist/canvas/global.css +2759 -510
  6. package/dist/canvas/index.js +168 -107
  7. package/dist/canvas/mcp-app.html +2936 -632
  8. package/dist/json-render/index.css +81 -1
  9. package/dist/json-render/index.js +20 -20
  10. package/dist/types/client/canvas/BarHint.d.ts +12 -2
  11. package/dist/types/client/canvas/BoardLinkDialog.d.ts +3 -1
  12. package/dist/types/client/canvas/BoardPinButton.d.ts +10 -0
  13. package/dist/types/client/canvas/BoardSwitcher.d.ts +1 -1
  14. package/dist/types/client/canvas/CanvasViewport.d.ts +1 -1
  15. package/dist/types/client/canvas/CommandBar.d.ts +3 -4
  16. package/dist/types/client/canvas/ConnectionBanner.d.ts +2 -1
  17. package/dist/types/client/canvas/ContextChip.d.ts +3 -0
  18. package/dist/types/client/canvas/CrossBoardReferences.d.ts +5 -0
  19. package/dist/types/client/canvas/EdgeLayer.d.ts +14 -3
  20. package/dist/types/client/canvas/EmptyState.d.ts +4 -4
  21. package/dist/types/client/canvas/HomeGraphView.d.ts +2 -0
  22. package/dist/types/client/canvas/HomeMapView.d.ts +1 -0
  23. package/dist/types/client/canvas/HomeReviewView.d.ts +6 -0
  24. package/dist/types/client/canvas/HomeView.d.ts +9 -7
  25. package/dist/types/client/canvas/KnowledgeDialog.d.ts +4 -0
  26. package/dist/types/client/canvas/LifecycleChrome.d.ts +5 -0
  27. package/dist/types/client/canvas/LifecycleFields.d.ts +7 -0
  28. package/dist/types/client/canvas/LifecyclePanel.d.ts +1 -0
  29. package/dist/types/client/canvas/MemoryInspector.d.ts +7 -0
  30. package/dist/types/client/canvas/NearPinLayer.d.ts +14 -0
  31. package/dist/types/client/canvas/NodeContextMark.d.ts +40 -7
  32. package/dist/types/client/canvas/RelationPresetsDialog.d.ts +4 -0
  33. package/dist/types/client/canvas/RelationsPanel.d.ts +4 -0
  34. package/dist/types/client/canvas/SessionPanel.d.ts +2 -0
  35. package/dist/types/client/canvas/canvas-area.d.ts +1 -1
  36. package/dist/types/client/canvas/graph-geometry.d.ts +27 -0
  37. package/dist/types/client/canvas/graph-model.d.ts +37 -0
  38. package/dist/types/client/canvas/memory-layout.d.ts +23 -0
  39. package/dist/types/client/canvas/use-chrome-height.d.ts +2 -0
  40. package/dist/types/client/canvas/use-focus-trap.d.ts +1 -0
  41. package/dist/types/client/canvas/use-memory-graph.d.ts +8 -0
  42. package/dist/types/client/canvas/use-pan-zoom.d.ts +4 -1
  43. package/dist/types/client/icons.d.ts +0 -10
  44. package/dist/types/client/nodes/AxStepControls.d.ts +1 -1
  45. package/dist/types/client/nodes/HtmlNode.d.ts +1 -0
  46. package/dist/types/client/nodes/InlineMarkdownEditor.d.ts +4 -4
  47. package/dist/types/client/nodes/MarkdownNode.d.ts +5 -1
  48. package/dist/types/client/nodes/McpAppNode.d.ts +4 -4
  49. package/dist/types/client/nodes/viewer-runtime-state.d.ts +1 -1
  50. package/dist/types/client/state/boards-store.d.ts +81 -9
  51. package/dist/types/client/state/canvas-store.d.ts +14 -1
  52. package/dist/types/client/state/context-chip-store.d.ts +22 -0
  53. package/dist/types/client/state/context-status-store.d.ts +35 -0
  54. package/dist/types/client/state/intent-bridge.d.ts +11 -8
  55. package/dist/types/client/state/knowledge-store.d.ts +22 -0
  56. package/dist/types/client/state/near-pin-store.d.ts +44 -1
  57. package/dist/types/client/state/presence-store.d.ts +4 -4
  58. package/dist/types/client/state/presentation.d.ts +28 -0
  59. package/dist/types/client/state/relation-store.d.ts +10 -0
  60. package/dist/types/client/state/session-store.d.ts +41 -2
  61. package/dist/types/client/state/workspace-settings.d.ts +7 -0
  62. package/dist/types/client/types.d.ts +13 -1
  63. package/dist/types/client/utils/keyboard.d.ts +2 -0
  64. package/dist/types/client/utils/time-ago.d.ts +4 -0
  65. package/dist/types/mcp/context-uri-template.d.ts +3 -1
  66. package/dist/types/server/agent-presence.d.ts +10 -3
  67. package/dist/types/server/ax-context.d.ts +1 -1
  68. package/dist/types/server/canvas-db.d.ts +30 -7
  69. package/dist/types/server/canvas-operations.d.ts +24 -2
  70. package/dist/types/server/canvas-provenance.d.ts +22 -2
  71. package/dist/types/server/canvas-serialization.d.ts +2 -0
  72. package/dist/types/server/canvas-state.d.ts +93 -15
  73. package/dist/types/server/canvas-validation.d.ts +1 -1
  74. package/dist/types/server/context-brief.d.ts +94 -6
  75. package/dist/types/server/context-reads.d.ts +33 -7
  76. package/dist/types/server/edit-summary.d.ts +20 -0
  77. package/dist/types/server/index.d.ts +71 -10
  78. package/dist/types/server/knowledge-lifecycle.d.ts +221 -0
  79. package/dist/types/server/lifecycle-status.d.ts +10 -0
  80. package/dist/types/server/memory-graph.d.ts +9 -0
  81. package/dist/types/server/mutation-history.d.ts +2 -0
  82. package/dist/types/server/operations/ops/ax-shared.d.ts +1 -1
  83. package/dist/types/server/operations/ops/boards.d.ts +2 -1
  84. package/dist/types/server/operations/ops/lifecycle.d.ts +2 -0
  85. package/dist/types/server/operations/ops/memory-graph.d.ts +2 -0
  86. package/dist/types/server/operations/ops/nodes.d.ts +5 -0
  87. package/dist/types/server/operations/ops/query.d.ts +23 -0
  88. package/dist/types/server/operations/registry.d.ts +1 -0
  89. package/dist/types/server/placement.d.ts +7 -0
  90. package/dist/types/server/scope-fence.d.ts +2 -1
  91. package/dist/types/server/spatial-analysis.d.ts +6 -3
  92. package/dist/types/server/tour-control.d.ts +32 -0
  93. package/dist/types/server/wiki-links.d.ts +14 -0
  94. package/dist/types/server/workbench-auth.d.ts +2 -0
  95. package/dist/types/shared/agent-context.d.ts +2 -0
  96. package/dist/types/shared/agent-presence.d.ts +15 -12
  97. package/dist/types/shared/auto-arrange.d.ts +1 -0
  98. package/dist/types/shared/boards.d.ts +4 -4
  99. package/dist/types/shared/knowledge-lifecycle.d.ts +41 -0
  100. package/dist/types/shared/knowledge-presets.d.ts +6 -0
  101. package/dist/types/shared/lifecycle-status.d.ts +24 -0
  102. package/dist/types/shared/memory-graph.d.ts +53 -0
  103. package/dist/types/shared/relations.d.ts +68 -0
  104. package/dist/types/shared/semantic-attention.d.ts +2 -0
  105. package/dist/types/shared/tour.d.ts +38 -0
  106. package/dist/types/shared/workspace-settings.d.ts +11 -0
  107. package/docs/RELEASE.md +21 -3
  108. package/docs/adr-001-bun-only-runtime.md +7 -1
  109. package/docs/adr-002-shared-product-separate-runtimes.md +93 -0
  110. package/docs/api-reference.md +109 -0
  111. package/docs/ax-host-adapter-contract.md +1 -1
  112. package/docs/ax-state-contract.md +5 -4
  113. package/docs/cli.md +153 -15
  114. package/docs/demos/pmx-canvas-demo.mp4 +0 -0
  115. package/docs/design/AgentContext.dc.html +3 -3
  116. package/docs/design/BoardPins.dc.html +37 -22
  117. package/docs/design/Categories.dc.html +208 -0
  118. package/docs/design/CategoryEditor.dc.html +33 -0
  119. package/docs/design/Chrome.dc.html +55 -9
  120. package/docs/design/ContextChip.dc.html +224 -0
  121. package/docs/design/ContextChip600.dc.html +136 -0
  122. package/docs/design/EmptyState.dc.html +45 -0
  123. package/docs/design/Flows.dc.html +23 -1
  124. package/docs/design/HeaderMarks.dc.html +183 -0
  125. package/docs/design/Home.dc.html +19 -1
  126. package/docs/design/HomeGraph.dc.html +86 -202
  127. package/docs/design/HomeMap.dc.html +23 -1
  128. package/docs/design/HomeTeam.dc.html +32 -14
  129. package/docs/design/Lifecycle.dc.html +22 -0
  130. package/docs/design/Lifecycle600.dc.html +18 -0
  131. package/docs/design/LifecycleVariants.dc.html +157 -0
  132. package/docs/design/LinkAuthorship.dc.html +139 -0
  133. package/docs/design/LinksChanged.dc.html +203 -0
  134. package/docs/design/LinksOptions.dc.html +137 -0
  135. package/docs/design/LinksOptions600.dc.html +134 -0
  136. package/docs/design/NearPin.dc.html +9 -10
  137. package/docs/design/Pane600.dc.html +4 -3
  138. package/docs/design/Relations.dc.html +3 -2
  139. package/docs/design/Restore.dc.html +152 -0
  140. package/docs/design/SeeChange.dc.html +267 -0
  141. package/docs/design/Uses.dc.html +12 -6
  142. package/docs/design/canvas.json +146 -19
  143. package/docs/design.md +454 -18
  144. package/docs/environment.md +0 -1
  145. package/docs/evals/curation-effect.md +128 -0
  146. package/docs/http-api.md +465 -38
  147. package/docs/mcp.md +150 -19
  148. package/docs/node-types.md +58 -3
  149. package/docs/plans/design-gaps-2026-10-08.md +53 -0
  150. package/docs/plans/plan-009-tech-debt-backlog.md +379 -0
  151. package/docs/plans/plan-016-context-made-visible-wave-1.md +150 -5
  152. package/docs/plans/plan-017-knowledge-categories-and-lifecycle.md +175 -0
  153. package/docs/plans/plan-018-connected-memory-wave-2.md +594 -0
  154. package/docs/plans/plan-019-post-0.9-roadmap.md +198 -0
  155. package/docs/product-context-vision-2026-09.md +17 -1
  156. package/docs/product-vision-2026-09.md +1082 -43
  157. package/docs/product-vision-review-2026-09.md +13 -1
  158. package/docs/screenshots/workbench-live-dark.png +0 -0
  159. package/docs/screenshots/workbench-live-light.png +0 -0
  160. package/docs/sdk.md +62 -2
  161. package/package.json +1 -1
  162. package/plugins/pmx-canvas/com.github.copilot/extensions/pmx-canvas/runtime.json +1 -1
  163. package/plugins/pmx-canvas/plugin.json +1 -1
  164. package/plugins/pmx-canvas/runtime.json +1 -1
  165. package/plugins/pmx-canvas/tools.json +601 -22
  166. package/skills/pmx-canvas/SKILL.md +234 -43
  167. package/skills/pmx-canvas/evals/evals.json +62 -0
  168. package/skills/pmx-canvas/references/ax-html-control-surface.md +6 -0
  169. package/skills/pmx-canvas/references/full-reference.md +120 -21
  170. package/skills/pmx-canvas/references/github-copilot-app-adapter.md +2 -2
  171. package/skills/pmx-canvas/references/importing-context.md +132 -0
  172. package/skills/pmx-canvas/references/installing-pmx-canvas.md +6 -6
  173. package/skills/pmx-canvas/references/tours-and-recording.md +16 -1
  174. package/skills/pmx-canvas-testing/SKILL.md +20 -0
  175. package/src/cli/agent.ts +2 -0
  176. package/src/cli/commands/ax.ts +12 -0
  177. package/src/cli/commands/boards.ts +87 -11
  178. package/src/cli/commands/edges.ts +28 -0
  179. package/src/cli/commands/groups.ts +7 -0
  180. package/src/cli/commands/nodes.ts +4 -2
  181. package/src/cli/commands/query.ts +34 -2
  182. package/src/cli/commands/record.ts +199 -48
  183. package/src/cli/index.ts +7 -1
  184. package/src/client/App.tsx +177 -70
  185. package/src/client/canvas/AttentionHistory.tsx +0 -2
  186. package/src/client/canvas/BarHint.tsx +40 -2
  187. package/src/client/canvas/BoardCopyDialog.tsx +1 -1
  188. package/src/client/canvas/BoardFolderDialog.tsx +7 -7
  189. package/src/client/canvas/BoardLinkDialog.tsx +138 -33
  190. package/src/client/canvas/BoardPinButton.tsx +33 -0
  191. package/src/client/canvas/BoardSwitcher.tsx +26 -40
  192. package/src/client/canvas/CanvasNode.tsx +360 -237
  193. package/src/client/canvas/CanvasViewport.tsx +45 -7
  194. package/src/client/canvas/CommandBar.tsx +29 -23
  195. package/src/client/canvas/CommandPalette.tsx +5 -12
  196. package/src/client/canvas/ConnectionBanner.tsx +3 -3
  197. package/src/client/canvas/ContextChip.tsx +296 -0
  198. package/src/client/canvas/ContextMenu.tsx +63 -5
  199. package/src/client/canvas/CrossBoardReferences.tsx +60 -0
  200. package/src/client/canvas/EdgeLayer.tsx +339 -76
  201. package/src/client/canvas/EmptyState.tsx +33 -18
  202. package/src/client/canvas/ExpandedNodeOverlay.tsx +72 -40
  203. package/src/client/canvas/ExternalWriters.tsx +57 -42
  204. package/src/client/canvas/HomeGraphView.tsx +942 -0
  205. package/src/client/canvas/HomeMapView.tsx +641 -0
  206. package/src/client/canvas/HomeReviewView.tsx +167 -0
  207. package/src/client/canvas/HomeView.tsx +687 -160
  208. package/src/client/canvas/IntentLayer.tsx +19 -12
  209. package/src/client/canvas/KnowledgeDialog.tsx +488 -0
  210. package/src/client/canvas/LifecycleChrome.tsx +133 -0
  211. package/src/client/canvas/LifecycleFields.tsx +91 -0
  212. package/src/client/canvas/LifecyclePanel.tsx +533 -0
  213. package/src/client/canvas/MemoryInspector.tsx +104 -0
  214. package/src/client/canvas/Minimap.tsx +3 -3
  215. package/src/client/canvas/NearPinLayer.tsx +187 -0
  216. package/src/client/canvas/NodeContextMark.tsx +175 -97
  217. package/src/client/canvas/Presentation.tsx +23 -57
  218. package/src/client/canvas/RelationPresetsDialog.tsx +413 -0
  219. package/src/client/canvas/RelationsPanel.tsx +82 -0
  220. package/src/client/canvas/SelectionBar.tsx +3 -6
  221. package/src/client/canvas/SessionPanel.tsx +90 -50
  222. package/src/client/canvas/SessionReceipt.tsx +311 -39
  223. package/src/client/canvas/ShortcutOverlay.tsx +1 -1
  224. package/src/client/canvas/SnapshotPanel.tsx +27 -36
  225. package/src/client/canvas/ToolRail.tsx +367 -192
  226. package/src/client/canvas/TopBar.tsx +354 -124
  227. package/src/client/canvas/canvas-area.ts +10 -3
  228. package/src/client/canvas/graph-geometry.ts +195 -0
  229. package/src/client/canvas/graph-model.ts +254 -0
  230. package/src/client/canvas/memory-layout.ts +106 -0
  231. package/src/client/canvas/use-chrome-height.ts +20 -0
  232. package/src/client/canvas/use-focus-trap.ts +31 -5
  233. package/src/client/canvas/use-memory-graph.ts +58 -0
  234. package/src/client/canvas/use-node-drag.ts +2 -1
  235. package/src/client/canvas/use-pan-zoom.ts +64 -7
  236. package/src/client/icons.tsx +0 -63
  237. package/src/client/mcp-app/style.css +0 -6
  238. package/src/client/nodes/AxStepControls.tsx +74 -50
  239. package/src/client/nodes/BoardNode.tsx +5 -1
  240. package/src/client/nodes/ContextNode.tsx +18 -11
  241. package/src/client/nodes/ExtAppFrame.tsx +0 -1
  242. package/src/client/nodes/FileNode.tsx +46 -42
  243. package/src/client/nodes/HtmlNode.tsx +44 -2
  244. package/src/client/nodes/ImageNode.tsx +1 -1
  245. package/src/client/nodes/InlineFormatBar.tsx +6 -9
  246. package/src/client/nodes/InlineMarkdownEditor.tsx +56 -17
  247. package/src/client/nodes/MarkdownNode.tsx +377 -109
  248. package/src/client/nodes/McpAppNode.tsx +50 -20
  249. package/src/client/nodes/MdFormatBar.tsx +21 -18
  250. package/src/client/nodes/PromptNode.tsx +1 -1
  251. package/src/client/nodes/ResponseNode.tsx +1 -1
  252. package/src/client/nodes/viewer-runtime-state.ts +54 -22
  253. package/src/client/state/attention-bridge.ts +64 -15
  254. package/src/client/state/boards-store.ts +193 -39
  255. package/src/client/state/canvas-store.ts +99 -12
  256. package/src/client/state/context-chip-store.ts +70 -0
  257. package/src/client/state/context-status-store.ts +53 -0
  258. package/src/client/state/intent-bridge.ts +51 -30
  259. package/src/client/state/knowledge-store.ts +43 -0
  260. package/src/client/state/near-pin-store.ts +115 -6
  261. package/src/client/state/presence-store.ts +7 -10
  262. package/src/client/state/presentation.ts +91 -0
  263. package/src/client/state/relation-store.ts +81 -0
  264. package/src/client/state/session-store.ts +144 -18
  265. package/src/client/state/sse-bridge.ts +206 -29
  266. package/src/client/state/workspace-settings.ts +11 -0
  267. package/src/client/theme/global.css +2759 -510
  268. package/src/client/types.ts +12 -0
  269. package/src/client/utils/keyboard.ts +10 -0
  270. package/src/client/utils/time-ago.ts +14 -0
  271. package/src/json-render/renderer/index.css +6 -1
  272. package/src/json-render/renderer/index.tsx +31 -1
  273. package/src/mcp/canvas-app.ts +12 -2
  274. package/src/mcp/context-uri-template.ts +7 -4
  275. package/src/mcp/server.ts +63 -41
  276. package/src/mcp/workbench-app.ts +39 -6
  277. package/src/server/agent-presence.ts +128 -28
  278. package/src/server/ax-context.ts +27 -13
  279. package/src/server/board-export.ts +12 -1
  280. package/src/server/canvas-db.ts +331 -42
  281. package/src/server/canvas-operations.ts +196 -84
  282. package/src/server/canvas-provenance.ts +53 -22
  283. package/src/server/canvas-serialization.ts +2 -0
  284. package/src/server/canvas-state.ts +950 -122
  285. package/src/server/canvas-validation.ts +9 -2
  286. package/src/server/context-brief.ts +345 -38
  287. package/src/server/context-reads.ts +179 -30
  288. package/src/server/demo-state.json +355 -24
  289. package/src/server/edit-summary.ts +74 -0
  290. package/src/server/html-surface.ts +8 -1
  291. package/src/server/index.ts +203 -13
  292. package/src/server/knowledge-lifecycle.ts +304 -0
  293. package/src/server/lifecycle-status.ts +232 -0
  294. package/src/server/memory-graph.ts +166 -0
  295. package/src/server/mutation-history.ts +18 -6
  296. package/src/server/operations/composites.ts +32 -11
  297. package/src/server/operations/http.ts +7 -2
  298. package/src/server/operations/index.ts +4 -0
  299. package/src/server/operations/mcp.ts +32 -1
  300. package/src/server/operations/ops/ax-presence.ts +1 -1
  301. package/src/server/operations/ops/ax-read.ts +57 -6
  302. package/src/server/operations/ops/ax-timeline.ts +28 -2
  303. package/src/server/operations/ops/backup.ts +5 -3
  304. package/src/server/operations/ops/batch.ts +35 -4
  305. package/src/server/operations/ops/boards.ts +188 -47
  306. package/src/server/operations/ops/canvas-wire.ts +31 -1
  307. package/src/server/operations/ops/edges.ts +36 -2
  308. package/src/server/operations/ops/groups.ts +6 -1
  309. package/src/server/operations/ops/json-render.ts +5 -1
  310. package/src/server/operations/ops/lifecycle.ts +262 -0
  311. package/src/server/operations/ops/memory-graph.ts +45 -0
  312. package/src/server/operations/ops/nodes.ts +107 -24
  313. package/src/server/operations/ops/query.ts +281 -68
  314. package/src/server/operations/ops/snapshots.ts +73 -1
  315. package/src/server/operations/ops/validate.ts +5 -1
  316. package/src/server/operations/ops/viewport.ts +97 -3
  317. package/src/server/operations/registry.ts +77 -26
  318. package/src/server/placement.ts +29 -0
  319. package/src/server/scope-fence.ts +78 -6
  320. package/src/server/server.ts +115 -16
  321. package/src/server/spatial-analysis.ts +48 -23
  322. package/src/server/tour-control.ts +82 -0
  323. package/src/server/wiki-links.ts +137 -0
  324. package/src/server/workbench-auth.ts +11 -0
  325. package/src/shared/agent-context.ts +3 -0
  326. package/src/shared/agent-presence.ts +15 -15
  327. package/src/shared/auto-arrange.ts +2 -0
  328. package/src/shared/boards.ts +4 -4
  329. package/src/shared/knowledge-lifecycle.ts +22 -0
  330. package/src/shared/knowledge-presets.ts +80 -0
  331. package/src/shared/lifecycle-status.ts +26 -0
  332. package/src/shared/memory-graph.ts +74 -0
  333. package/src/shared/relations.ts +98 -0
  334. package/src/shared/semantic-attention.ts +15 -1
  335. package/src/shared/tour.ts +23 -5
  336. package/src/shared/workspace-settings.ts +13 -0
  337. package/dist/types/client/canvas/ContextPinBar.d.ts +0 -1
  338. package/dist/types/client/canvas/FocusFieldLayer.d.ts +0 -1
  339. package/dist/types/client/canvas/kind-colors.d.ts +0 -3
  340. package/dist/types/server/agent-context.d.ts +0 -22
  341. package/src/client/canvas/ContextPinBar.tsx +0 -25
@@ -68,8 +68,8 @@ export interface SpatialContext {
68
68
  }[];
69
69
  annotations: SpatialAnnotationContext[];
70
70
  }
71
- /** Euclidean distance between two node centers */
72
- export declare function centerDistance(a: CanvasNodeState, b: CanvasNodeState): number;
71
+ /** Gap distance — how far apart two nodes are edge-to-edge (0 if overlapping) */
72
+ export declare function gapDistance(a: CanvasNodeState, b: CanvasNodeState): number;
73
73
  /**
74
74
  * Detect proximity clusters using single-linkage clustering.
75
75
  * Two nodes are "close" if their edge-to-edge gap is within the threshold.
@@ -78,9 +78,12 @@ export declare function centerDistance(a: CanvasNodeState, b: CanvasNodeState):
78
78
  */
79
79
  export declare function detectClusters(nodes: CanvasNodeState[], proximityThreshold?: number): SpatialCluster[];
80
80
  /**
81
- * Find the nearest unpinned nodes to each pinned node.
81
+ * Find the nearest unpinned nodes by their edge-to-edge gap from each pin.
82
+ * The inclusive distance limit is in world pixels, independent of card size.
82
83
  */
83
84
  export declare function findNeighborhoods(nodes: CanvasNodeState[], pinnedIds: Set<string>, maxNeighbors?: number, maxDistance?: number): SpatialContext['pinnedNeighborhoods'];
85
+ /** Shared lexical relevance for cards and library metadata. Scores are ranking details. */
86
+ export declare function searchRelevance(title: string, fields: Array<[string, number]>, query: string): number;
84
87
  /**
85
88
  * Full-text search across node titles and content.
86
89
  * Returns matching nodes with relevance score.
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Driving a board tour: the shared stop cursor and eased camera moves.
3
+ *
4
+ * Navigation, not editing: nothing here records undo history, and the cursor
5
+ * is in-memory (like presence) — a restart or board switch starts over at the
6
+ * first stop. The browser animates; the server only decides WHERE to go and
7
+ * broadcasts it, so an agent and every presenting viewer agree on the stop.
8
+ *
9
+ * This module must never import server.ts or index.ts.
10
+ */
11
+ import { type Camera, type Tour, type TourStop } from '../shared/tour.js';
12
+ export type TourStep = number | 'next' | 'previous';
13
+ export interface TourStepResult {
14
+ index: number;
15
+ total: number;
16
+ stop: TourStop;
17
+ }
18
+ export declare function currentTour(): Tour;
19
+ /** The stop the tour is on for the active board, or null when not touring. */
20
+ export declare function tourPosition(tour?: Tour): number | null;
21
+ /** Move the shared cursor. `next`/`previous` clamp at the ends; an explicit index must exist. */
22
+ export declare function goToTourStop(step: TourStep): TourStepResult;
23
+ export declare function exitTour(): void;
24
+ /**
25
+ * Resolve an eased camera move and store its end camera as the board viewport
26
+ * (unrecorded). The size is the last window a browser reported, so this is the
27
+ * server's best estimate; the browser re-resolves against its real canvas area.
28
+ */
29
+ export declare function moveCamera(input: unknown): {
30
+ stop: TourStop;
31
+ viewport: Camera;
32
+ };
@@ -0,0 +1,14 @@
1
+ import type { MemoryTarget, WikiLink } from '../shared/memory-graph.js';
2
+ export declare function wikiReferences(content: string): string[];
3
+ export interface WikiBoard {
4
+ id: string;
5
+ name: string;
6
+ cards: Array<{
7
+ id: string;
8
+ title: string;
9
+ }>;
10
+ }
11
+ /** IDs win over names; title matches must be unique. Never retarget an already bound link. */
12
+ export declare function resolveWikiLinks(content: string, previous: WikiLink[], boards: WikiBoard[]): WikiLink[];
13
+ /** Only server-owned bindings may navigate; the client still sanitizes rendered HTML. */
14
+ export declare function renderWikiMarkdown(content: string, links: WikiLink[], exists: (target: MemoryTarget) => boolean): string;
@@ -1,3 +1,5 @@
1
1
  /** Per-process capability used only to distinguish workbench clicks from HTTP agents. */
2
2
  export declare const workbenchToken: string;
3
3
  export declare function isWorkbenchToken(value: string | null): boolean;
4
+ /** Refuse an old tab's writes after a daemon restart, without downgrading its actor. */
5
+ export declare function refuseStaleWorkbenchWrite(req: Request): Response | null;
@@ -5,6 +5,8 @@ export interface AgentContextNode {
5
5
  kind: string;
6
6
  title: string | null;
7
7
  content: string | null;
8
+ /** Context excerpts do not serialize the card's complete incident relations. */
9
+ linksComplete?: false;
8
10
  metadata?: Record<string, unknown>;
9
11
  position?: {
10
12
  x: number;
@@ -45,20 +45,28 @@ export interface AgentPresence {
45
45
  opCount: number;
46
46
  /**
47
47
  * The agent's REAL context window, when its host reports it (tokens used /
48
- * window size). Null when no adapter reports — the top-bar meter then shows
49
- * the pinned-context estimate against the configured budget instead, and
50
- * says so.
48
+ * window size). Null when no adapter reports — the context chip then shows
49
+ * the brief's size against its budget instead.
51
50
  */
52
51
  contextUsage: {
53
52
  used: number;
54
53
  total: number;
55
54
  } | null;
56
55
  lastSeenAt: string;
56
+ /**
57
+ * What this session has done since it attached (AgentContext.dc.html lens:
58
+ * "Claude · this session"): ids of the cards read, created, edited and
59
+ * pinned on the open board. Only on attached presences; counts every agent
60
+ * on the board, like the receipt.
61
+ */
62
+ session?: SessionTouches;
57
63
  }
58
- export interface ContextBudget {
59
- /** Estimated tokens of the pinned-context payload. */
60
- used: number;
61
- total: number;
64
+ export interface SessionTouches {
65
+ startedAt: string;
66
+ read: string[];
67
+ created: string[];
68
+ edited: string[];
69
+ pinned: string[];
62
70
  }
63
71
  /**
64
72
  * One agent write, as the External Steering activity feed lists it. Derived
@@ -79,7 +87,6 @@ export interface AgentActivityEntry {
79
87
  }
80
88
  export interface AgentPresenceSnapshot {
81
89
  presences: AgentPresence[];
82
- budget: ContextBudget;
83
90
  /** True when any presence is attached — the master gate for agent chrome. */
84
91
  sessionActive: boolean;
85
92
  /** Most recent agent writes, newest first (bounded by MAX_ACTIVITY_ENTRIES). */
@@ -98,8 +105,6 @@ export declare const PRESENCE_TOOLING_SETTLE_MS = 4000;
98
105
  * "Thinking" chips on a silent board. */
99
106
  export declare const PRESENCE_THINKING_SETTLE_MS: number;
100
107
  export declare const MAX_PRESENCES = 16;
101
- /** Default `budget.total` when `PMX_CANVAS_CONTEXT_BUDGET_TOKENS` is unset. */
102
- export declare const CONTEXT_BUDGET_DEFAULT_TOKENS = 32000;
103
108
  /**
104
109
  * Source labels that name a TRANSPORT, not an agent. A write arriving under
105
110
  * one of these while exactly one session is attached is the attached agent's
@@ -117,7 +122,5 @@ export declare const HUMAN_STARTED_SESSION_LABEL = "Agent session";
117
122
  export declare function isSessionActive(presences: readonly AgentPresence[]): boolean;
118
123
  /** Writers that are live but not attached — the External Steering mode. */
119
124
  export declare function externalWriters(presences: readonly AgentPresence[]): AgentPresence[];
120
- /** Rough token estimate for a JSON payload (chars / 4) — good enough for a meter. */
121
- export declare function estimateTokens(text: string): number;
122
125
  /** Chip label per phase — shared by the top-bar chip and the on-canvas cursor chip. */
123
126
  export declare function agentPhaseLabel(presence: Pick<AgentPresence, 'phase' | 'detail'>): string;
@@ -18,6 +18,7 @@ export interface ArrangeEdge {
18
18
  id: string;
19
19
  from: string;
20
20
  to: string;
21
+ toBoardId?: string;
21
22
  }
22
23
  export interface AutoArrangeResult {
23
24
  nodePositions: Map<string, ArrangePosition>;
@@ -1,6 +1,6 @@
1
- /** The Home category migrated 0.6 snapshots land on, so they do not bury the boards in use. */
2
- export declare const MIGRATED_SNAPSHOT_CATEGORY = "From old snapshots";
1
+ /** The Home folder migrated 0.6 snapshots land on, so they do not bury the boards in use. */
2
+ export declare const MIGRATED_SNAPSHOT_FOLDER = "From old snapshots";
3
3
  /** Slash-separated folder paths shared by the UI, HTTP/MCP and SDK. */
4
- export declare function normalizeBoardCategory(value: string | null): string | null;
4
+ export declare function normalizeBoardFolder(value: string | null): string | null;
5
5
  /** Includes implicit parents, so a board in A/B can also be moved into A. */
6
- export declare function categoryAncestors(path: string): string[];
6
+ export declare function folderAncestors(path: string): string[];
@@ -0,0 +1,41 @@
1
+ import { z } from 'zod';
2
+ /** The same policy contract validates workspace writes and browser drafts. */
3
+ export declare const lifecycleSchema: z.ZodObject<{
4
+ decayType: z.ZodEnum<{
5
+ reality: "reality";
6
+ decision: "decision";
7
+ dependency: "dependency";
8
+ relevance: "relevance";
9
+ }>;
10
+ rate: z.ZodEnum<{
11
+ fast: "fast";
12
+ medium: "medium";
13
+ slow: "slow";
14
+ durable: "durable";
15
+ }>;
16
+ triggers: z.ZodArray<z.ZodString>;
17
+ revalidationMethod: z.ZodString;
18
+ cadenceDays: z.ZodOptional<z.ZodNumber>;
19
+ }, z.core.$strict>;
20
+ export declare const categorySchema: z.ZodObject<{
21
+ decayType: z.ZodEnum<{
22
+ reality: "reality";
23
+ decision: "decision";
24
+ dependency: "dependency";
25
+ relevance: "relevance";
26
+ }>;
27
+ rate: z.ZodEnum<{
28
+ fast: "fast";
29
+ medium: "medium";
30
+ slow: "slow";
31
+ durable: "durable";
32
+ }>;
33
+ triggers: z.ZodArray<z.ZodString>;
34
+ revalidationMethod: z.ZodString;
35
+ cadenceDays: z.ZodOptional<z.ZodNumber>;
36
+ id: z.ZodString;
37
+ name: z.ZodString;
38
+ glyph: z.ZodString;
39
+ }, z.core.$strict>;
40
+ export type Lifecycle = z.infer<typeof lifecycleSchema>;
41
+ export type KnowledgeCategory = z.infer<typeof categorySchema>;
@@ -0,0 +1,6 @@
1
+ import type { KnowledgeCategory } from '../server/knowledge-lifecycle.js';
2
+ /** Editable starter data. No runtime behavior depends on these names or ids. */
3
+ export declare const KNOWLEDGE_PRESETS: Record<string, {
4
+ categories: KnowledgeCategory[];
5
+ folders: Record<string, string>;
6
+ }>;
@@ -0,0 +1,24 @@
1
+ import type { MemoryTarget } from './memory-graph.js';
2
+ export interface SourceQualification extends MemoryTarget {
3
+ title: string;
4
+ reasons: string[];
5
+ unavailable?: true;
6
+ contentRevision?: number;
7
+ observedRevision?: number;
8
+ observedAt?: string;
9
+ }
10
+ export interface LifecycleQualification {
11
+ retired: boolean;
12
+ unknown: boolean;
13
+ due: boolean;
14
+ reasons: string[];
15
+ changedSinceRead: boolean;
16
+ lastReadAt: string | null;
17
+ lastValidatedAt: string | null;
18
+ contentRevision: number;
19
+ contentChangedAt: string | null;
20
+ /** The revisions a validating reviewer must have inspected, qualified by source relation. */
21
+ observations: Record<string, number | null>;
22
+ sources: SourceQualification[];
23
+ relevance: 'card-pinned' | 'board-pinned' | 'not-selected';
24
+ }
@@ -0,0 +1,53 @@
1
+ /** Board-qualified identities: card IDs alone are not unique across a library. */
2
+ export interface MemoryTarget {
3
+ boardId: string;
4
+ cardId?: string;
5
+ }
6
+ export interface WikiLink {
7
+ ref: string;
8
+ target?: MemoryTarget;
9
+ }
10
+ export declare function wikiLinksFromData(data: Record<string, unknown>): WikiLink[];
11
+ export declare const memoryKey: (target: MemoryTarget) => string;
12
+ export interface MemoryGraphNode extends MemoryTarget {
13
+ key: string;
14
+ kind: 'board' | 'card';
15
+ title: string;
16
+ summary: string;
17
+ folder: string | null;
18
+ inContext: boolean;
19
+ summaryOnly: true;
20
+ /** False when the focused view omits incident relations; cannot acknowledge all links. */
21
+ linksComplete?: boolean;
22
+ /** Card link revision captured with this projection. */
23
+ linksRevision?: number;
24
+ type?: string;
25
+ nodeCount?: number;
26
+ position?: {
27
+ x: number;
28
+ y: number;
29
+ };
30
+ }
31
+ export interface MemoryGraphEdge {
32
+ id: string;
33
+ from: string;
34
+ to: string;
35
+ kind: 'member' | 'portal' | 'wiki' | 'card' | 'previous';
36
+ relationKind?: string;
37
+ reason?: string;
38
+ label?: string;
39
+ type?: string;
40
+ source: MemoryTarget;
41
+ target: MemoryTarget;
42
+ missing: boolean;
43
+ }
44
+ export interface MemoryGraph {
45
+ nodes: MemoryGraphNode[];
46
+ edges: MemoryGraphEdge[];
47
+ unresolvedLinks: Array<{
48
+ source: MemoryTarget;
49
+ ref: string;
50
+ }>;
51
+ focus: string | null;
52
+ depth: number;
53
+ }
@@ -0,0 +1,68 @@
1
+ import { z } from 'zod';
2
+ export declare const relationKindSchema: z.ZodString;
3
+ export declare const relationReasonSchema: z.ZodString;
4
+ export declare const relationDefinitionSchema: z.ZodObject<{
5
+ kind: z.ZodString;
6
+ ink: z.ZodEnum<{
7
+ supports: "supports";
8
+ contradicts: "contradicts";
9
+ cites: "cites";
10
+ derived: "derived";
11
+ informs: "informs";
12
+ related: "related";
13
+ }>;
14
+ directed: z.ZodBoolean;
15
+ }, z.core.$strict>;
16
+ export declare const relationVocabularySchema: z.ZodArray<z.ZodObject<{
17
+ kind: z.ZodString;
18
+ ink: z.ZodEnum<{
19
+ supports: "supports";
20
+ contradicts: "contradicts";
21
+ cites: "cites";
22
+ derived: "derived";
23
+ informs: "informs";
24
+ related: "related";
25
+ }>;
26
+ directed: z.ZodBoolean;
27
+ }, z.core.$strict>>;
28
+ export type RelationDefinition = z.infer<typeof relationDefinitionSchema>;
29
+ export declare const relationPresetSchema: z.ZodObject<{
30
+ id: z.ZodString;
31
+ name: z.ZodString;
32
+ vocabulary: z.ZodArray<z.ZodObject<{
33
+ kind: z.ZodString;
34
+ ink: z.ZodEnum<{
35
+ supports: "supports";
36
+ contradicts: "contradicts";
37
+ cites: "cites";
38
+ derived: "derived";
39
+ informs: "informs";
40
+ related: "related";
41
+ }>;
42
+ directed: z.ZodBoolean;
43
+ }, z.core.$strict>>;
44
+ }, z.core.$strict>;
45
+ export type RelationPreset = z.infer<typeof relationPresetSchema>;
46
+ export declare const RELATION_KINDS: RelationDefinition[];
47
+ export declare const RELATION_PRESETS: Record<string, RelationDefinition[]>;
48
+ export declare function relationPreset(vocabulary?: RelationDefinition[]): string | null;
49
+ export declare function relationKind(edge: {
50
+ kind?: string;
51
+ type?: string;
52
+ }): string;
53
+ /** Direction is semantic, not inferred from ink or arrow decoration. */
54
+ export declare function relationSourceEnd(edge: {
55
+ kind?: string;
56
+ type?: string;
57
+ }): 'from' | 'to' | null;
58
+ export declare function relationDefinition(edge: {
59
+ kind?: string;
60
+ type?: string;
61
+ }, vocabulary?: RelationDefinition[]): RelationDefinition;
62
+ /** Keep the authored label and the explanation, rather than treating a label as a kind. */
63
+ export declare function relationText(edge: {
64
+ kind?: string;
65
+ type?: string;
66
+ label?: string | null;
67
+ reason?: string;
68
+ }): string;
@@ -12,6 +12,7 @@ export interface SemanticWatchEdgeSummary {
12
12
  edgeType: CanvasEdge['type'];
13
13
  fromId: string;
14
14
  toId: string;
15
+ toBoardId?: string;
15
16
  fromTitle: string | null;
16
17
  toTitle: string | null;
17
18
  }
@@ -84,6 +85,7 @@ export interface SemanticAttentionSnapshot {
84
85
  }
85
86
  export declare function formatCompactWatchEvent(event: SemanticWatchEvent): string;
86
87
  export declare class SemanticWatchReducer {
88
+ private currentBoardId;
87
89
  private currentLayout;
88
90
  private currentPins;
89
91
  private previousSpatial;
@@ -4,9 +4,39 @@ export declare const cameraSchema: z.ZodObject<{
4
4
  y: z.ZodNumber;
5
5
  scale: z.ZodNumber;
6
6
  }, z.core.$strip>;
7
+ /** A world-space box: `{ x, y }` is its top-left corner. */
8
+ export declare const rectSchema: z.ZodObject<{
9
+ x: z.ZodNumber;
10
+ y: z.ZodNumber;
11
+ width: z.ZodNumber;
12
+ height: z.ZodNumber;
13
+ }, z.core.$strip>;
14
+ export declare const tourTargetSchema: z.ZodUnion<readonly [z.ZodObject<{
15
+ nodeId: z.ZodString;
16
+ }, z.core.$strict>, z.ZodObject<{
17
+ rect: z.ZodObject<{
18
+ x: z.ZodNumber;
19
+ y: z.ZodNumber;
20
+ width: z.ZodNumber;
21
+ height: z.ZodNumber;
22
+ }, z.core.$strip>;
23
+ }, z.core.$strict>, z.ZodObject<{
24
+ viewport: z.ZodObject<{
25
+ x: z.ZodNumber;
26
+ y: z.ZodNumber;
27
+ scale: z.ZodNumber;
28
+ }, z.core.$strip>;
29
+ }, z.core.$strict>]>;
7
30
  export declare const tourStopSchema: z.ZodObject<{
8
31
  target: z.ZodUnion<readonly [z.ZodObject<{
9
32
  nodeId: z.ZodString;
33
+ }, z.core.$strict>, z.ZodObject<{
34
+ rect: z.ZodObject<{
35
+ x: z.ZodNumber;
36
+ y: z.ZodNumber;
37
+ width: z.ZodNumber;
38
+ height: z.ZodNumber;
39
+ }, z.core.$strip>;
10
40
  }, z.core.$strict>, z.ZodObject<{
11
41
  viewport: z.ZodObject<{
12
42
  x: z.ZodNumber;
@@ -27,6 +57,13 @@ export declare const tourSchema: z.ZodObject<{
27
57
  stops: z.ZodArray<z.ZodObject<{
28
58
  target: z.ZodUnion<readonly [z.ZodObject<{
29
59
  nodeId: z.ZodString;
60
+ }, z.core.$strict>, z.ZodObject<{
61
+ rect: z.ZodObject<{
62
+ x: z.ZodNumber;
63
+ y: z.ZodNumber;
64
+ width: z.ZodNumber;
65
+ height: z.ZodNumber;
66
+ }, z.core.$strip>;
30
67
  }, z.core.$strict>, z.ZodObject<{
31
68
  viewport: z.ZodObject<{
32
69
  x: z.ZodNumber;
@@ -47,6 +84,7 @@ export declare const tourSchema: z.ZodObject<{
47
84
  export type Tour = z.infer<typeof tourSchema>;
48
85
  export type TourStop = z.infer<typeof tourStopSchema>;
49
86
  export type Camera = z.infer<typeof cameraSchema>;
87
+ export type Rect = z.infer<typeof rectSchema>;
50
88
  export interface TourNode {
51
89
  id: string;
52
90
  type: string;
@@ -0,0 +1,11 @@
1
+ import { z } from 'zod';
2
+ export declare const workspaceSettingsSchema: z.ZodObject<{
3
+ agentSessions: z.ZodBoolean;
4
+ knowledgeLifecycle: z.ZodBoolean;
5
+ }, z.core.$strict>;
6
+ export type WorkspaceSettings = z.infer<typeof workspaceSettingsSchema>;
7
+ export declare const workspaceSettingsPatchSchema: z.ZodObject<{
8
+ agentSessions: z.ZodOptional<z.ZodBoolean>;
9
+ knowledgeLifecycle: z.ZodOptional<z.ZodBoolean>;
10
+ }, z.core.$strict>;
11
+ export declare const DEFAULT_WORKSPACE_SETTINGS: WorkspaceSettings;
package/docs/RELEASE.md CHANGED
@@ -10,6 +10,8 @@ single source of truth for the release dance — see also
10
10
  ## TL;DR
11
11
 
12
12
  1. Land all the changes you want in the release on `main` with green CI.
13
+ Run the tech-debt sweep (below) on everything since the last tag and fix what it finds
14
+ before bumping the version.
13
15
  2. Bump `package.json` `version`.
14
16
  Run `bun run build:plugin` to update the Agent Plugins manifest, canonical adapter runtime
15
17
  pin, and generated plugin copies. Publish that exact npm runtime version before advertising
@@ -63,6 +65,20 @@ following it copy-pasted a broken setup.
63
65
  grep -rn "pmx-canvas@0\." Readme.md docs/ # every hit must be the version you are about to ship
64
66
  ```
65
67
 
68
+ **Sweep for tech debt before every release.** Read `git diff <last-tag>..HEAD` for what
69
+ this release leaves behind, not just whether it works, and fix it before tagging rather
70
+ than listing it for later:
71
+
72
+ - **Orphans.** A surface removed but its data path kept: server work, env vars, protocol
73
+ fields, store signals, CSS, tests and docs that only served it.
74
+ - **Duplicates.** A second helper, constant or type doing what an existing one does;
75
+ parallel code paths for the same job.
76
+ - **Redundant work.** The same board, file or query read more than once per request; work
77
+ that runs on every event but whose result nobody uses.
78
+ - **Stand-ins.** A field or revision reused for a meaning it was not built for, where the
79
+ design is still open: record it in the plan with the decision it waits on.
80
+ - **Docs that describe what no longer exists**: `docs/`, skills, CLI help, Readme.
81
+
66
82
  **If this release touches CI or the release workflows, review that as
67
83
  release content.** A changed gate gets its first real run *on this
68
84
  release*: `e2e-cli` once launched Playwright without installing the
@@ -245,9 +261,11 @@ with `ok: true`, the published tarball is intact end-to-end.
245
261
  are workspace-local cache and must not be committed; they're gitignored
246
262
  but still appear in `git status`. Use `git restore --staged` if they
247
263
  sneak into a `git add -A`.
248
- - **`docs/screenshot.png`** updates whenever the showcase E2E runs.
249
- Don't bake those updates into a release commit unless the screenshot
250
- in `Readme.md` actually needs the refresh.
264
+ - **Showcase screenshots** go to Playwright's per-test output directory as
265
+ `screenshot.png`, leaving tracked images unchanged. To intentionally refresh
266
+ the README image, copy that capture to `docs/screenshot.png`, run
267
+ `bun run build:plugin`, and commit both the source image and
268
+ `plugins/pmx-canvas/assets/preview.png` together.
251
269
  - **CHANGELOG dates**: use the actual publish date in the
252
270
  `## [version] - YYYY-MM-DD` header, not the day you wrote the entry.
253
271
  - **npm publish is asynchronous now**: a successful publish prints "Your
@@ -4,6 +4,12 @@
4
4
  **Date:** 2026-06-12
5
5
  **Context for:** v0.2 stability release (docs/tech-debt-assessment-2026-06.md, Phase 2)
6
6
 
7
+ **Scope clarified, 2026-10-15:** this decision applies to the local distribution and its
8
+ Bun SDK. [ADR-002](adr-002-shared-product-separate-runtimes.md) records this narrowing and the
9
+ [vision's separate-runtime direction](product-vision-2026-09.md#likely-repository-structure-shared-product-separate-runtimes)
10
+ allows runtime-neutral shared product code and distinct Sites/Cloudflare adapters. It does
11
+ not require a Node dual-build, compatibility shims or a cloud dependency for local use.
12
+
7
13
  ## Context
8
14
 
9
15
  pmx-canvas ships as TypeScript source executed directly by Bun. `package.json` points `main`/`exports` at `src/server/index.ts`, the `bin` entry is `src/cli/index.ts` with a `#!/usr/bin/env bun` shebang, and `engines` requires `bun >= 1.4.2`. There is no compiled JS distribution; `dist/` carries only the client bundle, the json-render viewer, and type declarations.
@@ -16,7 +22,7 @@ The decisive observation: nobody integrates with pmx-canvas by importing it. Age
16
22
 
17
23
  ## Decision
18
24
 
19
- pmx-canvas stays Bun-only for the SDK and runtime.
25
+ The local pmx-canvas distribution stays Bun-only for the SDK and runtime.
20
26
 
21
27
  1. MCP (stdio) and the HTTP API are the universal integration surfaces. They are runtime-agnostic by construction: any client that can spawn a process or open a socket can use them.
22
28
  2. No Node dual-build (ESM + CJS dist of the server/SDK) will be produced. The package continues to ship TypeScript source executed by Bun.
@@ -0,0 +1,93 @@
1
+ # ADR-002: Shared product core, separate runtime editions
2
+
3
+ **Status:** Accepted architectural direction; implementation remains staged
4
+ **Date:** 2026-10-15
5
+ **Context for:** Local PMX Canvas, ChatGPT Sites and the later standalone Cloudflare edition
6
+ **Relationship:** Narrows [ADR-001](adr-001-bun-only-runtime.md) to the local runtime and SDK; does not replace it
7
+
8
+ ## Context
9
+
10
+ The [product vision](product-vision-2026-09.md#likely-repository-structure-shared-product-separate-runtimes)
11
+ keeps local PMX usable offline while adding hosted editions in stages. Boards, mutation
12
+ rules, context compilation and renderers should remain one product across those editions.
13
+ Sharing source code must not imply shared live state or a cloud dependency for local users.
14
+
15
+ Today's application couples product behavior to Bun, synchronous SQLite, process-wide state
16
+ and import-time wiring. Moving those modules into packages would not establish runtime
17
+ independence. Conversely, separate product forks would duplicate rules and let editions drift.
18
+ The architecture must separate runtime ownership without introducing distributed transactions
19
+ between closely related board, context and relation operations.
20
+
21
+ ## Decision
22
+
23
+ 1. **Keep one modular product in one repository.** Reuse product rules and contracts across
24
+ editions. Establish package boundaries from demonstrated reuse, not a speculative folder
25
+ split. Shared contracts and rules must not depend on runtime entrypoints or concrete
26
+ storage; remote clients must not import local execution machinery.
27
+ 2. **Give each edition an explicit composition root.** Local, Sites and later standalone
28
+ Cloudflare entrypoints construct their dependencies and own startup, shutdown and recovery.
29
+ Importing shared code must not install global listeners or start local services.
30
+ 3. **Keep runtime capabilities behind explicit boundaries.** Authentication supplies a caller
31
+ and grants to shared permission rules. Persistence, temporary session services and external
32
+ effects belong to runtime adapters. Files, network fetches, subprocess MCP, builds and
33
+ browser automation are capabilities, not assumptions of the shared core. Document unsupported
34
+ behavior per edition; preserve distinct iframe sandbox and host-protocol requirements.
35
+ 4. **Keep ownership explicit.** Requests target a workspace, board and caller independently
36
+ of a viewer's navigation. Durable board state and audit records have different lifetimes
37
+ from presence, connections, timers and waits. Every supported writer follows the relevant
38
+ mutation policy and commit guarantees defined in the vision.
39
+ 5. **Share three contracts:** operation requests/results, the workbench request/event/asset
40
+ protocol, and the editable board archive. MCP adapts product operations to supported host
41
+ capabilities; common registration code does not establish support for every resource,
42
+ subscription or embedded application on every host.
43
+ 6. **Separate editions, not every domain into a service.** Keep board, context and relation
44
+ consistency together initially. A separate deployment needs a concrete security,
45
+ execution-lifetime, scaling or failure-isolation reason. Package boundaries alone do not
46
+ justify network boundaries.
47
+ 7. **Preserve independent editions.** Local retains Bun, SQLite and offline-capable local
48
+ features without hosted credentials. Sites and standalone hosting own their respective
49
+ storage and operational integrations. Boards move through deliberate export/import copies,
50
+ not automatic synchronization. Local is not a thin client, and Sites is not a disposable fork.
51
+
52
+ ## Consequences
53
+
54
+ - Shared fixes can reach all editions, but each runtime needs contract and lifecycle checks.
55
+ Host support and platform limits must be verified on the actual platform, not inferred from
56
+ a portable build or simulated asynchronous storage.
57
+ - ADR-001's rejection of a Node dual-build remains valid for the local distribution. This
58
+ decision permits runtime-neutral product code and hosted adapters, not compatibility shims.
59
+ - Policy parity does not require every local SDK method to become asynchronous. Durable
60
+ completion across asynchronous storage is a separate contract; any SDK API change needs
61
+ its own versioned decision rather than a second permanent command implementation.
62
+ - Exact packages, interfaces, storage mechanisms, journal schema and archive version/upgrade
63
+ policy remain scoped implementation decisions. This ADR does not select services or promise
64
+ indefinite format compatibility.
65
+
66
+ ## Alternatives considered
67
+
68
+ - **Separate product forks per edition:** simpler initial porting, but duplicated permission,
69
+ revision and context behavior would drift. Rejected in favor of shared product rules.
70
+ - **Microservices for boards, context and relations:** independent deployment at the cost of
71
+ network failures and cross-service consistency. Rejected without a demonstrated need.
72
+ - **Package migration first:** creates release and import churn without proving isolation.
73
+ Rejected in favor of extracting a complete working slice first.
74
+ - **Hosted backend required by local PMX:** reduces runtime variants by sacrificing offline
75
+ ownership and existing local workflows. Rejected by the product vision.
76
+
77
+ ## Delivery and revisit gates
78
+
79
+ Owner acceptance remains first. Curation-effect runs and reruns are deferred to
80
+ [plan 019](plans/plan-019-post-0.9-roadmap.md) step 6 (2026-10-19); preceding work is not
81
+ evaluation-gated. Release and runtime-verification gates remain unchanged. Fix demonstrated
82
+ defects narrowly; this ADR does not authorize a broad refactor, deployment or release.
83
+
84
+ When the second runtime needs extraction, prove one read/edit/commit/reconnect slice with a
85
+ browser and agent conflict, a lost-response retry, persistence failure, restart, independent
86
+ board navigation and an unreadable linked source. Verify isolated runtime instances and the
87
+ installed local offline path. Prove the slice on the target platform before expanding the port;
88
+ package the boundaries once they are established.
89
+
90
+ Revisit deployment boundaries when measured requirements justify separate security, scaling
91
+ or execution lifetimes. Revisit adapter boundaries if a verified platform constraint cannot
92
+ preserve the shared product guarantees. Neither trigger automatically authorizes product forks
93
+ or a cloud dependency for local operation; changes require a new explicit decision.