policy.cedar CEDAR · UTF-8
 1// policy.cedar
 2permit(
 3  principal == Agent::"agent_marketing_bot",
 4  action in [Action::"gmail.send"],
 5  resource
 6) when 
 7  context.to_domain == "example.com" &&
 8  context.body_length < 2000
 9;

$ WARRANT CLAW

Your agents. Your rules.

The Cedar policy gate between your AI agent and Gmail. Mint an API key, bind a policy, and every send, read, or draft is evaluated before it leaves the proxy.

# 01 / POLICY PRESETS

Ship with a preset. Harden with your own.

Every API key binds to a Cedar policy set. Start with a preset, fork it, or drop in your own. Evaluated in-process; denied calls never touch Gmail.

read_only.cedar PRESET
 1// safe-by-default.
 2permit(
 3  principal,
 4  action in [
 5    Action::"gmail.list",
 6    Action::"gmail.get",
 7    Action::"gmail.search"
 8  ],
 9  resource
10);
11forbid(principal, action, resource)
12  unless  action in ReadOnly ;
draft_only.cedar PRESET
 1// write, but never send.
 2permit(
 3  principal,
 4  action in [
 5    Action::"gmail.drafts.create",
 6    Action::"gmail.drafts.update"
 7  ],
 8  resource
 9) when 
10  context.body_length < 8000
11;
12forbid(principal, Action::"gmail.send");
send_allow_domains.cedar PRESET
 1// send, but only to listed domains.
 2permit(
 3  principal,
 4  action == Action::"gmail.send",
 5  resource
 6) when 
 7  context.to_domain in [
 8    "example.com",
 9    "partner.co"
10  ] &&
11  context.attachments == 0
12;

# 02 / AUDIT LOG — every call, forever

Every tool call, evaluated and audited in D1.

Every principal, action, resource, and context is committed to Cloudflare D1 before the proxy talks to Gmail. Streamed to your dashboard; queryable by agent, action, or verdict.

tail -f ~/audit/decisions.log LIVE
2026-04-17T09:12:33Z gmail.send ALLOW agent_marketing_bot to=alice@example.com body=412b
2026-04-17T09:12:41Z gmail.search ALLOW agent_support_bot q="invoice" limit=25
2026-04-17T09:13:02Z gmail.send DENY agent_marketing_bot to=bob@evil.com constraint_failed:to_domain
2026-04-17T09:13:17Z gmail.drafts.create ALLOW agent_copy_writer subject="Week 16 recap" body=1.8kb
2026-04-17T09:13:24Z gmail.list ALLOW agent_triage label=INBOX unread=true
2026-04-17T09:13:39Z gmail.send DENY agent_copy_writer to=press@competitor.io constraint_failed:allow_list
2026-04-17T09:13:55Z gmail.get ALLOW agent_support_bot msg=18c9f1a label=CUSTOMER
2026-04-17T09:14:02Z gmail.send ALLOW agent_marketing_bot to=dana@example.com body=1.1kb
2026-04-17T09:14:18Z gmail.send DENY agent_triage to=anyone@anywhere.net policy:read_only
2026-04-17T09:14:27Z gmail.drafts.update ALLOW agent_copy_writer draft=r_8f2 body=3.2kb
store: cloudflare d1 retention: forever export: CSV · JSONL · Webhook

# 03 / WIRED IN

One proxy, four moving parts.

No SDK to adopt. Your agent points at the Warrant Claw endpoint with an API key; we do the rest.

 AGENT                API KEY              WARRANT CLAW            CEDAR                 GMAIL
┌───────────────┐     ┌───────────────┐     ┌───────────────┐     ┌───────────────┐     ┌───────────────┐
│  tool_call    │ ──► │  sk_...       │ ──► │  evaluate +   │ ──► │  permit /     │ ──► │  send / read  │
│  (json-rpc)   │     │  per agent    │     │  audit (D1)   │     │  forbid       │     │  draft / list │
└───────────────┘     └───────────────┘     └───────────────┘     └───────────────┘     └───────────────┘
        ▲                      │                      │                      │                      │
        │                      ▼                      ▼                      ▼                      ▼
        └──── retries on DENY ──── bind policy ──── commit row ──── decision ──── upstream 200 ────┘
▸ API KEY An sk_... token scopes every call to one agent identity and one policy bundle.
▸ CEDAR Your bound policies run in-process on every request. Context (to, domain, body length, attachments) is passed in.
▸ AUDIT Verdicts and payload digests are committed to Cloudflare D1 before any bytes hit Gmail. Nothing ships unlogged.