Architecture
Canvas layer model and ownership boundaries.
Canvas is organized as an isolated agent workspace topology:
@agent-html/react
-> headless collaboration protocol and interaction events
agent-html/*
-> agent operating context and reusable resources
agent-html/artifacts/*
-> durable artifact composition and content
packages/cli/src/*
-> Vite middleware dev host, guard, and stylesheet entrypoints
packages/cli/src/host/*
-> sandbox host, inspector, and prompt bridge
packages/cli/src/host/styles/*
-> host chrome implementation styles that consume Canvas tokensEach layer owns one decision. The protocol marks stable regions and emits
instrumented state changes. The agent-html workspace provides durable
context agents can read and reuse. Artifacts compose those resources into UI.
The CLI discovers, guards, serves, and routes artifacts through Vite middleware.
The host observes and operates on rendered metadata.
Protocol
Artifact and Block are headless protocol markers.
They own metadata, anchors, and accessibility minimums.
Artifact also owns the readable root container, with layout parameters
configured by Canvas CSS tokens instead of artifact source props. Block is
fully protocol-only: it accepts id, title, and children. It does not own
width, spacing, colors, borders, radius, shadow, cards, panels, grid structure,
or props passthrough.
@agent-html/react exports InteractionProvider,
useArtifactInteraction, useEmitArtifactStateChange,
useInstrumentedValueChange, and useInstrumentedCheckedChange. These helpers
record local control state and dispatch agent-html:state-change events.
Resources
Canvas resources live under agent-html:
AGENTS.md
package.json
components.json
tsconfig.json
styles/index.css
styles/base.css
styles/materials/*
styles/layouts/index.css
styles/layouts/composition.css
styles/internal/*
theme/*
components/ui/*
components/*.tsx
hooks/*
lib/*
types/*
assets/*
public/*
artifacts/*
artifacts/*/data/*Artifacts should consume these resources before adding local one-off helpers.
Composition
Artifacts decide block content layout explicitly:
<Artifact title="Project Brief">
<Block id="summary" title="Summary">
<Card>...</Card>
</Block>
</Artifact>Block marks an inspectable region. It is not a card, panel, or section style.
Do not put layout classes on Block; put layout inside the block content.
Host
The host renders artifacts, discovers blocks, displays guard issues, overlays
block prompt actions, handles floating prompts, applies theme presets, and
loads Canvas stylesheets. Host controls use Canvas UI primitives and theme
resources through #agent-html-playground/components/ui/* and
#agent-html-playground/theme/*; the host must not define artifact visual
language.
Host workbench code is a consumer and composer of runtime pipelines. Its owner map is:
host/api
-> dev-server API contract
host/artifact
-> artifact registry consumption and artifact module runtime
host/overlay
-> rendered Block metadata measurement and prompt anchors
host/prompt
-> floating prompt host state, drafts, and block message lifecycle
host/pipeline
-> Codex/example backend adapters and prompt formatting calls
host/interaction
-> artifact state-change event snapshots for prompt context
host/preferences
-> local host preference persistence
host/theme
-> host theme mode, preset layout, draft preview, and runtime variables
host/navigation
-> sidebar command surfaceReactCanvasHostWorkbench composes those owners. It should not directly own
dev-server route semantics, workspace validation, prompt backend execution,
message store publishing, theme side effects, artifact registry refresh rules,
or Canvas protocol semantics.
Pipeline Map
This page is the authoritative Canvas pipeline map. The shared block prompt model is:
artifactEntry + blockId + implementationPath + interactionSnapshot| Pipeline | Owner | Input | Output | Forbidden dependencies | Primary tests |
|---|---|---|---|---|---|
| Workspace source | agent-html | artifact entries, split block files, local resources | portable source workspace | generated bundles, lockfiles, vendored installs | workspace-contract.test.mjs |
| Workspace file/path helpers | react-canvas/paths.mjs + react-canvas/workspace-file.mjs | root path or source file path | POSIX workspace path or text source | generic filesystem abstraction, mutation APIs, host state | pipeline-ownership-contract.test.mjs, workspace-contract.test.mjs |
| Artifact discovery | react-canvas/paths.mjs | agent-html/artifacts/*.artifact.tsx | artifact entry file paths | app shell, runtime parser, host UI | dev-host.test.mjs, pipeline-ownership-contract.test.mjs |
| Artifact entry protocol guard | react-canvas/guard.mjs | artifact entry source | issues scoped as artifact-entry-protocol | layout or style props on Artifact or Block | guard.test.mjs |
| Block implementation source guard | react-canvas/guard.mjs | agent-html/artifacts/**/*.block.tsx | issues scoped as block-implementation-source | raw visual classes, native primitive bypasses | guard.test.mjs, style-ownership-contract.test.mjs |
| Workspace boundary guard | react-canvas/guard.mjs | artifact and block source imports | issues scoped as workspace-boundary | app imports, old runtime imports, public-file imports | guard.test.mjs, workspace-contract.test.mjs, architecture-boundaries.test.mjs |
| Dependency resolution | dev-server/vite.mjs | source import specifier | CLI-provided runtime module | agent-html/node_modules, source-owned runtime installs | runtime-resolution-contract.test.mjs |
| Module transform and render | Vite middleware + host artifact runtime | artifact entry file path | mounted artifact DOM with HMR-capable module graph | app shell, old runtime render APIs | dev-host.test.mjs, artifact-runtime.test.ts |
| Public/static asset serving | dev-server/routes.mjs + host/api URL helpers | public asset path or proxied font URL | served asset response or host URL | direct Host endpoint strings outside host/api | dev-host.test.mjs, routes.test.mjs, api.test.ts, architecture-boundaries.test.mjs |
| Artifact registry consumption | host/artifact/use-artifact-registry.ts | artifact registry response and pending artifact path | active artifact, guard issues, registry refresh operations | dev-server route implementation, workspace validation | app.test.tsx, pipeline-ownership-contract.test.mjs |
| Block overlay | packages/react + host overlay | rendered data-agent-html-block-* metadata | hover highlight and prompt target | artifact source mutation, host APIs in artifacts | block-overlay.test.ts, index.test.tsx |
| Block implementation lookup | dev server + host API | artifactEntry, blockId | implementationPath | selected source payloads, implementation source payloads | block-implementation.test.mjs, dev-host.test.mjs |
| Block prompt | react-canvas/prompt.mjs | artifactEntry, blockId, optional implementationPath, host interactionSnapshot | minimal prompt packet | selected source payloads, implementation source payloads | prompt.test.mjs |
| Create artifact | host/pipeline + react-canvas/prompt.mjs | create request and generated artifact file path | Codex/example turn request | dev-server implementation, artifact source mutation in Host | pipeline.test.ts, app.test.tsx |
| Guard fix | host/pipeline + react-canvas/prompt.mjs | guard errors for one artifact | Codex/example turn request | warnings-only prompt payloads, host UI state payloads | pipeline.test.ts, prompt.test.mjs |
| Interaction state | packages/react event protocol + host store | artifact-local control changes | host prompt interaction snapshot | filesystem, shell, MCP, privileged host APIs in artifact code | index.test.tsx, interaction-store.test.ts, prompt.test.mjs |
| Preferences persistence | host/preferences | local host preference state | persisted host preference patch | artifact source state, dev-server state | canvas-host-preferences.test.ts, use-canvas-host-preferences.test.ts |
| CSS/theme | agent-html/styles + package host styles + host theme owner | CSS tokens, content classes, theme presets, host chrome CSS | stylesheet and runtime variables | artifact-owned root chrome, sidebar token overrides, host chrome implementation in artifact context | style-ownership-contract.test.mjs, style-resource-contract.test.mjs, theme-preset.test.ts, theme-layout.test.ts |
Dev server routes are orchestration only. They are grouped into explicit runtime adapter pipelines:
host-shell
runtime-module
styles-and-assets
public-asset
artifact-registry-and-guard-report
artifact-source-mutation
block-lookup
codex-bridgeThe dev server owns server lifecycle, route dispatch, Vite runtime creation, dependency supply, and asset serving. Host shell, artifact module, stylesheet, public asset, artifact registry and guard report, artifact mutation, block lookup, and Codex bridge requests enter through those named pipelines. The dev server delegates host and artifact module transforms to Vite.
It does not own protocol semantics, host interaction state, artifact visual
language, or block prompt meaning. Those remain owned by @agent-html/react,
the host interaction store, Canvas styles/resources, and the prompt pipeline.
Boundary Governance
Canvas boundary checks follow the layer topology:
packages/react
-> protocol only; no host, workspace, docs, app, or archive imports
packages/cli/src/react-canvas
-> discovery, guard, prompt, and workspace path orchestration
-> no host UI, artifact source, Canvas UI, theme, docs, app, or archive imports
packages/cli/src/host
-> host inspector chrome and pipeline calls
-> Canvas UI/theme only through #agent-html-playground/components/ui/* and
#agent-html-playground/theme/*
agent-html/artifacts
-> artifact source
-> no host, app, docs, archive, public-file imports, or internal style importspackages/cli/src/react-canvas/architecture-boundaries.test.mjs owns the
topology checks. Use it as the executable boundary matrix before adding new
guard behavior. Workspace source constraints live in
workspace-contract.test.mjs, package/runtime ownership lives in
package-runtime-contract.test.mjs, pipeline ownership lives in
pipeline-ownership-contract.test.mjs, archive separation lives in
archive-runtime-boundary-contract.test.mjs, and style ownership lives in
style-ownership-contract.test.mjs plus style-resource-contract.test.mjs.
style-ownership-contract.test.mjs also records the current fixed-format
artifact layout exceptions for media, map, and carousel blocks. Those
exceptions are not a new styling surface; new artifact code should prefer Canvas
public composition classes and shrink that list when equivalent composition
classes exist.
Dependency Resolution
agent-html/package.json records source dependency metadata for local Canvas
resources. It is not an installation target. The CLI package provides runtime
dependencies. The dev host is the only mapping layer between source imports and
runtime modules: it resolves workspace imports through CLI-owned dependencies,
exact package aliases, Vite import-entry resolution, and explicit
optimizeDeps.
React and React DOM stay pinned through dedicated aliases so the host and artifacts share one renderer instance. Named exports used by workspace source must be present on the resolved runtime entries; this catches ESM/CJS mismatch before browser module loading fails.
The dependency contract is executable: workspace-contract.test.mjs checks
source-only workspace files, source metadata, and forbidden vendored installs.
package-runtime-contract.test.mjs checks CLI runtime ownership.
runtime-resolution-contract.test.mjs checks Vite dependency aliases, ESM
import entries, runtime exports, React singleton resolution, explicit
optimizeDeps, and filesystem allow-list boundaries. routes.test.mjs checks
route pipeline ownership. dev-host.test.mjs checks artifact rendering and
fresh-project startup through the real dev host.
Guard Scopes
Canvas guard reports one issue list with explicit scopes:
artifact-entry-protocol: validates the artifact entry, including default export,Artifact,Block, stableblockId, and protocol-only marker props.block-implementation-source: validates split block implementation source for source-level visual and primitive boundaries.workspace-boundary: validates imports and workspace access boundaries across artifact entries and block implementations.
The dev host treats all guard issues as preview feedback, but the scope names identify which pipeline owns the failure.
Interaction Source Of Truth
@agent-html/react owns portable instrumentation and the event protocol. Its
artifact-local snapshot helps controls compose locally, but it is not the
prompt context source of truth.
The host interaction store owns prompt context. It records
agent-html:state-change events by artifactEntry + blockId, compacts them,
and passes the resulting interactionSnapshot into the block prompt pipeline.