Guide3 min read

AI Agent Permissions, Enforced at Execution Time

AI agent permissions should be enforced server-side at execution time, not prompted. Here's how policy templates gate primitives, apps, and approvals.

Read the docs →

Guide
TL;DR
  • AI agent permissions decide which capabilities an agent can use and they should be enforced by the platform, not requested in a prompt.
  • A prompt-level 'don't do X' is bypassable; permissions have to live server-side, checked at execution time.
  • On Naïve, an Account Kit is the policy template: it enables specific primitives and specific third-party apps per tenant user.
  • You can gate down to individual tools (e.g. allow Gmail read + send only) and require human approval on sensitive actions.
  • Cards, domains, verification, formation, and connecting apps default to requiring approval; agent calls are gated, human dashboard/session calls are not.
  • Author a few kits (Starter/Pro/Enterprise) and assign them, instead of configuring every user by hand.

An AI agent that can act in the real world needs a hard answer to one question: what is it allowed to do? Get that wrong and the agent can spend money, connect accounts, or touch data it shouldn't. AI agent permissions are the controls that answer it — and the only version worth trusting is enforced by the platform at execution time, not written into a system prompt the model can be talked out of.

This is the enforcement layer of the multi-tenant playbook, sitting right on top of per-customer isolation. Here's how policy templates make least-privilege the default.

Why not just put the rules in the prompt?

Because a prompt is advisory. "Never issue a card without approval" holds right up until a crafted document, a jailbreak, or a plain model mistake convinces the agent otherwise. You cannot audit a natural-language instruction, and you cannot prove it will hold under adversarial input.

Enforcement has to happen where the action actually executes. If the platform checks permissions on every call, then a forbidden action fails no matter what the model decided — enforcement comes from code, not persuasion.

What is the policy template?

On Naïve, permissions live in an Account Kit — a reusable policy template you assign to a tenant user. It controls two things: which native primitives are enabled, and which third-party apps a user may connect.

{
  "name": "Pro",
  "primitives_config": {
    "cards":  { "enabled": true, "defaults": { "spending_limit_cents": 250000 } },
    "email":  { "enabled": true },
    "vault":  { "enabled": true },
    "social": { "enabled": false }
  },
  "connections_config": {
    "mode": "allowlist",
    "toolkits": ["gmail", "slack", "stripe", "hubspot", "notion", "linear"],
    "tools": { "gmail": { "enable": ["GMAIL_FETCH_EMAILS", "GMAIL_SEND_EMAIL"] } }
  }
}

Because the kit is enforced server-side, social being false here means no prompt can make this agent post — the capability simply isn't available to it.

How granular can permissions get?

Three levels, from coarse to fine:

  • Primitives — enable or disable each native capability (cards, email, vault, social, …), with defaults like a card spending_limit_cents.
  • Apps — choose a mode: open (every app), allowlist (only listed apps), or blocklist (all except listed).
  • Individual tools — within an allowed app, enable or disable specific tools. Allow Gmail, but only GMAIL_FETCH_EMAILS and GMAIL_SEND_EMAIL, for example.

That range is what makes real least-privilege possible: a Starter tier can be tightly boxed while an Enterprise tier opens up, all from the same mechanism.

How does approval fit in?

Some actions are too consequential to run unattended. Each gated primitive accepts requiresApproval; when it's on, the agent's action freezes as a pending approval (HTTP 202) until a human approves it.

Sensible defaults ship out of the box: cards, domains, verification, formation, and connecting a new app default to requiring approval. You can opt a primitive out with requiresApproval: false. And the gate is smart about who's calling — human callers from the dashboard or a session are not subject to it; only agent (API-key or MCP) calls are gated (per published docs). Naïve's governance primitive covers this approval-and-audit layer in depth.

How does this compare to rolling your own?

ConcernHand-rolled permissionsNaïve Account Kit
Where enforcedScattered if checks per requestServer-side, on every call
GranularityWhatever you remember to codePrimitive → app → individual tool
ApprovalsCustom queue + freeze/replay logicrequiresApproval + HTTP 202, built in
Scaling to many usersPer-user config driftAssign a shared kit; edit once, applies to all
AuditabilityPrompt text you can't verifyDeclarative policy you can read and diff

Where to start

Author one kit for your most common tier — enable the handful of primitives that tier needs, set an allowlist of apps, and leave the sensitive primitives on their default approval gate. Assign it to a tenant user and watch a forbidden action fail cleanly. For the full definition and the exact config surface, see what is an Account Kit? and the Account Kits docs.

Frequently Asked Questions
What are AI agent permissions?+
AI agent permissions define which capabilities an agent is allowed to use — which tools, which APIs, which third-party apps, and under what limits. For them to be trustworthy they must be enforced by the platform at execution time, not merely described in the system prompt, because a prompt instruction can be overridden by a crafted input.
Why can't I just tell the agent what it's allowed to do in the prompt?+
Because a prompt is a suggestion, not a control. Prompt injection, jailbreaks, and simple model error can all lead an agent to ignore 'don't do X.' Real permissions are checked server-side on every call, so an action the policy forbids fails regardless of what the model was convinced to attempt.
How do Account Kits enforce permissions?+
An Account Kit is a policy template you assign to a tenant user. Its `primitives_config` enables specific primitives (with defaults like a card spending limit), and its `connections_config` controls which third-party apps and even which individual tools are available. Naïve enforces the kit on every agent call, so permissions are configuration rather than per-request code.
Can I restrict an agent to specific tools within an app?+
Yes. Within an allowed toolkit you can enable or disable individual tools — for example, allow Gmail but only read and send, nothing else. App access itself has three modes: open (all apps), allowlist (only listed apps), or blocklist (all except listed), so you can be as broad or tight as each customer tier needs.
Which actions require human approval by default?+
Cards, domains, verification, formation, and connecting a new app default to requiring approval — the agent's action freezes as a pending approval (HTTP 202) until a human decides. You can opt a primitive out with `requiresApproval: false`. Human callers from the dashboard or a session are not subject to the approval gate; only agent (API-key/MCP) calls are gated (per published docs).
Do I configure permissions per user?+
You don't have to. You author a small number of Account Kits — for instance Starter, Pro, and Enterprise — and assign the right one to each tenant user. Change the kit and every user on it updates at once, which is what makes least-privilege practical across thousands of customers.
NT
Naïve Team

Building the agent-native backend.

Keep reading