pmx-canvas 0.6.2 → 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 +31 -0
- package/Readme.md +30 -3
- package/dist/canvas/global.css +32 -0
- package/dist/canvas/index.js +68 -66
- package/dist/json-render/index.js +57 -57
- package/dist/types/client/canvas/FeedbackDialog.d.ts +4 -0
- package/dist/types/client/canvas/auto-fit.d.ts +3 -0
- package/dist/types/client/nodes/use-iframe-content-height.d.ts +3 -3
- package/dist/types/client/state/human-store.d.ts +1 -0
- package/dist/types/json-render/catalog.d.ts +20 -20
- package/dist/types/json-render/schema.d.ts +40 -0
- package/dist/types/mcp/skills.d.ts +13 -0
- package/dist/types/server/bundled-skills.d.ts +32 -4
- package/docs/cli.md +7 -2
- package/docs/http-api.md +5 -1
- package/docs/mcp.md +35 -1
- package/docs/node-types.md +43 -1
- package/docs/product-context-vision-2026-09.md +17 -6
- package/docs/product-vision-2026-09.md +136 -41
- package/docs/product-vision-review-2026-09.md +277 -0
- package/package.json +11 -11
- package/skills/json-render-mcp/SKILL.md +118 -2
- package/skills/pmx-canvas/SKILL.md +43 -13
- package/skills/pmx-canvas/evals/evals.json +46 -0
- package/skills/pmx-canvas/references/installing-pmx-canvas.md +5 -5
- package/src/client/canvas/FeedbackDialog.tsx +86 -0
- package/src/client/canvas/ToolRail.tsx +225 -189
- package/src/client/canvas/auto-fit.ts +20 -1
- package/src/client/nodes/use-iframe-content-height.ts +44 -24
- package/src/client/state/human-store.ts +6 -6
- package/src/client/theme/global.css +32 -0
- package/src/json-render/catalog.ts +6 -0
- package/src/json-render/renderer/index.tsx +17 -0
- package/src/json-render/schema.ts +4 -0
- package/src/mcp/server.ts +9 -4
- package/src/mcp/skills.ts +47 -0
- package/src/server/bundled-skills.ts +92 -53
- package/src/server/operations/ops/nodes.ts +43 -11
- package/src/shared/content-height-reporter.ts +4 -2
|
@@ -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,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pmx-canvas",
|
|
3
|
-
"version": "0.6.
|
|
4
|
-
"description": "Spatial canvas workbench for coding agents
|
|
3
|
+
"version": "0.6.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",
|
|
7
7
|
"module": "./src/server/index.ts",
|
|
@@ -43,9 +43,9 @@
|
|
|
43
43
|
"typecheck": "tsc --noEmit && tsc -p tsconfig.tests.json",
|
|
44
44
|
"lint": "biome check .",
|
|
45
45
|
"lint:fix": "biome check --write .",
|
|
46
|
-
"test": "if [ -d tests/unit ]; then PMX_MCP_APP_HOST_STATE_FILE=/tmp/pmx-canvas-test-app-host-state.json PMX_CANVAS_DISABLE_BROWSER_OPEN=1 bun test tests/unit; else echo 'tests/ is not shipped in the npm package
|
|
46
|
+
"test": "if [ -d tests/unit ]; then PMX_MCP_APP_HOST_STATE_FILE=/tmp/pmx-canvas-test-app-host-state.json PMX_CANVAS_DISABLE_BROWSER_OPEN=1 bun test tests/unit; else echo 'tests/ is not shipped in the npm package — clone the repo to run the suite'; fi",
|
|
47
47
|
"test:unit": "PMX_MCP_APP_HOST_STATE_FILE=/tmp/pmx-canvas-test-app-host-state.json PMX_CANVAS_DISABLE_BROWSER_OPEN=1 bun test tests/unit",
|
|
48
|
-
"test:client": "if [ -d tests/client ]; then bun test --preload ./tests/client/setup.ts tests/client; else echo 'tests/ is not shipped in the npm package
|
|
48
|
+
"test:client": "if [ -d tests/client ]; then bun test --preload ./tests/client/setup.ts tests/client; else echo 'tests/ is not shipped in the npm package — clone the repo to run the suite'; fi",
|
|
49
49
|
"test:coverage": "PMX_MCP_APP_HOST_STATE_FILE=/tmp/pmx-canvas-test-app-host-state.json PMX_CANVAS_DISABLE_BROWSER_OPEN=1 bun test tests/unit --coverage --coverage-reporter=text --coverage-reporter=lcov --coverage-dir coverage && bun scripts/check-coverage.ts",
|
|
50
50
|
"test:web-canvas": "PMX_CANVAS_DISABLE_BROWSER_OPEN=1 bun run build && PMX_CANVAS_DISABLE_BROWSER_OPEN=1 bash scripts/run-playwright.sh",
|
|
51
51
|
"test:e2e": "bun run test:web-canvas",
|
|
@@ -59,11 +59,11 @@
|
|
|
59
59
|
},
|
|
60
60
|
"dependencies": {
|
|
61
61
|
"@joplin/turndown-plugin-gfm": "^1.0.64",
|
|
62
|
-
"@json-render/core": "0.
|
|
63
|
-
"@json-render/directives": "0.
|
|
64
|
-
"@json-render/mcp": "0.
|
|
65
|
-
"@json-render/react": "0.
|
|
66
|
-
"@json-render/shadcn": "0.
|
|
62
|
+
"@json-render/core": "0.21.0",
|
|
63
|
+
"@json-render/directives": "0.21.0",
|
|
64
|
+
"@json-render/mcp": "0.21.0",
|
|
65
|
+
"@json-render/react": "0.21.0",
|
|
66
|
+
"@json-render/shadcn": "0.21.0",
|
|
67
67
|
"@modelcontextprotocol/ext-apps": "^1.3.1",
|
|
68
68
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
69
69
|
"@preact/signals": "^2.0.0",
|
|
@@ -79,8 +79,8 @@
|
|
|
79
79
|
"devDependencies": {
|
|
80
80
|
"@biomejs/biome": "^2.5.2",
|
|
81
81
|
"@happy-dom/global-registrator": "^20.10.6",
|
|
82
|
-
"@json-render/devtools": "0.
|
|
83
|
-
"@json-render/devtools-react": "0.
|
|
82
|
+
"@json-render/devtools": "0.21.0",
|
|
83
|
+
"@json-render/devtools-react": "0.21.0",
|
|
84
84
|
"@playwright/test": "^1.58.2",
|
|
85
85
|
"@tailwindcss/cli": "^4.1.18",
|
|
86
86
|
"@testing-library/preact": "^3.2.4",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: json-render-mcp
|
|
3
|
-
description:
|
|
3
|
+
description: Builds interactive json-render panels with PMX Canvas native tools or standalone MCP Apps. Use for stateful forms, repeated content, and AX actions in PMX Canvas, or MCP-hosted UIs in Claude, ChatGPT, Cursor, and VS Code.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# @json-render/mcp
|
|
@@ -12,7 +12,123 @@ In `pmx-canvas`, prefer the native `canvas_render { action: "add-json-render" }`
|
|
|
12
12
|
directly in canvas node state and render them through the local `pmx-canvas` viewer route without
|
|
13
13
|
needing a separate sidecar server.
|
|
14
14
|
|
|
15
|
-
##
|
|
15
|
+
## PMX Canvas workflow (json-render 0.21)
|
|
16
|
+
|
|
17
|
+
1. Read `canvas://schema` (or use `canvas_render { action: "describe-schema" }`) for
|
|
18
|
+
the installed component catalog. PMX includes shadcn components and its own charts;
|
|
19
|
+
do not assume every component or action from an upstream example is registered.
|
|
20
|
+
2. Build a complete `{ root, elements, state }` spec. Validate with
|
|
21
|
+
`canvas_render { action: "validate", type: "json-render", spec }`.
|
|
22
|
+
3. Create it with `canvas_render { action: "add-json-render", title, spec }`.
|
|
23
|
+
For incremental generation, use `action: "stream-json-render"`, reuse the returned
|
|
24
|
+
`nodeId` for subsequent patches, and set `done: true` on the final call.
|
|
25
|
+
4. Inspect the panel and exercise its inputs. Schema acceptance does not prove that
|
|
26
|
+
an action reached the server or that a form edit was persisted.
|
|
27
|
+
|
|
28
|
+
### State, forms, and repeated content
|
|
29
|
+
|
|
30
|
+
- Put initial values in spec-level `state`, alongside `root` and `elements`. PMX seeds
|
|
31
|
+
its viewer from this object; do not put `initialState` on a component.
|
|
32
|
+
- Use JSON Pointer paths: `value: { "$bindState": "/form/title" }` for `Input`,
|
|
33
|
+
`Textarea`, or `Select`; `checked: { "$bindState": "/form/urgent" }` for `Checkbox`
|
|
34
|
+
or `Switch`. Supply the catalog's required `label` and `name` props. `$state` reads
|
|
35
|
+
a value only; `$bindState` also writes edits. `props.statePath` is not input binding.
|
|
36
|
+
- `repeat`, `watch`, `visible`, `on`, and `slots` are element fields, not props.
|
|
37
|
+
`repeat: { "statePath": "/projects", "key": "id" }` repeats the container's children.
|
|
38
|
+
Within those children, a nested container can use
|
|
39
|
+
`repeat: { "statePath": { "$item": "tasks" }, "key": "id" }` to iterate the current
|
|
40
|
+
project's tasks. Do not use `"/tasks"` (a root path) for that nested array.
|
|
41
|
+
`$item` and `$index` refer to the innermost repeat; use
|
|
42
|
+
`checked: { "$bindItem": "done" }` to edit that task's `done` field.
|
|
43
|
+
- Card body content uses `children: ["bodyId"]`. Named regions use
|
|
44
|
+
`slots: { "header": ["headingId"], "footer": ["actionsId"] }`. Every referenced ID
|
|
45
|
+
must exist in `elements`; do not put body content in `slots.default`. A header slot
|
|
46
|
+
replaces the Card's title and description props; without it, those props work as before.
|
|
47
|
+
- Watchers skip mount: `watch: { "/form/title": { "action": "setState", "params":
|
|
48
|
+
{ "statePath": "/dirty", "value": true } } }` runs after the value changes, not to
|
|
49
|
+
initialize `/dirty`. Seed initial and derived defaults explicitly. Avoid watchers
|
|
50
|
+
that write back to their own watched paths and create loops.
|
|
51
|
+
|
|
52
|
+
### Actions and persistence boundaries
|
|
53
|
+
|
|
54
|
+
- Bind buttons with `on.press`, for example an action named `ax.work.create` or
|
|
55
|
+
`ax.steer`, with its AX payload in `params`. PMX forwards only registered handlers;
|
|
56
|
+
invented action names cannot execute arbitrary tools, shell commands, or requests.
|
|
57
|
+
The server still validates the payload and the node's AX capabilities.
|
|
58
|
+
- AX handlers are **fire-and-forget** postMessages. Their `onSuccess` callbacks mean
|
|
59
|
+
local dispatch completed, **not server acknowledgment**. Do not clear a draft or
|
|
60
|
+
show “Saved” on that basis. Confirm via reflected AX state under reserved `/ax`
|
|
61
|
+
(where applicable), or query the server's AX state/timeline. Do not use `/ax` for drafts.
|
|
62
|
+
- Built-in `validateForm` writes `{ valid, errors }` to `/formValidation` (or
|
|
63
|
+
`params.statePath`) and returns without running `onSuccess`. Do not chain submission
|
|
64
|
+
through that callback, or assume a following action in an array is validation-gated.
|
|
65
|
+
Use an explicit validation step and state-based gating; server-side validation is
|
|
66
|
+
still required for any submitted data.
|
|
67
|
+
- Form edits, `setState`, and `$bindItem` mutate **viewer-local state**, not the stored
|
|
68
|
+
spec. Iframe reloads, including spec/stream updates, reset it from the latest spec's
|
|
69
|
+
initial state. Finish streaming before collecting input; persist important changes
|
|
70
|
+
through an explicit supported server interaction. Stored canvas nodes survive
|
|
71
|
+
reloads, but unsent local drafts do not.
|
|
72
|
+
|
|
73
|
+
### Example: editable task draft
|
|
74
|
+
|
|
75
|
+
Pass this object to `canvas_render`. Editing either field sets a local dirty flag;
|
|
76
|
+
the button requests a real AX work item without pretending the request was saved.
|
|
77
|
+
|
|
78
|
+
```json
|
|
79
|
+
{
|
|
80
|
+
"action": "add-json-render",
|
|
81
|
+
"title": "Task draft",
|
|
82
|
+
"spec": {
|
|
83
|
+
"root": "card",
|
|
84
|
+
"state": { "form": { "title": "Review release notes", "detail": "Check the upgrade caveats." }, "dirty": false },
|
|
85
|
+
"elements": {
|
|
86
|
+
"card": {
|
|
87
|
+
"type": "Card",
|
|
88
|
+
"props": { "title": "Task draft" },
|
|
89
|
+
"children": ["fields"],
|
|
90
|
+
"slots": { "footer": ["request"] }
|
|
91
|
+
},
|
|
92
|
+
"fields": {
|
|
93
|
+
"type": "Stack",
|
|
94
|
+
"props": { "direction": "vertical", "gap": "md" },
|
|
95
|
+
"children": ["title", "detail"],
|
|
96
|
+
"watch": {
|
|
97
|
+
"/form/title": { "action": "setState", "params": { "statePath": "/dirty", "value": true } },
|
|
98
|
+
"/form/detail": { "action": "setState", "params": { "statePath": "/dirty", "value": true } }
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
"title": {
|
|
102
|
+
"type": "Input",
|
|
103
|
+
"props": { "label": "Title", "name": "title", "value": { "$bindState": "/form/title" } }
|
|
104
|
+
},
|
|
105
|
+
"detail": {
|
|
106
|
+
"type": "Textarea",
|
|
107
|
+
"props": { "label": "Details", "name": "detail", "value": { "$bindState": "/form/detail" } }
|
|
108
|
+
},
|
|
109
|
+
"request": {
|
|
110
|
+
"type": "Button",
|
|
111
|
+
"props": { "label": "Request task", "variant": "primary" },
|
|
112
|
+
"on": {
|
|
113
|
+
"press": {
|
|
114
|
+
"action": "ax.work.create",
|
|
115
|
+
"params": { "title": { "$state": "/form/title" }, "detail": { "$state": "/form/detail" } }
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
The draft remains visible after dispatch. Verify that the work item appears in AX
|
|
125
|
+
state before reporting success. Repeated clicks can create duplicate work items.
|
|
126
|
+
|
|
127
|
+
## Standalone MCP App quick start
|
|
128
|
+
|
|
129
|
+
Use this path only when building a separate MCP Apps server rather than a native
|
|
130
|
+
PMX panel. PMX's `canvas_render` path needs none of the server, bundler, or client
|
|
131
|
+
configuration below.
|
|
16
132
|
|
|
17
133
|
### Server (Node.js)
|
|
18
134
|
|
|
@@ -18,12 +18,24 @@ 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,
|
|
25
25
|
read [Installing PMX Canvas](references/installing-pmx-canvas.md).
|
|
26
26
|
|
|
27
|
+
## Reading bundled skills over MCP
|
|
28
|
+
|
|
29
|
+
When the server advertises `io.modelcontextprotocol/skills`, supporting hosts can discover
|
|
30
|
+
bundled skills with `skills/list` and retrieve a manifest with `skills/get`. These are MCP
|
|
31
|
+
protocol methods, not canvas tools. Read `skill://pmx-canvas/SKILL.md` and relative supporting
|
|
32
|
+
files (for example `skill://pmx-canvas/references/installing-pmx-canvas.md`) through
|
|
33
|
+
`resources/read`, fetching only what is needed. Hosts without extension support can still read
|
|
34
|
+
ordinary resources or use installed filesystem skills; `canvas://skills` remains available.
|
|
35
|
+
Resource reads do not activate skills or authorize executing their scripts. The host must
|
|
36
|
+
preserve MCP origin and apply integrity/approval checks. Restart MCP after upgrading the package;
|
|
37
|
+
the served catalog is a startup snapshot. Local mirrors still use `skills sync` below.
|
|
38
|
+
|
|
27
39
|
## Required Operating Sequence
|
|
28
40
|
|
|
29
41
|
0. **After a `pmx-canvas` upgrade, refresh this skill first.** Run
|
|
@@ -237,8 +249,18 @@ graph 760×520, mcp-app 960×600, web-artifact 960×720. A *hosted* app opened w
|
|
|
237
249
|
`canvas_app { action: "open-mcp-app" | "diagram" }` — including the Excalidraw diagram preset — is
|
|
238
250
|
the exception: request `width: 720, height: 500` for its standard landscape preset instead of
|
|
239
251
|
relying on the 960×600 default for a directly created `mcp-app` node. After the app mounts, read
|
|
240
|
-
|
|
241
|
-
|
|
252
|
+
only its geometry, e.g. `pmx-canvas node get <id> --fields id,type,position,size`, and use the
|
|
253
|
+
persisted size for subsequent placement. With MCP tool execution that supports output projection,
|
|
254
|
+
project the layout to node id/type/position/size before returning it to context; otherwise prefer
|
|
255
|
+
a targeted `canvas_node { action: "get", id }`. Read the full layout only when its other state
|
|
256
|
+
is needed. Mounted apps may change the requested dimensions.
|
|
257
|
+
Authored iframe surfaces grow in height as content changes, up to 1400px. A growing ungrouped,
|
|
258
|
+
unpinned card moves down when needed to leave a 24px gap without moving its neighbors; grouped
|
|
259
|
+
cards retain their authored placement. Width stays explicit, and `strictSize` or manually resized
|
|
260
|
+
cards do not auto-grow. Fitting waits while a human holds the card, including in another tab;
|
|
261
|
+
automatic relocations are undoable. This is not a shrink-to-fit action or `view.fit` (which only changes zoom).
|
|
262
|
+
After content settles, inspect the rendered result and arrange the intended node IDs if more
|
|
263
|
+
spacing is needed; do not compensate with arbitrarily huge fixed frames.
|
|
242
264
|
Since 0.4.6 the server clamps explicit creation sizes UP to per-type
|
|
243
265
|
readability floors (e.g. markdown 360×180, graph/json-render/html 420×280, mcp-app 480×320) —
|
|
244
266
|
a tiny probe size silently becomes the floor. `strictSize: true` is the only opt-out (a fixed
|
|
@@ -291,8 +313,15 @@ The board has three modes, all gated on one fact — whether a session is attach
|
|
|
291
313
|
terminal: `pmx-canvas pump --consumer <your-key> --exec '<command>'`. It long-polls your
|
|
292
314
|
delivery queue, runs the command once per steer (message on stdin plus the
|
|
293
315
|
`PMX_STEER_MESSAGE`/`ID`/`SOURCE`/`TARGET`/`CREATED_AT` env envelope), and marks
|
|
294
|
-
per-consumer
|
|
295
|
-
|
|
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;
|
|
296
325
|
refused on Windows — read stdin there). `--parent <key>` rolls you up under an orchestrator's
|
|
297
326
|
chip; `--once` for scripts. See `pmx-canvas pump --help`.
|
|
298
327
|
|
|
@@ -467,20 +496,21 @@ Prefer `canvas_query { action: "search" }` over parsing the full layout.
|
|
|
467
496
|
iframe's per-mount nonce, so AX buttons only work inside the in-canvas node (0.4.4 Codex note).
|
|
468
497
|
Do not tell a user a standalone tab's controls will steer the agent.
|
|
469
498
|
- A hosted ext-app (Excalidraw) node in a **WebKit** host panel (e.g. the GitHub Copilot app's
|
|
470
|
-
embedded WKWebView)
|
|
471
|
-
|
|
472
|
-
|
|
499
|
+
embedded WKWebView) can remain blank even when its API session is healthy and `sessionStatus`
|
|
500
|
+
is `ready`. This host-specific rendering issue remains open; successful Chrome/Codex rendering
|
|
501
|
+
does not establish native-host health. Since 0.4.6 the canvas runs a **paint oracle +
|
|
473
502
|
recovery ladder** under WebKit: present-at-load ext-apps mount strictly one at a time (the
|
|
474
503
|
cold burst was the trigger), each frame answers a double-rAF **paint probe** after settle, and
|
|
475
504
|
on silence the ladder escalates — soft-expand cycle (the automatic analogue of the proven
|
|
476
505
|
enlarge+close) → serialized remount → an explicit "App surface failed to paint / Retry"
|
|
477
|
-
affordance.
|
|
478
|
-
|
|
506
|
+
affordance. Native Copilot/WebKit surfaces can still remain blank despite a successful
|
|
507
|
+
probe, including when visibility is reported as visible. The recovery trail
|
|
479
508
|
(`GET /api/canvas/debug/ext-app-recovery` / `window.__PMX_EXTAPP_LOG`) now records
|
|
480
509
|
`mount-slot`, `paint-ok`, `paint-fail`, `soft-expand-cycle`, `recovery-exhausted`, and
|
|
481
|
-
`assume-visible-rearm
|
|
482
|
-
|
|
483
|
-
|
|
510
|
+
`assume-visible-rearm`. Treat `paint-ok`/`paint-fail` as diagnostic evidence, not compositor
|
|
511
|
+
proof. Require a rendered screenshot in the affected host before declaring its surface
|
|
512
|
+
healthy; a Chromium pass does not close a native Copilot/WebKit failure. In a host that
|
|
513
|
+
reports the document hidden, `paint-ok` is recorded as
|
|
484
514
|
`paint-ok (unverified: host hidden)` — the app answered the paint probe, but nothing is
|
|
485
515
|
proven composited, so do not treat it as a verified paint. If a
|
|
486
516
|
tile still shows the Retry affordance, click Retry (fresh recovery budget) or expand-then-close;
|
|
@@ -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
|
}
|