Skip to main content
Every capability an agent has flows through one place — the tool call. Vetta enforces governance there, so a policy is checked before a tool runs, not audited after. Policies ship in Phase 1 with the primitives they protect.

Two layers, one decision

A policy is resolved from two layers, most specific wins:
  1. Organization default — a baseline every agent in the organization inherits.
  2. Agent override — per-agent, and per-tool within an agent.
The resolved policy is evaluated on every tool call, connect attempt, and primitive use. Nothing reaches an external system without passing it.

Per-tool permission policy

Each tool resolves to one of three permissions: Tools are configured with a single toolset object: a default_config that applies to every tool, and per-tool configs that enable a tool and override its permission. There is no separate flat tools[] array or top-level default field.
TypeScript
CLI
allow is convenient but not automatically the right default. For irreversible or externally-visible tools (payouts, deletes, sending mail) set ask — or deny if the agent should never have the capability — rather than leaning on the permissive baseline.

Responding to ask

When a tool is set to ask, the runtime streams a tool.confirm event and holds the turn. The session goes idle with stop_reason: "awaiting_approval". You resolve it by sending a decision back into the session — the same mechanism as any other input:
CLI
The decision records the approver — the user or API key id that answered — on the event and audit trail, so a sign-off is attributable after the fact. See the awaiting-approval loop for the driving code. A held tool consumes no budget while it waits, and — because the loop is durable — an agent can sit on a confirmation for hours at storage cost only. See Events & streaming for the event shapes.

Timeouts

An ask tool does not hold the turn indefinitely. Two fields on the policy bound the wait:
integer
How long an ask call may sit unanswered before on_timeout is applied. Omit for no timeout (the session waits indefinitely at storage cost).
string
default:"deny"
What happens when ask_timeout_seconds elapses with no response:
deny — reject the call as if denied; the deny message is fed back to the agent. Safe default.
allow — auto-approve and run the call.
escalate — keep the session idle / awaiting_approval and re-notify, deferring the decision rather than making one.

Connection & primitive scoping

Beyond individual tools, a policy scopes which external systems and primitives an agent may reach. This governs the identity surface — connections an agent acts through run under the same allow/ask/deny filter as bash.
object
Which built-in primitives are enabled for the agent — e.g. computer, browser, files, connections, and (coming soon, as agent tools) email, phone.
string
default:"allowlist"
How third-party connections are gated:
open — any connection type is allowed.
allowlist — only the listed connection types are allowed. Recommended for anything an agent runs unattended.
blocklist — every connection type except the listed ones is allowed.
open is permissive by design; prefer allowlist in production so a new connector type is not reachable until you add it.
string[]
The connection types the allowlist / blocklist applies to.
An agent that tries to connect or call outside its allowlist is refused with a typed forbidden error (a permission denial) before any external request is made.

Why the boundary matters

Because enforcement lives at the tool-call boundary rather than inside a prompt, a policy holds regardless of what the model decides to attempt. Combined with the budget gate — which prices every call before it runs — an agent left running unattended can neither exceed its spend nor touch a system it was not granted.

Next: the computer

The sandbox, filesystem, shell, and browser in depth.