pmx-canvas 0.1.17 → 0.1.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +99 -0
- package/Readme.md +12 -5
- package/dist/types/server/canvas-serialization.d.ts +2 -0
- package/dist/types/server/canvas-state.d.ts +2 -0
- package/docs/RELEASE.md +153 -0
- package/docs/bun-webview-integration.md +296 -0
- package/docs/cli.md +140 -0
- package/docs/evals/e2e-cli-coverage.md +61 -0
- package/docs/http-api.md +191 -0
- package/docs/mcp.md +135 -0
- package/docs/node-types.md +244 -0
- package/docs/plans/.gitkeep +0 -0
- package/docs/plans/plan-001-semantic-watch-mvp.md +335 -0
- package/docs/plans/plan-002-human-attention-layer-design-spec.md +679 -0
- package/docs/plans/plan-003-human-attention-layer-implementation-plan.md +572 -0
- package/docs/reactive-canvas-proposal.md +578 -0
- package/docs/release-review-0.1.0.md +38 -0
- package/docs/screenshot.png +0 -0
- package/docs/screenshots/demo-workbench-dark.png +0 -0
- package/docs/screenshots/demo-workbench-light.png +0 -0
- package/docs/screenshots/welcome-dark.png +0 -0
- package/docs/screenshots/welcome-light.png +0 -0
- package/docs/sdk.md +92 -0
- package/package.json +2 -1
- package/skills/pmx-canvas/SKILL.md +2 -0
- package/skills/pmx-canvas/references/excalidraw-diagram-authoring.md +145 -0
- package/src/cli/agent.ts +17 -0
- package/src/mcp/canvas-access.ts +2 -0
- package/src/mcp/server.ts +12 -4
- package/src/server/canvas-serialization.ts +48 -0
- package/src/server/canvas-state.ts +18 -5
- package/src/server/server.ts +2 -0
|
@@ -0,0 +1,578 @@
|
|
|
1
|
+
# Reactive Canvas Proposal
|
|
2
|
+
|
|
3
|
+
> Status: Proposal
|
|
4
|
+
> Date: 2026-03-31
|
|
5
|
+
> Scope: PMX Canvas architecture extension in this repo
|
|
6
|
+
|
|
7
|
+
## Decision
|
|
8
|
+
|
|
9
|
+
Build **Reactive Canvas: a live operating graph powered by a generalized reaction engine**.
|
|
10
|
+
|
|
11
|
+
This merges the two ideas:
|
|
12
|
+
|
|
13
|
+
- **Live Operating Graph** is the right product surface: live data on the canvas, semantic edges, AI synthesis, and durable outputs.
|
|
14
|
+
- **Canvas Reactions** is the right architectural kernel: it fits the current codebase and turns one-off computed behaviors into a general capability.
|
|
15
|
+
|
|
16
|
+
The single smartest addition is not query nodes alone and not rules alone. It is making the canvas itself **executable**: nodes and edges become a reactive program the human and agent shape together.
|
|
17
|
+
|
|
18
|
+
## Evaluation of the Two Inputs
|
|
19
|
+
|
|
20
|
+
### 1. "Live Operating Graph" is stronger on user value
|
|
21
|
+
|
|
22
|
+
It points at the clearest step-change in PMX:
|
|
23
|
+
|
|
24
|
+
- the canvas remembers and updates what matters
|
|
25
|
+
- cross-source synthesis becomes ambient instead of prompt-by-prompt
|
|
26
|
+
- spatial arrangement becomes configuration, not just presentation
|
|
27
|
+
|
|
28
|
+
It is compelling because it changes daily behavior:
|
|
29
|
+
|
|
30
|
+
- fewer repeated prompts
|
|
31
|
+
- less tab-juggling
|
|
32
|
+
- less manual synthesis across Jira, GitHub, Slack, and metrics
|
|
33
|
+
- clearer evidence trails when promoting an insight into durable memory
|
|
34
|
+
|
|
35
|
+
### 2. "Canvas Reactions" is stronger on implementation leverage
|
|
36
|
+
|
|
37
|
+
It matches this repo unusually well.
|
|
38
|
+
|
|
39
|
+
This codebase already has the core ingredients:
|
|
40
|
+
|
|
41
|
+
- **authoritative server state** in [`src/server/canvas-state.ts`](../src/server/canvas-state.ts)
|
|
42
|
+
- **disk persistence** to `.pmx-canvas.json` plus named snapshots
|
|
43
|
+
- **mutation recording / suppression** for computed changes
|
|
44
|
+
- **SSE fanout** to keep the browser synced
|
|
45
|
+
- **MCP / HTTP / SDK parity** as an explicit architectural rule
|
|
46
|
+
- a real computed special case today: [`src/server/code-graph.ts`](../src/server/code-graph.ts) auto-generates dependency edges from file nodes using `withSuppressedRecording()`
|
|
47
|
+
|
|
48
|
+
That means reactions are not a foreign idea. The repo already contains one hardcoded reaction system; it is just not generalized yet.
|
|
49
|
+
|
|
50
|
+
### 3. The right merge
|
|
51
|
+
|
|
52
|
+
Treat **reactions as the engine** and **live operating graph primitives as built-in reaction types**.
|
|
53
|
+
|
|
54
|
+
Concretely:
|
|
55
|
+
|
|
56
|
+
- query nodes are reaction-driven data sources
|
|
57
|
+
- formula nodes are reaction-driven synthesis sinks
|
|
58
|
+
- semantic edges define propagation semantics
|
|
59
|
+
- custom reaction rules expose the engine directly when users need it
|
|
60
|
+
- promotion/export is the durable output seam
|
|
61
|
+
|
|
62
|
+
## Repo Reality
|
|
63
|
+
|
|
64
|
+
The proposal should follow the code that exists, not the platform we wish were already here.
|
|
65
|
+
|
|
66
|
+
### What exists now
|
|
67
|
+
|
|
68
|
+
- Server-owned singleton canvas state
|
|
69
|
+
- SSE layout reconciliation
|
|
70
|
+
- Full node / edge persistence on disk
|
|
71
|
+
- Snapshot save / restore UX
|
|
72
|
+
- Grouping, selection, pinning, search, spatial analysis, code graph, undo / redo
|
|
73
|
+
|
|
74
|
+
### What does not exist in this checkout
|
|
75
|
+
|
|
76
|
+
- `product-graph.ts`
|
|
77
|
+
- `work-graph.ts`
|
|
78
|
+
- a durable evidence store
|
|
79
|
+
- a multi-canvas board library
|
|
80
|
+
|
|
81
|
+
That matters. In this repo, "promote to product memory" should be designed as an **export / integration seam**, not as a direct mutation into modules that are not present.
|
|
82
|
+
|
|
83
|
+
### Important implication
|
|
84
|
+
|
|
85
|
+
The original "saved canvases in localStorage" idea is not the right foundation here.
|
|
86
|
+
|
|
87
|
+
This repo already persists:
|
|
88
|
+
|
|
89
|
+
- server state to `.pmx-canvas.json`
|
|
90
|
+
- snapshots to `.pmx-canvas-snapshots/`
|
|
91
|
+
- client layout overrides to localStorage as a cache
|
|
92
|
+
|
|
93
|
+
So the first implementation should build on **server persistence and snapshots**, not invent a second persistence model.
|
|
94
|
+
|
|
95
|
+
## Implementation Hazards To Address Early
|
|
96
|
+
|
|
97
|
+
These are not reasons to avoid the feature. They are the specific places where the current architecture needs to be tightened first.
|
|
98
|
+
|
|
99
|
+
### 1. Change notifications are too coarse
|
|
100
|
+
|
|
101
|
+
`CanvasStateManager` only emits `'nodes' | 'pins'` level change notifications today.
|
|
102
|
+
|
|
103
|
+
Reactive propagation will need more precise events, for example:
|
|
104
|
+
|
|
105
|
+
- node added / updated / removed
|
|
106
|
+
- edge added / removed
|
|
107
|
+
- node pinned / unpinned
|
|
108
|
+
- query refreshed
|
|
109
|
+
- formula computed
|
|
110
|
+
|
|
111
|
+
### 2. Derived edges need provenance
|
|
112
|
+
|
|
113
|
+
The current code-graph feature identifies computed edges by ID prefix. That works for one built-in behavior, but it will not scale once multiple derived systems coexist.
|
|
114
|
+
|
|
115
|
+
Reactive Canvas should add explicit edge provenance, for example:
|
|
116
|
+
|
|
117
|
+
- `source: 'manual' | 'system'`
|
|
118
|
+
- `sourceKind: 'code-graph' | 'query-runtime' | 'reaction'`
|
|
119
|
+
|
|
120
|
+
Without that, manual and computed edges will collide semantically and operationally.
|
|
121
|
+
|
|
122
|
+
### 3. Batch updates need to participate in the same event model
|
|
123
|
+
|
|
124
|
+
The runtime already has multiple mutation paths. Before adding reactions, all server-side writes should reliably drive:
|
|
125
|
+
|
|
126
|
+
- persistence
|
|
127
|
+
- SSE updates
|
|
128
|
+
- undo / redo where appropriate
|
|
129
|
+
- resource notifications
|
|
130
|
+
|
|
131
|
+
Reactive behavior built on an incomplete mutation stream will become nondeterministic.
|
|
132
|
+
|
|
133
|
+
## Proposed Feature
|
|
134
|
+
|
|
135
|
+
### Core concept
|
|
136
|
+
|
|
137
|
+
Reactive Canvas turns the canvas into a live, typed graph:
|
|
138
|
+
|
|
139
|
+
- **sources** emit change events
|
|
140
|
+
- **history** records what changed and why
|
|
141
|
+
- **edges** define propagation meaning
|
|
142
|
+
- **sinks** recompute when upstream inputs change
|
|
143
|
+
- **rules** automate common canvas behaviors
|
|
144
|
+
- **exports** capture durable evidence when needed
|
|
145
|
+
|
|
146
|
+
### Primitive 1: Query Nodes
|
|
147
|
+
|
|
148
|
+
Add a new node type: `query`.
|
|
149
|
+
|
|
150
|
+
Query nodes bind to a data-producing tool call and refresh on a schedule or manually.
|
|
151
|
+
|
|
152
|
+
```ts
|
|
153
|
+
interface QueryNodeData {
|
|
154
|
+
title: string;
|
|
155
|
+
serverName: string;
|
|
156
|
+
toolName: string;
|
|
157
|
+
toolArgs: Record<string, unknown>;
|
|
158
|
+
refreshIntervalMs: number;
|
|
159
|
+
displayMode: 'count' | 'list' | 'table' | 'sparkline';
|
|
160
|
+
lastResult?: unknown;
|
|
161
|
+
lastResultAt?: string;
|
|
162
|
+
lastError?: string;
|
|
163
|
+
status: 'idle' | 'refreshing' | 'error';
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
The first implementation should not depend on arbitrary external MCP transport inside the browser. Query execution should be **server-side**, then pushed over the existing SSE channel.
|
|
168
|
+
|
|
169
|
+
### Primitive 2: Causal Change Ledger
|
|
170
|
+
|
|
171
|
+
Add a persisted causal ledger that records reactive changes as first-class events.
|
|
172
|
+
|
|
173
|
+
This is not just mutation history. It captures:
|
|
174
|
+
|
|
175
|
+
- what changed
|
|
176
|
+
- when it changed
|
|
177
|
+
- what caused it
|
|
178
|
+
- which upstream nodes were involved
|
|
179
|
+
- which reaction or runtime path fired
|
|
180
|
+
- what the previous and new outputs were
|
|
181
|
+
|
|
182
|
+
```ts
|
|
183
|
+
interface ReactiveEventRecord {
|
|
184
|
+
id: string;
|
|
185
|
+
at: string;
|
|
186
|
+
kind:
|
|
187
|
+
| 'query-diff'
|
|
188
|
+
| 'reaction-fired'
|
|
189
|
+
| 'formula-computed'
|
|
190
|
+
| 'promotion-created'
|
|
191
|
+
| 'manual-override';
|
|
192
|
+
nodeId?: string;
|
|
193
|
+
edgeIds?: string[];
|
|
194
|
+
causeNodeIds?: string[];
|
|
195
|
+
reactionId?: string;
|
|
196
|
+
summary: string;
|
|
197
|
+
before?: unknown;
|
|
198
|
+
after?: unknown;
|
|
199
|
+
metadata?: Record<string, unknown>;
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
User-facing value:
|
|
204
|
+
|
|
205
|
+
- "What changed since yesterday?"
|
|
206
|
+
- "Why did this node turn red?"
|
|
207
|
+
- "What caused this formula result?"
|
|
208
|
+
- "What changed since I last opened this canvas?"
|
|
209
|
+
|
|
210
|
+
The ledger is what makes the reactive system trustworthy. Without it, the canvas updates live but cannot explain itself.
|
|
211
|
+
|
|
212
|
+
### Primitive 3: Semantic Edges
|
|
213
|
+
|
|
214
|
+
Extend the edge type union with:
|
|
215
|
+
|
|
216
|
+
- `feeds`
|
|
217
|
+
- `compares`
|
|
218
|
+
- `blocks`
|
|
219
|
+
- `measures`
|
|
220
|
+
|
|
221
|
+
Existing edge types stay.
|
|
222
|
+
|
|
223
|
+
Meaning:
|
|
224
|
+
|
|
225
|
+
- `feeds`: upstream data should trigger downstream recomputation
|
|
226
|
+
- `compares`: side-by-side delta or contradiction analysis
|
|
227
|
+
- `blocks`: dependency / blocker propagation and attention signaling
|
|
228
|
+
- `measures`: compare live state against target / policy / goal
|
|
229
|
+
|
|
230
|
+
These edges are not just styling. They become routing hints for the reactive engine.
|
|
231
|
+
|
|
232
|
+
### Primitive 4: Formula-Capable Nodes
|
|
233
|
+
|
|
234
|
+
Do **not** require a brand-new `formula` node type first.
|
|
235
|
+
|
|
236
|
+
Instead, let existing display nodes become formula-capable via metadata:
|
|
237
|
+
|
|
238
|
+
```ts
|
|
239
|
+
interface FormulaData {
|
|
240
|
+
formula: string;
|
|
241
|
+
computeStatus: 'idle' | 'computing' | 'stale' | 'error';
|
|
242
|
+
lastComputedAt?: string;
|
|
243
|
+
lastComputedResult?: string;
|
|
244
|
+
}
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
This keeps the UI surface smaller:
|
|
248
|
+
|
|
249
|
+
- markdown node + formula = narrative synthesis
|
|
250
|
+
- status node + formula = compact health signal
|
|
251
|
+
- json-render / graph node + formula = structured synthesis later
|
|
252
|
+
|
|
253
|
+
### Primitive 5: Reaction Engine
|
|
254
|
+
|
|
255
|
+
Add a generalized server-side reaction runtime.
|
|
256
|
+
|
|
257
|
+
```ts
|
|
258
|
+
interface CanvasReaction {
|
|
259
|
+
id: string;
|
|
260
|
+
name: string;
|
|
261
|
+
enabled: boolean;
|
|
262
|
+
trigger:
|
|
263
|
+
| { event: 'node-added' | 'node-updated' | 'node-removed' | 'edge-added' | 'edge-removed' }
|
|
264
|
+
| { event: 'node-pinned' | 'node-unpinned' }
|
|
265
|
+
| { event: 'query-refreshed' }
|
|
266
|
+
| { event: 'formula-computed' }
|
|
267
|
+
| { event: 'manual' };
|
|
268
|
+
match?: Record<string, unknown>;
|
|
269
|
+
action: Record<string, unknown>;
|
|
270
|
+
source: 'system' | 'user' | 'agent';
|
|
271
|
+
}
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
Key point: **query refresh and formula recompute are just system reactions**.
|
|
275
|
+
|
|
276
|
+
That gives one engine with two layers:
|
|
277
|
+
|
|
278
|
+
- **built-in reactions** for query polling, propagation, code-graph recompute, formula evaluation
|
|
279
|
+
- **user / agent-authored reactions** later for things like auto-pin, auto-expand imports, and group summarization
|
|
280
|
+
|
|
281
|
+
### Primitive 6: Promote / Export
|
|
282
|
+
|
|
283
|
+
This belongs in the design, but not as a direct write into nonexistent product/work graph modules.
|
|
284
|
+
|
|
285
|
+
In this repo, the correct v1 shape is:
|
|
286
|
+
|
|
287
|
+
- `canvas_promote(...)` creates a structured evidence bundle
|
|
288
|
+
- bundle can be written to markdown / JSON in the workspace
|
|
289
|
+
- bundle can later be consumed by PMX proper or another host system
|
|
290
|
+
|
|
291
|
+
That keeps PMX Canvas standalone while preserving the future bridge to product memory.
|
|
292
|
+
|
|
293
|
+
## Why This Merge Is Better Than Either Proposal Alone
|
|
294
|
+
|
|
295
|
+
### Better than Live Operating Graph alone
|
|
296
|
+
|
|
297
|
+
Without reactions, query nodes, formula nodes, semantic edges, causal history, and saved boards risk becoming separate features with duplicated scheduling, propagation, and state logic.
|
|
298
|
+
|
|
299
|
+
### Better than Reactions alone
|
|
300
|
+
|
|
301
|
+
Without live data and synthesis primitives, reactions are clever but niche. They help debugging boards, but they do not create the broader category-defining surface.
|
|
302
|
+
|
|
303
|
+
### The merged shape
|
|
304
|
+
|
|
305
|
+
The canvas becomes:
|
|
306
|
+
|
|
307
|
+
- a **live dashboard**
|
|
308
|
+
- a **causal memory**
|
|
309
|
+
- a **spatial synthesis surface**
|
|
310
|
+
- a **reaction graph**
|
|
311
|
+
- an **evidence capture surface**
|
|
312
|
+
|
|
313
|
+
All with one conceptual model.
|
|
314
|
+
|
|
315
|
+
## Proposed Implementation Strategy
|
|
316
|
+
|
|
317
|
+
### Phase 1: Generalize the Runtime
|
|
318
|
+
|
|
319
|
+
Goal: create the engine before adding more surface area.
|
|
320
|
+
|
|
321
|
+
New files:
|
|
322
|
+
|
|
323
|
+
- `src/server/reaction-engine.ts`
|
|
324
|
+
- `src/server/query-runtime.ts`
|
|
325
|
+
|
|
326
|
+
Modified files:
|
|
327
|
+
|
|
328
|
+
- `src/server/canvas-state.ts`
|
|
329
|
+
- `src/server/index.ts`
|
|
330
|
+
- `src/server/server.ts`
|
|
331
|
+
- `src/mcp/server.ts`
|
|
332
|
+
|
|
333
|
+
Deliverables:
|
|
334
|
+
|
|
335
|
+
- richer typed canvas events
|
|
336
|
+
- server-side reaction registry
|
|
337
|
+
- typed canvas event stream for reactions
|
|
338
|
+
- reaction-safe computed mutations using existing suppression pattern
|
|
339
|
+
- provenance for derived edges / derived node updates
|
|
340
|
+
- query scheduling as built-in reactions
|
|
341
|
+
|
|
342
|
+
Why first:
|
|
343
|
+
|
|
344
|
+
- it subsumes the current hardcoded code-graph pattern cleanly
|
|
345
|
+
- it prevents query / formula logic from being bolted on separately
|
|
346
|
+
|
|
347
|
+
### Phase 2: Ship Query Nodes
|
|
348
|
+
|
|
349
|
+
Goal: first visible user value.
|
|
350
|
+
|
|
351
|
+
New files:
|
|
352
|
+
|
|
353
|
+
- `src/client/nodes/QueryNode.tsx`
|
|
354
|
+
|
|
355
|
+
Modified files:
|
|
356
|
+
|
|
357
|
+
- `src/server/canvas-state.ts`
|
|
358
|
+
- `src/client/types.ts`
|
|
359
|
+
- `src/client/canvas/CanvasViewport.tsx`
|
|
360
|
+
- `src/client/canvas/CanvasNode.tsx`
|
|
361
|
+
- `src/client/state/sse-bridge.ts`
|
|
362
|
+
- `src/server/server.ts`
|
|
363
|
+
- `src/server/index.ts`
|
|
364
|
+
- `src/mcp/server.ts`
|
|
365
|
+
|
|
366
|
+
New tools / endpoints:
|
|
367
|
+
|
|
368
|
+
- `canvas_add_query`
|
|
369
|
+
- `canvas_refresh_query`
|
|
370
|
+
- `POST /api/canvas/query`
|
|
371
|
+
- `POST /api/canvas/query/:id/refresh`
|
|
372
|
+
|
|
373
|
+
Validation:
|
|
374
|
+
|
|
375
|
+
- place a live query node on the canvas
|
|
376
|
+
- refreshes server-side
|
|
377
|
+
- result diffs update the node over SSE
|
|
378
|
+
- survives restart because node config lives in the persisted canvas state
|
|
379
|
+
|
|
380
|
+
### Phase 3: Add the Causal Change Ledger
|
|
381
|
+
|
|
382
|
+
Goal: make the system explainable and durable before adding more reactive complexity.
|
|
383
|
+
|
|
384
|
+
New files:
|
|
385
|
+
|
|
386
|
+
- `src/server/change-ledger.ts`
|
|
387
|
+
|
|
388
|
+
Possible new UI files:
|
|
389
|
+
|
|
390
|
+
- `src/client/canvas/ChangeFeedPanel.tsx`
|
|
391
|
+
|
|
392
|
+
Modified files:
|
|
393
|
+
|
|
394
|
+
- `src/server/canvas-state.ts`
|
|
395
|
+
- `src/server/query-runtime.ts`
|
|
396
|
+
- `src/server/server.ts`
|
|
397
|
+
- `src/mcp/server.ts`
|
|
398
|
+
- `src/client/state/sse-bridge.ts`
|
|
399
|
+
|
|
400
|
+
New tools / endpoints:
|
|
401
|
+
|
|
402
|
+
- `canvas_what_changed`
|
|
403
|
+
- `canvas_why_changed`
|
|
404
|
+
- `GET /api/canvas/changes`
|
|
405
|
+
- `GET /api/canvas/changes/node/:id`
|
|
406
|
+
|
|
407
|
+
Deliverables:
|
|
408
|
+
|
|
409
|
+
- persisted `ReactiveEventRecord` log
|
|
410
|
+
- query diffs recorded as structured events
|
|
411
|
+
- reaction and formula executions recorded with causes
|
|
412
|
+
- node-level "why did this change?" lookup
|
|
413
|
+
- a basic "since last visit" or recent changes feed
|
|
414
|
+
|
|
415
|
+
Validation:
|
|
416
|
+
|
|
417
|
+
- a query refresh that changes result writes a readable ledger event
|
|
418
|
+
- a user can ask why a node changed and see the causal chain
|
|
419
|
+
|
|
420
|
+
### Phase 4: Add Semantic Propagation + Formula Nodes
|
|
421
|
+
|
|
422
|
+
Goal: make the graph compute.
|
|
423
|
+
|
|
424
|
+
New files:
|
|
425
|
+
|
|
426
|
+
- `src/server/reactive-graph.ts`
|
|
427
|
+
- `src/server/formula-evaluator.ts`
|
|
428
|
+
|
|
429
|
+
Modified files:
|
|
430
|
+
|
|
431
|
+
- `src/server/canvas-state.ts`
|
|
432
|
+
- `src/client/types.ts`
|
|
433
|
+
- `src/client/canvas/EdgeLayer.tsx`
|
|
434
|
+
- `src/server/index.ts`
|
|
435
|
+
- `src/server/server.ts`
|
|
436
|
+
- `src/mcp/server.ts`
|
|
437
|
+
|
|
438
|
+
Deliverables:
|
|
439
|
+
|
|
440
|
+
- semantic edge types
|
|
441
|
+
- propagation walk from changed source nodes
|
|
442
|
+
- debounce / rate-limit formula evaluation
|
|
443
|
+
- formula metadata on markdown / status nodes
|
|
444
|
+
|
|
445
|
+
Validation:
|
|
446
|
+
|
|
447
|
+
- connect three query nodes to one formula-capable markdown node via `feeds`
|
|
448
|
+
- refreshing any upstream node recomputes the formula result once
|
|
449
|
+
|
|
450
|
+
### Phase 5: Expose Custom Reactions
|
|
451
|
+
|
|
452
|
+
Goal: let humans and agents program the canvas directly.
|
|
453
|
+
|
|
454
|
+
Possible new files:
|
|
455
|
+
|
|
456
|
+
- `src/client/nodes/ReactionNode.tsx`
|
|
457
|
+
|
|
458
|
+
New tools:
|
|
459
|
+
|
|
460
|
+
- `canvas_add_reaction`
|
|
461
|
+
- `canvas_remove_reaction`
|
|
462
|
+
- `canvas_list_reactions`
|
|
463
|
+
- `canvas_toggle_reaction`
|
|
464
|
+
|
|
465
|
+
Starter built-in actions:
|
|
466
|
+
|
|
467
|
+
- pin node
|
|
468
|
+
- focus node
|
|
469
|
+
- refresh query
|
|
470
|
+
- evaluate formula
|
|
471
|
+
- add import neighbors
|
|
472
|
+
- upsert summary node
|
|
473
|
+
|
|
474
|
+
Validation:
|
|
475
|
+
|
|
476
|
+
- debugging board can auto-pin red status nodes
|
|
477
|
+
- pinning a file can expand one-hop imports using the same generalized runtime
|
|
478
|
+
|
|
479
|
+
### Phase 6: Promote / Export
|
|
480
|
+
|
|
481
|
+
Goal: capture durable evidence without coupling this package to PMX internals that are not here.
|
|
482
|
+
|
|
483
|
+
New files:
|
|
484
|
+
|
|
485
|
+
- `src/server/canvas-promotion.ts`
|
|
486
|
+
|
|
487
|
+
Possible outputs:
|
|
488
|
+
|
|
489
|
+
- `docs/canvas-promotions/*.md`
|
|
490
|
+
- `artifacts/canvas-promotions/*.json`
|
|
491
|
+
|
|
492
|
+
Tool:
|
|
493
|
+
|
|
494
|
+
- `canvas_promote`
|
|
495
|
+
|
|
496
|
+
Validation:
|
|
497
|
+
|
|
498
|
+
- selecting a cluster can produce a timestamped evidence bundle with node refs, snapshots, and structured summary
|
|
499
|
+
|
|
500
|
+
## Non-Goals for This Repo's First Pass
|
|
501
|
+
|
|
502
|
+
- No direct mutation of `product-graph.ts` or `work-graph.ts` here
|
|
503
|
+
- No fully normalized evidence warehouse beyond the causal change ledger
|
|
504
|
+
- No multi-board storage system before reaction runtime exists
|
|
505
|
+
- No background live refresh for unopened canvases in v1
|
|
506
|
+
- No arbitrary browser-side MCP execution
|
|
507
|
+
|
|
508
|
+
## Saved Canvases, Re-scoped
|
|
509
|
+
|
|
510
|
+
The original "saved canvases" idea is still good, but it should be built on existing persistence primitives.
|
|
511
|
+
|
|
512
|
+
Recommended path:
|
|
513
|
+
|
|
514
|
+
- keep the existing always-persisted working canvas
|
|
515
|
+
- keep snapshots as named restore points
|
|
516
|
+
- later evolve snapshots into named "boards" if the workflow proves necessary
|
|
517
|
+
|
|
518
|
+
That avoids fighting the current architecture too early.
|
|
519
|
+
|
|
520
|
+
## Concrete Use Cases
|
|
521
|
+
|
|
522
|
+
### 1. Sprint Operating Board
|
|
523
|
+
|
|
524
|
+
- Query nodes: Jira bugs, stale PRs, deploy frequency
|
|
525
|
+
- Causal ledger: "bug count spiked after QA import" is visible as a recent change, not inferred from memory
|
|
526
|
+
- Semantic edges: all three `feed` a markdown node with a formula
|
|
527
|
+
- Formula output: a one-line sprint health summary
|
|
528
|
+
- Promote/export: capture the board state as a risk or status record
|
|
529
|
+
|
|
530
|
+
### 2. Production Investigation Board
|
|
531
|
+
|
|
532
|
+
- File nodes and status nodes already exist
|
|
533
|
+
- Reactions auto-pin red statuses and expand import neighbors on pin
|
|
534
|
+
- Query nodes later add live incident data or failing checks
|
|
535
|
+
- Formula node summarizes root-cause confidence as evidence accumulates
|
|
536
|
+
|
|
537
|
+
This is why the merge works: it serves both PM workflows and engineering investigation without creating two products.
|
|
538
|
+
|
|
539
|
+
## Success Criteria
|
|
540
|
+
|
|
541
|
+
Phase 1-2 are successful if:
|
|
542
|
+
|
|
543
|
+
- a user can create a live query node in under a minute
|
|
544
|
+
- query refreshes survive restart
|
|
545
|
+
- query updates arrive over SSE without corrupting layout reconciliation
|
|
546
|
+
|
|
547
|
+
Phase 3 is successful if:
|
|
548
|
+
|
|
549
|
+
- a user can answer "what changed?" and "why did this change?" without re-running analysis
|
|
550
|
+
- query, reaction, and formula events are persisted in a form that can later support promotion and summaries
|
|
551
|
+
|
|
552
|
+
Phase 4 is successful if:
|
|
553
|
+
|
|
554
|
+
- a formula-capable node recomputes from connected upstream data without duplicate evaluations
|
|
555
|
+
- semantic edges change behavior, not just visuals
|
|
556
|
+
|
|
557
|
+
Phase 5 is successful if:
|
|
558
|
+
|
|
559
|
+
- at least two current hardcoded behaviors can be expressed as reactions
|
|
560
|
+
- one user-authored debugging rule works end-to-end
|
|
561
|
+
|
|
562
|
+
Phase 6 is successful if:
|
|
563
|
+
|
|
564
|
+
- a promoted bundle provides enough evidence for later human review
|
|
565
|
+
- the export seam is useful before deeper PMX integration exists
|
|
566
|
+
|
|
567
|
+
## Recommendation
|
|
568
|
+
|
|
569
|
+
Build this as **Reactive Canvas**, with the following framing:
|
|
570
|
+
|
|
571
|
+
- **product promise**: a live operating graph on a spatial canvas
|
|
572
|
+
- **technical kernel**: a generalized reaction engine
|
|
573
|
+
- **first visible wedge**: query nodes
|
|
574
|
+
- **first trust layer**: a causal change ledger
|
|
575
|
+
- **first compounding step**: formula-capable nodes + semantic propagation
|
|
576
|
+
- **future bridge**: evidence export and promotion into external product memory systems
|
|
577
|
+
|
|
578
|
+
That is the most innovative, accretive, and buildable version of the idea in this repo as it exists today.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# PMX Canvas 0.1.0 — Release Review
|
|
2
|
+
|
|
3
|
+
**Date:** 2026-04-24
|
|
4
|
+
**Target:** public release of `pmx-canvas` 0.1.0
|
|
5
|
+
|
|
6
|
+
## TL;DR
|
|
7
|
+
|
|
8
|
+
**Ready to ship on the Bun-first release path.** The current tree passes build, typecheck,
|
|
9
|
+
unit tests, browser smoke, tarball pack/install smoke, and live endpoint checks. The remaining
|
|
10
|
+
work for release hygiene was documentation and workflow alignment, which is now tracked in the
|
|
11
|
+
same repo as code and package metadata.
|
|
12
|
+
|
|
13
|
+
## Verification Summary
|
|
14
|
+
|
|
15
|
+
| Check | Result | Notes |
|
|
16
|
+
|---|---|---|
|
|
17
|
+
| `bun run test` | ✅ | 159 passing unit/API/MCP/SDK tests |
|
|
18
|
+
| `bun run test:web-canvas` | ✅ | 26 passing Playwright tests, 1 skipped published-consumer scenario |
|
|
19
|
+
| `bun pm pack --dry-run` | ✅ | Tarball now includes `skills/` in addition to `src/`, `dist/`, and docs |
|
|
20
|
+
| `bun run release:smoke` | ✅ | Pack → install → boot → probe consumer flow passed |
|
|
21
|
+
| Live startup probes | ✅ | `/health`, `/api/canvas/state`, `/api/canvas/summary`, `/canvas/index.js`, and SSE stream responded correctly |
|
|
22
|
+
| Bun SDK import | ✅ | `import { createCanvas } from 'pmx-canvas'` works in Bun |
|
|
23
|
+
| Node SDK import | ⚠️ unsupported by design | Published export remains Bun-first; Node consumers should use CLI, MCP, or HTTP |
|
|
24
|
+
|
|
25
|
+
## Release Notes
|
|
26
|
+
|
|
27
|
+
- Persistence is documented and implemented as `.pmx-canvas/state.json` with automatic migration
|
|
28
|
+
from legacy `.pmx-canvas.json` and `.pmx-canvas-snapshots/`.
|
|
29
|
+
- The Bun package now ships the documented `skills/` directory alongside the CLI, MCP server,
|
|
30
|
+
HTTP surface, and Bun SDK.
|
|
31
|
+
- The publish workflow now validates the same release surfaces used in local release review:
|
|
32
|
+
browser smoke and consumer install/start smoke both run before `npm publish`.
|
|
33
|
+
|
|
34
|
+
## Known Scope
|
|
35
|
+
|
|
36
|
+
- The package is Bun-first. The SDK import path is intended for Bun runtimes.
|
|
37
|
+
- The Playwright `published-consumer` test remains opt-in because it requires an externally
|
|
38
|
+
provisioned install-style URL via `PMX_CANVAS_URL`.
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|