
# Tools

The `tools` block is an [agent's](/en/docs/ai-agents) capability allowlist: the tables it may touch and the actions it may take. It is the single most consequential thing you write about an agent, because it is the only place where "what this agent is for" becomes machine-checkable.

```yaml
agents:
  - name: support-agent
    role: support
    systemPrompt: You are a courteous support assistant. Resolve tickets accurately.
    tools:
      tables: [tickets, customers]
      actions: [record.read, record.update, email.send]
```

| Property        | Rule                                                                         |
| --------------- | ---------------------------------------------------------------------------- |
| `tools.tables`  | Table names the agent may access. At least one; each must exist in `tables`. |
| `tools.actions` | Action types the agent may perform. At least one, from the list below.       |

An agent with no `tools` block has **no access at all**. Secure by default, and quiet about it — an agent that seems to do nothing is often an agent whose allowlist you forgot.

## The Double Gate

Every call an agent attempts passes two independent checks, and both must allow it:

1. **RBAC gate** — does the agent's [role](/en/docs/auth-roles-rbac) permit this operation on this table?
2. **Allowlist gate** — is this table and this action written in `tools`?

The order does not matter; the conjunction does. The property this buys you is that **`tools` can only ever narrow a role, never widen one**. Listing `record.delete` on an agent whose role cannot delete grants nothing. So reviewing an agent means reviewing its role — the allowlist cannot smuggle in a capability the role withheld.

Row-level and field-level rules apply on top, unchanged. An agent bound to a role that only sees its own team's records sees only those, whatever its allowlist says.

:::callout
**List the smallest set that does the job, and re-derive it when the prompt changes.** An allowlist drifts the way a permission set does: someone adds `record.delete` for a one-off cleanup and it stays. Because the gate is a conjunction, tightening `tools` is always safe to try — if the agent still works, the entry was never needed.
:::

## Available Actions

Actions follow the same `type.operator` vocabulary as the [automation engine](/en/docs/automation-actions-overview), so a rule you already understand from an automation means the same thing here.

| Category   | Actions                                                                        |
| ---------- | ------------------------------------------------------------------------------ |
| **Record** | `record.read`, `record.create`, `record.update`, `record.delete`               |
| **State**  | `state.get`, `state.set`, `state.increment`, `state.delete`, `state.list`      |
| **HTTP**   | `http.request`                                                                 |
| **AI**     | `ai.generate`, `ai.classify`, `ai.extract`                                     |
| **Code**   | `code.runTypescript`                                                           |
| **Email**  | `email.send`                                                                   |
| **Auth**   | `auth.createUser`, `auth.assignRole`, `auth.banUser`, `auth.unbanUser`         |
| **File**   | `file.upload`, `file.download`, `file.delete`, `file.list`, `file.getMetadata` |

A few deserve comment.

**State** is a cross-run key-value store. It is what makes an agent more than a stateless prompt — a scheduled agent can remember what it processed last time without a table to hold it.

**AI** actions let an agent chain sub-tasks: classify a ticket, then extract fields from it, then generate a reply. Each is a fresh model call against the agent's own token budget.

**Auth** actions are the sharpest thing on this list. `auth.createUser`, `auth.assignRole` and `auth.banUser` mean an agent can alter who has access to your app. Grant them only to an agent whose role is itself privileged enough to justify it, and put them behind [approval](/en/docs/agent-approvals).

**`code.runTypescript`** executes in a sandbox, but it is still the broadest capability here — it is the action that turns "what the agent may do" from a list into a language.

## Internal versus External

`tools` scopes what the agent may do **inside** Sovrium. Reaching outside — an external MCP server's web search or document fetch — is a separate allowlist, `mcp.allowedTools`. See [Client Mode](/en/docs/mcp-client-mode).

The two are independent by design. A read-only internal agent that can search the web is a perfectly coherent configuration, and so is the reverse.

## Related Pages

- [Agents Overview](/en/docs/ai-agents) — the agent this block belongs to.
- [Permissions & Approval](/en/docs/agent-approvals) — gating the actions listed here.
- [Scheduling & Limits](/en/docs/agent-schedule-limits) — how often they may run.
- [Roles & RBAC](/en/docs/auth-roles-rbac) — the first gate.
- [Actions Overview](/en/docs/automation-actions-overview) — the same vocabulary in automations.
- [Client Mode](/en/docs/mcp-client-mode) — the external allowlist.
