Daemion docs

How do I manage extensions through the API?

Auth: Bearer token from device pairing
Base URL: http://localhost:3001
All examples tested against live gateway

Extensions are how you configure Daemion. Every agent, job, app, command, theme, and integration is an extension — a JSON record in SQLite that the engine loads at runtime. There is no separate table per type, no code deployment required. Add an extension and it’s live immediately.

The preferred way to create extensions is through chat — just describe what you want to an agent and it will create the extension for you. The API exists for programmatic use: scripts, CI pipelines, and agent-initiated creation at runtime.


How do I list extensions?

GET /extensions Auth required

List all extensions, with optional filters. Returns extensions ordered by creation date, newest first.

Parameter Type Description
type string Filter by extension type: command, agent, job, app, theme, renderer, integration, action, widget, artifact, capability, or control.
enabled boolean Filter by enabled state. Omit to return both enabled and disabled.
source string Filter by source: built-in, user, agent, or community.
owner_agent_id string Filter to extensions created by a specific agent.
bash
Verified

List all enabled job extensions

curl “http://localhost:3001/extensions?type=job&enabled=true
-H “Authorization: Bearer $DAEMION_TOKEN”

List extensions created by the opus agent

curl “http://localhost:3001/extensions?owner_agent_id=opus
-H “Authorization: Bearer $DAEMION_TOKEN”

Response shape:

json

[ { “id”: “ext_01abc123”, “type”: “job”, “name”: “daily-digest”, “description”: “Summarize yesterday’s threads and send a digest.”, “definition”: { “schedule”: “0 8 * * *”, “agent_id”: “sonnet” }, “source”: “user”, “enabled”: true, “created_at”: “2026-03-31T08:00:00Z”, “updated_at”: “2026-03-31T08:00:00Z” } ]


How do I get a single extension?

GET /extensions/:id Auth required

Fetch a single extension by its ID.

bash
Verified

curl “http://localhost:3001/extensions/ext_01abc123
-H “Authorization: Bearer $DAEMION_TOKEN”


How do I create an extension?

POST /extensions Auth required

Create a new extension. Validated against the Zod schema for the given type. Returns the created extension with its assigned ID.

Parameter Type Description
type REQUIRED ExtensionType One of the 12 extension types.
name REQUIRED string Unique, kebab-case identifier for the extension.
description REQUIRED string Human-readable description of what this extension does.
definition REQUIRED object Type-specific configuration. Shape varies by type — see the schema for each.
trigger_def object Optional trigger definition (cron, event, or webhook) that activates this extension automatically.
source string Origin of this extension: user, agent, or community. Defaults to user.
enabled boolean Whether the extension is active immediately. Defaults to false.

The primary way to create extensions is through chat. Describe what you need to an agent — “create a daily digest job that runs at 8am” — and the agent writes the extension record for you. Use this API for scripts and CI pipelines.

Creating a command extension:

bash
Verified

curl -X POST http://localhost:3001/extensions
-H “Authorization: Bearer $DAEMION_TOKEN”
-H “Content-Type: application/json”
-d ’{ “type”: “command”, “name”: “summarize”, “description”: “Summarize the current thread in three bullet points.”, “definition”: { “prompt”: “Summarize this thread in exactly three bullet points. Be concise.”, “agent_id”: “haiku” }, “source”: “user”, “enabled”: true }’

Creating a job extension with a cron trigger:

bash
Verified

curl -X POST http://localhost:3001/extensions
-H “Authorization: Bearer $DAEMION_TOKEN”
-H “Content-Type: application/json”
-d ’{ “type”: “job”, “name”: “morning-briefing”, “description”: “Fetch headlines and post a morning briefing thread.”, “definition”: { “agent_id”: “sonnet”, “prompt_file”: “jobs/morning-briefing/prompt.md” }, “trigger_def”: { “type”: “cron”, “expression”: “0 7 * * 1-5” }, “source”: “user” }‘


How do I update an extension?

PATCH /extensions/:id Auth required

Partially update an extension. Only fields you provide are changed — omitted fields are left as-is.

Parameter Type Description
name string New name for the extension.
description string Updated description.
definition object Replacement definition object. This is a full replace, not a deep merge — send the complete definition.
trigger object Replacement trigger definition.
enabled boolean Enable or disable the extension.
bash
Verified

curl -X PATCH http://localhost:3001/extensions/ext_01abc123
-H “Authorization: Bearer $DAEMION_TOKEN”
-H “Content-Type: application/json”
-d ’{ “description”: “Updated: summarize in five bullet points instead of three.”, “definition”: { “prompt”: “Summarize this thread in exactly five bullet points. Be concise.”, “agent_id”: “haiku” } }‘


How do I enable or disable an extension?

POST /extensions/:id/toggle Auth required

Toggle an extension's enabled state. Faster than PATCH when you only need to flip the switch.

bash
Verified

Toggle — flips enabled to disabled or disabled to enabled

curl -X POST http://localhost:3001/extensions/ext_01abc123/toggle
-H “Authorization: Bearer $DAEMION_TOKEN”

Response (full extension object):

json

{ “id”: “ext_01abc123”, “type”: “command”, “name”: “summarize”, “description”: “Summarize the current thread in three bullet points.”, “definition”: { “prompt”: “Summarize this thread in exactly three bullet points.”, “agent_id”: “haiku” }, “source”: “user”, “enabled”: false, “created_at”: “2026-03-31T08:00:00Z”, “updated_at”: “2026-03-31T09:00:00Z” }

Disabling a job extension stops it from firing on its trigger schedule. The extension record is preserved and can be re-enabled at any time. Disabling a command extension hides it from the command palette in the app.


How do I delete an extension?

DELETE /extensions/:id Auth required

Permanently delete an extension. This cannot be undone. Prefer disabling (toggle) if you might want to restore it.

bash
Verified

curl -X DELETE http://localhost:3001/extensions/ext_01abc123
-H “Authorization: Bearer $DAEMION_TOKEN”

Returns 204 No Content on success.


How do I read extension files?

Some extension types (jobs, agents) are backed by files on disk in addition to their database record. These endpoints let you inspect those files without shelling into the host machine.

List files for an extension

GET /extensions/:id/files Auth required

List the files on disk associated with this extension. Returns relative paths within the extension's directory.

bash
Verified

curl “http://localhost:3001/extensions/ext_01abc123/files
-H “Authorization: Bearer $DAEMION_TOKEN”

json

{ “root”: ”~/.daemion/agents/daemion”, “files”: [ { “name”: “daemion.yaml”, “isDirectory”: false }, { “name”: “agents”, “isDirectory”: true }, { “name”: “soul.md”, “isDirectory”: false } ] }

Read a specific file

GET /extensions/:id/file Auth required

Read the content of a specific file in the extension's directory.

Parameter Type Description
path REQUIRED string Relative path to the file within the extension directory, e.g. prompt.md
bash
Verified

curl “http://localhost:3001/extensions/ext_01abc123/file?path=prompt.md
-H “Authorization: Bearer $DAEMION_TOKEN”

Read and write the disk config

GET /extensions/:id/disk-config Auth required

Read the YAML configuration file on disk (job.yaml, agent.yaml, etc.) as a parsed object.

PATCH /extensions/:id/disk-config Auth required

Write config back to disk. Overwrites the existing file. The body is a JSON object (e.g. systemPrompt for agents).

bash
Verified

Read the disk config

curl “http://localhost:3001/extensions/ext_01abc123/disk-config
-H “Authorization: Bearer $DAEMION_TOKEN”

Write config back to disk

curl -X PATCH http://localhost:3001/extensions/ext_01abc123/disk-config
-H “Authorization: Bearer $DAEMION_TOKEN”
-H “Content-Type: application/json”
-d ’{ “systemPrompt”: “You are a helpful assistant.” }‘


Frequently asked questions

Q Can agents create extensions at runtime?
Yes — this is a first-class pattern. An agent can POST to /extensions during a conversation to create a new job, command, or integration on the fly. Set source: "agent" and owner_agent_id to the agent's ID so you can filter and audit agent-created extensions later.
Q What are the 12 extension types?
command — slash commands in the chat UI. agent — Claude agent identities with system prompts and model routing. job — autonomous work units that run on a schedule or trigger. app — Vite projects served by the gateway. theme — visual themes for the Daemion app. renderer — custom content renderers for chat turns. integration — connections to external services. action — discrete callable actions exposed to agents. widget — embeddable UI components. artifact — structured outputs produced by agents. capability — agent capability declarations (what it can do). control — runtime control surfaces (buttons, toggles, forms).
Q Where are extensions stored?
Extension records live in SQLite at ~/.daemion/daemion.db. File-backed extensions (jobs, agents) also have a directory on disk under jobs/ or agents/. The database record is the authoritative source — disk files are referenced by the definition.
Q What is the difference between the source values?
built-in — shipped with Daemion, not editable. user — created by you through the UI or API. agent — created autonomously by an agent during a conversation (see owner_agent_id). community — installed from the extension registry. Source affects display grouping in the app and determines whether an extension can be deleted.
Q What happens to running jobs when I disable the extension?
Disabling stops future trigger firings immediately. If a job is mid-execution when you toggle it off, the current run completes. The next scheduled trigger will not fire.

What can go wrong

Common errors

400 {"error": "validation failed", "details": [...]} — The request body failed Zod schema validation. The details array lists each failing field and why. Check that type is one of the 12 valid values and that definition matches the shape required for that type.

404 {"error": "extension not found"} — No extension with that ID exists in the database. Double-check the ID from GET /extensions.

403 {"error": "cannot disable essential extensions"} — Essential built-in extensions (core commands and actions) cannot be disabled. They can be inspected but not toggled off or deleted.

403 {"error": "cannot delete essential extensions"} — Essential extensions cannot be deleted. To customize behavior, create a new extension of the same type with source: "user".

404 on /extensions/:id/file?path=... — The file doesn’t exist in the extension’s disk directory. Use GET /extensions/:id/files first to see what files are present.

PATCH silently drops nested definition fields — The definition field is replaced wholesale on PATCH, not deep-merged. If you send "definition": { "agent_id": "haiku" }, any other keys that were in the definition before are removed. Always read the current definition first and merge client-side before patching.


What’s next?