Daemion docs

How do I create a widget extension?

A widget extension is a dashboard UI component. Widgets render on the Daemion home screen and display information — metrics, status indicators, quick-action buttons — that you want visible without entering a conversation.


When would I use a widget?

Use a widget when you want ambient visibility into something that changes over time. Good candidates:

  • Cost tracking — daily or monthly API spend with a progress bar toward budget
  • Job status — which jobs ran, when, and whether they succeeded
  • System health — gateway uptime, SQLite size, active agent count
  • Pending items — unread notifications, queued tasks, open PRs
  • Quick actions — one-tap buttons to trigger a common job or command

Widgets are not for interactive chat — use the chat surface for that. They are not for long-running agents — use a job extension for scheduled work.


How do I create one by chatting?

Tell Daemion what you want on your dashboard. The agent creates the extension record:

You: Create a widget showing daily API costs

Daemion: I’ll add a cost widget to your dashboard.

The Daily API Cost widget is live. It shows today’s spend, your daily budget, and a progress bar. I’ll pull the data from the gateway’s usage log. Want to set a budget limit so it turns red when you’re close?

You: Yes, $10 daily limit

Daemion: Updated — the widget will turn amber at 80% ($8) and red at 100% ($10).

The extension is written to SQLite immediately. No restart needed.


How do I create one via the API?

The API is the programmatic path — for scripts, CI pipelines, or agents creating widgets at runtime. Chat is the primary path for humans.

bash
Verified

curl -X POST http://localhost:3001/extensions
-H “Authorization: Bearer $DAEMION_TOKEN”
-H “Content-Type: application/json”
-d ’{ “type”: “widget”, “name”: “daily-api-cost”, “description”: “Shows today’s API spend against a configurable daily budget.”, “definition”: { “display”: “cost-meter”, “data_source”: “/usage/daily”, “budget_limit”: 10, “currency”: “USD”, “refresh_seconds”: 60, “thresholds”: { “warn”: 0.8, “critical”: 1.0 } }, “source”: “user”, “enabled”: true }’

The gateway validates the envelope against ExtensionSchema and stores the record. The definition field is open (GenericDefinitionSchema) — structure it to match what the dashboard renderer expects.


What does the widget schema look like?

Widget extensions use the generic definition schema. The top-level envelope (shared across all 12 extension types):

typescript

interface Extension { id: string; // e.g. “ext_09def789” — assigned by gateway on creation type: “widget”; name: string; // unique per type, kebab-case, 1-100 chars description: string; // human-readable, max 500 chars definition: Record<string, unknown>; // widget-specific config source: “built-in” | “user” | “agent” | “community”; enabled: boolean; created_at: string; // ISO 8601 updated_at: string; // ISO 8601 }

A typical definition for a data-display widget:

typescript

// Example definition shape — adapt to your widget type interface WidgetDefinition { display: string; // which renderer to use, e.g. “cost-meter”, “status-list”, “counter” data_source?: string; // gateway endpoint to poll, e.g. “/usage/daily” refresh_seconds?: number; // how often to re-fetch data (default: 60) [key: string]: unknown; // any additional renderer-specific config }


Frequently asked questions

Q Where does widget data come from?
Widgets read from gateway endpoints. Set data_source to any path exposed by the gateway (e.g. /usage/daily, /extensions, /threads). The dashboard fetches it on the configured interval and passes the response to the renderer.
Q Can an agent create widgets at runtime?
Yes. POST to /extensions with source: "agent". Agent-created extensions start disabled — the user enables them. This lets Daemion propose dashboard additions during a conversation.
Q How do I control widget layout and size?
Layout hints go in the definition field. Common conventions: "size": "small", "size": "wide", "size": "full". The dashboard renderer reads these to determine grid placement.
Q Can a widget have interactive buttons?
Yes — include "actions" in the definition with label/handler pairs. The renderer will surface them as tap targets that dispatch the handler prompt into the active thread.
Q How do I update or delete a widget?
Use PATCH /extensions/:id to update fields or DELETE /extensions/:id to remove it. See the Extensions API for the full reference.

What can go wrong

What can go wrong

400 &#123;"error": "validation failed"&#125; — The envelope failed ExtensionSchema validation. Check that type is exactly "widget", name is 1-100 characters, and description is under 500 characters.

401 &#123;"error": "unauthorized"&#125; — The Authorization header is missing or the bearer token doesn’t match. The token is in ~/.daemion/.gateway-token. Use $DAEMION_TOKEN in your shell.

403 &#123;"error": "cannot disable essential extensions"&#125; — Essential built-in widgets cannot be disabled.

403 &#123;"error": "cannot delete essential extensions"&#125; — Essential widgets cannot be deleted. Create a new widget with source: "user" and a different name to customize behavior.


What’s next?