Skip to main content
View as Markdown

Permissions & Approval

Two different questions, two different blocks. permissions says who may set an agent in motion. approval says which of its actions stop and wait for a person once it is running.

Who May Invoke

app.yaml
agents:
  - name: support-agent
    role: support
    systemPrompt: You are a courteous support assistant.
    permissions:
      type: agent
      trigger: [admin, member]
Property Description
permissions.type User-type discriminator. Always agent.
permissions.trigger Who may invoke: all, authenticated, or a role array such as [admin, member].

Each agent gets a synthetic user record at {name}@agents.sovrium.local. That domain is fixed and not configurable.

What Each Value Admits

Value Admits
omitted Any signed-in caller, and nobody else.
authenticated Any signed-in caller — the same rule as omitting the grant, said out loud.
all Everyone, anonymous callers included. The explicit opt-in for a public agent.
[admin, member] Callers holding one of the listed roles. admin satisfies any role array, whether or not it is listed.

Refusals Answer 404

A caller the grant does not admit gets 404 Not Found — never 403, never 401 — and the body names no agent. That is deliberate. The agent's name sits in the URL, so an answer distinguishing "exists, but not for you" from "no such agent" would let anyone map your deployment one guess at a time. The two responses are byte-identical.

The practical consequence is worth knowing before you debug one: on these routes the 404 is the permission error. There is no 403 to go looking for.

Invocation and Readback Both

trigger governs every surface that sets the agent in motion — the chat panel, POST /api/agents/{name}/execute, the manual schedule trigger, an automation — and also the surfaces that read it back: the agent's definition, its schedule, its token usage, and its pending approvals. Those readbacks serve the system prompt, the task prompt and the tools allowlist, which is precisely the material someone would want in order to aim a prompt injection at the agent.

GET /api/agents, the collection, requires a session in every case — including on a deployment where some agent declares trigger: all. all opens one agent to invocation; it does not open your inventory to enumeration. A caller who clears that gate still sees only the agents they may individually trigger.

One surface sits outside the grant on purpose: the agent's own cron schedule. A timer is not an external caller, so trigger: [admin] restricts who may invoke the agent without stopping it from running on its own.

trigger does not govern what the agent may then do: that remains its role plus its tools allowlist. A viewer allowed to trigger an admin-role agent is triggering something more privileged than themselves, so read trigger as delegation and set it deliberately.

Human-in-the-Loop Approval

approval inserts a person between the model's decision and its effect.

Property Description
approval.mode none (execute immediately), all (everything waits), or selective.
approval.required Actions needing approval — a subset of tools.actions. Required when mode: selective.
approval.timeout Seconds before a pending approval expires. Defaults to 3600.
approval.escalation { after: <seconds>, to: <role> } — hand an unactioned request to another role.
app.yaml
approval:
  mode: selective
  required: [record.delete, email.send]
  timeout: 1800
  escalation:
    after: 600
    to: admin

Read that as a timeline. The agent decides to send an email; the request goes to a human. Ten minutes later, nobody has acted, so it escalates to admin. Twenty minutes after that the timeout hits and the request expires unexecuted.

Choosing a Mode

Mode Right when
none Every action the agent can take is reversible and low-stakes. A read-only analyst.
selective Most work is routine but a few actions leave the building. The usual answer.
all A new agent you do not yet trust, or one whose whole remit is consequential.

selective is the default choice in practice, and the discipline is to ask of each action: if the model gets this wrong, can I undo it? record.update on an audited table is recoverable. email.send is not — the message is gone. Neither is auth.banUser, from the banned user's point of view.

Running all for a fortnight after deploying a new agent is a cheap way to learn what it actually does before narrowing to selective. The approval queue doubles as a log of intentions.

Approval and Scheduling

Scheduled runs respect approval. An agent with mode: all on a nightly cron does not execute at 3 a.m. — it queues a request that sits until someone arrives, and expires if timeout passes first.

That combination is usually a mistake, and worth naming: an unattended trigger paired with an attended gate produces an agent that reliably does nothing overnight. Either narrow to selective so the routine part proceeds, or accept that the schedule only prepares work for the morning. See Scheduling & Limits.

Last updated September 1, 2026

This documentation was written with AI, so errors or outdated content are possible. Sovrium is in beta. Contributions and corrections are welcome.

Built with Sovrium