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

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 Monitors spend in real-time and emits budget.hard_stop actions
State & UI ui/src/lib/status-card-state.ts, 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, the enforcement logic:

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:

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. The status card state mapper in 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 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, 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

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

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

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 showing used versus limit percentages.

Approving a Budget Override

// 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. 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 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 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 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 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, specifically the budgets.overview query that aggregates spend and limit data.

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 →