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-limitis 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.
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):
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:
// 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
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./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.POST /reseed to sync.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 "control", 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 controls cannot be disabled.
403 {"error": "cannot delete essential extensions"} — Essential controls cannot be deleted. Create a new control with source: "user" and a different name to override the setting.
What’s next?
- How do I create a capability extension? — per-agent skills and behavior rules
- How do I create a widget extension? — surface control metrics on your dashboard
- Extensions API — full CRUD reference