How Budget Enforcement Works with Hard-Stop Auto-Pause Behavior in Paperclip
Paperclip's hard-stop auto-pause mechanism automatically halts agents, projects, or entire companies when spending limits are breached, requiring manual approval before work can resume.
Budget enforcement in Paperclip operates through real-time evaluation of budget policies against aggregated cost events. The implementation centers on server/src/services/budgets.ts, which orchestrates status detection, scope pausing, incident creation, and approval-based resumption. This article breaks down the complete flow from threshold detection to manual override.
Detecting Budget Threshold Violations
The enforcement pipeline begins with budgetStatusFromObserved, which compares observed spending against policy limits. Located at lines 66-73 of server/src/services/budgets.ts, this function returns "hard_stop" when the observed amount reaches or exceeds the configured budget amount.
// Simplified flow when processing a cost event
const status = budgetStatusFromObserved(
observed, // aggregated cents spent
policy.amount, // budget limit in cents
policy.warnPercent // optional warning threshold (e.g., 80)
);
// Returns: "ok" | "warning" | "hard_stop"
The function evaluates three states: normal operation ("ok"), approaching limit ("warning"), and limit exceeded ("hard_stop"). The hard-stop outcome triggers the complete auto-pause cascade described below.
The Auto-Pause Cascade: Three Scope Types
When budgetStatusFromObserved returns "hard_stop", pauseAndCancelScopeForBudget (lines 52-58) initiates scope-specific pausing followed by in-flight work cancellation.
Pausing Individual Agents
For agent-scoped budgets, pauseScopeForBudget (lines 16-25) performs a direct status update:
// Agent pause: status becomes "paused", reason tracked
{
status: "paused",
pauseReason: "budget",
pausedAt: new Date().toISOString()
}
This immediately prevents the agent from accepting new tasks while preserving its configuration.
Pausing Projects
Project-scoped budgets receive a lighter touch (lines 29-36). The project retains its underlying status but gains pause metadata:
// Project pause: status unchanged, but pause fields populated
{
pauseReason: "budget",
pausedAt: timestamp,
// status remains as-is (e.g., "active")
}
This design allows project-level pausing without disrupting shared infrastructure that other projects might depend on.
Pausing Entire Companies
At the company scope (lines 41-48), the pause is absolute:
// Company pause: global status change affects all child entities
{
status: "paused",
pauseReason: "budget"
}
A company-level hard-stop freezes all operations across every agent and project within that organization.
Canceling In-Flight Work
After pausing, pauseAndCancelScopeForBudget optionally invokes cancelWorkForScope to terminate running jobs. This prevents partially-completed work from accruing additional costs after the pause takes effect. The cancellation hook accepts the paused scope's identifiers and propagates termination signals to downstream executors.
The optional nature of this step allows configuration-dependent behavior—some deployments may prefer to let current jobs finish while blocking new ones, while stricter configurations demand immediate termination.
Incidents, Approvals, and the Override Workflow
Critical to the hard-stop design is the mandatory human review. createIncidentIfNeeded (lines 80-92) executes two actions for hard-stop breaches:
- Logging: Creates a budget incident record documenting the breach amount, timestamp, and affected scope
- Approval creation: Generates a
budget-overrideapproval with type"hard"that must be explicitly granted before resumption
// After detecting hard_stop and pausing:
await createIncidentIfNeeded(policy, "hard", observed);
// Creates incident + approval; scope remains paused until approval granted
The approval workflow enforces organizational oversight. No automatic resumption occurs— even if additional funding becomes available, an authorized user must explicitly approve the override.
Resuming After Override Approval
Once approved, resumeScopeFromBudget (lines 61-78) reverses the pause state with scope-specific logic:
| Scope Type | Resume Behavior |
|---|---|
| Agent | status → "idle", pauseReason cleared |
| Project | pauseReason and pause timestamp cleared |
| Company | status restored, pauseReason cleared |
// Example: resuming a paused agent after approval
await resumeScopeFromBudget(policy);
// Agent now eligible for new work assignments
This symmetric design ensures that pause and resume operations maintain state consistency across all scope levels.
Policy Summary and UI Integration
buildPolicySummary (lines 40-48) exposes budget status to frontend consumers. The summary includes:
- Computed
status("hard_stop"when threshold exceeded) - Current
pauseReasonpropagated from the scope row - Formatted amounts and window information
The UI layer—specifically ui/src/lib/status-card-state.ts—maps pauseReason: "budget" to a "Paused — budget" badge, providing immediate visual indication of why operations halted. Supporting utilities in ui/src/lib/utils.ts format budget displays with appropriate suffixes like /mo for monthly windows.
Complete Budget Policy Example
// Creating a hard-stop enabled policy via API
const policy = {
companyId: "c123",
scopeType: "agent", // "agent" | "project" | "company"
scopeId: "a456",
metric: "billed_cents", // cost aggregation field
windowKind: "calendar_month_utc", // reset cadence
amount: 500_00, // $500.00 (cents)
warnPercent: 80, // notify at $400.00
hardStopEnabled: true, // ENABLE auto-pause
notifyEnabled: true, // alert on warning/hard-stop
isActive: true
};
With hardStopEnabled: true, this policy transforms from a monitoring tool into an enforcement mechanism with automatic operational consequences.
Summary
- Threshold detection:
budgetStatusFromObservedcompares observed spending againstpolicy.amount, returning"hard_stop"on breach (lines 66-73) - Scope pausing:
pauseScopeForBudgetapplies appropriate pause semantics to agents, projects, or companies (lines 16-48) - Work cancellation:
pauseAndCancelScopeForBudgetoptionally terminates in-flight jobs viacancelWorkForScope(lines 52-58) - Mandatory review:
createIncidentIfNeededgenerates a hard-type approval that blocks automatic resumption (lines 80-92) - Controlled resumption:
resumeScopeFromBudgetrestores operational status only after explicit approval (lines 61-78)
Frequently Asked Questions
What triggers a hard-stop auto-pause in Paperclip?
A hard-stop triggers when aggregated spending for a budget policy's scope (agent, project, or company) reaches or exceeds the configured amount. The budgetStatusFromObserved function evaluates this on every cost event, comparing observed cents against the policy limit.
Can paused scopes resume automatically?
No. Hard-stop pauses require explicit manual approval through the budget-override workflow. The createIncidentIfNeeded function creates a hard-type approval record that must be granted before resumeScopeFromBudget can clear the pause state.
What's the difference between warning and hard-stop states?
Warnings ("warning") alert users when spending crosses warnPercent of the budget but allow continued operation. Hard-stops ("hard_stop") actively pause the affected scope, cancel optional in-flight work, and enforce a mandatory approval gate before any resumption.
How does scope type affect pause behavior?
Agent pauses change status to "paused" directly. Project pauses set pauseReason without altering underlying status. Company pauses apply a global status: "paused" affecting all child entities. Each scope type uses pauseScopeForBudget with tailored update logic.
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 →