The Agent Canvas
Generative UI, Live Observability, and Agent-Built Dashboards Open source (MIT). Part of the OpenPawz project.The Problem
Today’s AI agents are black boxes that output text. You ask an agent to analyze your CI pipeline, and it writes four paragraphs. You ask it to monitor your portfolio, and it dumps a table into a chat bubble. You ask it to track a deployment, and it says “done” — but you can’t see anything. This creates three pain points that compound as agents get more capable:-
Invisible execution. What is the agent doing right now? Why has it been “thinking” for 12 seconds? Which tools did it call, and in what order? Debugging agent behavior means reading logs — the equivalent of debugging a web app by reading
console.logoutput in a text file. - Flat output. Agents produce text, but humans think in dashboards, charts, and spatial layouts. A trading agent should show you a live P&L curve, not a paragraph describing your positions. A research agent should show you a structured findings table, not a wall of markdown.
- Ephemeral results. Even when an agent produces useful structured data, it vanishes when you scroll up. There’s no persistent surface where agent-generated insights accumulate and stay accessible.
The Invention
The Agent Canvas introduces three layers that work together:| Layer | What it does | Analogy |
|---|---|---|
| Canvas (Generative UI) | Agents push live UI components — charts, tables, metrics, forms — into a persistent visual surface | AG-UI |
| Inspector (Agent X-Ray) | Real-time chain-of-thought, tool routing, memory recall, and context utilization — visible alongside the chat | DevUI |
| Telemetry (Observability) | Structured tracing across the full request lifecycle with cost, latency, and token metrics surfaced in the UI | OpenTelemetry |
Layer 1: The Canvas — Generative UI
What Exists Today
Pawz already has a generative UI primitive: the skill output system. Agents call theskill_output tool with structured data (type, title, JSON payload), which is persisted to the skill_outputs SQLite table and rendered as widget cards on the Today dashboard. Five widget types exist: status, metric, table, log, kv.
This works, but it’s limited in three ways:
- Post-hoc only. Widgets appear on the Today dashboard after execution — they are not visible during the agent turn.
- Static. Once rendered, a widget cannot be updated in real-time. The agent would need to call
skill_outputagain and the user would need to refresh. - Flat namespace. All widgets share the Today dashboard. There’s no concept of a per-session or per-agent canvas that groups related widgets into a coherent view.
What Changes
The Agent Canvas introduces a live rendering surface that agents populate during execution. Components appear as the agent streams — the user watches the dashboard materialize.Architecture
New Tauri Events
Two newEngineEvent variants:
app_handle.emit("engine-event", &event)) — no new transport needed.
Canvas Components
skill_output widget types with 5 new types (chart, card, progress, form, markdown). The original types are kept for backward compatibility.
Agent Tools
Two new tools available to agents:| Tool | Purpose |
|---|---|
canvas_push | Add a new component to the active canvas. Returns component_id. |
canvas_update | Update an existing component by component_id. Accepts partial data (patch). |
dashboard tool domain so agents discover them via the Librarian when intent suggests visualization (“show me”, “display”, “chart”, “dashboard”, “monitor”).
Persistence
Canvas components are persisted to a newcanvas_components table:
session_id set are ephemeral — tied to a conversation. Components with dashboard_id set belong to a saved dashboard. When a canvas is saved as a dashboard, its components are re-scoped from session to dashboard.
Charts Without a Charting Library
Forchart components, the Canvas renders lightweight SVG charts directly — no D3, Chart.js, or other dependency. This matches Pawz’s no-framework philosophy:
- Line/area charts: SVG
polyline+polygonwith calculated viewBox - Bar charts: SVG
rectelements with proportional heights - Pie charts: SVG
pathwith arc calculations - Sparklines: Minimal SVG inline in metric cards
(data: ChartData) → string (SVG markup). This keeps the bundle tiny and avoids the security surface of a charting library in a desktop app.
Relationship to Skill Outputs
The existingskill_output system is preserved. It serves a different purpose:
| Feature | Skill Outputs | Canvas |
|---|---|---|
| When | After agent turn completes | During agent turn (live streaming) |
| Where | Today dashboard (global) | Session canvas (per-conversation) |
| Scope | Cross-session (persists by skill_id) | Per-session (persists by session_id) |
| Updates | Upsert by (skill_id, agent_id) | Patch by component_id |
| Use case | Skill status cards, extension dashboards | Dynamic analysis, monitoring, workflows |
canvas_push for live visualization during a conversation, and skill_output to persist a summary widget on the Today dashboard after it’s done.
Saved Dashboards, Templates, Tabs, and Multi-Window
Not every canvas is throwaway. A trading dashboard you check every morning, a CI monitor you keep open during releases, a project health overview that lives for weeks — some dashboards become permanent fixtures of how you work. The Canvas supports a full dashboard lifecycle: ephemeral → saved → pinned → live. It supports templates for reusable blueprints, a tab system for managing multiple dashboards, and native OS windows for popping dashboards out of the app entirely.Dashboard Lifecycle
| State | Behavior |
|---|---|
| Ephemeral | Default. Tied to a chat session. The agent builds it during a conversation. Persisted in canvas_components but only loads when that session is reopened. |
| Saved | User clicks “Save Dashboard” or agent calls canvas_save. Gets a name, icon, and entry in the dashboards list. Survives independently of the originating session. |
| Pinned | A saved dashboard marked as always-available. Appears in the sidebar under a “Dashboards” group — same level as Today, Tasks, Research. |
| Live | A saved dashboard with an associated agent + refresh schedule. The agent periodically re-runs to update the components. Like a cron job that paints a dashboard. |
How Saving Works
Persistence
Agent Tools for Dashboard Lifecycle
| Tool | Purpose |
|---|---|
canvas_save | Save the current canvas as a named dashboard. Params: name, icon, pinned, refresh. |
canvas_load | Load a saved dashboard by name or ID into the active canvas. |
canvas_list_dashboards | List all saved dashboards (for the agent to reference). |
canvas_delete_dashboard | Delete a saved dashboard and its components. |
dashboard tool domain alongside canvas_push / canvas_update.
Dashboard Templates
Templates are reusable dashboard blueprints — a set of component definitions with placeholder data that an agent instantiates and populates. Think of them as the difference between an empty spreadsheet template and a filled-in spreadsheet.Where Templates Come From
- Agent-created. Any saved dashboard can be exported as a template by stripping its live data and keeping the component structure:
- Built-in. Pawz ships with starter templates for common use cases:
| Template | Components | Domain |
|---|---|---|
| Trading Overview | Portfolio value, P&L chart, open positions table, recent trades log | Trading |
| Project Health | Task burndown chart, agent activity log, file change metrics, blockers table | Projects |
| System Monitor | CPU/memory metrics, token usage chart, cost tracker, active channels status | System |
| Research Board | Findings table, source log, key insights cards, topic progress bars | Research |
| Email Digest | Unread count metric, priority inbox table, thread activity chart |
- Community. Templates are shareable through PawzHub (the existing skill marketplace). A template is just a JSON manifest — same distribution mechanism as community skills:
How Instantiation Works
Persistence
Agent Tools for Templates
| Tool | Purpose |
|---|---|
canvas_list_templates | List available templates (built-in + user-created + community). |
canvas_from_template | Instantiate a template as a new dashboard with placeholder components. |
canvas_create_template | Save the current dashboard structure as a reusable template. |
Tabs — Multiple Dashboards in One View
A user working with Pawz might have three, five, or ten dashboards they care about at once. The Canvas uses a tab bar to manage multiple dashboards within a single view — the same UX pattern as browser tabs or VS Code editor tabs.Tab Layout
Tab Types
| Tab Type | Source | Behavior |
|---|---|---|
| Session tab | Current chat session’s canvas | Ephemeral — disappears when session changes |
| Saved tab | Saved dashboard | Permanent — persists across app restarts |
| Pinned tab | Pinned dashboard | Always visible in tab bar, cannot be accidentally closed |
| Live tab | Dashboard with refresh schedule | Shows a pulse indicator, auto-updates on schedule |
Tab Operations
- Click a tab to switch dashboards
- Middle-click or × to close (pinned tabs require confirmation)
- Drag to reorder
- Right-click for context menu: Close, Close Others, Pin/Unpin, Pop Out to Window, Duplicate, Refresh Now
+button opens a dashboard picker: saved dashboards, templates, or “New blank canvas”- Tab overflow — when tabs exceed available width, a
›dropdown shows the full list (same pattern as VS Code tab overflow)
Tab State Persistence
Open tabs are persisted so the workspace restores on app launch:Multi-Window — Dashboards as Native OS Windows
This is the key UX unlock: dashboards don’t have to live inside the Pawz app. Any tab can be popped out into its own native OS window. The user arranges Pawz and their dashboard windows across monitors, workspaces, or virtual desktops however they want.How It Works
Tauri v2’sWebviewWindowBuilder creates additional native windows at runtime. Each window is a lightweight webview that renders a single dashboard (or its own tab bar of dashboards) — no sidebar, no chat, no navigation chrome. Just the bento grid of components.
The Multi-Window Workflow
CanvasUpdate, the event reaches all windows rendering that dashboard.
Window Management
| Action | How |
|---|---|
| Pop out | Right-click tab → “Pop Out to Window”, or drag tab out of tab bar |
| Pop back in | Close the window → dashboard returns as a tab in the main app |
| Multiple instances | Same dashboard can be open as a tab AND a window (both stay in sync) |
| Window memory | Window position and size remembered per dashboard. Next pop-out restores same geometry. |
| App quit | All windows close together. On relaunch, popped-out dashboards restore as tabs (or optionally restore the full window layout). |
Event Routing Across Windows
When the engine emits aCanvasPush or CanvasUpdate, Tauri delivers it to every window. Each window’s event listener filters by dashboard:
Window Persistence
Refresh — Keeping Dashboards Current
Live dashboards need fresh data. The refresh system ties into Pawz’s existing task/cron infrastructure:| Mode | Behavior |
|---|---|
| Manual | User clicks refresh or says “refresh my trading dashboard”. Agent re-runs once. |
| Scheduled | Dashboard has a refresh_interval (5m, 30m, 1h, 6h, 1d). Engine triggers the assigned agent with the refresh_prompt on schedule. |
| Event-driven | Dashboard refreshes when a specific event fires — webhook, channel message, task state change. Uses the existing events.rs dispatcher. |
| Agent-initiated | An agent decides on its own to update a dashboard — e.g., a trading agent pushes canvas_update when it detects a price spike. |
How Scheduled Refresh Works
How It All Fits Together
Layer 2: The Inspector — Agent X-Ray
The Concept
The Inspector is a collapsible panel that shows what the agent is doing under the hood — real-time, during execution. Think “browser DevTools, but for your AI agent.” While the Canvas is user-facing (“show me the results”), the Inspector is developer/power-user-facing (“show me the process”).What It Shows
| Section | Data Source | Display |
|---|---|---|
| Round Counter | Agent loop iteration | ”Round 3 of 8” with progress ring |
| Tools Loaded | Librarian discovery | Chips: github_list_workflows, github_get_run — showing which tools were loaded and when |
| Memory Recall | Auto-recall in run_agent_turn | List of recalled memories with relevance score and decay weight |
| Context Window | Token counting per round | Bar showing input/output tokens vs model limit — warns when approaching capacity |
| Tool Calls | ToolRequest / ToolResultEvent | Timeline of tool calls with name, duration, success/failure, and truncated output |
| Thinking | ThinkingDelta events (Claude, Gemini) | Collapsible reasoning trace — the agent’s chain of thought |
| Conductor View | Execution strategy (flows only) | Phase diagram: which nodes are collapsed, which are running in parallel, current phase highlighted |
Architecture
The Inspector requires no new Rust events. All the data it needs already flows through the existingengine-event channel:
delta→ shows the agent is generatingthinking_delta→ chain of thought (already emitted by Anthropic/Google providers)tool_request→ tool about to executetool_result→ tool finished (with timing)tool_auto_approved→ tool was auto-approved by policycomplete→ turn finished (withusagetoken counts)
Frontend
The Inspector renders as a collapsible drawer on the right side of the chat view (or below the canvas when both are open). Toggle via keyboard shortcut (Cmd+Shift+I / Ctrl+Shift+I) or a button in the chat toolbar.
Orchestrator Integration
For multi-agent flows (boss/worker orchestration and Conductor Protocol flows), the Inspector shows additional context:- Agent roster: Which agents are active, their roles, current status
- Delegation graph: Boss → Worker assignments with message flow
- Conductor strategy: Phase diagram showing collapse merges, parallel branches, and cycle rounds — matching the execution strategy from the Conductor Protocol’s compilation step
Layer 3: Telemetry — Observability
The Concept
Structured tracing across the full request lifecycle, surfaced in the Canvas and Inspector rather than requiring an external tool like Jaeger.Instrumentation
The Rust backend uses thetracing crate (already in the Tauri ecosystem) with OpenTelemetry-compatible span names:
Metrics Collected
| Metric | Source | Granularity |
|---|---|---|
| LLM latency | Provider streaming (time-to-first-token, total) | Per round |
| Token usage | Provider response (usage field) | Per round, per turn, per day |
| Token cost | pricing.rs cost tables | Per round, per turn, per day |
| Tool duration | Span timing around execute_tool | Per tool call |
| Memory recall time | Span timing around recall_memories | Per round |
| Tool discovery time | Span timing around Librarian search | Per round |
| MCP call duration | Span timing around Foreman worker execution | Per MCP call |
| Context utilization | Token count vs model context window | Per round |
Surfacing
Telemetry data flows to two places:- Inspector panel — real-time flame graph of the current agent turn. Each span is a row with a proportional duration bar. Users see exactly where time is spent.
- Canvas/Today dashboard — summary metric cards that agents can auto-generate:
- Optional export — for users who want full distributed tracing, the
tracingspans can be exported to any OTLP-compatible backend (Jaeger, Grafana Tempo, Azure Application Insights) via environment variable:
Implementation Plan
Phase 1: Canvas Core
Goal: Agents can push live UI components into a persistent per-session surface.| Task | Scope | Files |
|---|---|---|
CanvasComponent types | Rust | atoms/types.rs |
canvas_components table + CRUD | Rust | sessions/canvas.rs, sessions/schema.rs |
canvas_push / canvas_update tools | Rust | tools/canvas.rs |
CanvasPush / CanvasUpdate events | Rust | atoms/types.rs, agent_loop/mod.rs |
| Canvas view (split pane) | TypeScript | views/canvas/ (atoms, molecules, index) |
| SVG chart renderer | TypeScript | components/molecules/canvas-chart.ts |
| Event listener + incremental render | TypeScript | views/canvas/molecules.ts |
| Canvas persistence (load on session open) | Both | commands/canvas.rs, engine-bridge.ts |
Register canvas_push/canvas_update in dashboard domain | Rust | tools/mod.rs, tool_index.rs |
Phase 2: Saved Dashboards + Templates
Goal: Dashboards persist as named entities, templates enable reuse, sidebar shows pinned dashboards.| Task | Scope | Files |
|---|---|---|
dashboards table + CRUD | Rust | sessions/dashboards.rs, sessions/schema.rs |
dashboard_templates table + CRUD | Rust | sessions/templates.rs, sessions/schema.rs |
dashboard_id column on canvas_components | Rust | sessions/canvas.rs, sessions/schema.rs |
canvas_save / canvas_load / canvas_list_dashboards tools | Rust | tools/canvas.rs |
canvas_list_templates / canvas_from_template / canvas_create_template tools | Rust | tools/canvas.rs |
| Built-in templates (Trading, Project, System, Research, Email) | Rust | tools/canvas_templates.rs |
| Sidebar “Dashboards” group with pinned entries | TypeScript | main.ts, views/canvas/index.ts |
| Dashboard scheduled refresh (cron integration) | Rust | engine/events.rs, sessions/dashboards.rs |
| Template browsing in PawzHub | TypeScript | views/settings-skills/pawzhub.ts |
Phase 3: Tabs + Multi-Window
Goal: Multiple dashboards open simultaneously, with pop-out native windows.| Task | Scope | Files |
|---|---|---|
| Tab bar component | TypeScript | components/molecules/canvas-tabs.ts |
dashboard_tabs table + state persistence | Rust | sessions/schema.rs, commands/canvas.rs |
| Tab operations (open, close, reorder, pin) | TypeScript | views/canvas/molecules.ts |
| Tab overflow dropdown | TypeScript | components/molecules/canvas-tabs.ts |
dashboard_windows table + geometry persistence | Rust | sessions/schema.rs |
WebviewWindowBuilder pop-out command | Rust | commands/canvas.rs, main.rs |
Pop-out window route (/canvas?dashboard=X) | TypeScript | views/canvas/window.ts |
| Cross-window event routing | Both | engine-bridge.ts, views/canvas/molecules.ts |
| Window restore on app launch | Rust | main.rs |
| Tauri capabilities for multi-window | Both | tauri.conf.json, capabilities/default.json |
Phase 4: Inspector Panel
Goal: Real-time visibility into agent internals during execution.| Task | Scope | Files |
|---|---|---|
Add metadata fields to ToolRequest event | Rust | atoms/types.rs, agent_loop/mod.rs |
| Inspector drawer component | TypeScript | components/molecules/inspector.ts |
| Round counter + progress ring | TypeScript | components/molecules/inspector.ts |
| Tool call timeline renderer | TypeScript | components/molecules/inspector.ts |
| Thinking trace (collapsible) | TypeScript | components/molecules/inspector.ts |
| Context utilization bar | TypeScript | components/molecules/inspector.ts |
| Memory recall display | TypeScript | components/molecules/inspector.ts |
| Keyboard shortcut wiring | TypeScript | main.ts |
Phase 5: Telemetry
Goal: Structured tracing with metrics surfaced in the UI and optionally exported.| Task | Scope | Files |
|---|---|---|
Add tracing + opentelemetry crates | Rust | Cargo.toml |
Instrument run_agent_turn with spans | Rust | agent_loop/mod.rs |
| Instrument provider calls | Rust | providers/*.rs |
| Instrument tool execution | Rust | tools/mod.rs |
| Span collector → Inspector flame graph | Both | New telemetry bridge |
| Daily/weekly metric aggregation | Rust | sessions/telemetry.rs |
| OTLP export (optional) | Rust | engine/telemetry.rs |
Design Principles
1. No Framework, No Dependency
The Canvas renders with the same vanilla DOM approach as the rest of Pawz. Charts are SVG strings. Layouts are bento grid CSS. No React, no D3, no charting library. This keeps the bundle small and the security surface minimal.2. Existing Transport
Everything flows through the existingengine-event Tauri channel. No new WebSocket servers, no HTTP endpoints, no open ports. The Canvas is just new event types on the same IPC bridge.
3. Agent-Driven, Template-Assisted
The Canvas doesn’t decide what to show — agents do. Templates provide structure, but the agent populates them with live data and can modify the layout on the fly. This means the Canvas works for any domain: templates accelerate common cases, and the agent handles everything else from primitives.4. Progressive Disclosure
- Casual users see the Canvas (results) and never touch the Inspector
- Power users toggle the Inspector to understand agent behavior
- Developers export OTLP spans to Jaeger for full distributed tracing
5. Backward Compatibility
The existingskill_output system is unchanged. Agents that use skill_output today will continue to work. The Canvas is additive — new tools, new events, new view. No breaking changes.
Channel Integration
Agents on channels (Slack, Discord, Telegram) can reference saved dashboards by name:pawz://dashboard/{dashboard_id} for saved dashboards and pawz://canvas/{session_id} for ephemeral session canvases. Both formats route to the Canvas view. For WebChat users, the dashboard renders inline in the browser chat interface. For desktop users, it opens the dashboard tab (or pops out a new window if the user prefers).
Inspiration
This architecture draws from:- AG-UI Protocol — standardized Agent-User interaction with streaming responses, server-side UI pushing, and human-in-the-loop. The Canvas implements AG-UI’s generative UI concept within Pawz’s native Tauri architecture.
- DevUI (Microsoft Agent Framework) — inner-loop debugging with chain-of-thought visualization and real-time state monitoring. The Inspector is Pawz’s answer to DevUI, integrated into the app rather than a separate tool.
- OpenTelemetry — distributed tracing and metrics collection. The Telemetry layer uses the same span/metric model with optional OTLP export.
- The Golden Triangle — Kinfey Lo’s articulation of how these three concerns form a complete development lifecycle for agentic applications.
Try It
Coming soon. The Agent Canvas is under active development. When available:- Open a chat session with any agent
- Ask it to analyze, monitor, or visualize something — the Canvas appears automatically
- Say “save this as my [name] dashboard” to persist it
- Pin it to your sidebar for one-click access
- Pop it out into its own native window and put it on your second monitor
- Set up a refresh schedule so it stays current while you work
- Press
Cmd+Shift+I/Ctrl+Shift+Ito toggle the Inspector - Share a dashboard link with your team via Slack or Discord
License & Attribution
The Agent Canvas architecture is part of OpenPawz and is released under the MIT License. You are free to use, modify, and redistribute this design in any project, commercial or otherwise. Attribution is appreciated but not required. If you reference this work in academic papers or technical writing:OpenPawz (2026). “The Agent Canvas: Generative UI, Live Observability, and Agent-Built Dashboards.” https://github.com/OpenPawz/openpawz

