Escrow
Budget tracking, condition holds, approvals, and circuit breakers for Vant.
What
Escrow is Vant’s “final validation gate” before execution:
- Budget tracking - Monitor spending per agent
- Condition holds - Wait for conditions before proceeding
- Approval gates - Require approval for sensitive operations
- Circuit breakers - Fail fast on failing services
Quick Start
Import escrow:
const { Escrow } = require('./lib/escrow');
const escrow = new Escrow();
Budget
Track agent spending.
Set budget for an agent:
escrow.setBudget('agent-1', 10000);
console.log(escrow.getBudget('agent-1'));
// { limit: 10000, spent: 0, available: 10000 }
Check Spending
Check if operation is allowed:
const { allowed, reason, available } = escrow.canSpend('agent-1', 100);
console.log(allowed); // true
console.log(reason); // "budget_available"
Record Spending
Record a transaction:
escrow.recordSpend('agent-1', 50);
console.log(escrow.getBudget('agent-1').spent); // 50
Refund
Refund a transaction:
escrow.refund('agent-1', 25);
console.log(escrow.getBudget('agent-1').spent); // 25
Cost Configuration
Configure operation costs:
escrow.setCost('read', 1);
escrow.setCost('write', 5);
escrow.setCost('delete', 10);
escrow.setCost('admin', 50);
Get cost for an operation (falls back to _costs.default):
console.log(escrow.getCost('write')); // 5
Budget methods: setBudget(agentId, budget) / setBudgetLimit(agentId,
limit) / canSpend / recordSpend / refund / getBudget.
Holds
Hold execution until conditions are met.
Create a hold:
const r = escrow.hold('task-1', 'user_confirmation');
// { held: true, holdId } - or { held: false, reason: 'max_holds_exceeded' }
The hold carries the CONDITION (a string tag) and expires after
options.holdTimeout (default 300000 ms) - there is no per-hold timeout
option.
Check a hold:
escrow.checkHold('task-1');
Release hold:
escrow.release('task-1');
Approvals
Require approval for sensitive operations.
Request approval (sig: (operation, reason); no options object):
const approval = escrow.requestApproval('delete', 'Delete all user data');
// auto-approved immediately when the op needs none:
// { approved: true, reason: 'auto_approved' }
// otherwise:
// { approvalId: '<hex>', approved: false }
Approve
Approve an operation:
escrow.approve(approval.approvalId, 'admin');
Check
escrow.checkApproval(approval.approvalId);
(There is no reject method - deny by simply not approving; the
approval stays approved: false.)
Default Required
Operations that require approval by default:
// Default: ['delete', 'admin', 'write:critical']
console.log(escrow.options.approvalRequired);
Circuit Breaker
Integrate with service circuit breakers (crew-bus aware):
Check service:
const isOpen = escrow.isOpen('payment-svc');
console.log(isOpen); // false (closed = OK)
Open circuit on repeated failures:
for (let i = 0; i < 5; i++) {
escrow.recordFailure('payment-svc');
}
console.log(escrow.isOpen('payment-svc')); // true
Record successes and reset:
escrow.recordSuccess('payment-svc');
escrow.resetCircuit('payment-svc'); // via getBreaker().reset(service)
Before Execute
Validate operation before execution:
const result = await escrow.beforeExecute({
agentId: 'agent-1',
operation: 'read',
cost: 5,
service: 'db'
});
console.log(result.allowed); // true | false
console.log(result.reason); // reason string on refusal
This is the main entry point - sandbox operations go through this
(async; isOperationAllowed(op, ctx) delegates to it).
Quotas
Track quota usage per agent+operation pair. Quotas come from
options.defaultQuota + options.quotaWindow (defaults in the
constructor); there is no setQuota() method:
// checkQuota(agentId, operation = 'default')
const { allowed, used, limit } = escrow.checkQuota('agent-1', 'api');
// record usage yourself
escrow.incrementQuota('agent-1', 'api');
The window resets automatically when quotaWindow elapses.
Integration
Escrow integrates with sandbox:
const sandbox = require('./lib/sandbox');
const s = sandbox.create({
agentId: 'agent-1',
budget: 10000
});
When sandbox runs operations:
const result = s.write(() => doWork());
if (result.error) {
console.log(result.code); // "BUDGET_EXCEEDED" | "APPROVAL_REQUIRED"
}
See Sandbox for details. —