The budget that actually blocks.
Bridle sits in front of a payment: it reserves budget before paying, commits on settlement, releases on failure. It holds under real concurrency and fails closed — so an agent cannot overspend, even when twenty requests land at the same millisecond.
Watch the budget hold
One agent, a $50 window, twenty $4 payments fired at once. Flip between a naïve guardrail and Bridle, then fire.
The failure isn't the limit. It's concurrency.
A naïve guardrail checks spent + amount ≤ limit, then inserts. Fire twenty
parallel requests and every one reads the same remaining balance, every one passes, and the
agent overspends — while the unit tests stay green, because a mock has no notion of two
things happening at once. You can't SELECT sum(…) FOR UPDATE an aggregate, and
row locks don't protect a brand-new agent with zero rows. Bridle locks the decision,
not the data — and ships the proof.
Reserve → commit → release
Budget is reserved before the payment and committed on settlement. Decisions happen before money moves, not reconciled after.
Concurrency guarantee
Serialized per (agent, currency) with a Postgres advisory lock — even with no ledger row yet. A ≥20-way real-Postgres test fails CI if the DB is missing.
Declarative policy engine
Recipient allow/deny lists, per-category limits, and time windows — evaluated inside the same lock, with deterministic precedence.
Auditable decisions
Every allow and deny goes to a pluggable audit sink with a reason code. Best-effort and isolated — a failing sink can never break a valid payment.
Non-custodial, cross-rail
Bridle never holds keys and never moves funds — it only counts and decides. It sits above any wallet, rail, or x402 facilitator you bring.
Fail closed, by design
No policy, missing context, an unknown rule → deny with a typed error. A guardrail that fails open is not a guardrail.
Wrap a payment. Get the guarantee.
You bring the Postgres pool and the payment call; Bridle decides. Fail-safe by default — with no policy and no default budget, it denies.
import { BridleGuard } from '@igarzatech/bridle'; import { PostgresStorageAdapter } from '@igarzatech/bridle/postgres'; import { Pool } from 'pg'; // You own the pool. Bridle never creates connections or holds funds. const storage = new PostgresStorageAdapter(new Pool()); await storage.migrate(); const guard = new BridleGuard({ storage, config: { defaultBudget } }); // Reserve before paying. Under concurrency, exactly the budget gets through. await guard.checkAndReserve({ agentAddress, currency: 'USDC', amount: '4.00', reservationId }); await pay(); // your rail / x402 facilitator await guard.commit(reservationId); // or .release() on failure