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.
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):
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:
// 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
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./extensions with source: "agent". Agent-created extensions start disabled — the user enables them. This lets Daemion propose dashboard additions during a conversation.definition field. Common conventions: "size": "small", "size": "wide", "size": "full". The dashboard renderer reads these to determine grid placement."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.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
400 {"error": "validation failed"} — The envelope failed ExtensionSchema validation. Check that type is exactly "widget", name is 1-100 characters, and description is under 500 characters.
401 {"error": "unauthorized"} — 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 {"error": "cannot disable essential extensions"} — Essential built-in widgets cannot be disabled.
403 {"error": "cannot delete essential extensions"} — Essential widgets cannot be deleted. Create a new widget with source: "user" and a different name to customize behavior.
What’s next?
- How do I create an app extension? — full Vite applications surfaced in the dashboard
- How do I create a control extension? — system-wide configuration like budget limits
- Extensions API — full CRUD reference