# Paperclip Budget Control Features: A Complete Guide to Spend Management and Enforcement

> Master spend management with Paperclip's budget control features. Discover automatic enforcement, alerts, pausing, and approval workflows for effective resource allocation. Read the complete guide.

- Repository: [Paperclip/paperclip](https://github.com/paperclipai/paperclip)
- Tags: deep-dive
- Published: 2026-08-14

---

**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`](https://github.com/paperclipai/paperclip/blob/main/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

```typescript
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.

```typescript
// 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:

```typescript
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`](https://github.com/paperclipai/paperclip/blob/main/ui/src/lib/status-card-state.ts))
- Notification channels if `notifyEnabled` is 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:

1. **`createIncidentIfNeeded`** — records the threshold crossing in `budget_incidents`
2. **`pauseAndCancelScopeForBudget`** — immediately halts the scope and cancels in‑flight work

```typescript
// 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

```typescript
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:

```typescript
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:

```typescript
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`](https://github.com/paperclipai/paperclip/blob/main/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`](https://github.com/paperclipai/paperclip/blob/main/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`](https://github.com/paperclipai/paperclip/blob/main/ui/src/lib/status-card-state.ts) | UI mapping for "Paused — budget" status indicators |
| [`ui/src/lib/attention.ts`](https://github.com/paperclipai/paperclip/blob/main/ui/src/lib/attention.ts) | Inbox and board alert rendering for budget events |
| [`ui/src/api/budgets.ts`](https://github.com/paperclipai/paperclip/blob/main/ui/src/api/budgets.ts) | Frontend API client for budget endpoints |
| [`doc/spec/agent-runs.md`](https://github.com/paperclipai/paperclip/blob/main/doc/spec/agent-runs.md) | Agent‑run specification including `budget_blocked` terminal state |
| [`doc/plans/2026-03-14-budget-policies-and-enforcement.md`](https://github.com/paperclipai/paperclip/blob/main/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`](https://github.com/paperclipai/paperclip/blob/main/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.