Daemion docs

How do I create an app extension?

An app extension is a Vite project served by the gateway — a full interactive tool, dashboard, or fullstack application that lives inside Daemion and is accessible from the chat interface.


What is an app extension?

An app is a Vite project registered as an extension. The gateway manages its dev server lifecycle — starting, stopping, and restarting the Vite process — and proxies requests to it under /apps/:name/. Apps are not raw HTML files; they are full Vite projects with their own package.json, component structure, and build pipeline.

Apps come in five subtypes:

SubtypeWhat it is
htmlStatic HTML output, no dev server needed
chartData visualization (charts, graphs)
interactiveInteractive tool with state, Vite dev server required
markdownRendered markdown document
fullstackFull frontend + backend, Vite dev server required

The fullstack and interactive subtypes spin up a Vite dev server on a port in the range 5173–5273. The other subtypes serve static output.


When would I use an app extension?

Use an app extension when you want a persistent, dedicated interface for a task — something that lives alongside your chat threads rather than inside them. Examples:

  • A project dashboard that pulls from your jobs and threads
  • A budget tracker that reads from local files and renders charts
  • A custom code playground for a language or framework you use daily

If you just need to display something once inside a conversation, an artifact or renderer is a better fit. Apps are for tools you return to repeatedly.


How do I create an app through chat?

Open the Daemion app, start a new thread, and describe what you want:

text

Build me a project dashboard app that shows my active jobs and recent threads.

Daemion will scaffold the Vite project, register the extension, and confirm:

text

User: Build me a project dashboard app that shows my active jobs and recent threads.

Daemion: I’ll scaffold a project dashboard app for you.

[Creating Vite project at apps/project-dashboard/…] [Registering extension…]

Done. The project-dashboard app is registered and enabled. Visit it at /apps/project-dashboard/ once the dev server starts. You can ask me to iterate on the UI or add new data sources at any time.

The resulting extension record:

json

{ “id”: “ext_04ghi012”, “type”: “app”, “name”: “project-dashboard”, “description”: “Dashboard showing active jobs and recent threads.”, “definition”: { “subtype”: “fullstack”, “path”: “apps/project-dashboard”, “icon”: “layout-dashboard”, “color”: “#6366f1” }, “source”: “agent”, “enabled”: true, “created_at”: “2026-03-31T09:00:00Z”, “updated_at”: “2026-03-31T09:00:00Z” }


How do I create an app via the API?

If you already have a Vite project on disk, register it directly:

bash
Verified

curl -X POST http://localhost:3001/extensions
-H “Authorization: Bearer $DAEMION_TOKEN”
-H “Content-Type: application/json”
-d ’{ “type”: “app”, “name”: “project-dashboard”, “description”: “Dashboard showing active jobs and recent threads.”, “definition”: { “subtype”: “fullstack”, “path”: “apps/project-dashboard”, “icon”: “layout-dashboard”, “color”: “#6366f1” }, “source”: “user”, “enabled”: true }’

The gateway validates the definition, registers the extension, and returns the created record. For fullstack and interactive subtypes, the dev server starts automatically when the extension is enabled.


What does the full schema look like?

Defined in src/schema/extension.ts:62-69:

typescript

type AppSubtype = ‘html’ | ‘chart’ | ‘interactive’ | ‘markdown’ | ‘fullstack’;

interface AppDefinition { subtype: AppSubtype; // required — determines runtime behavior path?: string; // path to the Vite project root, relative to gateway cwd icon?: string; // icon name for the app launcher color?: string; // accent color (hex or CSS value) for the app tile }

The path field is resolved relative to the gateway’s working directory. If omitted, Daemion looks for a directory matching apps/{name} by convention.


Frequently asked questions

Q Do I need Vite installed?
The gateway resolves the Vite binary from the app's own node_modules/.bin/vite first. If that doesn't exist, it falls back to npx vite. For reliable dev server startup, install Vite locally inside the app directory: npm install vite --save-dev.
Q What ports do dev servers use?
The gateway allocates ports in the range 5173–5273. It probes each port for availability and skips ports already claimed by other running apps. You cannot pin a specific port — the gateway manages allocation automatically.
Q How do I stop or restart the dev server?
Toggle the extension off (POST /extensions/:id/toggle) to stop the dev server. Toggle it on to restart it. You can also ask Daemion in chat: "restart the project-dashboard app."
Q Can I update the app's UI by chatting?
Yes — this is the intended workflow. Describe the change you want in a thread: "Add a count of failed jobs in red at the top of the dashboard." Daemion edits the Vite project files directly. The dev server picks up the change via Vite's HMR.
Q What is the difference between fullstack and interactive?
Both subtypes start a Vite dev server. fullstack implies a backend API alongside the frontend (e.g., an Express server bundled with Vite). interactive is a frontend-only Vite project with client-side state. Use fullstack when the app needs server-side data fetching or persistence beyond what the gateway provides.

What can go wrong

App startup and registration errors

400 {"error": "Invalid app definition: ..."} — The subtype field is missing or is not one of the five valid values: html, chart, interactive, markdown, fullstack. Check the exact string — the schema does not accept aliases.

Dev server crashes on startup — The gateway waits up to 5 seconds for Vite to emit Local: or ready in on stdout. If the process exits before that, the runtime status is set to crashed. Check that the app directory exists, has a valid vite.config.*, and that dependencies are installed (npm install inside the app directory).

403 {"error": "cannot disable essential extensions"} — Essential built-in apps cannot be disabled.

App not reachable at /apps/:name/ — The dev server may still be starting. Poll GET /extensions/:id and check the runtime status field. A running status means the dev server is up and proxying is active.


What’s next?