Skip to main content

Policy

Every action an agent takes is a request for a capability, with a target (the tool, the path, the host, the server). The policy decides each request: allow it, deny it, or ask a person. An ask pauses the run until someone decides (durable runs); the security model explains the design.

How a request is decided

  1. A deny rule that matches wins.
  2. Otherwise an ask rule that matches: a person decides. An ask outranks an allow, so adding an allow rule to a profile does not lift that profile’s asks; remove the ask rule, or write your own policy.
  3. Otherwise an allow rule that matches.
  4. Otherwise the policy’s mode decides: permissive allows, interactive asks, strict denies, each with reason unknown_capability and no rule named, so the evidence tells it apart from a rule’s decision.
A decision is recorded in the run’s trace with its effect and reason_code (matched_allow, matched_ask, matched_deny, unknown_capability, approved when a person allowed an ask, follows_command for the runtime’s own listing after a sandbox command, and others). Two capabilities are decided when the agent connects, not during a run: mcp.server.start and mcp.server.connect. There is no run to pause then, so an ask on them fails the connection with ApprovalRequiredError; allow the servers you trust. The served agent’s policy also decides what an operator asks of OmniServe’s background API: background.task.* and background.run.*. A refusal there is an HTTP 403.

Writing a rule

Or the whole policy as a dict:
A policy can carry its budgets under a budgets key: in a dict policy, in a JSON policy file (policy_path), or as policy.budgets on a policy object. It takes the same shape as governance_config["budgets"] (budgets), and the budgets are hashed with the policy. Set budgets in the policy or in governance_config, not both: both is refused.

Rules on shell commands

Command rules decide which commands run without asking. They are not a security boundary: what a command can touch is decided by the sandbox it runs in. An allowed program can do anything its own options allow, and sudo rm is a command named sudo, not rm; sh build.sh runs a script as python x.py does; and git -c alias.x='!rm -rf build' x is a command named git.
Every command an agent runs reaches the policy as process.exec on sh (the execute tool runs sh -c <command>). A command matcher names a command by its first words:
How a command is read: only a plain chain (simple commands of literal words joined by &&, ||, ;, | or a newline) is split into its commands. Anything else makes the whole command unreadable: a redirect, $(...) or backticks, a variable or ~, a glob, a brace, an escape, a leading NAME=value, a subshell, a group, a heredoc, a function or loop, a command in the background, a program that runs text as a command (eval, source, exec, sh -c, trap, alias), or a shell reading commands from its input (... | sh). How a command is decided:
  • A deny or ask rule applies when any command of a readable line begins with its prefix: ls && rm -rf build is denied by the rule above.
  • An allow rule applies only when every command is matched by some allow rule and is named without a path (not ./git or /tmp/git): git status | head needs head allowed too.
  • An unreadable command is never allowed by a rule. Where the policy has any command rule for it, it is asked about, in every mode (refused in strict), with the reason code command_opaque: a deny rule on rm is not passed by eval "rm -rf x".
  • A policy without command rules decides exactly as before.
Words are literal: write alternatives (["-r", "-rf", "-fr"]) rather than patterns. A person asked to approve a command sees each command of a plain chain on its own line, or the whole text when it is unreadable, with control and invisible characters shown; the approval is bound to that exact text.

Capabilities

Built-in profiles

Each profile below is build_default_policy(name). Start from one and add rules, or write your own policy.

permissive-dev

Mode permissive.

interactive-dev

Mode interactive.

strict-production

Mode strict.