> ## Documentation Index
> Fetch the complete documentation index at: https://vetta.sh/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Policies

> Governance at the tool-call boundary: per-tool allow / ask / deny, plus connection and primitive scoping.

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](/docs/platform/organizations) 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](/docs/capabilities/tools) resolves to one of three permissions:

| Permission | Behavior                                                                                         |
| ---------- | ------------------------------------------------------------------------------------------------ |
| `allow`    | The tool runs without confirmation.                                                              |
| `ask`      | The runtime emits a `tool.confirm` event and **pauses the tool** until you approve or reject it. |
| `deny`     | The tool is not offered to the model at all — the agent cannot call it.                          |

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 TypeScript theme={"system"}
const agent = await vetta.agents.create({
  name: "ops",
  model: "zai-org/GLM-5.2-FP8",
  harness: "pi",
  budget: { capMicroUsd: "50000000", maxTaskMicroUsd: "5000000", period: "month" }, // $50 / $5
  tools: {
    default_config: { permission: "allow" },
    configs: {
      bash:            { enabled: true, permission: "allow" },
      publish_file:    { enabled: true, permission: "allow" },
      "tracker.get_issue": { enabled: true, permission: "ask" },  // a connection/MCP tool, keyed `<connector>.<tool>`
    },
  },
});
```

```bash CLI theme={"system"}
vetta agent update ops --file ops.json   # tool policy travels in the config file
```

<Note>
  `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.
</Note>

### 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](/docs/concepts/sessions) — the same mechanism as any other input:

```bash CLI theme={"system"}
vetta session confirm --session $SID --tool-call $CALL_ID          # or
vetta session confirm --session $SID --tool-call $CALL_ID --reason "not this account"
```

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](/docs/concepts/session-operations#awaiting-approval-loop) for the driving code.

A held tool consumes no budget while it waits, and — because the loop is [durable](/docs/concepts/runtime) — an agent can sit on a confirmation for hours at storage cost only. See [Events & streaming](/docs/concepts/events-and-streaming) for the event shapes.

#### Timeouts

An `ask` tool does not hold the turn indefinitely. Two fields on the policy bound the wait:

<ParamField path="ask_timeout_seconds" type="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).
</ParamField>

<ParamField path="on_timeout" type="string" default="deny">
  What happens when `ask_timeout_seconds` elapses with no response:
  <br />• `deny` — reject the call as if denied; the deny message is fed back to the agent. Safe default.
  <br />• `allow` — auto-approve and run the call.
  <br />• `escalate` — keep the session `idle` / `awaiting_approval` and re-notify, deferring the decision rather than making one.
</ParamField>

## Connection & primitive scoping

Beyond individual tools, a policy scopes *which* external systems and primitives an agent may reach. This governs the [identity](/docs/identity/overview) surface — connections an agent acts through run under the same allow/ask/deny filter as `bash`.

<ParamField path="primitives" type="object">
  Which built-in primitives are enabled for the agent — e.g. `computer`, `browser`, `files`, `connections`, and (coming soon, as agent tools) `email`, `phone`.
</ParamField>

<ParamField path="connections.mode" type="string" default="allowlist">
  How third-party connections are gated:
  <br />• `open` — any connection type is allowed.
  <br />• `allowlist` — only the listed connection types are allowed. Recommended for anything an agent runs unattended.
  <br />• `blocklist` — every connection type except the listed ones is allowed.
  <br />`open` is permissive by design; prefer `allowlist` in production so a new connector type is not reachable until you add it.
</ParamField>

<ParamField path="connections.list" type="string[]">
  The connection types the `allowlist` / `blocklist` applies to.
</ParamField>

```jsonc theme={"system"}
{
  "primitives": { "computer": true, "browser": true, "connections": true },
  "connections": { "mode": "allowlist", "list": ["crm", "tracker", "chat"] }
}
```

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](/docs/concepts/budgets) — 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.

<Card title="Next: the computer" icon="server" href="/docs/computer/index">
  The sandbox, filesystem, shell, and browser in depth.
</Card>
