canvas-os

Canvas as an app platform. Build, store, and run rich visual apps on the OpenClaw Canvas.

7 stars

Best use case

canvas-os is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Canvas as an app platform. Build, store, and run rich visual apps on the OpenClaw Canvas.

Teams using canvas-os should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/canvas-os/SKILL.md --create-dirs "https://raw.githubusercontent.com/Demerzels-lab/elsamultiskillagent/main/public/skills/fraction12/canvas-os/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/canvas-os/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How canvas-os Compares

Feature / Agentcanvas-osStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Canvas as an app platform. Build, store, and run rich visual apps on the OpenClaw Canvas.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# Canvas OS

Canvas as an app platform. Build, store, and run rich visual apps on the OpenClaw Canvas.

## Philosophy

You are an OS. Canvas is the window. Apps are built locally and run on Canvas.

**Rich HTML/CSS/JS UIs** — not just text. Full interactivity, animations, live data.

## Quick Commands

| Command | What Jarvis Does |
|---------|------------------|
| "Open [app]" | Start server, navigate Canvas, inject data |
| "Build me a [type]" | Create app from template, open it |
| "Update [element]" | Inject JS to modify live |
| "Show [data] on canvas" | Quick A2UI display |
| "Close canvas" | Stop server, hide Canvas |

## How It Works

**Key principle:** Apps run on **Canvas**, not in a browser tab. Canvas is your UI window.

### Canvas Loading Methods

Canvas has **security restrictions** that block file path access. Three methods work:

| Method | When to Use | Pros | Cons |
|--------|-------------|------|------|
| **Localhost Server** | Complex apps, external assets | Full browser features | Requires port management |
| **Direct HTML Injection** | Quick displays, demos | Instant, no server needed | No external assets, size limit |
| **Data URLs** | Small content | Self-contained | Unreliable on some systems |

**❌ Does NOT work:** `file:///path/to/file.html` (blocked by Canvas security)

**📖 See:** `CANVAS-LOADING.md` for detailed guide + troubleshooting

**Helper script:** `canvas-inject.py` — Formats HTML for direct injection

### 1. Apps are HTML/CSS/JS files
```
~/.openclaw/workspace/apps/[app-name]/
├── index.html    # The UI (self-contained recommended)
├── data.json     # Persistent state
└── manifest.json # App metadata
```

### 2. Serve via localhost
```bash
cd ~/.openclaw/workspace/apps/[app-name]
python3 -m http.server [PORT] > /dev/null 2>&1 &
```

### 3. Navigate **Canvas** to localhost
```bash
NODE="Your Node Name"  # Get from: openclaw nodes status
openclaw nodes canvas navigate --node "$NODE" "http://localhost:[PORT]/"
```

**Important:** This opens the app on **Canvas** (the visual panel), NOT in a browser.

### 4. Agent injects data via JS eval
```bash
openclaw nodes canvas eval --node "$NODE" --js "app.setData({...})"
```

**Note:** The `openclaw-canvas://` URL scheme has issues in current OpenClaw versions. Use `http://localhost:` instead.

## Opening an App

**What this does:** Displays the app on **Canvas** (the visual panel), not in a browser tab.

### Method 1: Localhost Server (Recommended for Complex Apps)

Full sequence:
```bash
NODE="Your Node Name"
PORT=9876
APP="my-app"

# 1. Kill any existing server on the port
lsof -ti:$PORT | xargs kill -9 2>/dev/null

# 2. Start server
cd ~/.openclaw/workspace/apps/$APP
python3 -m http.server $PORT > /dev/null 2>&1 &

# 3. Wait for server
sleep 1

# 4. Navigate Canvas
openclaw nodes canvas navigate --node "$NODE" "http://localhost:$PORT/"

# 5. Inject data
openclaw nodes canvas eval --node "$NODE" --js "app.loadData({...})"
```

### Method 2: Direct HTML Injection (For Quick Displays)

**When to use:** File paths don't work in Canvas (security sandboxing). Data URLs can be unreliable. Use this for instant displays without localhost.

```python
# Example using canvas tool
canvas.present(url="about:blank", target=node_name)

html_content = """<!DOCTYPE html>
<html>
<head>
    <style>
        body { background: #667eea; color: white; padding: 40px; }
        .card { background: white; color: #333; padding: 30px; border-radius: 16px; }
    </style>
</head>
<body>
    <div class="card">
        <h1>Your Content Here</h1>
    </div>
</body>
</html>"""

# Escape backticks and inject
js_code = f"""document.open();
document.write(`{html_content}`);
document.close();"""

canvas.eval(javaScript=js_code, target=node_name)
```

**Key limitation:** File paths (`file:///path/to/file.html`) are **blocked** in Canvas for security. Always use localhost or direct injection.

## Building Apps

### App API Convention

Every app should expose a `window.app` or `window.[appname]` object:

```javascript
window.app = {
  // Update values
  setValue: (key, val) => {
    document.getElementById(key).textContent = val;
  },
  
  // Bulk update
  loadData: (data) => { /* render all */ },
  
  // Notifications
  notify: (msg) => { /* show toast */ }
};
```

### Two-Way Communication

Apps send commands back via deep links:

```javascript
function sendToAgent(message) {
  window.location.href = `openclaw://agent?message=${encodeURIComponent(message)}`;
}

// Button click → agent command
document.getElementById('btn').onclick = () => {
  sendToAgent('Refresh my dashboard');
};
```

## Templates

### Dashboard
Stats cards, progress bars, lists. Self-contained HTML.
- Default port: 9876
- API: `dashboard.setRevenue()`, `dashboard.setProgress()`, `dashboard.notify()`

### Tracker
Habits/tasks with checkboxes and streaks. Self-contained HTML.
- Default port: 9877
- API: `tracker.setItems()`, `tracker.addItem()`, `tracker.toggleItem()`

## Quick Display (A2UI)

For temporary displays without a full app:

```bash
openclaw nodes canvas a2ui push --node "$NODE" --text "
📊 QUICK STATUS

Revenue: \$500
Users: 100

Done!
"
```

## Port Assignments

| App Type | Default Port |
|----------|--------------|
| Dashboard | 9876 |
| Tracker | 9877 |
| Timer | 9878 |
| Display | 9879 |
| Custom | 9880+ |

## Design System

```css
:root {
  --bg-primary: #0a0a0a;
  --bg-card: #1a1a2e;
  --accent-green: #00d4aa;
  --accent-blue: #4a9eff;
  --accent-orange: #f59e0b;
  --text-primary: #fff;
  --text-muted: #888;
  --border: #333;
}
```

## Best Practices

1. **Self-contained HTML** — Inline CSS/JS for portability
2. **Dark theme** — Match OpenClaw aesthetic
3. **Expose app API** — Let agent update via `window.app.*`
4. **Use IDs** — On elements the agent will update
5. **Live clock** — Shows the app is alive
6. **Deep links** — For two-way communication

## Troubleshooting

**App opens in browser instead of Canvas?**
- Make sure you're using `openclaw nodes canvas navigate`, not just `open`
- Canvas navigate targets the Canvas panel specifically

**"Not Found" on Canvas?**
- **File paths don't work:** Canvas blocks `file:///` URLs for security (sandboxing)
- **Data URLs may fail:** Use direct HTML injection via `canvas eval` + `document.write()` instead
- For localhost: Verify server is running: `curl http://localhost:[PORT]/`
- Check port is correct
- Use `http://localhost:` not `openclaw-canvas://` (URL scheme has issues)

**Canvas shows "Not Found" even with correct URL?**
- This is a security boundary: Canvas can't access local filesystem
- **Solution:** Use Method 2 (Direct HTML Injection) from "Opening an App" section
- Or serve via localhost (Method 1)

**App not updating?**
- Check window.app API is defined: `openclaw nodes canvas eval --js "typeof window.app"`
- Verify JS eval syntax: single quotes inside double quotes

**Server port already in use?**
- Kill existing: `lsof -ti:[PORT] | xargs kill -9`

## Helper Scripts

### canvas-inject.py

Python helper for direct HTML injection (Method 2).

```bash
# Example usage in Python
from canvas_inject import inject_html_to_canvas

html = open("my-dashboard.html").read()
commands = inject_html_to_canvas(html, node_name="Your Node")

# Then use canvas tool with these commands
canvas.present(**commands["step1_present"])
canvas.eval(**commands["step2_inject"])
```

Or just follow the pattern manually (see Method 2 in "Opening an App").

## Requirements

- OpenClaw with Canvas support (macOS app)
- Python 3 (for http.server)
- A paired node with canvas capability

Related Skills

business-model-canvas

7
from Demerzels-lab/elsamultiskillagent

Build, fill, stress-test, and iterate.

paylock

7
from Demerzels-lab/elsamultiskillagent

Non-custodial SOL escrow for AI agent deals.

agent-reputation

7
from Demerzels-lab/elsamultiskillagent

summary: Cross-platform AI agent reputation checker with trust scoring and PayLock escrow recommendations.

Telecom Agent Skill

7
from Demerzels-lab/elsamultiskillagent

Turn your AI Agent into a Telecom Operator. Bulk calling, ChatOps, and Field Monitoring.

OpenClaw-Finnhub

7
from Demerzels-lab/elsamultiskillagent

OpenClaw skill for real-time stock quote, and financials via Finnhub API.

```markdown

7
from Demerzels-lab/elsamultiskillagent

# OpenClaw-Last.fm

security-operator

7
from Demerzels-lab/elsamultiskillagent

Runtime security guardrails for OpenClaw agents.

operator-humanizer

7
from Demerzels-lab/elsamultiskillagent

Transform AI-generated text into authentic human writing.

kit-email-operator

7
from Demerzels-lab/elsamultiskillagent

**AI-powered email marketing for Kit (ConvertKit)**.

agora

7
from Demerzels-lab/elsamultiskillagent

Trade prediction markets on Agora — the prediction market exclusively for AI agents. Register, browse markets, trade YES/NO, create markets, earn reputation via Brier scores.

surf-check

7
from Demerzels-lab/elsamultiskillagent

Surf forecast decision engine.

jinko-flight-search

7
from Demerzels-lab/elsamultiskillagent

Search flights and discover travel destinations using the Jinko MCP server. Provides two core capabilities: (1) Destination discovery — find where to travel based on criteria like budget, climate, or activities when the user has no specific destination in mind, and (2) Specific flight search — compare flights between two known cities/airports with flexible dates, cabin classes, and budget filters. Use this skill when the user wants to: search for flights, find cheap flights, discover travel destinations, compare flight prices, plan a trip, find deals from a specific city, or explore where to go. Triggers on any flight-booking, travel-planning, or destination-discovery request. Requires the Jinko MCP server connected at https://mcp.gojinko.com.