How do I cap what my AI agent spends?

Short answer

Put the limit outside the model, between the agent and its wallet. With Rein, every payment an agent attempts is checked against a policy you write — a per-payment cap, a rolling budget, a per-task budget — before the payment is built. A payment over the limit is refused with nothing signed, sent or refunded. Rein never holds the agent's funds; it governs the agent's authority to spend them.

Why a prompt is not a cap

"Never spend more than $5" in a system prompt is an instruction to the same model that a prompt injection, a confused tool result or a retry loop can talk out of it. A cap only holds if the thing enforcing it is something the agent cannot reach. In Rein that is a policy engine: the agent can ask it for permission, and nothing else.

The limits that matter

Write the policy

A policy is data. This one caps any single payment at $0.50, the hour at $2, and any one task at $1:

policy.json
{
  "policyId": "research-agent-limits",
  "appliesTo": { "agents": ["agt_01J..."] },
  "rules": [
    { "id": "tx-cap",      "deny": { "amountGt": "0.50" } },
    { "id": "hour-budget", "deny": { "rollingSum": { "window": "1h", "gt": "2.00" } } },
    { "id": "task-budget", "deny": { "taskBudget": { "gt": "1.00" } } }
  ],
  "breakers": [{ "id": "velocity", "window": "24h", "txCount": 20, "valueCap": "5.00" }],
  "default": "allow"
}

Precedence is fixed: deny > escalate > allow > the policy default. An explicit deny always wins.

Put the agent behind it

If the agent runs in Claude Code, Cursor or any MCP harness, no code is needed. It gets a rein_fetch tool that pays only when policy allows:

mcp config
{
  "mcpServers": {
    "rein": {
      "command": "npx",
      "args": ["-y", "@reinconsole/mcp"],
      "env": {
        "REIN_ENGINE_URL": "http://127.0.0.1:8787",
        "REIN_AGENT_ID": "agt_01J..."
      }
    }
  }
}

If the agent is your own program, wrap its fetch once:

agent.mjs
import { createGuard } from '@reinconsole/sdk';

const guard = createGuard({ engineUrl: 'http://127.0.0.1:8787', agentId: 'agt_01J...' });
const fetch = guard.wrap(); // every x402 paywall now goes through the policy

What happens at the limit

To watch a budget refuse its fifth payment on your own machine, with no account, chain or funds, follow the five-minute runbook.

Related questions