live-canvas/SKILL.md
Live visual canvas for agents. Use when running multi-step tasks (deploys, installs, batch jobs), gathering config from the user (forms), showing plan approval (flowchart + buttons), or displaying live dashboards (metrics, charts, tables). The canvas opens a browser panel that updates in real time as the agent pushes components over WebSocket. Users can click buttons or submit forms and the agent receives the action. Server auto-starts on first use.
npx skillsauth add leprachuan/pot-o-skills live-canvasInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Give any agent a live visual workspace. Instead of walls of markdown, push rich interactive panels—progress boards, dashboards, forms, and plan diagrams—that update in real time as work progresses. Users can click buttons and submit forms; the agent receives those actions as structured responses.
| Trigger | Use This Template |
|---|---|
| Running a multi-step task (deploy, install, build) | progress_board |
| Displaying metrics, charts, or table data | data_dashboard |
| Collecting config/settings from the user | config_form |
| Showing a plan and asking for approval | plan_view |
import sys
sys.path.insert(0, '/opt/skills/live-canvas/claude/implementation')
from canvas import Canvas
c = Canvas() # auto-generates session ID; auto-starts server
c.open() # opens http://localhost:18793?session=<id> in browser
c.render(components: list) # full re-render
c.render_template(name, data) # render a built-in template
c.update(node_id, changes) # partial update (live, no flicker)
c.clear() # wipe canvas
c.open() # open browser tab
action = c.wait_for_action(timeout=60) # block until user clicks
wait_for_action returns a dict:
{"type": "action", "action_id": "approve", "data": {...}, "session_id": "...", "timestamp": "..."}
# or on timeout:
{"type": "timeout"}
progress_boardKanban board showing Todo / Running / Done columns with an overall progress bar.
Use for: deployments, installs, batch jobs, any multi-step workflow.
c.render_template("progress_board", {
"title": "Deploy v2.1",
"elapsed": "3m 12s", # optional
"steps": [
{"name": "Pull repo", "status": "done"},
{"name": "npm build", "status": "running"},
{"name": "Restart svc", "status": "pending"},
{"name": "Health check", "status": "pending"},
]
})
# Live update a step without full re-render:
c.update("step-1", {"status": "done"}) # index-based id
c.update("overall-progress", {"pct": 75})
Status values: done, running, pending, error, skip
data_dashboardMetrics row + optional line chart + optional table.
Use for: server status, Home Assistant devices, GitHub stats, monitoring.
c.render_template("data_dashboard", {
"title": "Server Status",
"metrics": [
{"label": "CPU", "value": "42%", "trend": "up"},
{"label": "RAM", "value": "6.1 GB"},
{"label": "Disk", "value": "78%", "trend": "down"},
{"label": "Svcs", "value": "4/4"},
],
"chart": { # optional
"label": "CPU last 1h",
"labels": ["10m", "20m", "30m", "40m", "50m", "60m"],
"datasets": [{"label": "CPU %", "data": [30, 45, 42, 55, 48, 42]}],
},
"table": { # optional
"headers": ["Process", "CPU", "MEM"],
"rows": [["node", "12%", "400 MB"], ["python", "5%", "120 MB"]],
},
})
config_formDynamic form rendered from a field schema. Returns submitted values.
Use for: collecting settings, rules, credentials, preferences from the user.
c.render_template("config_form", {
"title": "Email Triage Rules",
"description": "Configure how incoming emails are processed.",
"fields": [
{"name": "sender_filter", "label": "Sender filter", "type": "text", "placeholder": "e.g. @spam.com"},
{"name": "action", "label": "Action", "type": "select", "options": ["Move", "Delete", "Flag"]},
{"name": "notify", "label": "Notify me", "type": "checkbox", "default": True},
],
"submit_label": "Apply Rules",
"cancel_label": "Cancel",
})
action = c.wait_for_action(timeout=120)
if action["action_id"] == "submit":
values = action["data"] # {"sender_filter": "...", "action": "...", "notify": True}
plan_viewMermaid.js flowchart + Approve / Cancel buttons.
Use for: showing a plan before executing, getting explicit user approval.
c.render_template("plan_view", {
"title": "Rotate SSL Certificates",
"description": "This will renew and deploy 3 certificates.",
"mermaid": """flowchart TD
A[Check expiry] --> B{Expired?}
B -->|Yes| C[Generate new cert]
B -->|No| D[Skip]
C --> E[Deploy to nginx]
E --> F[Restart service]""",
"approve_label": "Execute Plan",
"cancel_label": "Cancel",
})
action = c.wait_for_action(timeout=300)
if action.get("action_id") == "approve":
# proceed with execution
pass
For full control, pass a component tree to render():
c.render([
{"type": "heading", "level": 2, "text": "My Dashboard"},
{"type": "row", "children": [
{"type": "metric", "id": "cpu-metric", "label": "CPU", "value": "42%"},
{"type": "metric", "id": "ram-metric", "label": "RAM", "value": "8 GB"},
]},
{"type": "progress", "id": "job-progress", "label": "Indexing…", "pct": 35},
{"type": "button", "label": "Cancel Job", "action_id": "cancel", "variant": "danger"},
])
| Type | Key Props |
|---|---|
| heading | level (1–4), text |
| text | text, muted (bool) |
| card | title, children, content |
| row | children |
| col | children |
| grid | cols (int), children |
| board | columns: [{id, title, items}] |
| progress | id, label, pct (0–100) |
| metric | id, label, value, trend (up/down) |
| badge | text, variant (success/warning/danger/info/neutral) |
| table | headers, rows |
| chart_bar | label, labels, datasets |
| chart_line | label, labels, datasets |
| log | label, lines (str or list) |
| button | label, action_id, variant (primary/ghost/danger/gold) |
| form | fields, actions |
| confirm | message, confirm_id, cancel_id |
| flowchart | content (Mermaid source) |
| code | content, language, label |
| list | items, ordered (bool) |
| divider | (no props) |
When Foster is on Telegram or WebEx (mobile channels), canvas URLs must be optimized for phone viewports (375–430px wide).
?mobile=1 to every canvas URL sent via Telegram or WebEx@media (max-width: 480px)) AND a body.mobile-mode class applied when ?mobile=1 is set — both paths produce the same mobile-friendly layout| Element | Desktop | Mobile |
|---|---|---|
| body | 16px font | 14px font, 8px padding |
| .c-row | flex-wrap: wrap (side-by-side) | flex-direction: column (stacked) |
| .c-grid | multi-column grid | grid-template-columns: 1fr |
| .board-wrap | repeat(auto-fit, ...) columns | single column |
| .btn, inputs | natural size | min-height: 44px for tap targets |
| .c-h1/.c-h2 | 28px / 22px | 18px / 16px |
| .metric-value | 28px | 20px |
import os
channel = os.environ.get('WEE_CHANNEL', 'webui').lower()
mobile = channel in ('telegram', 'webex')
url = canvas.viewer_url()
if mobile:
url += ('&' if '?' in url else '?') + 'mobile=1'
# Send url to user
CANVAS_PORT env var)localhost by default (override: CANVAS_HOST env var — set to Tailscale IP for remote access)0.0.0.0, so it accepts connections on all interfaces including TailscaleCanvas() starts canvas_server.py if not already runningsession_id has its own state; multiple agents can use the same serverpip install websocketsTo open the canvas on a remote device (phone, MacBook) via Tailscale:
export CANVAS_HOST=100.124.186.75 # lepbuntu Tailscale IP
python3 canvas.py
# Opens: http://100.124.186.75:18793/?session=...
Or set permanently in the agent's environment/.env.
The WebSocket in
index.htmlalso reads the host from the URL, so remote browsers connect to the correct Tailscale IP automatically.
data-ai
Interactive TODO board for Wee Canvas. Displays TODOs from both GitHub Issues (leprachuan/fosterbot-home) and flat files in two views: list and kanban. Features filtering, drag-and-drop status changes, quick-add, and auto-refresh every 30 seconds. Use when Foster asks to "show TODOs", "open TODO board", "view my tasks", or "TODO kanban".
tools
Web-based terminal tools for Wee Canvas: remote SSH terminal (WebSSH) and local bash terminal (ttyd). Embeds interactive terminal panels in Wee Canvas iframes. Use when the user asks for a 'web terminal', 'local terminal', 'browser SSH', 'webssh', or wants to interact with a host through the WebUI canvas. For browser windows, see the browser-window skill.
development
Use when you need to send WebEx notifications to flipkey-home-bot - supports markdown formatting, auto-retry with backoff, rate limiting, and message history tracking
tools
Production-ready TODO management with dual-source support (GitHub Issues + flat files), due dates, labels, and automatic reminders. Fully portable with environment variable configuration.