Sessions & Permissions
Permission tiers
Every agent session operates in one of three tiers:
| Tier | Capabilities |
|---|---|
| Autonomous | All capabilities — intended for sandboxed environments |
| Supervised | Chat, memory, tools. Every tool call requires approval — an auto-approve rule, a supervisor LLM decision, or a human — before it runs. Self-modification actions (create skills, modify schedules, update USER.md) are one case of this, not the whole story |
| Restricted | Chat and read-only tools only. No memory writes beyond MEMORY.md |
Set the default tier globally:
[session]
tier = "supervised"
Or per-agent:
[[agents]]
name = "home-automation"
session_tier = "restricted"
Approval workflows
In supervised mode, every tool call — not just self-modification actions like skill creation or schedule modification — produces an approval request unless an auto-approve rule or supervisor already resolved it. The user is notified via Telegram (inline keyboard with Approve/Deny buttons) or the REST API.
Approval requests have a 24-hour TTL. Unapproved requests expire automatically.
To stop being asked about tools you trust — or to have a second LLM triage approvals while you are asleep — see Supervisors & Auto-Approval.
Approval via Telegram
When the agent wants to create a skill, the user sees a message with inline buttons:
Approval required: Create skill “weather-check”
[Approve] [Deny]
Approval via API
# List pending approvals
curl -H "Authorization: Bearer dk_..." https://localhost:8080/api/v1/approvals
# Approve
curl -X POST -H "Authorization: Bearer dk_..." \
https://localhost:8080/api/v1/approvals/{id}/approve
Cost tracking
Denkeeper tracks LLM costs per session and globally. Two limits apply, both in USD:
[llm]
cost_limit_soft = 0.5 # warn but continue
cost_limit_hard = 1.0 # stop generation
Either can be overridden per agent:
[[agents]]
name = "research"
cost_limit_soft = 2.0
cost_limit_hard = 5.0
When the hard limit is reached, the agent refuses further LLM calls for that session. Fallback strategies can automatically switch to cheaper models before that happens — a [[llm.fallback]] rule with trigger = "cost_limit" fires on whichever limit its scope names ("soft" or "hard").
The older max_cost_per_session key is deprecated. It still loads — it is migrated to cost_limit_hard at startup — but new configs should use the two-limit form.