Daemion docs

How do I configure system behavior with a control extension?

A control extension is a named configuration record that governs system behavior. Controls are how you set budget limits, rate caps, feature flags, and other global settings that affect how Daemion operates across all agents and conversations.


When would I use a control?

Use a control when you want to define a rule or setting that applies system-wide rather than to a single agent or conversation. Good candidates:

  • Budget limits — cap daily or monthly API spend and get alerted when you’re close
  • Rate caps — limit how many turns an agent can take per hour or day
  • Feature flags — enable or disable experimental features without redeploying
  • Credential references — name a secret so integrations can reference it without embedding the value
  • Timeout settings — configure how long the gateway waits before cancelling a slow agent turn

Controls are not for per-agent behavior — use a capability extension for that. They are not for UI configuration — use a theme or widget extension for that.


How do I create one by chatting?

Tell Daemion what system rule you want to enforce:

You: Set a $10 daily budget limit

Daemion: I’ll create a control for your daily budget.

Done — daily-budget-limit is set to $10 USD. I’ll track API spend across all agents and warn you at 80% ($8). If you hit $10, I’ll pause new turns until midnight. Want me to add a Slack notification when you hit the warning threshold?

You: Yes, post to #alerts

Daemion: Updated — you’ll get a Slack alert at $8 and $10. The control is live immediately.

The control is stored in SQLite immediately. No restart needed.


How do I create one via the API?

The API is the programmatic path — for scripts or agents creating controls 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”: “control”, “name”: “daily-budget-limit”, “description”: “Caps daily API spend at $10 USD and pauses turns if the limit is reached.”, “definition”: { “setting”: “budget.daily_limit_usd”, “value”: 10, “currency”: “USD”, “on_approach”: { “threshold”: 0.8, “action”: “warn” }, “on_limit”: { “action”: “pause_turns” } }, “source”: “user”, “enabled”: true }’

The gateway validates the envelope against ExtensionSchema and stores the record. The definition field is open (GenericDefinitionSchema) — structure it to describe which system setting you’re configuring and what the value or rule should be.


What does the control schema look like?

Control 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: “control”; name: string; // unique per type, kebab-case, 1-100 chars description: string; // human-readable, max 500 chars definition: Record<string, unknown>; // control-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 system limit control:

typescript

// Example definition shape — adapt to your setting interface ControlDefinition { setting: string; // dot-path identifier for the setting, e.g. “budget.daily_limit_usd” value: unknown; // the setting value — number, string, boolean, or object on_approach?: { // optional: behavior as the limit is approached threshold: number; // fraction of limit, e.g. 0.8 = 80% action: string; // e.g. “warn”, “notify”, “throttle” }; on_limit?: { // optional: behavior when the limit is reached action: string; // e.g. “pause_turns”, “reject”, “notify” }; [key: string]: unknown; }


Frequently asked questions

Q How does a control differ from a capability?
A capability adds a skill or behavior to an agent. A control sets a system-wide rule that governs how Daemion operates — budgets, rate limits, feature flags. Controls apply regardless of which agent is active.
Q Can I use a control to store a credential?
Yes — create a control with definition.setting: "credential.github-token" and definition.value: "ghp_...". Other extensions reference it by the setting name, not the raw value. Keep credential controls with source: "user" and never expose them in logs.
Q Can an agent create controls at runtime?
Yes. POST to /extensions with source: "agent". Agent-created controls start disabled — the user enables them. This is the pattern for letting Daemion propose configuration changes during a conversation.
Q Do controls take effect immediately?
Yes. Controls are read from SQLite at runtime. Enabling or updating a control takes effect on the next relevant system operation — no restart needed. If you modified a file-backed extension, call POST /reseed to sync.
Q How do I update or delete a control?
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 "control", 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 controls cannot be disabled.

403 &#123;"error": "cannot delete essential extensions"&#125; — Essential controls cannot be deleted. Create a new control with source: "user" and a different name to override the setting.


What’s next?