Docs
The tool policy JSON, field by field
Every in/guard/out API key can carry one small JSON object that decides what the agents using that key may do: which tools they may call, up to which risk level, which actions need a human, and what personal data may leave through a tool call. You edit it in the dashboard's Keys tab – a guided form with a JSON view, so you never have to write it blind.
One policy is enforced from all three surfaces: tool calls the model proposes at the LLM boundary, MCP tools/call requests at the gateway, and non-LLM workflow steps asking the checkpoint API. In PREVENT mode a violation blocks the call; in FIX mode it is flagged and recorded. A key with no policy configured skips these checks entirely – nothing here affects plain chat traffic.
The whole object at a glance
{
"mode": "allowlist",
"allow": ["lookup_*", "search_orders", "send_email", "pay_invoice"],
"deny": ["*_admin", "drop_*"],
"authorized_tier": "write",
"risk_tiers": { "pay_invoice": "payment", "send_email": "network" },
"approval_tiers": ["payment", "delete"],
"pii_egress": {
"send_email": ["EMAIL_ADDRESS", "PERSON"],
"*": []
}
}| Field | Default | What it does |
|---|---|---|
| mode | "denylist" | How the allow/deny lists combine: "allowlist" (only listed tools run) or "denylist" (everything runs except deny matches). |
| allow | [] | Glob patterns for permitted tools. Only enforced in allowlist mode, and only when non-empty. |
| deny | [] | Glob patterns for forbidden tools. Checked in both modes – a deny match always wins. |
| authorized_tier | unset | The highest risk tier this key may use. A call above it is a permission escalation. Unset = no tier ceiling. |
| risk_tiers | unset | Overrides the tier a tool is classified into, by exact tool name (not a glob). Unlisted tools fall back to name heuristics. |
| approval_tiers | [] | Tiers that park a checkpoint call on human approval instead of allowing it. Read by the checkpoint API only. |
| pii_egress | unset | Maps a tool (glob) to the PII entity types it may receive. Unset = PII egress is observed, not policed. |
Every field is optional. Argument schemas are not part of the policy – they come from the tools definitions your request already declares, and calls are validated against them automatically.
Allow and deny lists
The core of the policy. Patterns are globs – lookup_* matches lookup_order and lookup_vendor. In allowlist mode, a tool that matches no allow pattern is a violation. In denylist mode (the default), everything is permitted except deny matches. The deny list is checked in both modes and always wins – so you can allowlist db_* while still denying db_admin.
{
"mode": "allowlist",
"allow": ["lookup_*", "search_orders", "send_email"],
"deny": ["*_admin"]
}Start with an allowlist of exactly the tools your agent legitimately uses. It is the single highest-leverage line of the policy: a prompt-injected instruction can steer the model toward any tool, but it cannot add one to this list.
Risk tiers and the authorized ceiling
Every tool call is classified into one of six risk tiers, ordered from harmless to consequential. Setting authorized_tier declares the highest tier this key is entitled to: any call above it is flagged (FIX) or blocked (PREVENT) as a permission escalation. If you never set it, no tier ceiling is enforced – the classification still appears in logs and the run graph.
| Tier (low → high) | Name substrings that map to it | Meaning |
|---|---|---|
| read | Everything not matched below | The default – lookups, searches, reads |
| network | http, fetch, request, curl, download, send, post, email, browse, url | Talks to the outside world |
| write | write, create, update, insert, save, edit, append, modify, set_, put_, upload | Changes state |
| exec | exec, shell, eval, spawn, command, run_, subprocess, system | Runs code |
| delete | delete, remove, destroy, drop, rmdir, unlink, purge | Destroys state |
| payment | charge, pay, transfer, refund, invoice, purchase, checkout, wire | Moves money |
The substring heuristic resolves to the most dangerous match (delete_and_pay is payment, not delete), and an unmatched name defaults to read. When a tool's name doesn't reveal what it does, pin it explicitly with risk_tiers – exact tool names, not globs:
{
"authorized_tier": "write",
"risk_tiers": { "issue_store_credit": "payment", "notify_customer": "network" }
}Independent of tiers, arguments are always scanned for classic destructive patterns – rm -rf, path traversal, sudo, piped installers, leaked AWS or private keys. Those checks are built in and need no configuration.
Approval tiers: the human in the loop
approval_tiers is read by the checkpoint API – the endpoint your workflow calls before a consequential non-LLM step (via the n8n Checkpoint node, the Python SDK, or a plain HTTP call). The decision logic is simple: a call that violates the policy is deny; a clean call whose tier is listed in approval_tiers is require_approval; everything else is allow.
{
"authorized_tier": "payment",
"approval_tiers": ["payment", "delete"]
}With that policy, a payment is within the key's authority – but it parks on a human every time:
POST /v1/checkpoint
Authorization: Bearer gr-...
X-Guardrails-Session-Id: run-42
{
"action": { "name": "pay_invoice", "arguments": { "iban": "DE89...", "amount": 4200 } },
"session_id": "run-42"
}
→ { "decision": "require_approval", "tier": "payment", "violations": {}, "request_id": "..." }Your workflow routes the three decisions however it likes – the n8n node exposes them as three outputs; wire Require Approval to a Slack sign-off and Deny to a stop path. The decision is recorded as a step in the same run as the agent's LLM calls.
PII egress: what may leave through a tool
in/guard/out screens PII into placeholders before anything reaches the model, so it knows exactly which values in a tool call are sensitive. pii_egress decides which tools may receive which PII entity types. Matching is by glob, the most specific pattern wins, "*" is the fallback – and a tool matched by nothing may receive no PII at all.
{
"pii_egress": {
"send_email": ["EMAIL_ADDRESS", "PERSON"],
"crm_*": ["PERSON", "PHONE_NUMBER", "EMAIL_ADDRESS"],
"*": []
}
}That policy reads: send_email may carry a customer's email address and name, CRM tools may carry contact details, and every other tool gets no PII. Entity types are Presidio's – EMAIL_ADDRESS, PERSON, PHONE_NUMBER, CREDIT_CARD, IBAN_CODE, US_SSN and the rest.
If you leave pii_egress out entirely, PII egress is observed rather than policed. Two things are violations regardless of any policy: the system-prompt canary appearing in tool arguments, and raw secrets (an AWS key, a private key) leaving through a tool call.
Two worked examples
An invoice-payment agent
Three tools, nothing else. Payments are within authority but always parked on approval; no PII leaves through any tool.
{
"mode": "allowlist",
"allow": ["fetch_invoice", "lookup_vendor", "pay_invoice"],
"authorized_tier": "payment",
"risk_tiers": { "pay_invoice": "payment" },
"approval_tiers": ["payment"],
"pii_egress": { "*": [] }
}A support agent
May read, update tickets, and email the customer – capped at the network tier, so a write to billing or a delete is an escalation. Only the email tool may carry contact PII.
{
"mode": "allowlist",
"allow": ["search_kb", "get_ticket", "update_ticket", "send_email"],
"deny": ["*_admin", "delete_*"],
"authorized_tier": "network",
"pii_egress": { "send_email": ["EMAIL_ADDRESS", "PERSON"], "*": [] }
}Two things this JSON deliberately does not contain. Budgets (per-run cost, step, and tool-call ceilings) are account settings, not per-key policy. And ordering rules – "payment only after vendor lookup" – live in a separate, versioned sequence policy, which you can write by hand or compile from an n8n workflow export in the same Keys tab.
Rollout advice is the same as everywhere in in/guard/out: configure the policy, run in FIX (observe) mode, watch the Runs tab for a few days, then flip the key to PREVENT once the flags match your intent.
Keep reading
Build the policy in the dashboard, not a text editor.
The Keys tab has a guided editor for everything on this page – with a JSON view when you want it. We're running a limited demo – sign up and we'll get you in as soon as we can.