agentsclimarketplace

Canvas

Skill haliphax-ai/skills/canvas

Custom agent skills

Install
npx -y skills add haliphax-ai/skills --skill canvas

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Interact with the OpenClaw Canvas web server for visual UI surfaces. Use when pushing A2UI JSONL dashboards, serving static HTML/CSS/JS files, querying canvas state from the SQLite cache, or switching between iframe and A2UI rendering modes. Covers session-scoped canvas URLs, static file storage, JSONL persistence, and all available A2UI components.

SKILL.md

13.5 KB, as published. Nobody here has run it

Canvas Web Server

The Canvas web server (haliphax-openclaw/openclaw-canvas-web) registers as a node with the OpenClaw gateway and serves two types of content per agent session:

  1. Static files (iframe mode) — HTML/CSS/JS served from the agent's workspace
  2. A2UI surfaces (component mode) — Declarative UI pushed via JSONL commands

Requirements

  • canvas-web MCP server configured in mcporter (see ~/openclaw-canvas-web/mcp/)
  • sqlite3 binary available on the system (for querying A2UI surface state)
  • OpenClaw Canvas web server running and connected to the gateway (appears as "Canvas Web Server" in openclaw nodes status)

Required Configuration

Store the following in your TOOLS.md file:

## Canvas
- **Canvas Base URL:** <base-url>  (e.g. https://example.com/canvas)

Ask your human for the canvas base URL if you don't have it. All canvas session URLs are derived from this value.

Your Canvas Session

Each agent has a personal canvas session URL:

<CANVAS_BASE_URL>/<agent-id>/

The session name matches your agent ID. All A2UI pushes and static files are scoped to this session.

Static File Storage

Static canvas files live in your workspace's canvas/ directory:

~/.openclaw/workspaces/<agent-id>/canvas/

The server maps agent IDs to workspace canvas directories and serves files at /_c/<session>/<path>.

File organization

  • Long-lived JSONL files — Store in canvas/jsonl/ for dashboards and surfaces you want to persist and re-push across sessions. Files here are auto-pushed — the server watches this directory and automatically pushes A2UI commands when .jsonl files are created or modified. No need to call mcporter.
  • Temporary JSONL files — Store in canvas/tmp/ for short-lived session work, experiments, and one-off surfaces

Note: The jsonl/ and tmp/ subdirectories are ignored by the iframe file watcher by default (no iframe reloads). The jsonl/ directory has its own dedicated watcher that auto-pushes A2UI content instead.

~/.openclaw/workspaces/<agent-id>/canvas/
├── index.html               # static HTML served via iframe
├── jsonl/
│   └── dashboard.jsonl      # persistent dashboard definition
├── tmp/
│   ├── debug-surface.jsonl  # temporary experiment
│   └── test-layout.jsonl    # one-off layout test

Pushing Content to the Canvas

Choose the right approach based on your task:

For most dashboard refreshes, a dataSourcePush is all you need — no component changes required.

Other canvas commands

MCP ToolDescription
canvas_pushPush A2UI JSONL payload
canvas_resetClear all A2UI surfaces for a session
canvas_showShow the canvas panel. Accepts an optional target param for external URL navigation.
canvas_hideHide the canvas panel
canvas_navigateNavigate to a path, URL, or openclaw-canvas:// URI (see below)
canvas_evalExecute JavaScript in the canvas (pass code via javaScript param)
canvas_snapshotCapture a screenshot (returns { format, base64 })

All tools accept an optional session parameter.

Navigation URL schemes

canvas_navigate supports three URL types:

  • Relative path — navigates within the current session's canvas directory (e.g., index.html)
  • External URL (http://, https://, data:) — loads the URL in the canvas iframe directly. Deep link and snapshot scripts are injected automatically into data: URLs.
  • openclaw-canvas:// URI — session-scoped navigation. Format: openclaw-canvas://<session>/<path>. The session is extracted from the URI and the canvas switches to that session's file.
# Navigate to another agent's canvas file
mcporter call canvas-web.canvas_navigate url="openclaw-canvas://developer/dashboard.html"

# Navigate to an external URL
mcporter call canvas-web.canvas_navigate url="https://example.com/report.html"

Switching Between Iframe and A2UI

The canvas view auto-switches based on content:

  • A2UI mode activates when a surface has a root set (via createSurface) and no static file subpath is in the URL
  • Iframe mode activates when navigating to a static file path (e.g., /<agent-id>/index.html)

To force iframe mode, navigate to a specific file. To force A2UI mode, push a surface with createSurface.

To clear A2UI and return to iframe:

mcporter call canvas-web.canvas_reset session=<agent-id>

Theming

Surfaces support DaisyUI theming via the theme property on createSurface. The value is a DaisyUI theme name string applied as data-theme on the renderer container.

Setting a theme

Include theme in your createSurface JSONL command:

{"createSurface": {"surfaceId": "main", "theme": "synthwave"}}

If omitted, the default theme is dark.

Available themes

Any DaisyUI theme is valid. Common options:

ThemeDescription
darkDefault dark theme
lightLight theme
cyberpunkBright yellow/pink retro-futuristic
synthwaveDark purple/navy with neon accents
retroWarm vintage palette
draculaDark with purple/pink highlights
businessProfessional dark theme

Switching themes

Push a new createSurface with a different theme value. The theme updates live without a page refresh:

{"createSurface": {"surfaceId": "main", "theme": "cyberpunk"}}

Persistence

Theme and catalogId are persisted in the SQLite cache. Both survive server restarts and are included in surface replay on client reconnect.

Catalog ID

Surfaces accept an optional catalogId identifying the component catalog package. When omitted, the default is @haliphax-openclaw/a2ui-catalog-all.

{"createSurface": {"surfaceId": "main", "theme": "dark", "catalogId": "@haliphax-openclaw/a2ui-catalog-basic"}}
Catalog IDDescription
@haliphax-openclaw/a2ui-catalog-allAll built-in components (default)
@haliphax-openclaw/a2ui-catalog-basicBasic components only
@haliphax-openclaw/a2ui-catalog-extendedExtended components only

Querying State from SQLite

Important: The OpenClaw gateway must have access to the SQLite database file. If the canvas web server and gateway run on separate hosts, ensure the database is accessible via a shared filesystem (NFS mount, Docker volume, bind mount, etc.).

A2UI surface state is persisted in a SQLite cache at:

~/.openclaw-canvas/a2ui-cache.db

Table: a2ui_surfaces

ColumnTypeDescription
sessionTEXT (PK)Session name (matches agent ID)
surfaceIdTEXT (PK)Surface identifier
componentsTEXT (JSON)Component map { id: component }
rootTEXTRoot component ID
dataModelTEXT (JSON)Data model including $sources
themeTEXTDaisyUI theme name
catalogIdTEXTCatalog URI

The primary key is the composite (session, surfaceId).

Query examples:

# List all surfaces across all sessions
sqlite3 ~/.openclaw-canvas/a2ui-cache.db "SELECT session, surfaceId, root FROM a2ui_surfaces"

# List surfaces for a specific agent session
sqlite3 ~/.openclaw-canvas/a2ui-cache.db "SELECT surfaceId, root FROM a2ui_surfaces WHERE session='<agent-id>'"

# Dump a surface's components
sqlite3 ~/.openclaw-canvas/a2ui-cache.db "SELECT components FROM a2ui_surfaces WHERE session='<agent-id>' AND surfaceId='main'" | jq .

# Check data sources
sqlite3 ~/.openclaw-canvas/a2ui-cache.db "SELECT json_extract(dataModel, '$.\$sources') FROM a2ui_surfaces WHERE session='<agent-id>' AND surfaceId='main'" | jq .

JSONL Commands

A2UI content is pushed as newline-delimited JSON commands. For full details and examples:

Validation feedback

canvas_push returns per-command validation results. Each command in the batch gets a result with ok, command, index, and optional error, componentErrors, and componentWarnings.

Structural validation checks envelope fields (e.g. missing surfaceId, non-array components).

Component-level validation checks each component's props against the schema defined in the catalog's catalog.json. Schemas are loaded from registered catalog packages at startup — there is no hardcoded schema map. Validation checks:

  • Required props — missing required props produce errors; the component is rejected
  • Type mismatches — wrong prop types produce errors; the component is rejected
  • Unknown props — props not in the schema produce warnings; the component is accepted
  • Unknown components — components not in any catalog produce warnings; the component is accepted

Example response with component-level validation:

{
  "ok": false,
  "results": [
    {
      "ok": false, "command": "updateComponents", "index": 0,
      "error": "ValidationFailed: img1: Missing required prop 'src'",
      "componentErrors": [{ "id": "img1", "errors": ["Missing required prop 'src'"], "warnings": [] }],
      "componentWarnings": [{ "id": "txt1", "errors": [], "warnings": ["Unknown prop 'typo' on 'Text'"] }]
    }
  ],
  "errors": [...]
}

Valid components in the same updateComponents batch are still processed — only components with errors are rejected. Warnings are informational and do not prevent processing.

Common validation errors:

  • createSurface: missing surfaceId
  • updateComponents: components must be an array
  • Missing required prop '<name>'
  • Prop '<name>' expected type '<type>', got '<actual>'
  • Unrecognized command

When errors are returned, fix the failing commands and re-push. Valid commands in the batch are still processed.

Streaming interface: Scripts and non-agent consumers can also connect directly to the canvas server's WebSocket and stream JSONL commands with per-command validation feedback in real-time. This is not available through agent tool calls, which use the batch interface described above.

Components and Reactive Data Binding

For the full list of available A2UI components, their JSONL schemas, and use cases, see:

formatString in JSONL: Use ${expression} for interpolated strings on Text, ProgressBar, Badge map, Repeat templates, etc. (e.g. ${title}, ${$value}, ${score | percentOfMax}). Do not use {{...}} there. The only common {{...}} placeholder is {{value}} inside optional emitTo URLs on inputs — that is a separate client-side substitution, not formatString. See references/reactive.md.

Component summary

CategoryComponents
LayoutColumn, Row, Stack, Wrap, Spacer, Divider
ContainersAccordion (collapsible panels), Tabs (switchable tabbed panels)
DisplayText, Badge, Image, ProgressBar, AudioPlayer, Video, Table, Repeat
InputButton, Checkbox, TextField, Select, MultiSelect, Slider, DateTimeInput

Key features

  • Sorting — Table and Repeat support optional sortable prop. Tables sort by clicking column headers (⬆/⬇); Repeat includes a sort direction dropdown.
  • Formatting — Table supports column-level display formatters via the formatters prop (e.g., boolean for ✅/❌ rendering).
  • Filtering — Select and MultiSelect bind to data sources for reactive filtering. Clearing a MultiSelect shows all data (empty selection = no filter).
  • Reactive props — Accordion expanded and Tabs active props react to surface updates, allowing agents to programmatically toggle panels or switch tabs.

Deep Linking

Both iframe content and A2UI components can take advantage of the canvas URL schemes:

  • openclaw:// — agent runs via a confirmation dialog (iframe HTML). See references/deep-linking.md.
  • openclaw-fileprompt:// — subagent task loaded from a file under <agent>/canvas (path after the scheme, not ?file=). A2UI Button POSTs to /api/file-spawn. Same doc.
  • openclaw-canvas:// — session-relative content references (e.g., images served from an agent's canvas directory).

Canonical reference (stays in sync with this skill): openclaw-canvas-web docs/deep-linking.md.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.