Permissions and security¶
Permission, authentication, and isolation answer different questions: may this action run, who is calling, and what can the process reach. Configure all three. Neither an authenticated A2A request nor a sandbox replaces the Permission Gate.
Decision order¶
The tool registry checks the Permission Gate before dispatching a tool:
- Built-in rulings deny catastrophe-class commands, including recursive deletion of a root or home tree.
- User rules in
permissions.toolschoosedeny,allow, orask. - An unmatched call uses its tool's default tier.
- The current permission mode interprets the
asktier.
Read-only tools and recognized read-only local shell commands generally default
to allow. Mutations and unknown MCP tools generally default to ask. There are
explicit allow-default exceptions, such as deliver_files, which hands a file
to the requesting user. A user rule still overrides a default. Do not assume a
tool is denied merely because it is absent from the config.
Modes¶
permissions.mode |
How an ask-tier call is handled |
|---|---|
ask |
Ask the interactive user |
smart (default) |
A model reviewer allows or escalates to the user |
full |
Run without asking |
All modes retain built-in denials and user deny rules. Smart review is not a
guarantee of safety: use explicit deny rules for prohibited operations. If the
reviewer fails or times out, the call escalates rather than being auto-approved.
If no approval responder is available, a still-asking call is refused.
raven agent -m never has one: after the reply it lists every refused call,
and exits with status 3 when any of them needed approval, so an unattended
driver can tell a run that skipped its changes from one that made them. It
also lists questions nobody could answer. Those do not change the exit
status, because the turn continued with its best judgment. Pass
--permission-mode full when a one-shot must mutate.
The global config supplies the starting mode. A conversation can override it
through session-scoped config.set; that mode is saved with the conversation.
Check the conversation's mode as well as the global value during troubleshooting.
Configure tools and shell prefixes¶
Merge a fragment like this into your existing configuration:
{
"permissions": {
"mode": "ask",
"tools": {
"exec": {
"*": "ask",
"git status *": "allow",
"git diff *": "allow",
"git push *": "deny"
},
"write_file": "ask",
"edit_file": "ask",
"a2a_send": "ask"
}
}
}
Only exec has the command-prefix table. Other entries name a tool and a tier;
this is not an arbitrary path-glob ACL. The example blocks an ordinary direct
git push, not every possible way a shell program could publish data.
Shell matching follows these rules:
- A specific pattern matches token prefixes (
git status *also matchesgit status). Several matching specific patterns resolve strictest-wins:deny > ask > allow, independent of their order. *is used only when no specific pattern applies. Thus* = askdoes not prevent a specificgit status * = allowfrom working.- Compound commands allow only when every segment allows; a denied segment
denies the call.
git *does not implicitly authorizesudo git .... - Command/process substitution, backticks, heredocs, or unconfined redirection
may leave only the fallback rule applicable to
allowandaskpatterns. This is conservative parsing, not a proof about every program a command can launch. - A
denypattern is asked about every command the string runs, before any of that: behind a wrapper (sudo,env,bash -c,xargs,doas,watch), inside a substitution, after a shell keyword, or under a path (/usr/bin/curl). Socurl * = denyalso refusesbash -c "curl ..."andcurl ... > /tmp/out. It cannot see a command a program builds for itself (python -c, a script file, an alias).
Unlike OpenCode's ordered rules, Raven does not use last-match-wins. Do not
paste another product's permission schema or precedence into Raven. Avoid
"*": "allow" unless broad unattended execution is intentional.
Approval scope¶
| Choice | Scope |
|---|---|
| Allow once | The pending action |
| Allow for this session | Still-asking action keys in that conversation |
| Don't ask again | A validated, user-confirmed exec prefix persisted in config |
| Deny | Refuse the action; normally the turn can continue |
| Deny and stop | Refuse and end the current turn |
For shell commands, session grants include the command segment, machine, and working directory. Built-in file writers key by path and working directory; browser acting tools share a per-site key. Other tools generally key the exact call. Session grants live in memory; they are not the persisted global prefix rules. Neither grant overrides a deny. Expired or denied actions are not asked again unchanged in the same turn.
Delegation is a separate trust boundary¶
Raven's gate governs its own registry calls, not every command an external agent might execute inside its process.
- Inbound ACP: Raven can request permission from its editor/host through
session/request_permission. - Outbound ACP: Raven's unattended client automatically prefers the
child's
allow_alwaysorallow_onceoption. Enabling this agent is not a promise of human review for each internal operation. Your refusals do travel: a request whose shell command matches yourdenyrules ortools.exec.extraDenyPatternsis answered with the child's reject option, and Raven's own agents (Raven-Code and its siblings) carry those rules in their rendered config, so they refuse such a call without asking. A third-party agent is held only for what it asks about, and a rule you add reaches an already running Raven agent when it is next launched. The ask tier and the mode are not carried. - CLI and other backends: inspect their command, environment, working directory, and native permission policy. Host permission rules are not automatically inherited across every backend.
- A2A: the shared bearer token admits a remote operator. The host's tool gate still applies, but the current inbound A2A turn has no tool-approval responder. Its question broker is not a permission UI.
- DAG:
confirm: truerequests approval for the declared graph, not for every action discovered later. Without an ask channel, the current implementation logs a notice and proceeds without confirmation; this flag is not a fail-closed security control. Skill/MCP selection depends on backend capability; a downgrade notice means it is not a reliable enforcement boundary there.
Prefer narrow credentials, an isolated account or container, and explicitly partitioned working files when allowing unattended child agents.
Sandbox, files, and untrusted content¶
Sandboxing controls execution placement. A BoxLite VM can mount the real workspace read-write; deleting inside that mount deletes real files. The gate therefore does not auto-approve a command simply because a sandbox exists. Third-party backends may not use Raven's executor. See Sandbox.
Working-directory protections, DAG reference confinement, channel sender allowlists, and network restrictions are additional controls with different scopes. Prompt-injection labels mark tool results and sub-agent output as untrusted data; they do not make model judgement infallible. Check credentials and network reach separately from prompt instructions.
ACP redacts recognized secrets in outgoing arguments, previews, errors, and permission descriptions. A2A turn failures expose a fixed message and retain the detailed exception in local logs. Neither mechanism guarantees every log or transcript is safe to publish. Keep secrets out of task prompts where possible, and review/redact diagnostic exports before sharing.
Diagnose a refused or stalled action¶
| Symptom | Check |
|---|---|
full still refuses a command |
Built-in or user deny; changing mode does not override it |
| Smart mode asks unexpectedly | Reviewer escalation, timeout, or unavailable provider |
| Headless task refuses a mutation | No approval responder; configure narrowly before launching |
| A compound command asks | Every segment and redirection must be covered |
| A previous grant no longer applies | Different directory, machine, site, conversation, or process restart |
| A child acted without asking | Outbound ACP/native child policy, not just the host gate |
Inspect permission.decision, permission.source, and smart reviewer fields
on the tool-call trace span. Implementation entry points are
raven/permissions/gate.py, raven/permissions/rules.py,
raven/permissions/session.py, and raven/acp_client/permissions.py.