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 cents
  • windowKind — 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 hit
  • notifyEnabled — controls notification delivery
  • isActive — 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:

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:

  1. createIncidentIfNeeded — records the threshold crossing in budget_incidents
  2. pauseAndCancelScopeForBudget — 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 resolved
  • dismiss — 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:

  1. Detects the pause state via status / pauseReason fields
  2. Invokes resumeScopeFromBudget to clear the pause flag
  3. 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →