The HTML versions cover everything the markdown did. Migrating the
two pieces unique to canvases.md into canvases-feature.html before
deletion:
- A compact "Validation rules" section listing every cap and
reservation (version=1, id pattern, core- reserved prefix,
256KB/canvas, 32/session, payload-must-match, diff-specific
caps from pass 13).
- The canvas-id namespacing distinction (id vs canvasType as
separate concerns) — already added previously, now adjacent
to validation rules so reference content is grouped.
Updated cross-doc links in canvases-launch.html and the feature
writeup footer to point at remaining HTML files plus source files
in packages/core. No more references to canvases.md or
canvases-launch.md anywhere in the docs.
Removes:
- docs/canvases.md
- docs/canvases-launch.md
Keeps:
- docs/canvases-feature.html (full writeup, source of truth)
- docs/canvases-launch.html (showcase / launch)
- docs/canvases-codex-review-2026-05-06.html (review writeup)
- docs/assets/canvases/* (screenshots)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Codex consult on the v0.4 renderer-plugin design surfaced five
corrections that the prior commit (c7a79a88e) got wrong. Updates
all four canvas docs (source-of-truth, launch md, launch html,
feature writeup html) to reflect the corrected design.
What changed:
1. Architecture is runtime registries, not extensible types.
- The CanvasArtifact discriminated union for built-ins stays
closed and strictly typed.
- Plugin canvases land in a separate PluginCanvasArtifact branch
with `type: string; payload: unknown`.
- Three registries from one discovery step: Node schema registry
(core uses to validate at runtime), generated web renderer map
(next bundles statically as packages/web/src/generated/canvas-
renderers.ts), optional generated TS union (ergonomics only).
2. "Build-time only" was understating runtime needs.
- Core's canvas-log.ts must validate plugin payloads at runtime.
That means core loads installed plugin manifests + Zod schemas
at AO startup. Renderers are still web-build-time-bundled,
but plugins are runtime dependencies in Node — just not
URL-loaded.
3. Trust framing is now honest.
- "Same as npm install" was technically true but product-
dangerous. Build-time bundling removes the remote-loading
risk; it does NOT reduce blast radius. A renderer plugin can
read same-origin auth tokens, call APIs, keylog, alter UI.
- Docs now state explicitly: "Installing a canvas renderer
plugin grants full dashboard code execution." v0.4 install
path will surface this as a warning. Iframe sandboxing
deferred — half-baked iframe is worse than no sandbox.
4. Realistic ship cost: 1.5–3 engineer-weeks of core work, not
"half a day". Half a day is the plugin author's effort.
5. Namespacing is two separate concerns. Canvas `id` is filesystem
identity (reserves `core-*`); `canvasType` is renderer dispatch
(does not reserve ids). A Claude agent can produce a
`type: "flamegraph"` canvas without being the flamegraph plugin.
6. Plugin packaging requires:
- Compiled ESM with declarations (not raw TSX).
- Separate Node-safe schema entrypoint and browser-safe renderer
entrypoint via package.json `exports`.
- React as peerDependency in renderer.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The previous "Tier 3: add a renderer needs a core PR" framing wasn't
honest open-source extensibility — it was just a permissive license.
This commit reframes Tier 3 as a renderer plugin model:
- Anyone can ship `@aoagents/ao-plugin-canvas-{name}` packages.
- Plugin declares own canvasType id, payload schema (Zod), and
React renderer.
- AO's build-time plugin registry walks installed packages, generates
a TypeScript file extending the CanvasArtifact discriminated union,
and the web build bundles the renderers.
- Trust boundary is `npm install` — same as every other AO plugin.
- No core PR. No runtime code injection. Build-time only.
Adds a new Tier 4: promote a popular renderer plugin into core's
built-in set when the ecosystem has converged on it. The bar is
"this is now standard infrastructure", not "this is a new idea".
Updates the contract from "constrained UI in core" to three rules:
1. Anyone supplies any data, in any supported type.
2. Anyone ships a new type via plugin (npm trust).
3. Nobody dynamically loads JS at runtime.
The non-goal list now distinguishes "dynamically-loaded React"
(rejected) from "build-time-bundled renderer plugins" (the v0.4
unlock). Mirrors the change across docs/canvases.md (source of
truth), docs/canvases-launch.{md,html} (showcase), and
docs/canvases-feature.html (full writeup).
No code change in v0.1. The plugin slot lands in v0.4 with its own
design pass — this commit just documents the direction.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replaces the brief "how extensible" paragraph with a structured
three-tier guide: emit JSON (zero code), implement CanvasProducer
(v0.2, ~30 lines), or add a new renderer type (core PR, half-day).
Each tier names the actual files to touch and the gating cost.
Folds the old "Suggested first uses" examples into Tier 1 since they
were just zero-code use cases anyway. Adds an explicit trade-off
section that names the "expressive data, constrained UI" contract:
anyone emits data, only core merges new types, no third-party JS in
the supervisor dashboard.
Both the markdown and HTML showcase docs stay in sync.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replace the "mobile gracefully hides" framing with a direct statement
that canvases are a desktop-only feature for now. Removes the
canvases-mobile.png screenshot since it was just showing absence.
Adds an explicit "Mobile — deferred" entry in the design doc roadmap
that points at the !isMobile guard in SessionDetail.tsx.
Behavior unchanged — the code already gated the rail on !isMobile.
This is a docs-only edit to set expectations honestly.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Self-contained docs/canvases-launch.html — same content as the markdown
showcase but as a single shareable HTML file. Inline CSS matches AO's
dark theme (token colors copied from globals.css). Uses the same
screenshots from docs/assets/canvases/. Renders identically in any
browser, no build step needed — open with file://, paste in Slack, host
as a github pages preview, all work the same.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>