Platform

The platform, component by component.

Every agent call -- Gmail send, Drive read, database query, browser click -- is checked against a per-user, per-tool permission map before it reaches the downstream system. This page is what that looks like in practice.

01   What you get

Six capabilities that add up to one enforcement point.

[ 01 ]

Scoped permissions

Per-tool permission keys, scoped to the user. Checks happen in the logic layer, not the transport. No path bypasses the check.

[ 02 ]

Sub-tokens

Issue a bearer token scoped to a subset of your own permissions, with a TTL and usage tracking. Revocation is immediate.

[ 03 ]

Guardrails

Pre-execution, real-time, and post-execution checks: injection, PII redaction, sensitive-topic filtering, human-in-the-loop for high-risk actions.

[ 04 ]

Audit trail

Every action, token use, and permission change is logged with append-only semantics and optimistic locking at the data layer.

[ 05 ]

Per-user credentials

OAuth refresh tokens stored encrypted per user, rotated on a timer, never shared across tenants.

[ 06 ]

Transport agnostic

Web, REST, and MCP all pass permissions down to the same logic layer. One enforcement point, three entry points, identical semantics.

02   Deep dive

How each component works.

[ 01 ] Scoped permissions

The check happens in the logic module, not the transport.

Each protected module declares its permission keys and uses the AccessControlled macro. Every transport -- Web, REST, MCP -- passes the user's permission map down to that module. If the key is missing, the call returns {:not_allowed, reason} and every transport translates that into its own response format.

Permission keys never leave the server process. They are not serialised into responses, cookies, or logs.

# in every protected module
@permission Permissions.Keys.gmail()
@module_name "Gmail"
use AccessControlled

# at request time
with :ok <- allowed?(perms),
      :ok <- guardrails(args),
      {:ok, r} <- execute(args) do
     audit.log(...)
     {:ok, r}
end
[ 02 ] Sub-tokens

Agents should not inherit their owner's full reach.

A sub-token (prefix st_) is a bearer token scoped to a strict subset of the owner's permissions, with a TTL, usage counter, and audit trail. At authentication time the sub-token's scope intersects with the owner's current permission map before anything downstream sees it.

Revocation is immediate: strip the owner of a key, and every sub-token scoped to it stops working on the next request.

# sub-token record
{
  "id": "st_a1b2c3...",
  "owner": "james",
  "scope": ["Gmail", "Calendar"],
  "expires_at": 1713456000000,
  "use_count": 34,
  "last_used_at": 1713455912000
}

# at the router
scope ∩ owner.permissions → effective
[ 03 ] Guardrails

Three checkpoints per action.

Pre-execution blocks injection, path traversal, and malformed requests before they reach your systems. Real-time requires human approval for high-risk operations. Post-execution redacts PII and strips credentials before outputs reach the agent.

  • Prompt injection prevention
  • PII detection across 20+ categories
  • Content-safety classification with configurable thresholds
  • Topic filters (medical, legal, financial)
  • Custom rules expressed as code, not configuration
# guardrail pipeline
pre  → injection / path check
mid  → human-approval gate
post → PII redaction

# on high-risk call
"agent wants to DELETE
 FROM production.orders
 WHERE ... -- approve?"
[ 04 ] Audit trail

What happened is always knowable.

Every tool call, every permission change, every sub-token use is logged with user, agent, inputs, outputs, and cost. Append-only. Optimistic locking at the database layer means concurrent writes fail loud rather than silently corrupt.

Primary keys are millisecond timestamps, so id / 1000 is the creation Unix second. Creation time is free on every row.

{
  "agent": "sales-agent",
  "user": "[email protected]",
  "tool": "crm.search_contacts",
  "args": { "query": "Acme" },
  "checks": {
    "scope": "passed",
    "pii": "passed"
  },
  "latency_ms": 42,
  "cost_usd": 0.0018
}
03   Integration surface

Point any client at AI Agent Gateway and inherit the enforcement model.

No framework rewrites. No new SDK. Three transports, one enforcement point.

Transport Typical client Shape of call
MCP (Model Context Protocol) Claude, Cursor, MCP-aware agents tools/call over JSON-RPC with bearer token
REST / HTTPS Scripts, backend services, legacy agents Conventional JSON over HTTPS
WebSocket (WSS) Long-lived agents, browser extensions Message-framed bidirectional channel
04   Deployment

One instance per customer. In your infrastructure.

[ 01 ] SELF-HOSTED

Inside your VPC.

One virtual machine, one process tree, one SQLite per module. Runs on the Erlang VM (BEAM), the same runtime that powers RabbitMQ.

[ 02 ] AIR-GAPPED

No external dependencies.

Runs in fully isolated networks. Credential encryption is local. No telemetry, no phone-home, no third-party services required.

[ 03 ] MANAGED

Dedicated single-tenant cloud.

We run it for you on a dedicated instance. No multi-tenancy. Your data never touches another customer's process tree.

05   Start

Deploy in five minutes. No agent changes required.

Every agent call routes through AI Agent Gateway before it reaches its target. Per-user, per-tool permissions; configurable guardrails; one row per request in the audit log; the agent never holds the credentials.