{"id":"f5a0f5c6-e698-4f4d-95a6-2aaf99610786","slug":"pskoett-pmx-canvas","kind":"skill","name":"pmx-canvas","summary":"A live canvas for coding agents & human interaction. A visual workbench where nodes, edges, charts, diagrams, and interactive UIs all live together. Agents stream in data, you explore the graph, edit","owner":"pskoett","repoUrl":"https://github.com/pskoett/pmx-canvas","license":"MIT","licenseTier":"permissive","trust":"community","stars":28,"match":null,"fewStars":false,"format":"skill","createdAt":"2026-03-25T20:28:55.000Z","addedAt":"2026-10-14T11:04:40.612Z","logoUrl":"https://avatars.githubusercontent.com/u/177305814?u=45f3a2479556e6ac6682f06a64da3bc2fa1ccc84&v=4","linkOnly":false,"collection":null,"skillPath":null,"categories":["design-media","data-analytics","memory-knowledge"],"tags":[],"runtime":"node","local":true,"cloudCapable":false,"cloudCapability":"unknown","cloudReadyOnPlatform":false,"needsApiKey":false,"reviewed":false,"syncedAt":"2026-10-14T20:33:33.136Z","sample":false,"url":"https://conduits.dev/tools/pskoett-pmx-canvas","language":"TypeScript","transports":["stdio"],"install":{"npm":"pmx-canvas"},"requirements":{"env":[],"upstreamMayCharge":false},"tools":null,"readme":"# pmx-canvas\n\n**Relationships and knowledge lifecycle:** explain connections with kinds and reasons, use\nshared editable relation templates in Home, explicitly apply them to boards, and inspect evidence\nand downstream impact. Board dropdowns filter only relation kinds actually present, not presets.\nFolder categories supply\nexplicit lifecycle defaults. Review due reasons, separate read/content/validation clocks,\nevidence-backed outcomes and reversible retirement appear in the workbench and agent context.\nNothing classifies cards automatically or treats reading as validation.\nSee the [contract and examples](docs/http-api.md#knowledge-lifecycle-data-plan-017-slice-1).\n\npmx-canvas is a visual workspace for planning, discovery, analysis, coordination,\nand orchestrating work with agents—from exploring an idea to directing its\nexecution and carrying the learning forward.\n\n**The board is your extended memory and your agent's working memory.** Use it\nto research, analyze, work with dashboards, and start or plan coding and other\nknowledge work—not just to prepare context for an agent. In the [long-term vision](docs/product-vision-2026-09.md#the-one-line-vision)\nyour boards link into a wiki you can see as a map, bringing useful understanding\nback into whatever you do next, and any board can be shared or presented.\n\n**A moldable canvas for agent-assisted thinking.** An infinite 2D surface\nwhere files, plans, status, charts, fetched web pages, annotations, code\ndiffs, and diagrams live side by side. Every node carries its own renderer; agents\n(and you) build new views in the middle of a session — even streaming a\nstructured panel into place as they generate it — not as a separate tooling\nproject. Pin what matters and the agent reads your spatial curation as\nstructured context.\n\n**The board is the presentation.** Click **Present** to step through a saved tour\n(or groups in reading order), with chrome hidden and smooth camera moves.\nOptionally capture that same tour with\n`pmx-canvas record --mode deterministic --present --output tour.mp4`. See the\n[tour model and CLI walkthrough](docs/cli.md#tour-and-presentation).\n\n<p align=\"center\">\n  <img src=\"docs/screenshots/workbench-live-dark.png\" alt=\"Live multi-agent workbench — dark theme: two agents on the board, review cards, an architecture diagram, and the writers pill\" width=\"49%\" />\n  <img src=\"docs/screenshots/workbench-live-light.png\" alt=\"Live multi-agent workbench — light theme\" width=\"49%\" />\n</p>\n<p align=\"center\"><sub>A real working board: two agents attached (the writers pill, top right), review cards they co-wrote, and a mermaid architecture diagram — dark and light themes.</sub></p>\n\n<p align=\"center\">\n  <img src=\"docs/screenshots/demo-workbench-dark.png\" alt=\"Structured workbench demo — dark theme\" width=\"49%\" />\n  <img src=\"docs/screenshots/demo-workbench-light.png\" alt=\"Structured workbench demo — light theme\" width=\"49%\" />\n</p>\n\nPMX Canvas is a collaborative spatial workspace that humans and agents share\nin real time. Either side adds material; the human curates spatial structure\n(grouping, positioning, pinning); the agent reads that curation through\n`canvas://pinned-context` and acts on it. Spatial arrangement is\ncommunication — proximity means relatedness, pinning means *focus here*.\n\nThe database holds many named boards. **Home is the library view, not a board**:\na folder tree with the boards pinned into the agent's context, the open folder's\nsubfolders and board cards (a thumbnail, the README line, cards and links), and\na details pane for the selected board (in-context switch, README, pinned cards,\nlinks, Open board). Boards use nested folder paths (up to eight 60-character\nsegments); a new folder exists once a board is filed beneath it. Agents can explicitly open/switch boards; deletion\nremains human-only. Creating a board or a copy from reusable cards leaves it\ninactive. Agents open its returned ID before writing; this also switches the\nshared workbench the human sees. Agents may list, read, rename, file into folders, and\nsearch boards without switching. Home\nprovides a copy-preview dialog; an open board's command palette offers a\nboard-link picker. Neither depends on native browser prompts.\n\nHome also offers **Map** (nested, collapsible folder regions with draggable, saved board\npositions) and **Graph** (live board/card clusters with focus, filters and force controls).\nSelect a board or card for its connections, context status and Open action. Graph's overview\ngroups cross-board links; selection reveals exact endpoints. Both views update as agents work,\nwithout losing your camera or selection. Folders organize where boards live; links independently\nshow how they relate. Markdown saves\nbind `[[Board]]`, `[[Board#Card]]`, and `|alias` forms to durable IDs, ignoring\ncode; ambiguous or missing targets stay explicit. A human can create an\nunresolved board-only link with exactly its authored name, then the source is\nre-saved with its captured board and revision. Native cross-board card\nconnections appear in the source card footer and the **More** card picker.\nCopies record their previous board. Auto-arrange stays local; static exports\nshow external connection evidence without remote lines.\n\nAgents explore the same summary-only projection through\n`GET /api/canvas/memory-graph`, SDK `getMemoryGraph()`, CLI `memory-graph`,\n`canvas_query { action: \"graph\" }`, or `canvas://graph{?focus,depth}`.\nFocus is a board ID, a JSON qualified key `[boardId,cardId|null]`, or `pins`;\ndepth is 0–4 (default 2), undirected and membership-inclusive. Summaries are\ncapped at 280 characters. Discovery counts links seen on their owning boards,\nwithout switching boards or marking full content read. Rich kinds and reasons travel with\nrelations. Source changes flag explicitly dependent conclusions, not unrelated navigation.\n\nOpen **Categories** on Home to edit workspace categories or apply an editable preset, and use\nfolder settings to assign or inherit one. Delete an unused category there; assigned categories\nname the folders to clear or reassign first. Home's **Review needed** count lists the affected\nboards; **Review** opens the next affected card. On a card, **More → Review** asks for a short\nnote and **Checked, still correct**. **Not now** closes without changing its review state.\n**Settings and history** holds its defaults, four clocks and advanced outcomes.\nApplied evidence-backed retain/revise/externalize\nvalidates the version checked. Retire removes the card from active briefs, not from the board\nor search; Restore (or the retirement Undo toast) is audited and does not validate it.\nThe board's **All / To review / Retired** filter dims other cards. Unknown lifecycle is counted\non Home and never silently assigned an expiry. Refresh recipes ask an agent to act, never run tools.\n\n## Main features\n\n### 01 / Curate\n\nDrag, group, arrange, and **pin** nodes spatially. Connect nodes with typed\nedges — flow, depends-on, relation, references — drawn as smooth curves that\nleave each card perpendicular to its border and bend toward their target.\nEdges stay editable in place: double-click one to relabel, retype, restyle, or\ndelete it, or click it and press Delete. Curation is the channel\nfrom human intent to agent context — the agent reads `canvas://pinned-context`\nand `canvas://spatial-context` (proximity clusters, reading order, pinned\nneighborhoods) and uses your layout to ground its next action.\n\n### 02 / Mix any data source\n\nFiles, web pages, screenshots, structured panels, charts, diagrams, embedded\nMCP Apps, and bundled web artifacts all live on the same surface. A file node\nfollows the file on disk as the agent edits it — source with line numbers, a\nCSV or TSV as a real table, a PDF inline — and can be re-pointed at another\nfile (patch its `path`) without losing its edges, pins, or position. Anything else binary shows its name\nand size rather than decoded gibberish, and a very large text file renders\ntruncated with a note saying so. Code review has its own node: a unified\ndiff with per-file headers and colored added and removed lines. Diagrams can\nbe drawn by hand in Excalidraw or written as plain mermaid text and rendered\non the spot. Context cards, execution ledgers, and agent trace pills round out\nthe set. Any rich surface — HTML, mermaid, json-render, graph, webpage, or a\nweb artifact — can be **opened as a site**, full-page in its own browser tab\nwith one click; the canvas and the tab render the same document. The reach of\nthe canvas is the union of its [built-in node types](docs/node-types.md) and\n**whatever your agent's harness already has access to** — MCP servers, CLIs,\nfile reads, web fetch, anything on its toolbelt.\n\nDropping a PDF or Office document attaches the original (up to 20 MiB). It does\nnot bundle a converter or automatically launch an agent. Clicking **Ask agent to\nimport** also authorizes processing by the connected host's tools/model provider;\nthere is no separate consent confirmation. The agent returns Markdown sections\nwith references and warnings for review. Multi-card imports are placed together\nin a free area, in a group named after the source file. Remote hosts may require\nmanual transfer; OCR, charts, and host format support are not guaranteed.\n\nJSON-render panels support bound form state, nested repeats, watchers, and Card\nheader/footer slots. Form edits remain viewer-local until explicitly submitted;\nsee [JSON-render nodes](docs/node-types.md#json-render-nodes). Authored iframe cards\ncan grow with their content and move clear of neighbors, with human-grab deferral\nand undoable relocation. This is grow-only height fitting, not shrink-to-content\nor camera zoom; see [sizing limits](docs/node-types.md#automatic-sizing-of-authored-iframe-cards).\n\n### 03 / Annotate\n\nDraw freehand marks directly on the canvas to circle, underline, connect, or\ncall out what matters without turning the markup into another node. Annotations\npersist with state and snapshots, can be erased in the browser, and appear to\nagents as compact spatial context: target, bounds, and nearby canvas content.\n\n### 04 / Control your context\n\nSteer the agent and see its work, without prompt engineering or copy-paste.\nPin a node in the browser and the MCP server fires a\n`notifications/resources/updated` event the agent's harness picks up\nimmediately — an explicit, low-noise control over what the agent sees next.\nEach pinned node then shows whether an agent has read it since you pinned it,\nand turns amber with \"changed since read\" when you edit it after the agent's\nlast read. The budgeted context brief is a map of titles, summaries and relations:\nit does not mark card content read; pulling a card's text in full does. Link visibility\nis tracked separately, so a summary can mark its relations seen without marking its text read.\nNodes an agent created or edited carry a violet sparkle with authorship in the type icon's hint until you edit them,\nand a pin an agent made carries a violet dot with its reason on hover.\n\nAfter a session, its receipt lists the cards it read, pinned, created and edited.\n**See change** opens one card's stacked Before/After with changed words marked;\n**Undo this card** restores its whole pre-session content without moving it or its links.\nExcerpts may be clipped; the caption makes clear that Undo affects the whole card.\nCards whose latest editor is human are left alone, rather than merging edits. The receipt\nstays available when you visit another board, with a button to reopen its board before\nUndo or snapshot comparison; going Home dismisses it. In a narrow\nwindow, click the agent's initial for live counts, **Dim untouched nodes**, and the session panel.\n\nOn top of pins, a host-agnostic **AX (agent-experience) layer** turns the\ncanvas into a shared workspace between you and the agent:\n\n- **Agent-native nodes** — most node types can act as interactive controls for\n  the agent out of the box: a node can focus context, create or update work,\n  add evidence, request input or approval, or send steering without leaving the\n  board. The sandboxed surfaces — HTML nodes and MCP apps — stay off until a\n  node opts in, since their content is author-supplied.\n- **Focus** — promote nodes into the agent's active context without moving the viewport.\n- **Work items & approval gates** — track visible tasks tied to nodes, and gate\n  high-impact actions behind a human `pending → approved/rejected` decision. A\n  linked node shows its work item's status on the title bar, and a live work\n  board lays the whole queue out by status and keeps itself current — useful\n  when several agents are working at once.\n- **Steering messages & agent-event timeline** — send instructions to the\n  active session, and read a normalized, bounded timeline of prompts, tool\n  runs, evidence (logs/diffs/screenshots/test-output), and failures.\n- **Node interactions** — eligible nodes emit one capability-gated, validated\n  interaction envelope from native controls, the sandboxed HTML / MCP-app\n  bridges (`window.PMX_AX.emit`), or json-render spec actions. The server is the\n  single trust boundary and clamps sandboxed surfaces to their own node.\n- **Elicitations, mode requests, commands & policy** — request structured human\n  input, propose a plan/execute/autonomous mode transition, invoke registry\n  commands (`pmx.plan`, `pmx.review`, …), and read a tool/prompt policy.\n- **Host capability** — adapters report what the host can do, for diagnostics.\n\nRecent additions in this layer: a **composer** steers directly from the board\n(with a target picker when several agents are connected); the **session panel**\nshows work items, approval gates, and a filterable timeline where every row\nnames its writer; a shared **undo stack** knows whether the human or the agent\nmade each edit, and undoing an agent's edit tells the agent as steering; a\n**scope fence** confines an agent's writes to selected nodes; and grabbing a\nnode in the browser locks it against agent edits while you hold it. Dialogs,\nprompts, and tooltips are all in-canvas — every flow works identically in\nembedded browser panes (Copilot, Codex, Claude Code desktop) where native\nbrowser UI doesn't exist.\n\nCanvas-bound state (focus, work items, approvals, review annotations,\nelicitations, mode requests, policy) rides canvas snapshots and restore; the\ntimeline persists for continuity but is retention-bounded and never restored by a\nsnapshot. Every primitive is reachable from MCP, the HTTP API, the SDK, and\n`pmx-canvas ax …`. The core never depends on any host SDK, so adapters (e.g. the\nGitHub Copilot app) map onto the same neutral surfaces without making PMX Canvas\nvendor-specific.\n\n### 05 / Run several agents on one board\n\nThe canvas is built for more than one writer. Every connected agent is named on\nits cursor, its top-bar session chip, and its activity rows, all in the agent\nviolet (subagents in their own fuchsia) — you always see who is where. Workers roll up under their\norchestrator's chip (`+2 workers`), each session chip has its own End button,\nand an idle board with no writers stays byte-clean.\n\n<p align=\"center\">\n  <img src=\"docs/screenshots/multi-agent-live.png\" alt=\"Two agent sessions and three rolled-up workers live on one board — named agent cursors on the cards, per-chip End buttons, the attributed session timeline, and the all-agents composer\" width=\"100%\" />\n</p>\n<p align=\"center\"><sub>Two agent sessions (Claude Code +3 workers, GitHub Copilot) and their cursors live on one board, with the writer-attributed timeline and the all-agents composer.</sub></p>\n\nSteering is **addressed and reliable**: the composer's picker lists every\nconnected writer with live pump health (`· polling`, `· 2 queued`), an\naddressed steer waits in that agent's delivery queue until the agent claims\nand marks it, and broadcasts age out instead of greeting every future\nconsumer. Each host wakes its own way — the GitHub Copilot extension pumps\nsteers into real Copilot turns, Codex picks them up through its app-native\nheartbeat, and any CLI agent becomes reactive with one command:\n\n```bash\npmx-canvas pump --consumer amp --exec 'amp -x {message}'\n```\n\nA failed hand-off is never silently swallowed: the steer stays pending and the\npump exits non-zero. Presence is honest too — \"thinking\" settles to idle after\nsilence, tool calls never clobber an explicit phase, and an attached writer\nthat has never made a spatial write still parks its cursor at its last\nactivity so it cannot be invisible. Agents coordinate with each other over the\nsame steering queue (agent-to-agent hand-offs, reviews, and territory splits),\nand the `pmx-canvas-orchestration` skill documents the choreography.\n\n### 06 / Save\n\nSpatial state auto-saves to `.pmx-canvas/canvas.db` (debounced ~500 ms) —\ngit-committable, shareable across machines, and survives both browser\nrefresh and server restart. Autosave is not a backup: `pmx-canvas backup` and\nits optional server-run schedule copy the whole board library, while restore\nkeeps the replaced database. Backup and scheduling are backend/CLI operations;\nthere is no Home backup button. A board can also be exported as a self-contained\nHTML file. Export previews what is included, omits local file contents unless\nexplicitly requested, and locks board-link cards because an exported file has\nno live target library (the target title is not embedded). Named [snapshots](docs/mcp.md), full\nundo/redo, and an auto-detected code graph (JS/TS, Python, Go, Rust) make\nthe canvas durable rather than throwaway. Stop the server before committing\nthe DB so SQLite WAL data is checkpointed into the file.\n\n### 07 / Any agent\n\nHarness-agnostic. Drive the canvas from [MCP](docs/mcp.md) (24 tools,\n15 static canvas resources plus two context/graph resource templates, change notifications), the [CLI](docs/cli.md), the\n[HTTP API](docs/http-api.md), or the [Bun SDK](docs/sdk.md) — all\n[environment variables documented here](docs/environment.md). Works with\nClaude Code, the GitHub Copilot app and CLI, Codex, Amp, Cursor, Windsurf, or\nany agent that can spawn an MCP stdio server, call a CLI, or hit an HTTP\nendpoint.\n\n### 08 / Native app adapters\n\nPMX Canvas doesn't just run in a browser tab — it embeds **natively inside the\nagent apps you already use**, as a thin adapter layer over the same neutral AX\nsurfaces (the core never imports a host SDK).\n\n<p align=\"center\">\n  <img src=\"docs/screenshots/github-copilot-app.png\" alt=\"PMX Canvas as a native canvas panel in the GitHub Copilot app\" width=\"100%\" />\n</p>\n<p align=\"center\"><sub>PMX Canvas as a native canvas panel in the GitHub Copilot app.</sub></p>\n\n<p align=\"center\">\n  <img src=\"docs/screenshots/codex-app.png\" alt=\"PMX Canvas workbench in the Codex in-app Browser\" width=\"100%\" />\n</p>\n<p align=\"center\"><sub>The live PMX workbench in the Codex in-app Browser.</sub></p>\n\n<p align=\"center\">\n  <img src=\"docs/screenshots/claude-code-desktop.png\" alt=\"PMX Canvas in the Claude Code desktop app's built-in browser pane, driven over MCP\" width=\"100%\" />\n</p>\n<p align=\"center\"><sub>Claude Code desktop: the workbench in the built-in browser pane, mutated live over MCP.</sub></p>\n\n<p align=\"center\">\n  <img src=\"docs/screenshots/amp-orb-portal.png\" alt=\"PMX Canvas running as an Amp orb service, viewed through the Amp portal in the Volt theme\" width=\"100%\" />\n</p>\n<p align=\"center\"><sub>AMPCode: the canvas as an orb service through the Amp portal (Volt theme).</sub></p>\n\n- **GitHub Copilot app** — a committed project canvas extension\n  (`.github/extensions/pmx-canvas/`) opens the live PMX workbench in a native\n  Copilot panel (light-themed by default to match the app, via the `?theme=`\n  session override), wakes Copilot when the board sends a steer, injects\n  pinned/focused AX context on prompt submission, and exposes actions for focus,\n  work items, approval gates, review annotations, the AX timeline, and\n  host-capability reporting. Actions stay bound to the server shown by their\n  panel and are withheld if that server no longer matches the panel workspace.\n  Install it into any repo with\n  `pmx-canvas copilot install-extension` (`--dry-run` to preview).\n- **Codex app** — native through the Codex in-app Browser (opened to\n  `/workbench`) plus the PMX MCP server: agents read `canvas://ax-context` /\n  `canvas_ax_state { action: \"get\" }` and label Codex-originated focus with\n  `source: \"codex\"`. No extension API needed — Codex's two native surfaces\n  (MCP + in-app Browser) are exactly what the canvas requires.\n- **Claude Code desktop app** — the workbench runs in the desktop app's\n  built-in browser pane alongside the PMX MCP server, same zero-adapter recipe\n  as Codex: open `http://localhost:4313/workbench?theme=daylight` (or\n  `?theme=auto` to follow the app's appearance) in the app's browser and the\n  live board, pins, and Ghost Cursor all work in-panel — themed to match the\n  pane without changing what other clients see.\n- **AMPCode orbs + portal** — run the canvas as an orb service and view the\n  live workbench through the Amp portal (the `*.onamp.dev` URL ampcode.com\n  embeds for the thread). Zero configuration: orbs set `AMP_ORB` in the\n  service environment, and the canvas auto-adapts to the portal's constraints\n  — it defaults straight to the proxy-safe polling transport (the portal\n  proxy buffers the live event stream). Direct HTTP polls wait for new events\n  instead of pausing two seconds between reads, keeping guest cursors responsive.\n  It renders HTML, graph, json-render,\n  and app surfaces inline via `srcdoc` because the nested-iframe embed blocks\n  `src`-URL child iframes (`?transport=sse` and `?iframe-mode=src` override\n  either behavior when diagnosing). Non-orb buffering proxies get the same\n  protections via runtime detection: an SSE watchdog that falls back to\n  polling, and the boot-time iframe probe.\n\nAny other app browser (the ChatGPT desktop app, an IDE webview, …) works the\nsame zero-adapter way: open the workbench URL, and add `?theme=<name|auto>` to\ngive that panel its own session-local default theme.\n\nThe contract is host-agnostic, so a new host plugs in the same way: map its\nhooks, canvas, and session APIs onto PMX's AX primitives — no core changes.\n\n## Prerequisites\n\n- [Bun](https://bun.sh) >= 1.4.2\n\nThe published SDK entrypoint is Bun-first. Node.js consumers should use the\nCLI, MCP server, or HTTP API.\n\n## Install\n\n```bash\nbunx pmx-canvas              # Run without installing (recommended for one-off use)\nbun add -g pmx-canvas        # Install globally — exposes the `pmx-canvas` command\nbun add pmx-canvas           # Install into a project (needed for the Bun SDK)\nnpm install -g pmx-canvas    # npm works too — still requires Bun on PATH to run\n```\n\n`pmx-canvas` is Bun-first: the CLI is a TypeScript file with a `#!/usr/bin/env bun`\nshebang, so Bun must be installed even when you fetch the package via npm or pnpm.\n\nTo work on the canvas itself, clone the repo — see [Development](#development).\n\n## Quick start\n\n### Run the canvas\n\n```bash\nbunx pmx-canvas              # Start canvas, open browser\nbunx pmx-canvas --demo       # Start with the showcase demo board\nbunx pmx-canvas --no-open    # Headless (good for daemons / CI)\nbunx pmx-canvas --theme=volt # Pick a theme (nine ship; PMX_CANVAS_THEME works too)\nbunx pmx-canvas --mcp        # Run as MCP server (stdio)\nbunx pmx-canvas --help       # All commands\n```\n\nFor the experimental ChatGPT/MCP Apps integration, use the separate\n[`--mcp-app` profile](docs/mcp.md#private-mcp-app-preview). It embeds the real\nPMX workbench with selection/pin context; prompts stay in ChatGPT's own composer.\nHost iframe policy and trusted-human restrictions still apply; this is not\nyet a published plugin or a natively verified ChatGPT integration.\n\nThemes are a tool-rail picker away too, and any one panel can override the\nshared theme for itself with `?theme=<name|auto>`.\n\nPress `?` on the board for the full keyboard map. Shortcuts follow the\nplatform — `⌘` on a Mac, `Ctrl` on Windows and Linux, where `Ctrl+Y` also\nredoes and `Backspace`/`Delete` both delete the selection.\n\nThe canvas opens at `http://localhost:4313`. Try `--demo` first — it seeds a\nshowcase board with every node type on it: notes and status, files, a diff, a\nCSV table, charts of every kind, mermaid diagrams, the HTML primitives,\nstructured panels, a grouped cluster, labeled edges, and context pins.\n\n### Connect your agent (MCP)\n\nAdd to your agent's MCP config:\n\n```json\n{\n  \"mcpServers\": {\n    \"canvas\": {\n      \"command\": \"bunx\",\n      \"args\": [\"pmx-canvas\", \"--mcp\"]\n    }\n  }\n}\n```\n\nThe canvas auto-starts on first tool call. Keep the config portable: commit it\nto the repo and let the workspace default to the launch directory — hard-coding\nan absolute `PMX_CANVAS_WORKSPACE_ROOT` breaks other checkouts and machines.\nSet that env var only when your host spawns the MCP server from an incidental\ndirectory (e.g. `~/.copilot`) instead of the project root.\n\nVerify any environment in one command against a running server:\n\n```bash\nbunx pmx-canvas smoke\n```\n\nIt checks server health + workspace, CLI/server version skew, the MCP stdio\ninitialize handshake, a temp-node create/search/remove round-trip, and board\nvalidation — JSON report, exit 1 on failure.\n\n### Use inside the GitHub Copilot app\n\nThe standalone [agent plugin](docs/agent-plugin.md) in `plugins/pmx-canvas/` bundles PMX's\nMCP tools and native Copilot canvas. It uses the Agent Plugins 1.0 format: other compatible\nclients get the MCP tools and browser workbench, not Copilot's native side panel.\n\nThis repository includes a project canvas extension:\n\n```text\n.github/extensions/pmx-canvas/extension.mjs\n```\n\nWhen loaded by the Copilot app, it opens the PMX workbench natively, starts a\nmatching local PMX server when needed, and injects `AX` pinned/focused context\nas hidden per-turn context. The adapter is thin: PMX state still lives in\n`.pmx-canvas/canvas.db`, and the same HTTP, MCP, CLI, and SDK surfaces remain\navailable to non-GitHub agents. See\n[`github-copilot-app-adapter.md`](skills/pmx-canvas/references/github-copilot-app-adapter.md)\nfor the full setup and live-test checklist.\n\n### Use inside the Codex app\n\nCodex needs no extension — its two native surfaces are exactly what the canvas\nrequires. Add the PMX MCP server to the Codex workspace config (same snippet as\n[Connect your agent](#connect-your-agent-mcp)), then open the returned\n`/workbench` URL in the **Codex in-app Browser** so you can see mutations live.\nAgents read pinned/focused context from `canvas://ax-context` /\n`canvas_ax_state { action: \"get\" }` and label Codex-originated focus with\n`source: \"codex\"`. See\n[`codex-app-adapter.md`](skills/pmx-canvas/references/codex-app-adapter.md) for\nthe full workflow and live-test checklist.\n\n### Use inside AMPCode orbs and the Amp portal\n\nThe portal and the agent's MCP connection are separate. For native Canvas tools,\nmerge this into the workspace's `.amp/settings.json` (not `.mcp.json`):\n\n```json\n{\n  \"amp.mcpServers\": {\n    \"canvas\": {\n      \"command\": \"bunx\",\n      \"args\": [\"pmx-canvas@0.8.2\", \"--mcp\"],\n      \"includeTools\": [\"canvas_*\"],\n      \"env\": {\n        \"PMX_CANVAS_WORKSPACE_ROOT\": \"/absolute/path/to/project\",\n        \"PMX_CANVAS_PORT\": \"14313\",\n        \"PMX_CANVAS_URL\": \"\",\n        \"PMX_CANVAS_AGENT_SOURCE\": \"amp\"\n      }\n    }\n  }\n}\n```\n\nReplace the root and example port with the portal service's actual workspace and local\nlistening port, including an orb-assigned port. Configure this inside the orb/runner;\nsettings on your laptop are not automatically available there.\nIn the PMX product checkout, use `\"command\": \"bun\"` and\n`\"args\": [\"run\", \"src/mcp/server.ts\"]` to test the checked-out source instead.\nRun `amp mcp doctor` in that workspace. If it reports `awaiting approval`, the user\nmust review the command and run `amp mcp approve canvas` there; the agent must not\nself-approve or bypass workspace trust. Then reload MCP connections and confirm\n`connected`, Canvas tool discovery, and matching `/health.workspace`, version and\nactive board before writes. An open portal or standalone MCP handshake does not prove\nnative discovery. PMX ships no dedicated Amp lifecycle adapter: an active agent can\npoll steering, but MCP setup alone does not wake an idle thread or activate skills.\nSee the bundled [Amp setup and verification guide](skills/pmx-canvas/references/installing-pmx-canvas.md#amp-connect-the-agent-separately-from-the-portal)\nand [Amp MCP configuration](https://ampcode.com/docs/customize/mcp).\n\nFor the visible workbench, run `pmx-canvas` as an orb service (the orb sets\n`AMP_ORB` in the environment automatically) and open the workbench through the\nthread's portal URL. A consumer-workspace service recipe:\n\n```yaml\n# .amp/services.yaml — supervised portal service\nservices:\n  pmx-canvas:\n    command: pmx-canvas --no-open\n    portal: true\n    health: /health\n```\n\n```bash\n# .agents/setup — install the CLI (pin the exact version: a fresh orb running\n# @latest can silently pick up a newer release than the one you validated)\nnpm install -g pmx-canvas@0.8.2\n```\n\nThe server binds the portal-assigned `$PORT` automatically (gated on the\n`AMP_ORB` env the orb always sets, so a stray `PORT` elsewhere never changes\nthe default), restores `.pmx-canvas/canvas.db`, and the portal manifest picks\nit up — no port flags or `$PORT` interpolation in the service command. The\norb image needs Bun >= 1.4.2; WebView automation (`pmx-canvas screenshot`)\nalso needs a working Chrome installation. The canvas detects the orb and the portal's nested-iframe\nembed on its own: live updates arrive over the proxy-safe polling transport,\nand iframe-backed nodes (HTML, mermaid, graph, json-render, web artifacts)\nrender inline via `srcdoc` with their theme styling included. Two things can't\nbe inlined and stay blocked by the portal embed: cross-origin hosted apps (e.g.\nthe hosted Excalidraw MCP app), and PDF file nodes — a PDF node offers an\n\"Open PDF\" link there instead of a preview.\nDebug overrides: `/workbench?transport=poll|sse` and\n`?iframe-mode=srcdoc|src`. After verifying the workspace, `pmx-canvas smoke --port=<actual-port>`\nchecks health, versions, a standalone MCP handshake, node lifecycle and validation.\nUse a disposable board: it performs temporary writes and leaves history. This does\nnot verify native Amp discovery or browser rendering.\n\n### Install the agent skill (recommended)\n\nThe fastest way to get a working canvas is to install the `pmx-canvas` agent\nskill. It teaches the agent how to install the package, start the server, and\ndrive every node type, group, snapshot, and search the canvas exposes.\n\n```bash\n# 1. GitHub CLI extension (gh >= 2.90)\ngh skill install pskoett/pmx-canvas pmx-canvas\n\n# 2. Agent Skills CLI (runtime-agnostic)\nnpx skills add pskoett/pmx-canvas/skills/pmx-canvas\n\n# 3. Manual clone + copy\ngit clone https://github.com/pskoett/pmx-canvas.git\ncp -r pmx-canvas/skills/pmx-canvas <your-agent-skills-dir>\n```\n\nCommon harness skill directories: `.claude/skills/` (Claude Code),\n`.github/skills/` or `.copilot/skills/` (Copilot CLI),\n`.agents/skills/` (cross-harness convention). Once the canvas is running,\nthe agent can read `canvas://skills` and pull in companion skills\n(`pmx-canvas-orchestration` for running several agents on one board,\n`control-session-orchestrator`, `web-artifacts-builder`, `json-render-*`,\n`pmx-canvas-testing`, `playwright-cli`, etc.) as the work demands.\n\nThe MCP server also supports the [Skills extension](docs/mcp.md#skills-extension-sep-2640):\ncompatible hosts discover skills through `skills/list` and read instructions, references,\nscripts, and assets at `skill://<name>/<path>`. Files come from the running MCP package;\nrestart MCP after an upgrade. Host support determines automatic skill loading, and reading\na skill never grants permission to execute its scripts. Filesystem installation remains available.\n\n## Bugs, feature requests, and feedback\n\nClick the small bug icon below the logo in the left toolbar (**Bug and feedback**).\nChoose Bug report, Feature request, or General feedback, then enter a title and\ndescription. **Continue on GitHub** opens a prefilled issue in this repository;\nsign in to GitHub, review it, and submit. Issues are public. No board data, workspace\npaths, screenshots, or logs are attached automatically.\n\n## Documentation\n\n- **[Node types](docs/node-types.md)** — every node type, edge types, and\n  the three-tier visual matrix (json-render → html → web-artifact)\n- **[CLI reference](docs/cli.md)** — full command surface, daemon mode,\n  watch streams, WebView automation\n- **[MCP reference](docs/mcp.md)** — 24 tools, 15 static canvas resources, two\n  context/graph resource templates, plus bundled\n  skill resources, Skills extension, change notifications, node-type routing\n- **[HTTP API](docs/http-api.md)** — REST endpoints, SSE, batch operations\n- **[AX host-adapter contract](docs/ax-host-adapter-contract.md)** — how native\n  host adapters connect context, steering, activity, and human gates\n- **[Bun SDK](docs/sdk.md)** — `createCanvas()` for TypeScript on Bun\n- **[Release process](docs/RELEASE.md)** — maintainer-only\n\n## Scope\n\n- **Single-machine, today.** One canvas per `bunx pmx-canvas` instance, on\n  one machine. No built-in multi-user auth — collaboration means humans and\n  agents on the same machine: every browser tab and every connected agent\n  pointed at the same `localhost:4313` shares one live board, with per-writer\n  presence (cursors, chips, minimap dots) for all of them. To share across\n  machines, commit `.pmx-canvas/canvas.db`.\n- **What leaves your machine.** The core canvas runs entirely on\n  `localhost`. Network egress only happens for explicit, opt-in flows:\n  `webpage` nodes and remote-URL `image` nodes fetch the address you give\n  them; `mcp-app` / `canvas_app { action: \"diagram\" }` calls go to whatever\n  MCP server URL you configure (the Excalidraw preset uses\n  `https://mcp.excalidraw.com/mcp`); building a web artifact runs a package\n  manager, which fetches a React/Tailwind toolchain plus that artifact's declared dependencies (and, if neither pnpm nor bun is present, installs pnpm globally) from the npm\n  registry; and `bunx` itself reads the registry on first install. Nothing\n  else phones home.\n\n## Tech stack\n\n- **Runtime:** [Bun](https://bun.sh)\n- **UI:** [Preact](https://preactjs.com) + [@preact/signals](https://github.com/preactjs/signals);\n  the json-render/graph viewer bundle is React + [recharts](https://recharts.org),\n  and mermaid nodes render with [mermaid](https://mermaid.js.org)\n- **Styling:** CSS custom properties + Tailwind (json-render bundle only)\n- **Server:** Bun.serve (HTTP + SSE)\n- **MCP:** [@modelcontextprotocol/sdk](https://github.com/modelcontextprotocol/typescript-sdk) (stdio)\n\n## Development\n\n```bash\ngit clone https://github.com/pskoett/pmx-canvas.git\ncd pmx-canvas\nbun install\nbun run build\nbun run dev            # Start + open browser\nbun run dev:demo       # Start with the showcase demo board\nbun run test           # Unit tests\nbun run test:e2e       # Playwright end-to-end tests\nbun run test:all       # Unit tests + browser smoke\n```\n\nFor developer flows on the `pmx-canvas` repo itself (release process,\ncontribution gates, agent-skill mirroring) see\n[`AGENTS.md`](AGENTS.md) and [`docs/RELEASE.md`](docs/RELEASE.md).\n\n## Contributing\n\nContributions welcome. Please open an issue first to discuss what you'd like\nto change.\n\n1. Fork the repo\n2. Create a feature branch (`git checkout -b feature/my-change`)\n3. Run `bun run test:all` before submitting\n4. Open a pull request\n\n## License\n\n[MIT](LICENSE)\n"}