pmx-canvas 0.6.3 → 0.6.4
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 +12 -0
- package/Readme.md +21 -6
- package/dist/canvas/global.css +32 -0
- package/dist/canvas/index.js +51 -49
- package/dist/types/client/canvas/FeedbackDialog.d.ts +4 -0
- package/docs/cli.md +7 -2
- package/docs/node-types.md +43 -1
- package/docs/product-context-vision-2026-09.md +1 -1
- package/docs/product-vision-2026-09.md +135 -42
- package/docs/product-vision-review-2026-09.md +277 -0
- package/package.json +1 -1
- package/skills/pmx-canvas/SKILL.md +10 -3
- package/skills/pmx-canvas/evals/evals.json +46 -0
- package/skills/pmx-canvas/references/installing-pmx-canvas.md +4 -4
- package/src/client/canvas/FeedbackDialog.tsx +86 -0
- package/src/client/canvas/ToolRail.tsx +225 -189
- package/src/client/theme/global.css +32 -0
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
# Vision Review — September 2026
|
|
2
|
+
|
|
3
|
+
**Status:** Accepted and folded into [`product-vision-2026-09.md`](product-vision-2026-09.md) on 2026-09-23; this document keeps the reasoning and the full design sketch.
|
|
4
|
+
**Date:** 2026-09-23
|
|
5
|
+
**Scope:** An independent review of the long-term direction set by [`product-vision-2026-09.md`](product-vision-2026-09.md) and [`product-context-vision-2026-09.md`](product-context-vision-2026-09.md), checked against what has shipped since and against the real board in use today, plus a design sketch for boards as the wiki. Written against `main` `561e6ec5` (v0.6.3, clean tree, equal to `origin/main`).
|
|
6
|
+
**Method:** Read all three September documents (review, vision, context vision) and the 0.6.0–0.6.3 changelog; re-checked the review's trust findings in current source; read the live board the globally installed MCP server writes to, read-only, titles and counts only. No code was run and no board was modified.
|
|
7
|
+
|
|
8
|
+
## Where things stand
|
|
9
|
+
|
|
10
|
+
- **Three vision documents in September; none of their 0.6 plan has shipped.** The vision's 0.6 was many boards, trust, the cheap tool surface, frame-host consolidation and a binary, in 2–3 weeks. Seventeen days and three releases later, 0.6.0–0.6.3 carried the Bun 1.4.2 upgrade, field-report fixes, the MCP Skills extension and json-render updates.
|
|
11
|
+
- **The afternoon-sized trust defects are all still present.** `ax.approval.resolve` never checks the caller, so an agent can approve its own gate. `requestJson` never reads `res.ok`, so a human's failed write is silent. The webpage fetcher uses `redirect: 'follow'` with no host filter. There is no boards table.
|
|
12
|
+
- **The black-tile problem is on round ten.** 0.6.2 ships it as a known limitation for Copilot/WebKit Excalidraw tiles, and `ExtAppFrame.tsx` grew to 1,591 lines.
|
|
13
|
+
- **The real board today is plain.** `C4 2026 OKR planning`: 26 markdown cards, 4 groups, 29 edges, 8 pins, no annotations, no iframe-backed nodes, written from Copilot sessions. 2 of 152 recorded steers were sent in September. 108 snapshots put `canvas.db` at 29.6 MB for a 30-node board.
|
|
14
|
+
|
|
15
|
+
## Thesis
|
|
16
|
+
|
|
17
|
+
**pmx-canvas is the medium where human and agent thinking lands and stays.** It is not primarily a context compiler, and it is not a knowledge-management system. On every real board the agent writes the board, the human shapes it, and the board itself is the product: OKRs, planning overviews, discovery maps, decks. Agent context is a by-product of that.
|
|
18
|
+
|
|
19
|
+
The 2026-09-06 correction to "the human's extended memory" was right, and the evidence now supports it. Pins went from 1–2 on test boards to 8 on the first board that is plainly the maintainer's own work. Curation shows up when the human owns the artifact.
|
|
20
|
+
|
|
21
|
+
## Keep
|
|
22
|
+
|
|
23
|
+
These moves from the vision are sound and should go ahead as written.
|
|
24
|
+
|
|
25
|
+
- **Many boards (move 0).** Real work is still being overwritten into snapshot rows.
|
|
26
|
+
- **One journal as the truth (move 4).** The highest-leverage architectural bet: undo that survives restart, SSE resume, the time scrubber, an audit trail, the sync model for sharing, and the end of full-copy snapshot bloat.
|
|
27
|
+
- **Agent output as cards (move 3).** Asks, work items and evidence belong on the surface.
|
|
28
|
+
- **Author on every node and a budgeted brief (Part 1).**
|
|
29
|
+
- **Trust that is not a label (move 7).**
|
|
30
|
+
|
|
31
|
+
## Disagreements
|
|
32
|
+
|
|
33
|
+
### 1. The vision is growing faster than the product
|
|
34
|
+
|
|
35
|
+
In eighteen days the scope went from "agent working memory" to a memory graph, a maintained wiki, working and confirmed revisions, personal and shared audiences, publication governance, derived-content permissions and hosted multiplayer. That is four products: a canvas, an agent control plane, a knowledge-management system and a team collaboration service, for one maintainer.
|
|
36
|
+
|
|
37
|
+
The biggest risk to the long-term vision is not its direction. It is that each document adds scope while host compatibility work takes the throughput. No new vision document should be written until move 0 and the trust fixes ship.
|
|
38
|
+
|
|
39
|
+
### 2. Boards are the wiki
|
|
40
|
+
|
|
41
|
+
The context vision designs a second data model (entities, immutable revisions, confirmation, publication, audience intersection) to bring pmx-context-frame into the canvas. Most of what it wants follows from making boards first-class instead:
|
|
42
|
+
|
|
43
|
+
- named boards;
|
|
44
|
+
- a board library with a title, summary, last-touched date and search;
|
|
45
|
+
- cross-board links, where a node references a node on another board;
|
|
46
|
+
- a brief that can retrieve from past boards.
|
|
47
|
+
|
|
48
|
+
That library is the memory graph, and it needs no second filing system. Confirmation and publication should wait until a second person needs something from these boards; until then they are governance for an audience that does not exist. The [design sketch](#design-sketch-boards-are-the-wiki) below works this out.
|
|
49
|
+
|
|
50
|
+
### 3. The destination is "share this board", not hosted SaaS
|
|
51
|
+
|
|
52
|
+
**Decided with the maintainer, 2026-09-23: this is the destination.** It replaces hosted multi-tenant multiplayer (vision Part 3) as the long-term end state.
|
|
53
|
+
|
|
54
|
+
Hosted multi-tenant multiplayer competes head-on with established whiteboard products that have teams, funding and their own MCP integrations. What they cannot easily be is local-first, host-agnostic, and inside the agent's pane in Claude Code, Codex, Copilot and Amp. That is where this product can win.
|
|
55
|
+
|
|
56
|
+
An OKR board is something a PM presents, so the natural steps are:
|
|
57
|
+
|
|
58
|
+
1. a read-only share link (listen mode plus a token);
|
|
59
|
+
2. comments;
|
|
60
|
+
3. a second human writer;
|
|
61
|
+
4. accounts and per-board roles, single-tenant.
|
|
62
|
+
|
|
63
|
+
Each step is justified only by someone using the one before it.
|
|
64
|
+
|
|
65
|
+
### 4. The core thesis is still unmeasured
|
|
66
|
+
|
|
67
|
+
Nobody has shown that a pin changes what an agent does. This is cheap to settle:
|
|
68
|
+
|
|
69
|
+
- record which resources each agent session reads;
|
|
70
|
+
- record whether pinned nodes were in the context it read;
|
|
71
|
+
- add one fixed eval under `docs/evals/`: the same task on a curated and an uncurated board.
|
|
72
|
+
|
|
73
|
+
Until that exists, "attention is the compiler" is a belief.
|
|
74
|
+
|
|
75
|
+
### 5. The host tax sets the roadmap
|
|
76
|
+
|
|
77
|
+
Four hosts, sandboxed iframes and WebKit took most of the 0.5 and 0.6 work. Move 5's single frame host is necessary but not sufficient. Name one reference surface where everything must work (the standalone browser, or the compiled binary in its own window), and treat embedded panes as best-effort with an honest fallback. Otherwise field reports keep setting the roadmap.
|
|
78
|
+
|
|
79
|
+
**Decided with the maintainer, 2026-09-24:** Chromium at 600 px, for now; WebKit joins the gate on a trigger. See [vision move 5](product-vision-2026-09.md#5-keep-every-node-type-unify-how-they-render-m).
|
|
80
|
+
|
|
81
|
+
### 6. The host's chat is the steering channel
|
|
82
|
+
|
|
83
|
+
Canvas steering went nearly silent once real work moved to Copilot, whose own chat sits beside the board. The evidence is one board, so this is a signal rather than a finding. Steering and the fleet layer stay, per the 2026-09-06 decision, but they are unlikely to drive growth. The canvas wins on what host chat cannot do: a persistent, spatial, shareable result.
|
|
84
|
+
|
|
85
|
+
## Design sketch: boards are the wiki
|
|
86
|
+
|
|
87
|
+
### Principle
|
|
88
|
+
|
|
89
|
+
A wiki is pages, links between them, and a way to find your way around. The canvas already has a better page than a wiki does: a board. So instead of adding a knowledge model beside the boards, make boards linkable, nestable and mappable. Nothing new is filed; the structure grows out of the work.
|
|
90
|
+
|
|
91
|
+
### Concepts
|
|
92
|
+
|
|
93
|
+
| Concept | What it is | New or existing |
|
|
94
|
+
|---|---|---|
|
|
95
|
+
| Board | A named canvas: nodes, edges, groups, pins, annotations, its own snapshots | New as a stored entity; today a workspace has exactly one |
|
|
96
|
+
| Home | The board a workspace opens on when nothing else is chosen; level 0 | New, an ordinary board |
|
|
97
|
+
| Portal | A `board` node: a card that stands for another board | New node type |
|
|
98
|
+
| Level | A board's shortest distance from Home through portals | Derived, never stored |
|
|
99
|
+
| Link | A reference from a card on one board to another board or card | New: portals plus `[[wiki links]]` in markdown |
|
|
100
|
+
| Board map | A generated board that shows every board and link | New, built like the code graph |
|
|
101
|
+
| README card | The one card on a board marked as its summary | New flag on an existing markdown node |
|
|
102
|
+
|
|
103
|
+
### Levels grow from placement
|
|
104
|
+
|
|
105
|
+
A portal on a board makes the target one level below it. Levels are computed from Home by shortest path each time the library changes; nothing stores a level, so moving a portal re-levels a board without a migration.
|
|
106
|
+
|
|
107
|
+
```
|
|
108
|
+
Home level 0
|
|
109
|
+
├── Tech Enabling level 1 (area board)
|
|
110
|
+
│ ├── C4 2026 OKR planning level 2
|
|
111
|
+
│ ├── Delivery metrics level 2
|
|
112
|
+
│ └── Product discovery level 2
|
|
113
|
+
└── Workshops level 1
|
|
114
|
+
└── Working with agents (deck) level 2
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
- **No fixed tiers.** Org, team, initiative and working board are names a user may give boards, not a taxonomy the product enforces. A mandatory taxonomy is the part of a wiki people stop maintaining.
|
|
118
|
+
- **A graph, not a tree.** A board may have portals on several parents; its level is the shortest one. `Product discovery` can sit under both `Tech Enabling` and a quarterly planning board.
|
|
119
|
+
- **Cycles are allowed.** Two boards may portal to each other; shortest-path levelling cannot loop.
|
|
120
|
+
- **Orphans are visible.** A board no portal reaches has no level and appears in an "Unplaced" lane on the board map, which is the wiki's missing-link report for free.
|
|
121
|
+
|
|
122
|
+
### Links
|
|
123
|
+
|
|
124
|
+
- **Portal.** Dropping a board onto another board, or choosing "Link board" from the context menu, creates a portal node with `data.boardId`. Double-click opens the target board. A portal renders text only: title, README summary, last-touched time, and the titles of its pinned cards. It never embeds the live board, so nesting cannot multiply iframes.
|
|
125
|
+
- **Wiki link.** `[[Board name]]` and `[[Board name#Card title]]` in any markdown card. On save the server resolves the name to a board id (and card id) and stores the ids beside the text, so renaming a board does not break links. The markdown renderer shows a resolved link as a chip that opens the target; an unresolved link renders as a dashed chip that offers "Create board", which is how a wiki grows a new page.
|
|
126
|
+
- **Backlinks.** Every board's library entry lists the boards that link to it. The portal card and the board's top bar both show the count.
|
|
127
|
+
|
|
128
|
+
### The board map is a board
|
|
129
|
+
|
|
130
|
+
The graph view is not a separate screen. It is a generated board with one node per board and one edge per link, rebuilt the way `code-graph.ts` builds file dependencies: auto-edges carry their own prefix (`boardmap-`), stay out of mutation history, and recompute on a debounce when boards or links change.
|
|
131
|
+
|
|
132
|
+
- **Arrangement is the human's.** Nodes are generated, but positions the human drags are kept, so the map can be laid out by meaning rather than force. New boards appear near their first parent.
|
|
133
|
+
- **Encoding.** Portal edges solid, wiki-link edges dotted. Node size from card count, fade from time since last touched, one colour per level.
|
|
134
|
+
- **Pinning a board on the map pulls it into the agent's brief.** Today a pinned neighborhood means nearby cards on one board; on the map it means linked boards. It is the same gesture one level up, and it is the retrieval control for the whole wiki.
|
|
135
|
+
- **Everything else works.** Groups, annotations, search and focus behave as on any board, because it is one. The name is "board map" to avoid confusion with the existing `graph` chart node type.
|
|
136
|
+
|
|
137
|
+
### How the wiki grows
|
|
138
|
+
|
|
139
|
+
- **Make board.** On a group's context menu: its cards move to a new board named after the group, and a portal takes the group's place. A cluster that outgrew its board becomes a page of its own.
|
|
140
|
+
- **Inline board.** On a portal's context menu: the reverse. The target board's cards come back as a group, and the board is archived.
|
|
141
|
+
- **New session, new board or chosen board.** A session starts on a board the human picks, or a new one linked from the board it was started from. This replaces today's "Before session" snapshot (`server.ts:138`) as the way work is kept apart; snapshots go back to being bookmarks.
|
|
142
|
+
|
|
143
|
+
Group, board and board of boards are one continuous scale, and a board moves along it by a gesture, not by filing.
|
|
144
|
+
|
|
145
|
+
### What the agent gets
|
|
146
|
+
|
|
147
|
+
- **`canvas://boards`.** The library: id, name, README summary, parents, level, links, backlinks, card count, last touched. Bounded like every other read: summaries are previews, not bodies.
|
|
148
|
+
- **A board target everywhere.** Every operation accepts `board`; an MCP session binds to one board at start, so an agent never writes to a board it did not choose. A write to another board is an explicit target, never an accident of which board the human is looking at.
|
|
149
|
+
- **A cross-board brief.** The brief carries the current board first, then boards pinned on the map, then boards one link away, each as README summary plus pinned card titles, with full content by explicit pull. This is the budgeted brief of vision Part 1 with the board library as its second tier.
|
|
150
|
+
- **One composite tool.** A `canvas_board` composite (`list`, `create`, `open`, `rename`, `archive`, `link`, `make-board`, `inline`) plus the `board` field on existing tools. That moves the tool count from 22 to 23 and needs the tool-surface freeze test and the four transports updated together.
|
|
151
|
+
|
|
152
|
+
### Data model
|
|
153
|
+
|
|
154
|
+
- A `boards` table: `id`, `name`, `created_at`, `updated_at`, `archived_at`.
|
|
155
|
+
- A `board_id` column on `nodes`, `edges`, `annotations`, `context_pins` and `snapshots`. Node ids are already unique across the database, so pins stay keyed by node.
|
|
156
|
+
- A `board_links` table (`from_board`, `from_node`, `to_board`, `to_node`, `kind`) rebuilt from portals and parsed wiki links; it is a projection, not a source of truth.
|
|
157
|
+
- The README flag lives in the node's `data`.
|
|
158
|
+
|
|
159
|
+
Migration: the current board becomes Home. The nine real boards in snapshot history (vision, "What the real boards show") restore as boards under Home, which is the first test of the whole design.
|
|
160
|
+
|
|
161
|
+
### State architecture: the honest cost
|
|
162
|
+
|
|
163
|
+
`CanvasStateManager` is one singleton holding one board, and 400+ call sites assume it. Two stages keep the cost down:
|
|
164
|
+
|
|
165
|
+
1. **One active board per server.** Opening a board saves and loads, the same as a restore. Reads of other boards (library, portals, brief, map) query SQLite directly and never load a second board into memory. Agent writes to a board other than the active one are refused with a clear error. This is enough for one person with one or two agents and is the first stage of move 0 (resized from S to M on 2026-09-24: `board_id` on five tables, per-board snapshots, a `board` target on every transport).
|
|
166
|
+
2. **Concurrent boards.** A registry of state managers keyed by board id, loaded on demand, so an agent can work on one board while the human looks at another. This is an L-sized change and should wait until stage 1 is used and the journal (move 4) exists, since each board then gets its own journal.
|
|
167
|
+
|
|
168
|
+
### What this replaces in the context vision
|
|
169
|
+
|
|
170
|
+
- The separate entity and immutable-revision model: boards and cards are the entities; the journal is the revision history.
|
|
171
|
+
- The personal wiki: a workspace's board library is the personal wiki.
|
|
172
|
+
- Working versus confirmed: postponed. When needed it is a label on a card or board, not a second store.
|
|
173
|
+
- Personal versus shared: postponed until sharing exists. Sharing is per board; a portal to a board the viewer cannot see renders as a locked card with no title. Sharing a board never shares what it links to.
|
|
174
|
+
|
|
175
|
+
### Open questions
|
|
176
|
+
|
|
177
|
+
- **Scope of Home.** The store is per workspace (`.pmx-canvas/canvas.db`), and real PM work already lives in one workspace. Keep the wiki per workspace; revisit a user-level library only if work spreads across several.
|
|
178
|
+
- **Board-level pins versus map pins.** Both feed the brief; the map should show which boards the current brief includes, which is the attention heat of the vision applied to boards.
|
|
179
|
+
- **Archive semantics.** Archived boards leave the map and the brief but keep their links resolvable, and a link to one renders greyed.
|
|
180
|
+
|
|
181
|
+
### Success criteria
|
|
182
|
+
|
|
183
|
+
- The nine real boards are restored under Home and reachable in two clicks from the map.
|
|
184
|
+
- `C4 2026 OKR planning` links to the April OKR board, and an agent starting a new session on a fresh board answers "what changed since the April OKRs?" from the brief without being told which board to read.
|
|
185
|
+
- A group turned into a board and inlined back leaves the original board byte-identical apart from ids and timestamps.
|
|
186
|
+
- A board with 20 portals renders no more iframes than one without them.
|
|
187
|
+
|
|
188
|
+
### Sequence
|
|
189
|
+
|
|
190
|
+
| Step | Size | Delivers |
|
|
191
|
+
|---|---|---|
|
|
192
|
+
| Many boards, one active (stage 1) | S | Boards, Home, open and switch, restore of the nine boards |
|
|
193
|
+
| Portals, README card, `canvas://boards` | M | Levels, library, backlinks |
|
|
194
|
+
| Wiki links and the board map | M | Links in cards, the generated map, orphan lane |
|
|
195
|
+
| Cross-board brief and map pins | M | Retrieval across the wiki |
|
|
196
|
+
| Make board and inline board | S | Organic growth |
|
|
197
|
+
| Concurrent boards (stage 2) | L | After the journal; agents on other boards |
|
|
198
|
+
|
|
199
|
+
## Additional moves
|
|
200
|
+
|
|
201
|
+
Four moves that follow from what the real boards contain. Two make the sharing destination real before any network work; two keep a board wiki useful over time instead of letting it pile up.
|
|
202
|
+
|
|
203
|
+
### Static export: the first step to sharing (S)
|
|
204
|
+
|
|
205
|
+
Sharing through a network mode has to wait for the trust fixes, since the vision makes move 7 mandatory before any port is opened. A self-contained HTML file of one board does not: the renderer and the board's data in one file, read-only, with pan, zoom and card expand. It can be attached to an email or a chat message, or posted to a wiki page.
|
|
206
|
+
|
|
207
|
+
- No server, no authentication, no attack surface, and the app produces the file itself, so the no-externals rule holds.
|
|
208
|
+
- The sharing path becomes **export → link → comments → second writer**. The first step puts a board in front of a colleague, which is the second-user milestone (resized from S to M on 2026-09-24 and shipped on its own as 0.7.x).
|
|
209
|
+
- The live `C4 2026 OKR planning` board has a "Workshop flow" card; exporting that board for the workshop's participants is the first real test.
|
|
210
|
+
- Iframe-backed nodes export their stored markup inside sandboxed iframes, as they render today. A node whose content cannot be inlined (a live MCP app) exports as its last screenshot and says so.
|
|
211
|
+
|
|
212
|
+
### Tours: the board is the presentation (M)
|
|
213
|
+
|
|
214
|
+
Five of the real boards include agent-generated HTML slide decks, one with 15 slides. The agent rebuilt as slides content that already existed as cards. A tour is an ordered path through a board's cards, seeded from the reading order `spatial-analysis.ts` already computes and editable by the human. Arrow keys move the camera card to card, and a card fills the screen when it is the current step.
|
|
215
|
+
|
|
216
|
+
- A deck stops being a separate artifact that drifts from its board.
|
|
217
|
+
- Tours carry into exports and share links, so presenting a board and sharing it are one feature.
|
|
218
|
+
- HTML decks stay as a capability; they stop being the only way to present.
|
|
219
|
+
|
|
220
|
+
### Recipe cards: boards that can be refreshed (M)
|
|
221
|
+
|
|
222
|
+
The real boards are full of numbers from elsewhere: 13 metric charts, developer-experience metrics, and an "Atlassian OKR-board mirror" card on the live board. They go stale silently, and in a board wiki staleness is the rot that kills wikis.
|
|
223
|
+
|
|
224
|
+
Node provenance already records a source and a refresh strategy (`canvas-provenance.ts`), but only for files, URLs, images, apps and artifacts. Add one source kind, the **recipe**: the tool call and prompt that produced the card, recorded when an agent writes it.
|
|
225
|
+
|
|
226
|
+
- The canvas never fetches the external data itself; it stores the recipe and marks the card stale after a set age.
|
|
227
|
+
- "Refresh this board" hands the stale recipes to whichever agent is attached, which rewrites the cards through the normal write path.
|
|
228
|
+
- The board map shows staleness beside last-touched time, so it is visible which parts of the wiki are out of date.
|
|
229
|
+
- A recipe is data, never instructions: refreshing runs only when a human asks, and the agent treats the recipe as a request it can decline.
|
|
230
|
+
|
|
231
|
+
### New board from this board: continuity across cycles (S)
|
|
232
|
+
|
|
233
|
+
The same OKR board appears in April and again for C4. **New board from this board** copies the structure (groups, the README card, recipe cards) without the content, and links the new board to the old one as its previous board.
|
|
234
|
+
|
|
235
|
+
- Recurring work forms chains on the board map without anyone filing it.
|
|
236
|
+
- The design sketch's success test, "what changed since the April OKRs?", becomes answerable because the link exists.
|
|
237
|
+
- It is templates for free: any board can be the pattern for the next one.
|
|
238
|
+
|
|
239
|
+
| Move | Size | Needs first |
|
|
240
|
+
|---|---|---|
|
|
241
|
+
| Static export | S | nothing |
|
|
242
|
+
| New board from this board | S | many boards (stage 1) |
|
|
243
|
+
| Tours | M | nothing; better with export |
|
|
244
|
+
| Recipe cards | M | nothing; better with the board map |
|
|
245
|
+
|
|
246
|
+
## Proposed vision
|
|
247
|
+
|
|
248
|
+
> **Think with your agents on boards that are still there next week.** Every session lands on a named board, the boards link into a wiki you can see as a map, the agent reads what you curated, and you can share or present a board with anyone.
|
|
249
|
+
|
|
250
|
+
| Horizon | Content |
|
|
251
|
+
|---|---|
|
|
252
|
+
| Now (weeks) | Human-only answers with requester withdraw (decided 2026-09-24), backed by a real secret, toasts on failed writes, a redirect host filter, many boards with one active (restore the nine lost boards), instrumentation of what agents read, and static export. |
|
|
253
|
+
| Foundation (1–2 months) | Portals, the board library, wiki links, the board map and the cross-board brief; new board from this board, tours and recipe cards; the journal and author on every node, with snapshots as bookmarks; agent output as cards; the SDK routed through the registry. |
|
|
254
|
+
| Reach (1.0 and after) | Read-only share links and the time scrubber in 1.0, then comments, then a second writer. |
|
|
255
|
+
| Only if pulled by use | Personal and shared knowledge governance; multi-tenant hosting. |
|
|
256
|
+
|
|
257
|
+
No capability or node type is cut. The fleet layer, every node type and the MCP-app host stay; this changes only what comes first.
|
|
258
|
+
|
|
259
|
+
## The one thing that matters most
|
|
260
|
+
|
|
261
|
+
There is still no second user. The repository has 18 stars, every pull request is the maintainer's, and npm downloads are plausibly CI and release smoke. Every long-term claim about wikis, teams or hosting is speculation until someone else depends on a board. The next milestone should be "one colleague opens a shared board", not an architecture move.
|
|
262
|
+
|
|
263
|
+
## Evidence
|
|
264
|
+
|
|
265
|
+
| Claim | Source |
|
|
266
|
+
|---|---|
|
|
267
|
+
| 0.6.0–0.6.3 contents | `CHANGELOG.md` at `561e6ec5` |
|
|
268
|
+
| Gate self-approval still possible | `src/server/operations/ops/ax-work.ts`, `ax.approval.resolve` handler has no caller check |
|
|
269
|
+
| Silent human write failures | `src/client/state/intent-bridge.ts`, no `res.ok` check in `requestJson` |
|
|
270
|
+
| Fetcher follows redirects | `src/server/webpage-node.ts:246` |
|
|
271
|
+
| No boards table | `CREATE TABLE` list in `src/server/canvas-db.ts` |
|
|
272
|
+
| Black tile known limitation | `CHANGELOG.md` 0.6.2, Known limitations |
|
|
273
|
+
| `ExtAppFrame.tsx` 1,591 lines | `wc -l` at `561e6ec5` |
|
|
274
|
+
| Live board contents (30 nodes, 29 edges, 8 pins, 0 annotations) | read-only `sqlite3` over `nodes`, `edges`, `context_pins`, `annotations`, 2026-09-23 |
|
|
275
|
+
| Steering volume (152 total, 89 browser, 2 in September) | read-only `sqlite3` over `ax_steering`, grouped by source and date |
|
|
276
|
+
| 108 snapshots, 29.6 MB database | `snapshots` count and file size, 2026-09-23 |
|
|
277
|
+
| Session-driven snapshots from Copilot | `snapshots.name` ("Before session · GitHub Copilot"), September rows |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pmx-canvas",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.4",
|
|
4
4
|
"description": "Spatial canvas workbench for coding agents — infinite 2D canvas with agent-native CLI, MCP integration, nodes, edges, file watching, and snapshots",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/server/index.ts",
|
|
@@ -18,7 +18,7 @@ Humans curate agent context by pinning nodes; agents read that curation through
|
|
|
18
18
|
|
|
19
19
|
## Runtime prerequisites
|
|
20
20
|
|
|
21
|
-
PMX Canvas 0.6.
|
|
21
|
+
PMX Canvas 0.6.4 requires **Bun >=1.4.2**, including when installed through npm.
|
|
22
22
|
Check `bun --version` and ensure Bun is on the MCP host's PATH, not just your shell's;
|
|
23
23
|
use an absolute executable path if needed. Install/configure only when requested.
|
|
24
24
|
For pinned installation, MCP configuration, managed services, and disposable verification,
|
|
@@ -313,8 +313,15 @@ The board has three modes, all gated on one fact — whether a session is attach
|
|
|
313
313
|
terminal: `pmx-canvas pump --consumer <your-key> --exec '<command>'`. It long-polls your
|
|
314
314
|
delivery queue, runs the command once per steer (message on stdin plus the
|
|
315
315
|
`PMX_STEER_MESSAGE`/`ID`/`SOURCE`/`TARGET`/`CREATED_AT` env envelope), and marks
|
|
316
|
-
per-consumer
|
|
317
|
-
|
|
316
|
+
executed steers per-consumer after the command exits 0 — a failed hand-off stays pending
|
|
317
|
+
after retries and the pump exits non-zero. **Startup exception:** by default the pump
|
|
318
|
+
silently marks pending backlog delivered for this consumer **without executing it**.
|
|
319
|
+
Start the pump before accepting new tasks, or review queued instructions and deliberately
|
|
320
|
+
pass `--backlog=deliver` to execute them. A startup acknowledgement is not proof of work;
|
|
321
|
+
`--once` can remain waiting for a fresh steer after skipping history. With reviewed backlog,
|
|
322
|
+
`pmx-canvas pump --consumer <your-key> --exec '<command>' --backlog=deliver --once`
|
|
323
|
+
executes one queued steer. This does not automatically wake an existing desktop task.
|
|
324
|
+
`{message}` in the template expands to a quoted env reference (never spliced;
|
|
318
325
|
refused on Windows — read stdin there). `--parent <key>` rolls you up under an orchestrator's
|
|
319
326
|
chip; `--once` for scripts. See `pmx-canvas pump --help`.
|
|
320
327
|
|
|
@@ -486,6 +486,52 @@
|
|
|
486
486
|
"type": "output_check"
|
|
487
487
|
}
|
|
488
488
|
]
|
|
489
|
+
},
|
|
490
|
+
{
|
|
491
|
+
"id": 20,
|
|
492
|
+
"name": "pump-startup-skip-history",
|
|
493
|
+
"prompt": "In an isolated workspace I queued an instruction for testbot, then started pmx-canvas pump --consumer testbot --exec cat --once. The instruction disappeared from pending, but cat printed nothing and the pump says parked. Did it perform the work? Explain what to do for future tasks without replaying old instructions.",
|
|
494
|
+
"expected_output": "Explains that default startup acknowledges pending history for this consumer without executing it. Does not report the work as performed or infer execution from delivery marks. Explains that --once waits for one successful command execution and can remain parked after skipping history. Keeps the safety default and starts the pump before accepting new tasks; a fresh addressed test message should reach cat and allow --once to exit. Does not promise automatic wakeup of an existing desktop task.",
|
|
495
|
+
"assertions": [
|
|
496
|
+
{
|
|
497
|
+
"name": "acknowledgement-is-not-execution",
|
|
498
|
+
"description": "Identifies default startup skipping and marking backlog, and explicitly says the old instruction was not executed",
|
|
499
|
+
"type": "output_check"
|
|
500
|
+
},
|
|
501
|
+
{
|
|
502
|
+
"name": "once-waits-for-execution",
|
|
503
|
+
"description": "Explains why --once remains parked after skipping history and proposes a fresh addressed message after pump startup",
|
|
504
|
+
"type": "output_check"
|
|
505
|
+
},
|
|
506
|
+
{
|
|
507
|
+
"name": "preserves-safe-default",
|
|
508
|
+
"description": "Does not replay old instructions, change runtime defaults, or claim automatic desktop-task wakeup",
|
|
509
|
+
"type": "output_check"
|
|
510
|
+
}
|
|
511
|
+
]
|
|
512
|
+
},
|
|
513
|
+
{
|
|
514
|
+
"id": 21,
|
|
515
|
+
"name": "pump-startup-deliver-reviewed-backlog",
|
|
516
|
+
"prompt": "In a disposable POSIX workspace, one harmless message is already queued for testbot. I reviewed it and want the pump to print it using cat, acknowledge it after success, and exit. Give the command and explain how you would verify it, including a failing-command control.",
|
|
517
|
+
"expected_output": "Uses pmx-canvas pump --consumer testbot --exec cat --backlog=deliver --once against the verified isolated target. Explains that omitting --backlog=deliver would skip and acknowledge the old message without executing cat. Verifies the queued message appears in command output, the pump exits successfully, and it is no longer pending for testbot. Uses a separate disposable message/consumer for a command exiting nonzero and confirms it remains pending after retries. Does not treat queue acknowledgement alone as proof of execution.",
|
|
518
|
+
"assertions": [
|
|
519
|
+
{
|
|
520
|
+
"name": "explicit-reviewed-backlog-mode",
|
|
521
|
+
"description": "Chooses --backlog=deliver with --once, the correct consumer and harmless cat command, rather than silently relying on default startup",
|
|
522
|
+
"type": "output_check"
|
|
523
|
+
},
|
|
524
|
+
{
|
|
525
|
+
"name": "verifies-output-and-delivery",
|
|
526
|
+
"description": "Requires actual command output and successful exit as well as a per-consumer pending check; contrasts the default skip behavior",
|
|
527
|
+
"type": "output_check"
|
|
528
|
+
},
|
|
529
|
+
{
|
|
530
|
+
"name": "failure-remains-pending",
|
|
531
|
+
"description": "Keeps the failing-command control isolated and expects nonzero exit after retries with the instruction still pending",
|
|
532
|
+
"type": "output_check"
|
|
533
|
+
}
|
|
534
|
+
]
|
|
489
535
|
}
|
|
490
536
|
]
|
|
491
537
|
}
|
|
@@ -4,7 +4,7 @@ Use this reference when the `pmx-canvas` skill is installed but the `pmx-canvas`
|
|
|
4
4
|
|
|
5
5
|
## Prerequisites and version
|
|
6
6
|
|
|
7
|
-
The examples pin **PMX Canvas 0.6.
|
|
7
|
+
The examples pin **PMX Canvas 0.6.4**, which requires **Bun >=1.4.2** even when
|
|
8
8
|
installed through npm: the CLI runs through Bun, not Node. Check `bun --version`
|
|
9
9
|
first. If missing or older, follow the [Bun installation instructions](https://bun.sh/docs/installation)
|
|
10
10
|
with the user's authorization. Ensure Bun is on the MCP host's PATH as well as the
|
|
@@ -17,11 +17,11 @@ in `SKILL.md`. Do not pair newer checkout guidance with an older runtime unknowi
|
|
|
17
17
|
## Install from npm
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
|
-
npm install -g pmx-canvas@0.6.
|
|
20
|
+
npm install -g pmx-canvas@0.6.4
|
|
21
21
|
pmx-canvas --version
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
-
Without a global install, use `bunx pmx-canvas@0.6.
|
|
24
|
+
Without a global install, use `bunx pmx-canvas@0.6.4` in place of `pmx-canvas` in
|
|
25
25
|
the commands below. Do not use unpinned `bunx pmx-canvas` for a version-specific check.
|
|
26
26
|
|
|
27
27
|
## Choose the workspace and target
|
|
@@ -91,7 +91,7 @@ discards empty env values, remove `PMX_CANVAS_URL` from its launch environment i
|
|
|
91
91
|
"mcpServers": {
|
|
92
92
|
"canvas": {
|
|
93
93
|
"command": "bunx",
|
|
94
|
-
"args": ["pmx-canvas@0.6.
|
|
94
|
+
"args": ["pmx-canvas@0.6.4", "--mcp"],
|
|
95
95
|
"env": {
|
|
96
96
|
"PMX_CANVAS_WORKSPACE_ROOT": "/absolute/path/to/project",
|
|
97
97
|
"PMX_CANVAS_PORT": "14313",
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { useRef, useState } from 'preact/hooks';
|
|
2
|
+
import { useFocusTrap } from './use-focus-trap';
|
|
3
|
+
|
|
4
|
+
/** Draft only: GitHub owns authentication and the final public submission. */
|
|
5
|
+
export function FeedbackDialog({ onClose }: { onClose: () => void }) {
|
|
6
|
+
const ref = useRef<HTMLFormElement>(null);
|
|
7
|
+
const [kind, setKind] = useState('Bug report');
|
|
8
|
+
const [title, setTitle] = useState('');
|
|
9
|
+
const [description, setDescription] = useState('');
|
|
10
|
+
useFocusTrap(ref, true);
|
|
11
|
+
|
|
12
|
+
return (
|
|
13
|
+
<div class="text-prompt-backdrop feedback-backdrop" onPointerDown={onClose}>
|
|
14
|
+
<form
|
|
15
|
+
ref={ref}
|
|
16
|
+
class="text-prompt feedback-dialog"
|
|
17
|
+
role="dialog"
|
|
18
|
+
aria-modal="true"
|
|
19
|
+
aria-labelledby="feedback-title"
|
|
20
|
+
aria-describedby="feedback-privacy"
|
|
21
|
+
action="https://github.com/pskoett/pmx-canvas/issues/new"
|
|
22
|
+
method="get"
|
|
23
|
+
target="_blank"
|
|
24
|
+
rel="noopener noreferrer"
|
|
25
|
+
onPointerDown={(e) => e.stopPropagation()}
|
|
26
|
+
onKeyDown={(e) => {
|
|
27
|
+
e.stopPropagation();
|
|
28
|
+
if (e.key === 'Escape') {
|
|
29
|
+
e.preventDefault();
|
|
30
|
+
onClose();
|
|
31
|
+
}
|
|
32
|
+
}}
|
|
33
|
+
>
|
|
34
|
+
<div id="feedback-title" class="text-prompt-title">
|
|
35
|
+
Bug and feedback
|
|
36
|
+
</div>
|
|
37
|
+
<p id="feedback-privacy" class="feedback-note">
|
|
38
|
+
Opens a draft issue in pskoett/pmx-canvas. Review and submit it on GitHub using your account. Issues are
|
|
39
|
+
public. Only what you enter below is included; no board contents, workspace paths, screenshots, or logs are
|
|
40
|
+
attached.
|
|
41
|
+
</p>
|
|
42
|
+
<label>
|
|
43
|
+
Feedback type
|
|
44
|
+
<select class="text-prompt-input" value={kind} onChange={(e) => setKind(e.currentTarget.value)}>
|
|
45
|
+
<option>Bug report</option>
|
|
46
|
+
<option>Feature request</option>
|
|
47
|
+
<option>General feedback</option>
|
|
48
|
+
</select>
|
|
49
|
+
</label>
|
|
50
|
+
<label>
|
|
51
|
+
Title
|
|
52
|
+
<input
|
|
53
|
+
class="text-prompt-input"
|
|
54
|
+
name="title"
|
|
55
|
+
required
|
|
56
|
+
maxLength={120}
|
|
57
|
+
value={title}
|
|
58
|
+
onInput={(e) => setTitle(e.currentTarget.value)}
|
|
59
|
+
placeholder="A short summary"
|
|
60
|
+
/>
|
|
61
|
+
</label>
|
|
62
|
+
<label>
|
|
63
|
+
Description
|
|
64
|
+
<textarea
|
|
65
|
+
class="text-prompt-input"
|
|
66
|
+
required
|
|
67
|
+
maxLength={1200}
|
|
68
|
+
rows={6}
|
|
69
|
+
value={description}
|
|
70
|
+
onInput={(e) => setDescription(e.currentTarget.value)}
|
|
71
|
+
placeholder="What happened, what you expected, and steps to reproduce — or describe your idea."
|
|
72
|
+
/>
|
|
73
|
+
</label>
|
|
74
|
+
<input type="hidden" name="body" value={`## ${kind}\n\n${description.trim()}`} />
|
|
75
|
+
<div class="text-prompt-actions">
|
|
76
|
+
<button type="button" class="text-prompt-cancel" onClick={onClose}>
|
|
77
|
+
Cancel
|
|
78
|
+
</button>
|
|
79
|
+
<button type="submit" class="text-prompt-confirm" disabled={!title.trim() || !description.trim()}>
|
|
80
|
+
Continue on GitHub ↗
|
|
81
|
+
</button>
|
|
82
|
+
</div>
|
|
83
|
+
</form>
|
|
84
|
+
</div>
|
|
85
|
+
);
|
|
86
|
+
}
|