Skip to content

Autonomy levels & approvals

Read-only, supervised, and full autonomy levels and the tool-level approval gate.

Autonomy levels decide how much an agent can do on its own; the approval gate decides what it must check with you first. Together they are the innermost layer of Revka’s security model — every tool call is evaluated against the autonomy level before it runs, and in supervised mode the Approval Manager can pause for a yes/no decision on individual tool calls.

This page covers the three autonomy levels, how to set them, and how the tool-level approval gate behaves on the CLI versus in chat channels. Use it when you are deciding how much to trust an agent on a given channel, or when you want to stop being prompted for a tool you already trust.

The autonomy level is the policy engine’s entry point. It is enforced by SecurityPolicy and controls whether the agent can take actions at all, independent of the command allowlist, workspace boundary, and rate limiter that sit alongside it.

read_only

Observe only. All tool actions are blocked — including otherwise-safe read commands like ls and cat. The safest choice for untrusted channels.

supervised

The default. The agent acts within the allowlists, but medium- and high-risk commands require approval (approved = true), and the Approval Manager can prompt for individual tool calls.

full

No approval gates. Medium-risk approval prompting is skipped, but the command allowlist, workspace boundary, and block_high_risk_commands are still enforced.

Set the level in the [autonomy] section of ~/.revka/config.toml:

[autonomy]
level = "supervised" # read_only | supervised | full
KeyTypeDefaultMeaning
levelstring"supervised"read_only, supervised, or full

The current level is injected into the agent’s system prompt automatically (via SecurityPolicy::prompt_summary()), so the model knows what it is allowed to do.

The practical difference is the approval gate:

  • In supervised mode, a medium- or high-risk command runs only if the call carries approved = true (see The approved flag). The Approval Manager may also prompt interactively before a tool call.
  • In full mode, there is no medium-risk approval prompt. The agent acts without asking — within the limits that are still enforced.

A non-wildcard allowlist entry is the exception worth knowing: if you add a high-risk command such as ssh to allowed_commands, it bypasses block_high_risk_commands, but in supervised mode it still needs approved = true to run.

Beyond the per-command risk policy, Revka has a separate Approval Manager — a pre-execution hook that runs before LLM tool calls in supervised mode. It is distinct from workflow and SOP approval gates: those pause an entire run, while this operates at the level of a single tool call. It keeps a session-scoped “Always” allowlist and writes to the audit trail.

Tune which tools the gate prompts for using two lists in [autonomy]:

[autonomy]
level = "supervised"
auto_approve = ["file_read", "weather"] # never prompt for these
always_ask = ["shell"] # always prompt, even if "Always" was chosen
KeyTypeDefaultMeaning
auto_approvelist[]Tools that are never prompted for
always_asklist[]Tools that always prompt, overriding the session “Always” allowlist

A "*" wildcard in either list covers all tools. always_ask wins over the session allowlist — even if you previously chose Always for a tool, listing it in always_ask forces a prompt every time.

In an interactive CLI session, supervised mode prompts on stdin before running a tool that is not auto-approved:

🔧 Agent wants to execute: shell
command: rm -rf ./build/
[Y]es / [N]o / [A]lways for shell:
  1. Yes — approve this one call.

  2. No — deny this call. The denial is recorded (see Trust-adaptive autonomy).

  3. Always — approve this call and add the tool to the session-scoped “Always” allowlist so it is not prompted again this session — unless it is in always_ask.

There is no stdin to read in a non-interactive context, such as a message arriving over Telegram, Discord, or another channel. In that mode, any tool that would require approval is auto-denied rather than left hanging.

One exception: MCP-namespaced tools (named service__tool) are auto-approved in non-interactive mode.

The approved field is how an explicit approval rides along with a tool call. It appears on tools that can execute medium- or high-risk actions — most notably shell — and on the cron and SOP tools that schedule them.

{ "command": "ls -la", "approved": false }
  • approved (boolean, default false) — set true to explicitly approve a medium- or high-risk command in supervised mode.

In supervised mode, a medium/high-risk command with approved = false is rejected by the policy with a "Blocked by security policy"-class error. Setting approved = true is what satisfies the gate. In full mode the flag is not needed for medium-risk commands; in read_only mode nothing executes regardless of the flag.

The same field is honored by the cron and SOP surfaces — for example, cron_add and cron_run accept "approved": true to pre-approve a medium-risk shell job. Note that shell jobs created through the gateway cron API are not pre-approved (approved defaults to false), so medium-risk commands scheduled that way are rejected at run time.

The approved field is internal to Revka’s security model. When a tool call is forwarded to an external MCP server, the wrapper strips approved first, because MCP servers do not understand it.

The Approval Manager can be wired to a per-domain trust tracker. When it is, your approval decisions feed back into the agent’s effective autonomy, so an agent that keeps doing the wrong thing in a domain loses the ability to do it silently.

Every denial is logged as a UserOverride correction. Repeated corrections in a domain push its trust score down. When a domain crosses the regression threshold, its effective autonomy is downgraded by one tier — and the downgrade tightens the approval gate accordingly:

Effective downgradeEffect on the gate
Full → SupervisedThe tool now prompts, even though the configured level is full
Supervised → ReadOnlyThe tool prompts even if it is in the session “Always” allowlist, preventing silent execution

This is automatic — there is nothing to configure on the approval side. The behavior is driven by the trust scoring engine; tune its thresholds in the [trust] config section, documented under prompt injection, leak detection & trust.

Recommended Start every channel at the lowest level that still lets the agent do its job:

  • Untrusted or public channelsread_only. The agent can answer questions but cannot touch the system.
  • Your own channels and the CLIsupervised (the default). You stay in the loop for anything risky via the approval gate.
  • Trusted automation you have already vettedfull, with a tight allowed_commands allowlist and block_high_risk_commands = true so the remaining guardrails still hold.

The agent loop

Where the approval gate sits in the model-driven tool-call cycle. See The agent loop.