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
- Per payment —
amountGt: refuse any single payment above a price. - Rolling budget —
rollingSum: { window, gt }: refuse the payment that would take the last hour, day or week over a total. - Velocity —
txCount: { window, gt }: refuse the 51st call in an hour, whatever each one cost. - Per task —
taskBudget: { gt }: cap one unit of work, so one runaway job cannot spend the day's budget. - Breakers — an envelope that escalates to a human instead of denying: the payment is parked until someone releases it with a signature.
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:
{
"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:
{
"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:
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
- Denied payments never exist: the guard stops before a signature, so there is nothing to refund.
- Escalated payments wait for a human to sign the decision. The wait has a timeout, and a timeout is a deny.
- Every decision is signed and hash-chained, so the record of what was allowed cannot be quietly edited.
- Fail-closed: if the policy engine cannot be reached, the payment is refused, not waved through.
To watch a budget refuse its fifth payment on your own machine, with no account, chain or funds, follow the five-minute runbook.