pmx-canvas 0.5.0 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +45 -0
- package/Readme.md +9 -6
- package/dist/canvas/global.css +83 -6
- package/dist/canvas/index.js +177 -116
- package/dist/canvas/mermaid-entry.js +1303 -1303
- package/dist/json-render/index.js +101 -102
- package/dist/types/client/canvas/canvas-area.d.ts +14 -0
- package/dist/types/client/nodes/ExtAppFrame.d.ts +2 -0
- package/dist/types/server/canvas-operations.d.ts +10 -0
- package/docs/RELEASE.md +14 -0
- package/docs/adr-001-bun-only-runtime.md +1 -1
- package/docs/bun-webview-integration.md +2 -2
- package/docs/product-context-vision-2026-09.md +207 -0
- package/docs/product-review-2026-09.md +174 -0
- package/docs/product-vision-2026-09.md +200 -0
- package/docs/screenshot.png +0 -0
- package/package.json +5 -5
- package/skills/pmx-canvas/SKILL.md +61 -30
- package/skills/pmx-canvas/references/installing-pmx-canvas.md +126 -18
- package/skills/web-artifacts-builder/scripts/bundle-artifact.sh +12 -1
- package/src/cli/commands/pump.ts +13 -2
- package/src/cli/index.ts +1 -0
- package/src/client/canvas/CanvasViewport.tsx +11 -0
- package/src/client/canvas/TopBar.tsx +85 -45
- package/src/client/canvas/canvas-area.ts +33 -0
- package/src/client/canvas/use-pan-zoom.ts +7 -0
- package/src/client/nodes/ExtAppFrame.tsx +152 -23
- package/src/client/state/canvas-store.ts +29 -11
- package/src/client/theme/global.css +83 -6
- package/src/server/canvas-operations.ts +41 -6
- package/src/server/index.ts +4 -2
- package/src/server/operations/mcp.ts +45 -31
- package/src/server/operations/ops/ax-presence.ts +3 -0
- package/src/server/operations/ops/nodes.ts +12 -0
- package/src/server/operations/ops/snapshots.ts +6 -19
- package/src/server/scope-fence.ts +1 -1
|
@@ -23,3 +23,17 @@ export declare function canvasAreaCenter(): {
|
|
|
23
23
|
x: number;
|
|
24
24
|
y: number;
|
|
25
25
|
};
|
|
26
|
+
export interface CanvasFitInsets {
|
|
27
|
+
top: number;
|
|
28
|
+
right: number;
|
|
29
|
+
bottom: number;
|
|
30
|
+
left: number;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Screen-space insets Fit must reserve for the floating chrome that overlays
|
|
34
|
+
* the canvas region: the bottom command bar (whose pinned-chip row grows it)
|
|
35
|
+
* and the bottom-right minimap. Measured from the live elements — fit's old
|
|
36
|
+
* world-space padding shrank with the fit zoom and parked nodes underneath
|
|
37
|
+
* both (0.5.0 Amp report, finding A; architecture rule 9's trap).
|
|
38
|
+
*/
|
|
39
|
+
export declare function canvasFitInsets(): CanvasFitInsets;
|
|
@@ -3,6 +3,8 @@ import { AppBridge } from '@modelcontextprotocol/ext-apps/app-bridge';
|
|
|
3
3
|
import type { CanvasNodeState } from '../types';
|
|
4
4
|
type ExtAppBridgeNotifications = Pick<AppBridge, 'sendToolInput' | 'sendToolResult'>;
|
|
5
5
|
type DisplayMode = 'inline' | 'fullscreen' | 'pip';
|
|
6
|
+
/** Paint probe outcome: only a content-carrying tick counts as painted. */
|
|
7
|
+
export type PaintProbeVerdict = 'content-verified' | 'tick-no-content' | 'timeout';
|
|
6
8
|
interface ExtAppHostDimensionsTarget {
|
|
7
9
|
clientWidth?: number;
|
|
8
10
|
clientHeight?: number;
|
|
@@ -178,6 +178,16 @@ export declare function setCanvasContextPins(nodeIds: string[], mode?: CanvasPin
|
|
|
178
178
|
nodeIds: string[];
|
|
179
179
|
};
|
|
180
180
|
export declare function listCanvasSnapshots(options?: Parameters<typeof canvasState.listSnapshots>[0]): CanvasSnapshot[];
|
|
181
|
+
/**
|
|
182
|
+
* Snapshot save with unchanged-board reuse — the ONE path every surface must
|
|
183
|
+
* take (op registry, SDK). The SDK once called saveCanvasSnapshot directly and
|
|
184
|
+
* stacked identical snapshots the HTTP/MCP path deduplicated (0.5.0 Codex
|
|
185
|
+
* finding V).
|
|
186
|
+
*/
|
|
187
|
+
export declare function saveCanvasSnapshotWithReuse(name: string): {
|
|
188
|
+
snapshot: CanvasSnapshot | null;
|
|
189
|
+
reused: boolean;
|
|
190
|
+
};
|
|
181
191
|
export declare function saveCanvasSnapshot(name: string): CanvasSnapshot | null;
|
|
182
192
|
export declare function restoreCanvasSnapshot(idOrName: string): Promise<{
|
|
183
193
|
ok: boolean;
|
package/docs/RELEASE.md
CHANGED
|
@@ -250,3 +250,17 @@ with `ok: true`, the published tarball is intact end-to-end.
|
|
|
250
250
|
- **Node 24 deprecation timeline**: GitHub Actions is migrating
|
|
251
251
|
`actions/checkout`, `setup-node`, `upload-artifact` to Node 24 by
|
|
252
252
|
June 2, 2026. The publish workflow already pins `@v5` of all three.
|
|
253
|
+
- **npm token failures wear two disguises** (both hit the 0.5.0 publish,
|
|
254
|
+
after build/tests/provenance all succeeded):
|
|
255
|
+
- `404 Not Found - PUT …/pmx-canvas` on a package that exists = the
|
|
256
|
+
token was rejected (npm masks permission refusals as 404). Rotate the
|
|
257
|
+
`NPM_TOKEN` repo secret.
|
|
258
|
+
- `EOTP: This operation requires a one-time password` = the account
|
|
259
|
+
enforces 2FA on writes and the token doesn't have **Bypass 2FA**
|
|
260
|
+
ticked — CI cannot answer an OTP. A granular token needs that box
|
|
261
|
+
checked to publish from Actions.
|
|
262
|
+
- Both are fixed without re-tagging: update the secret, then
|
|
263
|
+
`gh run rerun <publish-run-id> --failed` re-publishes the same tag.
|
|
264
|
+
- npm restricts bypass-2FA tokens for direct publishing by **Jan 2027**
|
|
265
|
+
— migrate to Trusted Publishing (OIDC; `publish.yml` already has
|
|
266
|
+
`id-token: write`) and delete the token before then.
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
## Context
|
|
8
8
|
|
|
9
|
-
pmx-canvas ships as TypeScript source executed directly by Bun. `package.json` points `main`/`exports` at `src/server/index.ts`, the `bin` entry is `src/cli/index.ts` with a `#!/usr/bin/env bun` shebang, and `engines` requires `bun >= 1.
|
|
9
|
+
pmx-canvas ships as TypeScript source executed directly by Bun. `package.json` points `main`/`exports` at `src/server/index.ts`, the `bin` entry is `src/cli/index.ts` with a `#!/usr/bin/env bun` shebang, and `engines` requires `bun >= 1.4.2`. There is no compiled JS distribution; `dist/` carries only the client bundle, the json-render viewer, and type declarations.
|
|
10
10
|
|
|
11
11
|
The runtime dependence on Bun is not incidental. `Bun.serve` is the HTTP + SSE server, `bun:sqlite` is the persistence layer, `Bun.WebView` backs the screenshot/evaluate automation tools, and `bun test` is the test runner. These are load-bearing APIs across `src/server/`, not shims that a bundler could paper over.
|
|
12
12
|
|
|
@@ -12,7 +12,7 @@ This document tracks:
|
|
|
12
12
|
|
|
13
13
|
**Implemented** for Phase 1.
|
|
14
14
|
|
|
15
|
-
The repo now targets Bun `>=1.
|
|
15
|
+
The repo now targets Bun `>=1.4.2`, and PMX Canvas ships an opt-in, server-owned WebView automation session that can:
|
|
16
16
|
|
|
17
17
|
- start a headless browser session for `/workbench`
|
|
18
18
|
- report WebView runtime status
|
|
@@ -192,7 +192,7 @@ If `chromePath` or `chromeArgv` is provided, PMX Canvas forces a Chrome-backed s
|
|
|
192
192
|
|
|
193
193
|
The repo now requires:
|
|
194
194
|
|
|
195
|
-
- Bun `>=1.
|
|
195
|
+
- Bun `>=1.4.2`
|
|
196
196
|
|
|
197
197
|
That change is reflected in:
|
|
198
198
|
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
# Vision extension: boards, personal wiki, and workspace context
|
|
2
|
+
|
|
3
|
+
**Status:** Proposed for discussion, not an implementation commitment.
|
|
4
|
+
**Date:** 2026-09-06
|
|
5
|
+
**Companions:** [Product review](product-review-2026-09.md), [product vision](product-vision-2026-09.md).
|
|
6
|
+
**Request:** Review the existing vision and explore hosted users building their own wiki by describing their work, with their boards contributing context, and cross-cutting organizational context shared within a workspace. Reuse the logic of the personal/context-frame projects inside pmx-canvas's own store rather than depend on an external wiki.
|
|
7
|
+
**Method:** Read both documents and current canvas context/provenance/caller contracts; research threads inspected both actual reference projects after user-authorized local-file transfers. The shared snapshot matched the previously inspected files; the personal transfer superseded its initially empty checkout. Reconsulted the oracle on private maintenance versus confirmation/publication using those findings. Static source analysis only: no reference services, onboarding, or promotion jobs were executed, and earlier audit tests/adoption measurements were not rerun. The public example is no longer the basis for this proposal.
|
|
8
|
+
|
|
9
|
+
## Position
|
|
10
|
+
|
|
11
|
+
**Work visually with your agents, build understanding as you go, and bring the right knowledge into whatever comes next.**
|
|
12
|
+
|
|
13
|
+
pmx-canvas is for **planning, discovery, analysis, and coordination with agents**. This is its intended purpose, not merely an initial audience experiment. Boards are the working surface; personal knowledge and deliberately shared workspace knowledge provide continuity across them through one underlying knowledge model.
|
|
14
|
+
|
|
15
|
+
- **Shape the work together.** Arrange, connect, pin, and annotate to express relationships and relevance that shape what agents read and help steer what they do next. Agents bring questions, proposals, and results back onto the same surface. Spatial layout provides context; not every move or camera gesture expresses intent.
|
|
16
|
+
- **Make memory useful in the next task.** Resume without re-explaining everything. Bring relevant prior learning and authorized cross-team decisions, dependencies, and conflicts into the work—not merely into a growing collection of notes.
|
|
17
|
+
- **Keep context honest as work changes.** Show sources and revisions, surface known changes and conflicts, and make uncertainty and review needs visible. Help people judge what still applies; do not treat a newer timestamp as truth or silently replace confirmed knowledge.
|
|
18
|
+
|
|
19
|
+
The important distinction: **a board is evidence of work, not automatically an authoritative statement about the organization.** Remembering every board is useful. Treating every brainstorm, rejected option, generated answer, or private note as accepted organizational context is not.
|
|
20
|
+
|
|
21
|
+
Preserve the existing decisions: all node types and fleet capabilities stay; the app owns storage and history; 6b remains undecided; hosted multiplayer is later work. This extension does not authorize starting those implementations.
|
|
22
|
+
|
|
23
|
+
### Revised conclusion after inspecting both projects
|
|
24
|
+
|
|
25
|
+
**Combine their logic, not their deployment machinery.** The personal frame supplies the daily work and learning loop; the shared frame supplies cross-cutting organizational knowledge and governed promotion; canvas supplies the visual working surface. A hosted canvas can make these three roles one coherent experience without requiring users to manage repositories, QMD collections, plugins, or promotion archives.
|
|
26
|
+
|
|
27
|
+
The largest correction to the first proposal is that **routine private wiki upkeep should not require approval for every edit**. The personal frame already instructs agents to maintain knowledge during work. Preserve that convenience through explicit scoped delegation, visible source-backed working revisions, history, and undo. Confirmation of a claim and disclosure to colleagues remain separate, deliberate actions. This is agent-assisted learning during work, not a promise that an unattended background process understands every session.
|
|
28
|
+
|
|
29
|
+
The loop is bidirectional: work produces personal understanding; selected outcomes become shared knowledge; authorized shared decisions inform the next person's work. Cross-cutting context is not the union of employee wikis, and shared authority does not erase a person's explicitly divergent interpretation.
|
|
30
|
+
|
|
31
|
+
## Review of the existing plan
|
|
32
|
+
|
|
33
|
+
### What I would keep
|
|
34
|
+
|
|
35
|
+
- **Many named boards first.** This directly addresses the continuity problem described by the real-board evidence. Recover historical boards without treating snapshots as a normal board picker. Verify backups and recovered content before any destructive storage change.
|
|
36
|
+
- **A budgeted agent brief.** Context selection is a stronger differentiator than adding more tools. Show why material was included and allow explicit retrieval of its source.
|
|
37
|
+
- **Agent output on the working surface.** Ask and status cards should be spatially usable while keeping their underlying lifecycle and fleet behavior.
|
|
38
|
+
- **App-owned storage, durable attribution, consistent mutation policy.** These help local users immediately and establish useful hosted foundations.
|
|
39
|
+
- **Renderer consolidation without capability cuts.** Optimize actual rendering cost rather than infer that a feature is unnecessary from one person's usage.
|
|
40
|
+
|
|
41
|
+
### What I would revise before implementation
|
|
42
|
+
|
|
43
|
+
1. **Sequence around user outcomes, not the number of refactors.** The proposed 0.6 combines multi-board persistence, trust, schema work, frame consolidation, and packaging in 2–3 weeks. That estimate is not established by the review. First prove preservation, explicit board targeting, visible write failures, and a useful context loop; let renderer and packaging work ship independently rather than gate that outcome.
|
|
44
|
+
2. **Bring mutation-policy convergence and durable identity forward.** Routing the SDK through policy is independent of choosing five versus 22 MCP tools. Establish a consistent write boundary before promising complete journal coverage or trusted attribution.
|
|
45
|
+
3. **Separate history from semantic memory.** A journal records operations; a wiki records durable understanding. A log alone does not implement an audit policy, permission-aware replay, concurrent editing UX, or meaningful synthesis. Start with transactional state-plus-event durability; full replay and time scrubbing need demonstrated value, not prerequisite status for a wiki experiment.
|
|
46
|
+
4. **Do not exclude everything completed or generated.** Completed work chatter can leave the default brief; a completed decision may be the most important context next month. A generated view of accepted knowledge is not equivalent to unreviewed agent speculation. Lifecycle, authority, and relevance are separate dimensions.
|
|
47
|
+
5. **Do not make automatic session projection the default definition of memory.** Files, diffs, and test output fit coding work but not every PM board. Automatically register the board; make verbose session projection opt-in or compact and collapsed. Recency alone must not let a noisy feed consume the brief.
|
|
48
|
+
6. **Replace the human-only token claim with a threat model.** A boot secret in workbench HTML is accessible to an agent that can fetch that HTML. It does not establish human intent. Hosted roles require authenticated, scoped principals; a promise of human confirmation additionally requires a confirmation mechanism unavailable to the agent. A same-user shell agent can also modify an accessible SQLite file: app ownership alone is not process isolation.
|
|
49
|
+
7. **Correct the provenance claim.** Current node data already contains persisted source provenance; what is missing is durable authenticated writer attribution and acceptance history. Extend those concepts rather than invent a second source-provenance system.
|
|
50
|
+
8. **Treat hosted as more than a login screen.** Revocation, derived-content permissions, backups/restores, uploads, quotas, sandbox isolation, and operational recovery are new responsibilities. Node-level compare-and-set can be a starting conflict policy, but requires visible conflict/retry behavior; it does not settle collaborative text editing.
|
|
51
|
+
9. **Use measurements as evidence, not promises.** The earlier audit describes a particular tree and machine. Current context construction already has text previews and bounded pending steering. The claimed 10,000-token saving depends on what schemas hosts actually load; on-demand help alone does not remove advertised schemas. Measure current payloads before fixing budgets. Net-negative lines are not a user-value release gate.
|
|
52
|
+
|
|
53
|
+
The north star is planning, discovery, analysis, and coordination visually with agents, with useful understanding carried into the next task. Validate which spatial signals and memory workflows best serve that purpose—not whether these activities are merely an initial audience experiment. Pins, camera attention, and the time scrubber remain ideas to validate, not proven sources of value.
|
|
54
|
+
|
|
55
|
+
## The user experience
|
|
56
|
+
|
|
57
|
+
1. **Describe your work.** “I lead developer experience, work with these teams, and own these outcomes.” The assistant proposes a small personal home: responsibilities, initiatives, goals, people, and open questions. No mandatory taxonomy or blank-wiki setup project.
|
|
58
|
+
2. **Work on named boards.** A discovery board, quarterly plan, and workshop deck remain separate and recoverable. Each board is automatically listed as a source in the owner's context, within its existing permissions.
|
|
59
|
+
3. **Remember without manual filing.** After the user delegates maintenance of specified private sources, the assistant updates existing personal working pages during the task. Source links, a quiet change history, and undo replace a compulsory wiki-edit review queue. Unknowns stay unknown; generated interpretations stay labeled.
|
|
60
|
+
4. **Confirm what matters.** “Keep this as my decision” confirms an exact revision with its evidence and owner. New agent changes remain working revisions, not silently renewed confirmation. Pinning still means attention, not publication.
|
|
61
|
+
5. **Resume with relevant memory.** A new board retrieves labeled personal working knowledge alongside confirmed personal context and authorized workspace knowledge. For shared organizational facts, shared canon has authority; for personal preferences, the person's context applies. Conflicting or newer evidence is shown rather than overwritten.
|
|
62
|
+
6. **Share deliberately.** Publish a reviewed decision, goal, or dependency to the workspace. Another participant benefits without gaining access to the author's private wiki.
|
|
63
|
+
|
|
64
|
+
Example: a PM explores options on a discovery board, accepts a decision into personal context, then publishes an appropriately sourced workspace decision. A team lead opens a planning board and receives that decision plus related shared dependencies—not the PM's private stakeholder notes or abandoned brainstorming.
|
|
65
|
+
|
|
66
|
+
## One model, distinct scopes
|
|
67
|
+
|
|
68
|
+
| Surface | Responsibility | What it must not imply |
|
|
69
|
+
|---|---|---|
|
|
70
|
+
| Board | Spatial working material, artifacts, asks, evidence | Everything visible is accepted knowledge |
|
|
71
|
+
| Personal wiki | Durable context owned by one person across boards | Workspace membership grants access |
|
|
72
|
+
| Workspace context | Deliberately shared goals, decisions, ownership, dependencies | A union of everyone's private context |
|
|
73
|
+
| Agent brief | Budgeted, task-specific view over authorized material | A new source of truth or permission grant |
|
|
74
|
+
|
|
75
|
+
Use common entities, revisions, source links, and relations. Personal and workspace entities have separate ownership and audience. Model a hosting tenant separately from a person's private area and a collaborative workspace; a local filesystem workspace is not automatically an organizational security boundary. Cross-tenant membership and personal portability remain later decisions.
|
|
76
|
+
|
|
77
|
+
A board node may reference a canonical entity, display its current accepted revision, or pin an exact historical revision. Scratch cards need not become wiki entities. Board-local comments and proposals do not silently update canonical content. Restoring or deleting a board does not rewind or delete accepted workspace knowledge.
|
|
78
|
+
|
|
79
|
+
Start with flexible pages and a few useful semantic kinds—decision, assumption, goal, initiative, responsibility—not a large ontology. Identity uses stable IDs, not titles. Updating the existing object should be the default; duplicates and conflicts need explicit reconciliation rather than silent last-writer-wins synthesis.
|
|
80
|
+
|
|
81
|
+
## Automation and publication policy
|
|
82
|
+
|
|
83
|
+
**Automate remembering. Require authorization when content gains authority or reaches a broader audience.** Visibility and acceptance are independent: a shared draft is not an accepted decision, and an accepted personal note is not shared.
|
|
84
|
+
|
|
85
|
+
| Stage | Default behavior | Guardrail |
|
|
86
|
+
|---|---|---|
|
|
87
|
+
| Evidence | Register boards and source revisions automatically | Registration neither widens access nor fetches every external reference |
|
|
88
|
+
| Personal working revision | Maintain source-linked private pages during work under explicit scoped delegation | Reversible and labeled as working knowledge; cannot silently replace confirmed content in storage or retrieval |
|
|
89
|
+
| Review view | Show a consolidated diff when inspection, reconciliation, or confirmation is needed | Not a mandatory stop for every private edit; show evidence, uncertainty, and changes |
|
|
90
|
+
| Confirmed revision | Record endorsement of exact content | Confirmation means user endorsement, not objective truth; later drafts do not inherit it |
|
|
91
|
+
| Publication | Release exact content to an explicit destination | Requires target publishing authority and authority to disclose restricted source-derived content; does not implicitly confirm the claim |
|
|
92
|
+
|
|
93
|
+
Delegate maintenance once with concrete sources and scope, not blanket authority: “Maintain my private working memory from these boards; ask before confirming claims or sharing.” An explicit human request can confirm a specific revision; “summarize my week” does not authorize publication to colleagues. A private edit needs no new approval while it remains within that delegation. An agent edit to confirmed content creates a working revision; carrying confirmation or publication forward requires new authorization. Do not use model confidence, timeouts, pins, task completion, or movement onto a shared board as implicit approval.
|
|
94
|
+
|
|
95
|
+
Use two independent dimensions: working versus confirmed **entity revision**, and personal versus explicitly shared **audience**. Do not introduce sentence-level approval machinery initially. Working and confirmed revisions share an entity identity but stay distinguishable; a page mixing them cannot wear a blanket “confirmed” badge. Confirmed content cannot be silently displaced in a brief, title, summary, or relation either. When newer working evidence conflicts, show both with their status. A source's embedded instructions cannot authorize maintenance, confirmation, or disclosure.
|
|
96
|
+
|
|
97
|
+
For example, a confirmed “launch requires security sign-off” and a later draft “Tuesday if review passes” must not become “committed launch: Tuesday” in the next brief. Retaining the old revision in history is insufficient if retrieval loses its condition. Routine private maintenance remains automatic; endorsement does not.
|
|
98
|
+
|
|
99
|
+
Prevent the review queue itself from leaking: a proposal derived from private sources stays private until disclosure is authorized. The target workspace is not automatically allowed to see it merely because publication there is proposed.
|
|
100
|
+
|
|
101
|
+
### Shared synthesis needs its own source boundary
|
|
102
|
+
|
|
103
|
+
Generate shared drafts from a clean, target-scoped context. Do not reuse a personal assistant conversation containing restricted information and merely filter its citations afterward. Private information can influence conclusions without appearing in citations.
|
|
104
|
+
|
|
105
|
+
By default, an automatic derivative's audience cannot exceed the intersection of its inputs' audiences. Explicit authorized publication is a separate operation, not a side effect of summarization. This rule covers titles, backlinks, search indexes, embeddings if introduced, cached briefs, exports, notifications, and historical payloads—not just the final page text.
|
|
106
|
+
|
|
107
|
+
Permissions are checked before retrieval, ranking, and generation. An agent's access is bounded by its authenticated principal, delegated scope, and destination audience. Pinning changes relevance, never permissions. Source material is data, not authority to execute instructions found inside it.
|
|
108
|
+
|
|
109
|
+
On source revision or permission changes, invalidate affected derived caches and mark/recompute drafts as needed. Distinguish removing a board from the working surface from erasing retained evidence. Define deletion and retention policy before hosting; an append-only journal cannot be an excuse to retain private content forever. Revocation prevents future retrieval but cannot recall information already disclosed.
|
|
110
|
+
|
|
111
|
+
## Storage direction
|
|
112
|
+
|
|
113
|
+
**Keep this inside pmx-canvas, with SQLite as the initial candidate—not an external wiki requirement.** The important decision is ownership and lifecycle, not committing today to one physical database layout for every hosted team.
|
|
114
|
+
|
|
115
|
+
An eventual design needs records for boards; knowledge entities and immutable revisions; source references to exact board/node revisions; relations; ownership and access grants; proposals and acceptance events. Preserve source provenance, writer attribution, and acceptance as distinct facts. Treat search and summaries as rebuildable projections, not canonical state.
|
|
116
|
+
|
|
117
|
+
Commit authoritative state changes and their durable events atomically. A board journal may support board history; workspace knowledge has an independent lifetime and needs its own revision/event coverage. Do not force workspace entities into a board just to reuse a board-local journal. Full event-sourced reconstruction is not required for the first useful knowledge feature.
|
|
118
|
+
|
|
119
|
+
Use text search and explicit links first. Add embeddings only if retrieval evaluation shows a gap. Physical database placement, cross-database transactions, hosting concurrency, and blob storage remain implementation choices to test later.
|
|
120
|
+
|
|
121
|
+
### Translate the reference logic into one application
|
|
122
|
+
|
|
123
|
+
| Reference responsibility | Native canvas equivalent | Do not carry forward as a requirement |
|
|
124
|
+
|---|---|---|
|
|
125
|
+
| Setup interview and wiki scaffolding | Confirmed role/team/preferences profile, unknowns left explicit, editable context home | Host-specific installation and registration steps |
|
|
126
|
+
| Inbox/raw/workspace/wiki/artifacts | Capture, preserved source, active board, maintained knowledge, output with lineage | A folder tree the user must maintain |
|
|
127
|
+
| Personal QMD plus shared graph reads | One permission-aware retrieval contract with separate personal/shared scopes and authority labels | QMD dependency or a local mirror of shared canon |
|
|
128
|
+
| Promotion staging, hashes, central triage | Source-linked proposed object revision, exact review, transactional publication and audit | Git branch/archive transport or acceptance-as-publication |
|
|
129
|
+
| Drift reports and protected personal pages | Revision-aware reconciliation, explicit conflict state, preserved personal divergence | Silent overwrite or “newer timestamp means true” |
|
|
130
|
+
| Canvas pins, edges, source/artifact nodes | Board references into durable knowledge and evidence; bounded attention input | Every board becoming canonical or every artifact copied into a wiki |
|
|
131
|
+
|
|
132
|
+
The database can host all these logical roles without three independent stores. Keep their lifetimes and ownership distinct. Retrieval should return source identity/revision, scope, working/confirmed status, and freshness information consistently—even on fallback/error paths. In a brief, personal relevance and organizational authority are different ranking inputs; neither bypasses access checks. Reuse useful graph semantics before porting entire engines or introducing a universal ontology.
|
|
133
|
+
|
|
134
|
+
## What to reuse from context-frame
|
|
135
|
+
|
|
136
|
+
**Reference access, 2026-09-06:** The user supplied Amp projects `pskoett/pmx-context-frame` and `pskoett/pmx-context-frame-personal`, not GitHub repositories. Both now have inspected user-authorized reference transfers. Shared-file comparisons confirmed the prior structural findings. The personal research used transferred local Mac working files, not the empty `origin/main`; the missing-file blocker is resolved. No private personal or business content is reproduced here, and no runtime behavior is inferred merely from successful extraction.
|
|
137
|
+
|
|
138
|
+
Research records: [workspace project inspection](https://ampcode.com/threads/T-01a075f7-ce1a-717d-b7b5-543983bf386c), [personal project inspection](https://ampcode.com/threads/T-01a075f7-d585-72d2-a929-99e40a2087bb). File ranges below refer to the project named by each subsection, not pmx-canvas.
|
|
139
|
+
|
|
140
|
+
### Actual personal behavior
|
|
141
|
+
|
|
142
|
+
- **The lifecycle is already explicit.** Inbox → preserved raw sources → active workspace/canvas/artifacts → maintained wiki → selected shared-candidate staging. Navigation, inventory, and maintenance log are distinct from outputs (`README.md:32–54,132–150`; `wiki/index.md:11–40`; `wiki/wiki-system.md:158–165`).
|
|
143
|
+
- **Onboarding by conversation exists as agent instructions.** The setup skill interviews role/team/artifact preferences and namespace, scaffolds profile/team/method pages, leaves unknowns as stubs, updates indexes/log, and can be rerun. External configuration changes require confirmation. This is not a built-in wizard or proof of completed onboarding (`.github/skills/setup/SKILL.md:10,23–34,52–79,81–110`).
|
|
144
|
+
- **Private maintenance is not per-edit approval-gated.** Agents are instructed to update maintained pages during work, preserve sources, and update indexes/log. This is task-time editorial responsibility, not guaranteed background automation. Canon reconciliation must preserve intentional personal divergence and not silently overwrite durable pages (`AGENTS.md:79–85`; `wiki/wiki-system.md:70–105,158–175`; `plugins/pmx-frame/skills/update-context/SKILL.md:92–107`).
|
|
145
|
+
- **Archive code preserves evidence, not synthesis.** It validates the inbox source and a local target or no-promotion reason, moves the original into a monthly archive, and writes path/time/outcome/target metadata. The agent still decides the reusable learning. Artifact retention is classification-first, not age-only deletion (`scripts/inbox-archive.mjs:24–76`; `artifacts/README.md:13–30`).
|
|
146
|
+
- **Personal and shared retrieval are intentionally separate.** QMD indexes only personal wiki, selects `self`, and labels parsed hits `personal-draft`; malformed JSON passes through untagged, so that is not a universal enforced envelope. Bootstrap removes non-self documents and serializes index mutation. Freshness uses mtimes and optional Git lag, not semantic validation (`.qmd/index.yml:1–7`; `scripts/qmd-query.mjs:18–44`; `scripts/qmd-enforce-personal-only.mjs:7–23`; `scripts/qmd-bootstrap.mjs:8–39`; `scripts/qmd-freshness.mjs:118–153`).
|
|
147
|
+
- **Authority depends on the question.** Local orientation reads personal navigation and relevant work. For shared facts, shared canon outranks personal drafts, using bounded graph discovery then exact page reads, with a repository fallback when needed. Conflicts are surfaced and personal divergence preserved; the instructions do not justify flattening everything into one undifferentiated index (`AGENTS.md:44–55`; `plugins/pmx-frame/skills/pmx-shared-context/SKILL.md:12–44,56–75,96–112`).
|
|
148
|
+
- **Promotion packages selected objects.** Frozen IDs, source metadata, and group-reachable evidence are required by the template; trust is assigned centrally. An admin wrapper delegates validation to a separate canon CLI, computes hashes/actions and source Git state, deposits an inbox batch, and optionally commits locally. It does not itself remotely push or publish canon; admin/private labels are workflow assumptions, not app ACLs (`publish/pmx/object-template.md:6–23,48–55`; `AGENTS.md:87–117`; `scripts/pmx-promote.mjs:220–315`).
|
|
149
|
+
- **Maintenance supports judgment.** Scripts report drift, learnings, retention, and unreviewed outputs; template updates preserve user-owned content. They do not automatically synthesize or reconcile the wiki. Scheduled CI checks skill staleness, and no automatic host context-injection hook is shipped (`scripts/pmx-context-sync.mjs:141–208`; `scripts/context-maintenance.mjs:159–175,237–303`; `plugins/pmx-frame/skills/update/scripts/update-derived-frame.mjs:20–47,81–87,140–188`; `.github/workflows/skills-staleness.yml:3–26`; `AGENTS.md:136–148`).
|
|
150
|
+
- **Board documentation is not runtime evidence.** `.pmx-canvas/README.md:5–9,22–48` describes personal JSON state/snapshots, but the transferred directory has only documentation/placeholders, no actual board state. The plugin launches external canvas; its skill warns about runtime/version skew. Typed nodes, meaningful edges, artifacts, and pinned neighborhoods describe intended integration, not implemented local board storage (`plugins/pmx-frame/.mcp.json:40–46`; `plugins/pmx-frame/skills/pmx-canvas/SKILL.md:21–28,104–137,176–185,228–236`). Do not replace current canvas SQLite with this potentially stale JSON description; QMD's SQLite is a rebuildable retrieval index, not an authoritative board database.
|
|
151
|
+
|
|
152
|
+
### Actual workspace behavior
|
|
153
|
+
|
|
154
|
+
- **A durable object graph, not just templates.** `raw/` retains captures; `wiki/` contains linked durable objects; organization/domain/product/team/person hubs connect strategy, goals, assumptions, experiments, and decisions. Only wiki files feed the graph. Explicit IDs and kinds take precedence over path-derived fallbacks (`docs/architecture.md:3–13,55–91`; `src/context-engine.ts:413–434,530–565,635–661`).
|
|
155
|
+
- **Compact-first retrieval is implemented.** One parser/index feeds CLI and graph services; lexical search, node lookup, bounded neighborhoods and paths precede separately fetched full pages. Typed relations retain source page/field and differ from navigational links. Search defaults to 25/max 100 results; neighborhoods max depth 3/max 100 nodes; paths max depth 8; page bodies cap at 256 KiB. These are existing defaults, not proposed canvas budgets (`src/context-engine.ts:590–617,872–960,973–989,1028–1043,1080–1092,1159–1184`; `src/mcp.ts:26–60`).
|
|
156
|
+
- **Index freshness is not live synchronization.** Graph metadata is indexed when the service is constructed, while page bodies are read from disk on demand. A canvas implementation should return coherent revisions and invalidate indexes on writes rather than inherit that mismatch. “Stale” currently means overdue `review_by`; “orphan” means zero graph degree, not false or useless content (`src/graph-service.ts:29–46,77–79`; `src/context-engine.ts:1137–1156`).
|
|
157
|
+
- **Personal-to-shared promotion is already a deliberate boundary.** Personal frames submit `inbox/promotions/<batch>/`. Central editorial intake rewrites personal observations into neutral shared context, preserves identity/provenance, resolves links, and distributes sources. The workspace contract and personal packaging code support this handoff, but no end-to-end publication was executed during this review (`AGENTS.md:25–53`; `docs/promotion-contract.md:13–23`).
|
|
158
|
+
- **Acceptance is not publication.** `promotions:accept` records triage state/history; it does not validate, rewrite, copy, or publish objects. Optional batch lint overlays proposals in a disposable copy. Keep this distinction explicit when implementing transactional publication in canvas (`src/cli.ts:448–457`; `src/promotions.ts:459–535`).
|
|
159
|
+
- **Stable identities and provenance are concrete reusable contracts.** Promotion objects specify `id`, `kind`, `title`, `owner`, `status`, `sources`, timestamps, and schema version; namespaced ULIDs survive path/type changes. Manifests describe origins/actions/checksums; triage records actor/reason/history. Enforcement is weaker than the prose: some comparisons run only when fields are supplied, empty object lists warn, and documented `baseCanonRef` lacks implementation (`docs/promotion-contract.md:32–77`; `src/contract.ts:277–333,448–489`; `src/promotions.ts:398–417,428–507`).
|
|
160
|
+
- **There is validation, but not hosted authorization.** Duplicate IDs, broken references, and missing local sources fail lint; some missing metadata only warns. The server is anonymous: host/origin checks and limits are not user/workspace ACLs. Compact output is not redacted; it includes owner, summary, and source references. Canon-over-personal precedence is agent guidance, not enforced ranking or authorization (`src/context-engine.ts:725–805,872–886`; `src/server.ts:30–59,89–139`; `docs/space/instructions.md:14–21`).
|
|
161
|
+
- **Automation is mixed.** Parsing, querying, lint, contracts, and triage are implemented code. Editorial synthesis remains human/agent work. A weekly/manual agent workflow is checked in, but execution and enablement were not verified; external Space sync is explicitly unbuilt. Promotion-branch CI restrictions do not apply to every writer (`.github/workflows/promotion-check.yml:34–72`; `.github/workflows/weekly-promotion-triage.md:1–44,62–99`; `docs/space-distribution.md:75–88`).
|
|
162
|
+
|
|
163
|
+
### How this changes the proposal
|
|
164
|
+
|
|
165
|
+
The workspace reference is substantially more developed than the public example: reuse its object contracts, typed/provenanced relations, bounded graph retrieval, review dates, and explicit promotion states—not merely its folder organization. Translate these semantics into app-owned records and transactions; do not import path fallbacks or Git as required persistence.
|
|
166
|
+
|
|
167
|
+
Cross-cutting context should connect strategy → objectives → delivery through assumptions, evidence, and decisions. Keep ownership, reporting lines, roles, and cross-domain functions distinct; an operational board must not silently redefine organizational structure. These are current modeling policies, not automatic inference (`docs/context-stack.md:18–44`; `AGENTS.md:55–92`).
|
|
168
|
+
|
|
169
|
+
**Automatically remember the board; promote selected durable outcomes, not the entire board as shared truth.** The reference's canvas note already describes an external workbench contributing outcomes (`docs/pmx-canvas.md:3–17`). It does not implement the proposed SQLite/personal-wiki integration. Shared accepted objects can then flow back into personal agents' briefs as authorized references—not cloned editable wiki pages. Show source scope and acceptance status when personal interpretations differ from shared decisions; a trust label must not silently erase contrary evidence.
|
|
170
|
+
|
|
171
|
+
Reviewed personal-to-shared promotion is an existing design on both sides, not a new concept invented by this proposal. Equally important, routine private upkeep is already agent-maintained without blanket per-edit approval. App-enforced publication, revision-conflict checks, complete contract validation, consistent authority labels, and derived-content ACLs remain additions. Source inspection establishes scripts and instructions, not their operational success.
|
|
172
|
+
|
|
173
|
+
## Oracle challenge and recommendation
|
|
174
|
+
|
|
175
|
+
The oracle agreed with unified storage/model but rejected unified audience or authority. Its decisive counterexample: a private staffing note influences a shared roadmap summary, which cites only a shared card and converts “consider delaying” into “will delay.” Citation ACL checks and a human review can both pass while confidentiality and decision status are wrong.
|
|
176
|
+
|
|
177
|
+
Adopt clean destination-scoped synthesis, preserve tentative/rejected/accepted states, and authorize exact content when confirming or publishing it. Do not claim that review detects every leak or that these policies prove security. A person can still paste restricted prose into an already shared source; the product can enforce access and explicit publication, not guarantee leak-proof semantics.
|
|
178
|
+
|
|
179
|
+
**Second consultation, after both reference inspections:** The oracle endorsed automatic private working revisions under explicit onboarding delegation and corrected its earlier broad review recommendation. Exact authorization belongs at confirmation and disclosure transitions, not every private semantic edit. Crucially, protect confirmed content in retrieval as well as storage: a draft cannot silently become the user's endorsed position merely because it is newer. Working/confirmed revision and personal/shared audience are separate dimensions; triage acceptance is neither confirmation nor publication. This policy is a proposed native-app refinement, not a claim that the reference scripts already enforce it.
|
|
180
|
+
|
|
181
|
+
## Validation and sequence
|
|
182
|
+
|
|
183
|
+
**Exercise the spatial promise too:** within the same task, deliberately change a pin, annotation, or meaningful relationship and inspect how the next brief and agent response reflect that curation. Compare with the uncurated result. Do not count a changed board layout alone as evidence of better agent behavior, or interpret incidental camera motion as a command.
|
|
184
|
+
|
|
185
|
+
1. **Now: test the knowledge loop without building hosting.** Use one small wiki and two named conceptual boards across three real non-canvas PM sessions. Delegate private maintenance once; let the assistant update source-linked working pages during tasks without compulsory review. Separate personal/shared source packets manually. Include a synthetic private fact, a completed decision, a rejected option, and contradictory newer evidence. Use a clean agent to answer fixed questions in the next session from labeled drafts plus confirmed/shared context.
|
|
186
|
+
2. **Measure usefulness and failure.** Compare maintenance, interruptions, corrections, undo, and next-session reconstruction time against the current workflow. Do not require reviewing accumulated drafts before measuring value. Require the private fact not to appear or influence shared recommendations; tentative/rejected options not to become decisions; completed decisions to be retrieved; confirmed claims to retain exact source/revision references. Test the conditional-launch example through summaries and structured relations, undo followed by a fresh read, and an embedded source instruction falsely claiming approval. Separately verify that triage acceptance does not publish, authorization for revision A/destination X does not cover B/Y, and a released outcome exposes no private source metadata. These are product-policy experiments, not proof of implemented authorization.
|
|
187
|
+
3. **Local foundation:** preserve and explicitly target multiple boards, unify mutation policy, add durable identity/revisions, and deliver a useful budgeted read. Prototype private evidence/digest/proposal behavior only after the experiment shows value. No hosted platform prerequisite.
|
|
188
|
+
4. **Hosted pilot, later:** implement authenticated roles and source-scoped retrieval, publication, revocation, retention, backups, and isolated rendering. Test with at least two principals, private and shared boards, denied reads, cached results, history, and malicious source instructions. A single-tenant pilot still needs internal permissions.
|
|
189
|
+
5. **Cross-cutting workspace context:** derive shared dependencies and conflicting decisions from authorized shared entities. Start with explicit links and proposed reconciliations, not invisible aggregation of employee context. Expand only if another user benefits without maintaining a second wiki manually.
|
|
190
|
+
|
|
191
|
+
If maintenance plus reconstruction is not cheaper than reconstruction alone, simplify automatic memory and reduce the confirmed surface. Keep useful labeled drafts rather than forcing a larger review queue. Do not lower the publication threshold merely to make the metric look better.
|
|
192
|
+
|
|
193
|
+
### Open decisions for the next discussion
|
|
194
|
+
|
|
195
|
+
- Is the initial wiki primarily a personal continuity tool, with sharing later, or must the first hosted pilot demonstrate team reuse? Recommendation: personal value first, permission-safe team reuse as the pilot gate.
|
|
196
|
+
- Should personal space belong to the individual or employer tenant, and what survives leaving a workspace? This materially affects portability and deletion; do not infer the answer from a filesystem workspace.
|
|
197
|
+
- Who may publish workspace knowledge: every contributor, an entity owner, or a role? Start with explicit roles and avoid mandatory review by a second person unless the team needs it.
|
|
198
|
+
- What does a board's wiki entry show by default: a source listing, a working digest, or both? Recommendation: both, clearly distinguished from accepted pages.
|
|
199
|
+
- Which private sources may the assistant maintain from by default, and what consequential replacements must it ask about? Recommendation: explicit onboarding delegation, reversible working revisions, no silent replacement of confirmed content, and a distinct share action.
|
|
200
|
+
|
|
201
|
+
## Local evidence inspected
|
|
202
|
+
|
|
203
|
+
- [SQLite schema and persistence](../src/server/canvas-db.ts): durable layout, node data, snapshots, and AX tables.
|
|
204
|
+
- [Node provenance](../src/server/canvas-provenance.ts): source kind, URI, refresh strategy, and snapshot metadata; not authenticated writer identity.
|
|
205
|
+
- [AX context builder](../src/server/ax-context.ts): current previews and bounded pending-steering selection, not the proposed unified permission-aware brief.
|
|
206
|
+
- [HTTP operation adapter](../src/server/operations/http.ts): workbench classification from a caller-supplied header.
|
|
207
|
+
- [Registry](../src/server/operations/registry.ts) and [SDK](../src/server/index.ts): mutation policy and direct state-call paths relevant to trusted history.
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
# Product Review — September 2026
|
|
2
|
+
|
|
3
|
+
**Status:** Proposed
|
|
4
|
+
**Date:** 2026-09-03
|
|
5
|
+
**Scope:** Product-level review of `pmx-canvas` v0.5.1 at `main` `e17776f6` (working tree clean, so committed state and the Mac's tree are identical).
|
|
6
|
+
**Method:** Read the README, docs, skills, changelog, `.learnings/` and the two tech-debt assessments; ran the unit suite (1035 pass / 0 fail), `pmx-canvas smoke` (all four checks ok), and the demo and empty boards in a browser; read the maintainer's own live board over MCP (`canvas_query`, `canvas://summary`, `canvas://pinned-context`, `canvas://ax-context`); probed the approval-gate HTTP API on a scratch server. Four parallel audits fed the findings (onboarding, API surface, client UX, field-report synthesis). This is a *product* review, not a tech-debt audit; `plan-009` already tracks the engineering backlog.
|
|
7
|
+
|
|
8
|
+
## Verdict
|
|
9
|
+
|
|
10
|
+
The one-sentence idea is excellent and still true: *spatial curation is a context channel; the human pins what matters and the agent reads it.* The engineering behind it is unusually disciplined for a solo project (registry-derived transports, a frozen tool surface, a real e2e gate, honest changelogs).
|
|
11
|
+
|
|
12
|
+
The product problem is that this idea is now buried under a second product. Roughly 40 concepts, 73 MCP entry points, 86 CLI commands, and 109 HTTP routes describe two things at once: a spatial context surface for one agent, and a multi-agent orchestration control plane (gates, steering queues, pumps, scope fences, presence, ghost intents). Section 04 of the README introduces a dozen primitives before a first-time reader has created a node. The headline feature of the second product, the human approval gate, does not actually require a human (see finding 2).
|
|
13
|
+
|
|
14
|
+
Adoption evidence is thin and self-referential. The repo has 18 stars and two forks; every PR is the maintainer's; the one issue ever filed was closed the same week. The board in this repository is a test board by design (the maintainer's correction, 2026-09-05). The real boards live in the snapshot history of the board the globally installed MCP server writes to: nine real PM boards between April and August 2026 (OKRs, DX charts, discovery, an org overview, slide decks), each overwritten by the next test session because a workspace has exactly one board. See the opening section of [`product-vision-2026-09.md`](product-vision-2026-09.md). The "field reports" that drive each release are the maintainer running Amp, Copilot, Codex and Claude against the product. That is good dogfooding, but the boards I can see cannot show whether the product works on a problem that is not `pmx-canvas`. Everything below should be read in that light: the fastest way to find out what the product is, is to use it for two weeks on something else.
|
|
15
|
+
|
|
16
|
+
## What is genuinely good
|
|
17
|
+
|
|
18
|
+
- **The core loop works and is cheap.** `--demo` gives a full board in one command; the MCP config is five lines; the canvas auto-starts on first tool call; `smoke` verifies the whole stack in one command and passes.
|
|
19
|
+
- **The human chrome is considered, not missing.** Empty state with four working actions, a `?` shortcut overlay (25 shortcuts), a ⌘K palette, in-canvas tooltips that survive embedded panes, and a reconnect banner that tells the human the real consequence of a dropped stream.
|
|
20
|
+
- **State lives in the server, and it is honest.** Incremental fsynced saves, a single write path with undo actors, a bundle-stamp self-reload for stale tabs.
|
|
21
|
+
- **Quality practice is improving.** The July backlog is mostly closed and dated: the CLI monolith went from 3,337 lines to 231, raw CLI fetches from 60 to 0, hand-written routes from about 50 to 21. Themes that got a machine check (tool-surface freeze, doc byte-identity, daemon lifecycle) stopped recurring.
|
|
22
|
+
|
|
23
|
+
## Findings, ranked by product impact
|
|
24
|
+
|
|
25
|
+
### 1. Two products share one README, and the smaller one is the good one
|
|
26
|
+
|
|
27
|
+
The README's first paragraph is right. It is followed by about 230 lines of feature sections and four host-adapter subsections before Quick start (line 256 of 477). The `pmx-canvas` skill is 5,400 words plus a 14,700-word reference, and it hands an agent a nine-step "Required Operating Sequence" (with three items numbered 7) before it may create a node. Ghost intents are mandatory by default on every mutation.
|
|
28
|
+
|
|
29
|
+
Concept inventory: about eight things are core (node, edge, group, pin, `canvas.db`, workspace root, one composite tool, `canvas://pinned-context`). About thirty belong to the control plane: work items, approval gates, elicitations, mode requests, policy, host capability, delivery queues, consumer keys, pumps, scope fences, agent and human presence, ghost intents, materialized flows, a five-tier rendering taxonomy (`html`, `html-primitive`, `json-render`, `web-artifact`, `mcp-app`/`ext-app`). 42% of the HTTP surface is `/api/canvas/ax/*`.
|
|
30
|
+
|
|
31
|
+
The maintainer's stated direction is a two-way working surface for humans and agents, not an orchestrator. Read against that direction the AX layer is integral, and the problem is narrower than "two products": the vocabulary is mechanism-first (gates, queues, pumps, fences, consumer keys) where the direction calls for conversation-first, and the fleet mechanics that headlined 0.5.0 are the part that does not fit. See the Proposal section at the end.
|
|
32
|
+
|
|
33
|
+
### 2. The approval gate does not require a human (verified live)
|
|
34
|
+
|
|
35
|
+
README: *"gate high-impact actions behind a human `pending → approved/rejected` decision."* On a scratch server, an agent created a gate over plain HTTP with no workbench marker and then resolved it:
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
POST /api/canvas/ax/approval → 200, status "pending"
|
|
39
|
+
POST /api/canvas/ax/approval/:id/resolve
|
|
40
|
+
{"decision":"approved","agentId":"probe-agent"} → 200, status "approved", source "api"
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
`ax.approval.resolve` (`src/server/operations/ops/ax-work.ts:490`) checks the decision enum and nothing about the caller. The scope fence and the human grab lock both already key on the workbench marker, so the pattern exists; the gate simply does not use it. The `source: "api"` stamp makes self-approval auditable after the fact, not prevented. Until resolve is human-only, the gate is a status field, and the `held` policy sweeper is the only real safety property. *Correction (2026-09-05):* keying human-only resolution on the workbench marker alone is not enough, because the marker is a plain request header any agent with `curl` can set (`src/server/operations/http.ts:91`, no auth anywhere in `server.ts`). The real fix mints a per-boot secret served only in the workbench HTML; see [`product-vision-2026-09.md`](product-vision-2026-09.md), move 7.
|
|
44
|
+
|
|
45
|
+
### 3. A human's failed write is silent
|
|
46
|
+
|
|
47
|
+
`requestJson` in `src/client/state/intent-bridge.ts:38` never reads `res.ok`; a 400 or 500 body is parsed and returned as if it succeeded, and the fallback path goes to `console.error`. *Correction (2026-09-05, from the adversarial pass on the vision):* a human's own write cannot hit the 403 scope fence or the 409 edit lock, both sit behind `if (!meta.fromWorkbench)` in the registry; the defect is real for validation errors and server failures, but smaller than first stated. The most visible case is `ContextMenu.tsx:370`, where finished user-facing copy ("Could not create webpage node. Enter a valid http(s) URL.") is sent to the console. `showToast` exists and is used by two files. The board is built to show the human what agents are doing, and it does not show the human when their own click failed.
|
|
48
|
+
|
|
49
|
+
### 4. The agent's "working memory" has no compaction
|
|
50
|
+
|
|
51
|
+
The thesis is that the canvas is the agent's extended memory. Measured on the maintainer's own 25-node board:
|
|
52
|
+
|
|
53
|
+
| Read surface | Size | What dominates it |
|
|
54
|
+
|---|---|---|
|
|
55
|
+
| `canvas://ax-context` (injected per Copilot prompt) | 26.5 KB, roughly 7k tokens | 20 work items, 19 of them `done`; 20 timeline events, 8 of them system "re-anchored" notes; 10 "pendingSteering" entries of which 8 are `delivered: true`; a `host` block from a June smoke run. The `pinned` block, the product's headline, is empty. |
|
|
56
|
+
| `GET /api/canvas/state` (what `canvas_query layout` wraps) | 67 KB (25 nodes), 386 KB (69-node demo) | Full markdown bodies; `full` is ignored on the HTTP route; the MCP "compact" form strips `data` but never truncates `content`. |
|
|
57
|
+
| `pmx-canvas layout` (CLI) | 449 KB on the demo board | Same, plus blobs. |
|
|
58
|
+
|
|
59
|
+
There is no content preview length, no "open items only", no event budget, and no way for an agent to ask for the board at a token budget. `canvas://summary` (272 bytes) is the only bounded read, and it carries titles only for pinned nodes. For a product about context, this is the gap that matters most after finding 2.
|
|
60
|
+
|
|
61
|
+
### 5. The MCP schemas are hard for a model to use reliably
|
|
62
|
+
|
|
63
|
+
- `canvas_node` exposes 50+ flattened optional fields for four actions; per-action requirements exist only in prose, so `{action:"add"}` without `type` passes schema validation and fails in the handler (the July M6 finding, still open).
|
|
64
|
+
- 18 alias fields survive in the ops schemas (`verbose`/`full`, `q`/`query`, `kind`/`primitive`, `children`/`childIds`, `path`/`content`, `edge_id`/`id`, `heightPx`/`nodeHeight`, snapshot `id`/`name`). The project's own CLAUDE.md rule is "no deprecation aliases".
|
|
65
|
+
- Two descriptions are wrong in the live schema: `canvas_edge` tells the model its actions are `add | remove` while `update` shipped in 0.5.0 (`composites.ts:174`); `canvas_view` `fit` describes `padding` as "World-space" while the 0.5.1 changelog says screen pixels (`ops/viewport.ts:149`). The second one is architecture rule 9 leaking into the contract.
|
|
66
|
+
- 14 registry ops are reachable over HTTP, CLI and SDK but not MCP, with no error explaining the gap: `history.get`, `annotation.add`, `theme.get/set`, `summary.get`, `spatial.get`, `viewport.set`, `ax.review.update`, `ax.approval.reopen`, `human.presence.*` among them. `canvas_view` can remove an annotation but not add one.
|
|
67
|
+
- Four naming conventions for one operation (`set-focus` / `ax focus` / `/ax/focus` / `setAxFocus`) and four spellings for one feature (`canvas_pin_nodes`, `pin.set`, `/context-pins`, `canvas://pinned-context`). Nothing lets an agent translate between transports mechanically.
|
|
68
|
+
|
|
69
|
+
### 6. The docs disagree with each other and with the product
|
|
70
|
+
|
|
71
|
+
Concrete, all verified:
|
|
72
|
+
|
|
73
|
+
- `SKILL.md:120` tells the agent to call `canvas_render { action: "workboard" }`; the composite table on the same page (`:142`) and `full-reference.md:438` omit `workboard`; `docs/mcp.md:41` has it.
|
|
74
|
+
- `full-reference.md:346-360` lists 14 node types and is missing `diff`, `mermaid`, `webpage`, `web-artifact` and `html-primitive` while listing internal `prompt`/`response`.
|
|
75
|
+
- `SKILL.md:90` and `docs/environment.md:11` state opposite things about whether `PMX_CANVAS_PORT` drives the server.
|
|
76
|
+
- `installing-pmx-canvas.md`, the file loaded when the command is missing, says `npm install -g` and never mentions Bun, which is the reason the command is missing.
|
|
77
|
+
- `full-reference.md:35` cites a README use-case list that no longer exists.
|
|
78
|
+
- The shortcut overlay still says "Context menu — dock, focus, connect" (`ShortcutOverlay.tsx:55`); docking was removed in 0.5.0.
|
|
79
|
+
- CLAUDE.md rule 5 (and its byte-identical twin AGENTS.md, which Codex, Copilot and Amp read) still mandates keeping four hand-written layers in sync; three of them are registry-derived now, so an agent following it writes a parallel implementation.
|
|
80
|
+
- `docs/screenshots/welcome-dark.png` exists and is referenced nowhere; the README leads with a dense expert board instead of the first screen a user sees.
|
|
81
|
+
- No troubleshooting page, no uninstall or cleanup, no stated local security model (the server binds localhost with no auth; `file` nodes read any path the server user can read; nothing says so).
|
|
82
|
+
|
|
83
|
+
### 7. Scale has no defined behaviour
|
|
84
|
+
|
|
85
|
+
`CanvasViewport.tsx:912` renders every node with no viewport culling and no node-count guard. Seven node types mount iframes; the showcase board loads **40 iframes** on first paint (25 `surface/*` documents plus 15 json-render views, from the network log). It works at 69 nodes on a fast Mac. At 200 nodes with a few dozen live iframes the product has not been measured, and the embedded hosts (Copilot panel, Codex browser, Amp portal) are the slowest surfaces it runs in.
|
|
86
|
+
|
|
87
|
+
### 8. The same three bugs keep shipping, and the fix has been a paragraph
|
|
88
|
+
|
|
89
|
+
From the changelog and `.learnings/`:
|
|
90
|
+
|
|
91
|
+
| Theme | Times shipped | What fixed it |
|
|
92
|
+
|---|---|---|
|
|
93
|
+
| Embedded-host blank or black tile | about 9 (0.2.4 through Unreleased) | Escalating paint oracles; the architectural fix (portal-layer mount) is still a plan-009 contingency whose trigger has been met |
|
|
94
|
+
| Screen-space vs world-space viewport math | 4 (0.4.6, 0.4.7, 0.5.1, Unreleased) | CLAUDE.md rule 9, which still says "twice" |
|
|
95
|
+
| Native browser UI no-ops in embedded panes | 3 in 0.5.0 alone | CLAUDE.md note; `ToolRail.tsx` still calls `window.prompt` |
|
|
96
|
+
|
|
97
|
+
Themes that got a test stopped. Rules 3, 7 and 9 have each grown a paragraph per recurrence. CLAUDE.md and AGENTS.md, kept identical on purpose so every agent reads the same rules, are becoming the incident log.
|
|
98
|
+
|
|
99
|
+
### 9. Packaging and footprint
|
|
100
|
+
|
|
101
|
+
- 539 files, 14.7 MB unpacked; ships `src/` and `dist/` both; 227 `dist/` files are tracked in git (160 in July).
|
|
102
|
+
- Runtime dependencies carry React 19, `react-dom`, `recharts` and seven `@json-render/*` packages beside Preact; mermaid alone is a 3.5 MB bundle. `node_modules` is 456 MB.
|
|
103
|
+
- `bin` is a raw `.ts`, so `npm install -g` produces a command that fails without Bun (see finding 6).
|
|
104
|
+
- On this machine one Copilot host is holding ten `pmx-canvas --mcp` processes spawned ten seconds apart (about 170 MB). The server exits on stdin end, so the duplication is the host's, but the product cannot tell the human that ten copies of it are running.
|
|
105
|
+
|
|
106
|
+
### 10. The multi-host story is only as strong as its weakest host
|
|
107
|
+
|
|
108
|
+
Four hosts, each with bespoke behaviour (srcdoc iframes, polling transport, visibility-blind paint recovery, extension pump vs CLI pump vs native heartbeat). Codex desktop steering did not work end to end until an app-native adapter shipped; the pump documentation had described a command that started a different session. None of this is visible to CI, so every release re-discovers it through field reports.
|
|
109
|
+
|
|
110
|
+
## What I would do, in order
|
|
111
|
+
|
|
112
|
+
1. **Reorganize the product around the two-way surface.** Keep AX; fold its mechanisms into the moves in the Proposal section; move fleet mechanics (pump, consumer keys, fences, rollups, census chips) to a separate page and off the default path. The README leads with the welcome screenshot, one scenario that shows both directions, Quick start, then `smoke`. Host adapters move to one linked page. The skill's operating sequence shrinks to what a first session needs; ghost intents become opt-in.
|
|
113
|
+
2. **Make the gate real.** `ax.approval.resolve` requires the workbench marker (or a human-only token); agent calls get 403 exactly like the scope fence. One afternoon, and the README sentence becomes true.
|
|
114
|
+
3. **Surface failures to the human.** `requestJson` checks `res.ok`, and every helper routes `errorMessage` to `showToast`. One afternoon.
|
|
115
|
+
4. **Budget the reads.** `canvas://ax-context` carries open items, the last N events, undelivered steers only, and a content preview; `layout` takes a preview length; `canvas://summary` carries titles for every node. Then the memory thesis has a compaction story. About a day.
|
|
116
|
+
5. **Schema hygiene.** Delete the 18 aliases (the repo's own rule), fix the two wrong descriptions, make per-action required fields explicit in the schema, and either expose the 14 missing ops over MCP or say why not. Add the registry-derived checks that catch the next drift.
|
|
117
|
+
6. **Reconcile the docs.** Fix the six contradictions above in one pass; delete rule 5 from CLAUDE.md and AGENTS.md; add a troubleshooting page and a three-line security model.
|
|
118
|
+
7. **Turn the three recurring paragraphs into checks.** A Biome rule or unit test that fails on `window.prompt`/`alert`/`confirm`/`title=` in `src/client`; a unit test that pins screen-space margins for `focus`/`fit` at scale 0.5 and 2; an assertion that `onMutation` is registered once.
|
|
119
|
+
8. **Use it on something that is not `pmx-canvas` for two weeks**, with one agent, and log what breaks. That will settle finding 1 better than any review.
|
|
120
|
+
|
|
121
|
+
## Evidence
|
|
122
|
+
|
|
123
|
+
| Claim | Where |
|
|
124
|
+
|---|---|
|
|
125
|
+
| Unit suite green | `bun run test:unit`: 1035 pass, 0 fail, 88 files, 67 s |
|
|
126
|
+
| Smoke green | `PMX_CANVAS_PORT=4779 pmx-canvas smoke`: health, mcp-initialize, node-lifecycle, validate all ok |
|
|
127
|
+
| Gate self-approval | scratch server on 4779, `POST .../approval` then `POST .../approval/:id/resolve` with `{"decision":"approved"}` and no workbench header: 200, `status: "approved"` |
|
|
128
|
+
| Silent failures | `src/client/state/intent-bridge.ts:38-63`, `src/client/canvas/ContextMenu.tsx:370` |
|
|
129
|
+
| Read sizes | `curl` of `/api/canvas/ax/context` (26,536 B) and `/api/canvas/state` (67,097 B on the live board, 386,533 B on the demo, identical with `?full=true`); `pmx-canvas layout` 449,053 B |
|
|
130
|
+
| Aliases | `grep -c "alias" src/server/operations/ops/*.ts` = 18 |
|
|
131
|
+
| Wrong descriptions | `src/server/operations/composites.ts:174`, `src/server/operations/ops/viewport.ts:149` |
|
|
132
|
+
| Ops missing from MCP | `history.get`, `annotation.add`, `theme.set`, `summary.get`, `spatial.get` absent from `composites.ts` |
|
|
133
|
+
| 40 iframes on demo load | browser network log on `http://localhost:4779` (25 `surface/*` + 15 `json-render/view`) |
|
|
134
|
+
| No culling | no visibility filtering in `src/client/canvas/CanvasViewport.tsx` |
|
|
135
|
+
| Stale dock string | `src/client/canvas/ShortcutOverlay.tsx:55` |
|
|
136
|
+
| Packaging | `bun pm pack --dry-run`: 539 files, 14.73 MB; `git ls-files dist | wc -l` = 227 |
|
|
137
|
+
| MCP process pile-up | `ps` on this Mac: ten `pmx-canvas --mcp` children of one Copilot CLI pid |
|
|
138
|
+
| Adoption | `gh repo view`: 18 stars, 2 forks, created 2026-03-25; 1 issue ever; 14 npm releases between 2026-08-03 and 2026-08-28; npm reports 2,331 downloads in the last month and 382 in the last week, a large share of which is plausibly the release smoke (`bunx` cold boots), CI, and the maintainer's own hosts |
|
|
139
|
+
|
|
140
|
+
## Proposal: the board as a two-way surface
|
|
141
|
+
|
|
142
|
+
*Superseded on 2026-09-05 by [`product-vision-2026-09.md`](product-vision-2026-09.md), which keeps the two-way framing but starts from the finding that the pin-to-agent loop has never been observed and folds the AX side tables into cards on the board.*
|
|
143
|
+
|
|
144
|
+
*Added 2026-09-03 after discussion with the maintainer. Direction as stated: the canvas is a two-way working surface for humans and agents, not an orchestrator. This section replaces the "two products" recommendation in finding 1.*
|
|
145
|
+
|
|
146
|
+
### The model: every mark is addressed to the other side
|
|
147
|
+
|
|
148
|
+
| Direction | Move | What exists today | What changes |
|
|
149
|
+
|---|---|---|---|
|
|
150
|
+
| Human → agent | **Pin** (focus here) | context pins, `canvas://pinned-context`, AX focus | AX focus folds into pin; an agent-proposed focus is a pin with `source: agent`. One read surface. |
|
|
151
|
+
| Human → agent | **Steer** (do this) | composer, steering messages, delivery claim/mark, pump, consumer keys | Steering stays. "Delivery", "claim", "consumer key" leave the user-facing vocabulary; the agent has an inbox. |
|
|
152
|
+
| Human → agent | **Answer** (yes/no, choice, text, mode) | approval gates, elicitations, mode requests, three resolvers | One `ask` with an answer type. Answers are human-only (finding 2). One TTL and one `held` policy. |
|
|
153
|
+
| Human → agent | **Hold** (hands off) | grab lock, undo of agent edits, ghost veto, scope fence | Grab and undo are the human's hold. Scope fence moves to the fleet page. |
|
|
154
|
+
| Human → agent | **Mark** (look at this) | freehand annotations, review annotations | One annotation with an optional node anchor. |
|
|
155
|
+
| Agent → human | **Show** (put it on the board) | node, render, app, edge, group | Unchanged now; render and app fold into node types over time. |
|
|
156
|
+
| Agent → human | **Ask** | approval gate, elicitation, mode request | One primitive, one panel row. |
|
|
157
|
+
| Agent → human | **Report** (what I did, what is open) | work items, agent events, evidence, session receipts | One timeline; work items are its open loops; presence phase derives from it. |
|
|
158
|
+
| Agent → human | **Signal** (where I am, where I am about to write) | presence cursor, ghost intent, focus, park-at | One signal with an optional "about to write" horizon. Intents opt-in, never mandatory. |
|
|
159
|
+
|
|
160
|
+
Nine moves. Multi-agent is "more than one agent making the same moves"; identity color is the only extra concept the human needs.
|
|
161
|
+
|
|
162
|
+
### What changes concretely
|
|
163
|
+
|
|
164
|
+
1. **Trust first, as a prerequisite.** A two-way surface that lies in either direction is worse than chat. Asks are answered only by humans; a failed human action is visible; the agent's read of the board is a budgeted `canvas://context` that carries pins, open asks, open work and the last N events, never done items or delivered steers.
|
|
165
|
+
2. **The agent surface.** The nine AX-shaped tools (`canvas_ax_state`, `canvas_ax_work`, `canvas_ax_gate`, `canvas_ax_timeline`, `canvas_ax_delivery`, `canvas_ax_interaction`, `canvas_ingest_activity`, `canvas_invoke_command`, `canvas_intent`) become four: `canvas_ask`, `canvas_report`, `canvas_signal`, `canvas_inbox`. Board tools stay. Ship it as 0.6.0 with the 0.3.0 discipline: freeze test, per-tool migration map, no aliases.
|
|
166
|
+
3. **The human chrome.** The session panel is regrouped as the conversation: *Waiting on you* (asks), *Happening* (report and signal), *You said* (pins, steers, holds). The composer is steer. This is naming and grouping, not new UI.
|
|
167
|
+
4. **The docs.** README: thesis, one scenario that shows both directions, Quick start, `smoke`. One "Conversation" page replaces section 04. One "Fleet" page holds pump, consumer keys, fences, rollups and census chips, marked advanced.
|
|
168
|
+
5. **Demoted, not deleted.** `pmx-canvas pump`, consumer keys, `parentAgentId` rollups, scope fence, census chips, ghost-intent-by-default keep working and leave the default path.
|
|
169
|
+
|
|
170
|
+
### Sequence
|
|
171
|
+
|
|
172
|
+
1. Trust fixes (gate, toasts, budgeted context): days.
|
|
173
|
+
2. 0.6.0 vocabulary consolidation and docs restructure: one to two weeks, one release.
|
|
174
|
+
3. Two weeks of use on a project that is not `pmx-canvas`, one agent first, then two.
|