Paperclip Budget Control Features: A Complete Guide to Spend Management and Enforcement
Paperclip implements budgets as first‑class control‑plane resources with automatic enforcement, soft‑threshold alerts, hard‑stop pausing, and board‑approval workflows.
The Paperclip AI platform treats financial governance as a core infrastructure concern. Its budget system lets organizations set spending limits on companies, agents, or projects—with automatic enforcement that prevents over‑spend without human intervention. This article examines every budget control feature in paperclipai/paperclip, referencing actual source paths and implementation details.
What Paperclip Budget Policies Define
A budget policy stores the complete configuration for spending control. In server/src/services/budgets.ts, the upsertPolicy function (lines 509‑570) handles creation and updates.
Each policy contains:
amount— limit in centswindowKind— time window for spend aggregation (e.g.,calendar_month_utc)warnPercent— threshold for soft alerts (default typically 80%)hardStopEnabled— whether to pause scope when limit is hitnotifyEnabled— controls notification deliveryisActive— soft‑delete flag
await apiClient.patch(
"/api/companies/abc123/budgets",
{
scopeType: "agent",
scopeId: "agent-42",
amount: 500_000, // $5,000.00 per month
windowKind: "calendar_month_utc",
warnPercent: 80,
hardStopEnabled: true,
notifyEnabled: true,
isActive: true,
},
);
Policies can target three scope types: company, agent, or project. The service validates scope ownership before persisting to the budget_policies table.
How Paperclip Calculates Observed Spend
The computeObservedAmount function (lines 58‑66) aggregates cost_events.costCents for the relevant scope and time window. This query runs on every cost event evaluation.
// Pseudo-code representing the aggregation logic
const observed = await db
.select({ total: sum(cost_events.costCents) })
.from(cost_events)
.where(
and(
eq(cost_events.scopeType, policy.scopeType),
eq(cost_events.scopeId, policy.scopeId),
gte(cost_events.timestamp, windowStart),
lte(cost_events.timestamp, windowEnd)
)
);
Cost events represent actual infrastructure spend—LLM tokens, compute time, or external API calls. The budget engine is event‑driven: spend updates propagate in near‑real‑time.
Soft‑Threshold Alerts in Paperclip
When observed spend reaches the warning percentage, Paperclip creates a soft incident without interrupting operations. In evaluateCostEvent (lines 73‑81), the soft branch fires:
if (observed >= policy.amount * (policy.warnPercent / 100)) {
// Soft threshold breached
await createIncidentIfNeeded({
policyId: policy.id,
thresholdType: "soft",
// ...
});
// UI alert rendered via ui/src/lib/attention.ts
}
Soft incidents appear in:
- The Inbox (attention system)
- Dashboard status cards (
ui/src/lib/status-card-state.ts) - Notification channels if
notifyEnabledis true
These alerts give teams advance warning to adjust usage or request budget increases before hard enforcement triggers.
Hard‑Stop Enforcement and Automatic Pausing
If spend exceeds the budget amount and hardStopEnabled is true, Paperclip executes hard enforcement. The evaluateCostEvent hard branch (lines 93‑101) invokes:
createIncidentIfNeeded— records the threshold crossing inbudget_incidentspauseAndCancelScopeForBudget— immediately halts the scope and cancels in‑flight work
// Hard-stop branch in evaluateCostEvent
await pauseScopeForBudget(scopeType, scopeId, {
pauseReason: "budget_exhausted",
});
await cancelWorkForScope(scopeType, scopeId); // aborts queued/running work
Scope pausing updates the target's status fields with timestamps. The optional cancelWorkForScope hook—provided by the orchestration layer—guarantees zero additional spend during the pause state.
Hard‑stop incidents also generate a budget‑override approval that board members must approve before resumption. This creates an auditable governance checkpoint.
Budget Incident Lifecycle and Board Approvals
The budget_incidents table tracks every threshold crossing. The createIncidentIfNeeded function (lines 50‑68) ensures idempotency—duplicate events for the same threshold don't spawn multiple incidents.
| Incident Field | Purpose |
|---|---|
thresholdType |
soft or hard |
status |
open, dismissed, or resolved |
requiresApproval |
true for hard stops with override workflow |
createdAt / resolvedAt |
Audit timestamps |
Board members resolve incidents via resolveIncident (lines 71‑115). Supported actions:
raise_budget_and_resume— increases policy amount, clears pause, marks resolveddismiss— anomaly dismissal without budget change
await apiClient.patch(
"/api/companies/abc123/budget-incidents/incident-99",
{
action: "raise_budget_and_resume",
amount: 750_000, // raise to $7,500.00
decisionNote: "Approved after review",
},
);
This workflow ensures no automatic resumption without human approval—a critical safety property for financial governance.
Automatic Resume When Budgets Increase
The upsertPolicy function includes automatic resume logic (lines 94‑106). When a new budget exceeds current observed spend for a paused scope, the system:
- Detects the pause state via
status/pauseReasonfields - Invokes
resumeScopeFromBudgetto clear the pause flag - Enables normal operation without manual intervention
This balances safety with ergonomics: raising a budget automatically unblocks work, but only when the new limit legitimately covers existing spend.
Invocation Guard: Blocking Agents at Runtime
Before any agent wakes, getInvocationBlock (lines 18‑64) checks company, agent, and project budgets. If any applicable policy is in hard‑stop state:
const block = await apiClient.post(
"/api/agents/agent-42/invocation-block",
{ companyId: "abc123" },
);
if (block) {
console.log(`Cannot invoke: ${block.reason}`);
// Returns { blocked: true, reason: "Budget exhausted for agent agent-42" }
}
The guard evaluates all three scope levels and returns the most restrictive block. This prevents race conditions where an agent might invoke despite a parent‑level budget exhaustion.
Budget Dashboard and Operational Visibility
The overview function (lines 30‑46) aggregates policy health for executive visibility:
const overview = await apiClient.get("/api/companies/abc123/budgets/overview");
// Response includes:
// - policies[] with amount, observedAmount, status, paused flags
// - activeIncidents[] with severity and approval status
// - pausedAgentCount, pausedProjectCount
// - pendingApprovalCount for board action items
This powers the budget dashboard in ui/src/api/budgets.ts, showing:
- Real‑time spend vs. limit percentages
- Which scopes are paused and why
- Outstanding approval requests requiring board attention
Key Implementation Files in Paperclip
| File | Budget Responsibility |
|---|---|
server/src/services/budgets.ts |
Core engine: policy CRUD, spend aggregation, incident handling, pause/resume logic |
packages/db/src/schema/*.ts |
Database schema: budget_policies, budget_incidents, cost event relationships |
ui/src/lib/status-card-state.ts |
UI mapping for "Paused — budget" status indicators |
ui/src/lib/attention.ts |
Inbox and board alert rendering for budget events |
ui/src/api/budgets.ts |
Frontend API client for budget endpoints |
doc/spec/agent-runs.md |
Agent‑run specification including budget_blocked terminal state |
doc/plans/2026-03-14-budget-policies-and-enforcement.md |
Design document for the budgeting model |
Summary
- Budget policies define spend limits per company, agent, or project with configurable windows and thresholds
- Soft alerts fire at warning percentages without interrupting work
- Hard stops automatically pause scopes and cancel in‑flight work when limits are exceeded
- Board approvals gate resumption through explicit override workflow with audit logging
- Automatic resume occurs when budget increases legitimately cover existing spend
- Invocation guards block agent wake‑ups at runtime when budgets are exhausted
- Dashboard overview provides operational visibility into policy health and pending actions
Frequently Asked Questions
How does Paperclip prevent agents from running when a budget is exhausted?
Paperclip's getInvocationBlock function checks company, agent, and project budgets before every agent invocation. If any applicable policy is in hard‑stop state, the call returns a block object with a descriptive reason and the agent wake‑up is prevented. This guard runs in server/src/services/budgets.ts lines 18‑64.
What happens when a Paperclip budget reaches the soft warning threshold?
At the soft threshold (default 80% of limit), Paperclip creates a budget_incidents row with thresholdType: "soft" and triggers UI alerts via the attention system. No work is interrupted. The incident appears in the Inbox and on dashboard status cards until dismissed or the budget increases.
Can a paused agent or project resume automatically in Paperclip?
Yes, but only when the budget condition is legitimately resolved. The upsertPolicy function automatically resumes paused scopes when a new budget amount exceeds current observed spend. Hard‑stop incidents requiring board approval must be resolved manually via resolveIncident with an explicit action.
Who can approve budget overrides in Paperclip?
Board members with appropriate permissions can resolve hard‑stop incidents through the PATCH /api/companies/:companyId/budget-incidents/:incidentId endpoint. The resolveIncident function validates authorization, updates the policy, clears pause flags, and logs the decision note for audit purposes.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →