# How Paperclip Enforces Budgets with Hard-Stop Auto-Pause at Agent and Company Levels

> Discover how Paperclip enforces budgets with hard-stop auto-pause. Learn about its three-layer system that automatically pauses workflows when spending exceeds limits at agent and company levels.

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

---

**Paperclip implements a three-layer enforcement system where a runtime watchdog continuously monitors spend against budget records and automatically pauses any task, agent, or company workflow the moment spending exceeds its configured limit.**

Paperclip treats budget enforcement as a critical infrastructure concern, not an afterthought. The system provides granular control over spending through **hierarchical budgets** that can be attached to companies, projects, or individual agents. When any threshold is breached, Paperclip triggers an immediate hard-stop to prevent runaway costs, requiring explicit human approval to resume operations. This article examines the complete implementation based on the `paperclipai/paperclip` source code.

## The Three-Layer Enforcement Architecture

Paperclip's budget enforcement operates across three coordinated layers:

| Layer | File Path | Responsibility |
|-------|-----------|--------------|
| **Data model** | `packages/db/src/schema/*` | Stores budget amounts, windows (monthly/lifetime), and current spend |
| **Runtime watchdog** | [`server/src/services/task-watchdog-scope.ts`](https://github.com/paperclipai/paperclip/blob/main/server/src/services/task-watchdog-scope.ts) | Monitors spend in real-time and emits `budget.hard_stop` actions |
| **State & UI** | [`ui/src/lib/status-card-state.ts`](https://github.com/paperclipai/paperclip/blob/main/ui/src/lib/status-card-state.ts), [`ui/src/lib/attention.ts`](https://github.com/paperclipai/paperclip/blob/main/ui/src/lib/attention.ts) | Surfaces paused states and budget alerts to users |

This architecture ensures that budget violations are detected immediately, enforced automatically, and communicated clearly to operators.

## How the Watchdog Detects Over-Budget Conditions

The **task watchdog** runs on every scheduler tick to evaluate spending against budget limits. Its detection logic follows four steps:

1. **Query the spend ledger** — aggregates compute seconds, bytes processed, and other billable metrics for the current run
2. **Retrieve the budget record** — selects the appropriate scope: agent-specific, project-specific, or company-wide
3. **Calculate percentage used** — `observedAmount / amountLimit`
4. **Emit hard-stop action** when the percentage exceeds 100%

From [`server/src/services/task-watchdog-scope.ts`](https://github.com/paperclipai/paperclip/blob/main/server/src/services/task-watchdog-scope.ts), the enforcement logic:

```typescript
if (spend > budget.amountLimit) {
  const action = {
    type: "budget.hard_stop",
    details: {
      observedAmount: spend,
      budgetAmount: budget.amountLimit,
    },
  };
  await actionQueue.enqueue(action);
}

```

The watchdog creates an `Action` of type `budget.hard_stop` that enters a persistent queue for reliable processing. This decoupling ensures that budget enforcement survives even if the watchdog process restarts.

## Propagating the Pause Through the State Machine

Once the `budget.hard_stop` action is dequeued, the **task state machine** handles the transition. The state machine updates the task record atomically to prevent race conditions:

```typescript
case "budget.hard_stop":
  task.state = "paused_budget";
  task.pauseReason = "budget";
  await tasks.update(task);
  break;

```

The `paused_budget` state is terminal for task execution — no further compute is scheduled until the pause is cleared. The `pauseReason` field enables precise UI messaging and audit logging.

The UI layer consumes this state through the `budgets.overview` query defined in [`ui/src/lib/queryKeys.ts`](https://github.com/paperclipai/paperclip/blob/main/ui/src/lib/queryKeys.ts). The status card state mapper in [`ui/src/lib/status-card-state.ts`](https://github.com/paperclipai/paperclip/blob/main/ui/src/lib/status-card-state.ts) translates `paused_budget` into user-facing labels like "Paused — budget".

## Alerting Users and Enabling Budget Overrides

When a hard-stop occurs, Paperclip surfaces the condition through multiple channels:

- **Attention system** — [`ui/src/lib/attention.ts`](https://github.com/paperclipai/paperclip/blob/main/ui/src/lib/attention.ts) generates priority alerts that appear in the Inbox and on affected task cards
- **Status badges** — UI components read the `paused_budget` label to render visual indicators
- **Approval workflow** — A dialog requires human authorization to increase the budget

The approval system uses policy definitions found in [`ui/storybook/fixtures/paperclipData.ts`](https://github.com/paperclipai/paperclip/blob/main/ui/storybook/fixtures/paperclipData.ts), including:

- `policyId: "budget-company-ok"` — for company-level budget overrides
- `policyId: "budget-agent-hard-stop"` — for agent-specific budget releases

Once approved, the override updates the budget record and clears the pause, allowing the state machine to resume the task.

## Hierarchical Budget Enforcement Paperclip Prioritizes

Paperclip evaluates budgets from most specific to most general, ensuring precise control with appropriate blast radius:

1. **Agent-level budgets** — Monthly caps on individual agent consumption
2. **Project-level budgets** — Aggregated limits for all activity within a project
3. **Company-level budgets** — Organization-wide spending guards

If multiple budgets exist, the watchdog checks them in order and emits `budget.hard_stop` for the **most specific entity that breached its limit**. This design means:
- An agent hitting its personal cap pauses only that agent's tasks
- A company-wide breach pauses all organizational activity
- Project budgets provide intermediate containment

## Practical Implementation Examples

### Setting a Monthly Agent Budget

```typescript
// POST /api/agents/:agentId/budget
await fetch(`/api/agents/${agentId}/budget`, {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ budgetMonthlyCents: 250_000 }) // $2,500/mo
});

```

The budget persists to the `agent_budget` table, and the watchdog begins monitoring immediately.

### Simulating Over-Budget for Testing

```typescript
import { recordSpend } from "@paperclipai/server/src/services/spend";

await recordSpend({
  agentId,
  bytes: 1_000_000_000, // Large usage to trigger breach
});

```

This helper accelerates the next watchdog tick to generate a `budget.hard_stop` action.

### Handling Paused Tasks in React Components

```tsx
import { useTask } from "@paperclipai/ui/src/hooks/useTask";

const { task } = useTask(taskId);

if (task.state === "paused_budget") {
  return <BudgetPausedAlert task={task} />;
}

```

`BudgetPausedAlert` consumes formatted messages from [`attention.ts`](https://github.com/paperclipai/paperclip/blob/main/attention.ts) showing used versus limit percentages.

### Approving a Budget Override

```typescript
// POST /api/budgets/:budgetId/override
await fetch(`/api/budgets/${budgetId}/override`, {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ newAmountCents: 500_000 }) // Increase to $5,000/mo
});

```

The approved override updates the budget record, clears the `paused_budget` state, and resumes task execution.

## Audit Logging for Compliance

All budget actions are preserved in the activity log via [`server/src/services/work-products.ts`](https://github.com/paperclipai/paperclip/blob/main/server/src/services/work-products.ts). This enables post-hoc analysis of:
- When hard-stops occurred
- Which budget threshold was exceeded
- Who approved overrides and when

The immutable log supports financial compliance and operational reviews.

## Summary

- **Hierarchical budgets** at company, project, and agent levels provide flexible spending controls
- **Real-time detection** via [`task-watchdog-scope.ts`](https://github.com/paperclipai/paperclip/blob/main/task-watchdog-scope.ts) monitors spend on every scheduler tick
- **Automatic hard-stop** through `budget.hard_stop` actions pauses execution immediately upon breach
- **Clear UI surfacing** via `paused_budget` state and [`attention.ts`](https://github.com/paperclipai/paperclip/blob/main/attention.ts) alerts ensures operators understand the condition
- **Human-in-the-loop overrides** require explicit approval via policy-gated workflows to prevent accidental overspend
- **Complete audit trails** in [`work-products.ts`](https://github.com/paperclipai/paperclip/blob/main/work-products.ts) support compliance and forensic analysis

## Frequently Asked Questions

### What happens when multiple budget levels are configured?

Paperclip checks budgets from most specific to most general: agent, then project, then company. The watchdog emits `budget.hard_stop` for the first threshold exceeded, pausing only the affected scope. A company-wide breach pauses all activity; an agent breach pauses only that agent.

### Can automatic pauses be disabled or converted to warnings?

No — the hard-stop mechanism is mandatory by design. The source code in [`task-watchdog-scope.ts`](https://github.com/paperclipai/paperclip/blob/main/task-watchdog-scope.ts) does not support configurable enforcement modes. Teams requiring softer controls must implement external monitoring that queries the `budgets.overview` endpoint and reacts before the 100% threshold is reached.

### How quickly does the watchdog detect budget violations?

Detection latency equals the scheduler tick interval plus action queue processing time. The watchdog evaluates spend on every tick, so violations are caught within seconds of the ledger update. The action queue provides durability, ensuring hard-stops execute even across process restarts.

### Where is budget state stored and how is it queried?

Budget configurations live in schema files under `packages/db/src/schema/*` (e.g., `agent_budget`, `company_budget` tables). The UI queries current state through React-Query keys defined in [`ui/src/lib/queryKeys.ts`](https://github.com/paperclipai/paperclip/blob/main/ui/src/lib/queryKeys.ts), specifically the `budgets.overview` query that aggregates spend and limit data.