Spend guardrails

Add spend guardrails to CrewAI

Screwtape.ai decides whether an AI agent is allowed to spend money, and keeps the proof. Call POST /v1/judge before any payment. Pay only on pass. Screwtape advises and records; your CrewAI code must honor the verdict.

Install-free snippet

Evidence is an array of strings. Free: 3 calls/day with no key, 10/day with a free key.

import os, requests

def spend_allowed(task: str, planned_action: str, evidence: list[str] | None = None) -> dict:
    headers = {"content-type": "application/json"}
    if os.getenv("SCREWTAPE_KEY"):
        headers["authorization"] = f"Bearer {os.environ['SCREWTAPE_KEY']}"
    r = requests.post(
        "https://screwtape.ai/v1/judge",
        headers=headers,
        timeout=20,
        json={"task": task, "agent_output": planned_action, "evidence": evidence or []},
    )
    if r.status_code != 200:
        return {"verdict": "fail", "reasons": [f"check unavailable: HTTP {r.status_code}"]}  # fail closed
    return r.json()

# Call before any payment. Pay only on pass.
v = spend_allowed(
    "Pay invoice INV-42 from Acme",
    "Pay $120.00 to Acme",
    ["PO-42: Acme, $120.00"],
)
if v["verdict"] == "pass":
    pay()  # your payment call
elif v["verdict"] == "retry":
    fix_and_retry(v["reasons"])
else:
    ask_a_human(v["reasons"])

# Optional: catch a duplicate invoice first
# POST https://screwtape.ai/v1/duplicate with the same Bearer key
# Optional: reserve against a shared run cap
# POST https://screwtape.ai/v1/budget  {run_id, event_id, amount, cap, merchant}
# Optional: sign what the agent did
# POST https://screwtape.ai/v1/receipt  {agent_id, event_id, action, status}

Why check before a CrewAI payment?

Agents can pay the wrong amount, the wrong party, or the same invoice twice. Screwtape returns pass, fail, or retry with reasons and a signed receipt so your code can stop before the payment runs.

Do I need to install a package?

No. Call HTTPS endpoints with your HTTP client. Optional free API key via POST /v1/signup. Without a key you still get a small shared free allowance per day.

What if the check is unavailable?

Fail closed: treat a non-200 response as fail and do not pay. The snippets below do that.

How do I catch a duplicate invoice?

POST /v1/duplicate with the invoice fields before or instead of judge. It returns unique, duplicate, possible_duplicate, or replay.

How do I share a budget across agents?

POST /v1/budget with run_id, event_id, amount, cap, and merchant. Honor block. Children inherit the root cap.

How do I keep proof of what the agent did?

POST /v1/receipt with agent_id, event_id, action, and status. Verify for free at GET /v1/receipt/verify or on /verify/. To close a whole run, send children: a list of prior receipt ids; the summary signs a root digest over them.

All spend-guardrail guides · Framework connection examples · Machine-readable API notes · Verify a receipt · Receipt format