How Paperclip Tracks Costs by Aggregating Token Usage: A Deep Dive into the ACP Pipeline

Paperclip tracks costs by capturing token usage at the AI-agent runtime level, persisting each event to a cost_events table, and aggregating those records with SQL to power dashboards, billing reports, and daily token caps.

Paperclip is an open-source AI compute platform (ACP) that provides infrastructure for running AI agents at scale. Understanding how it tracks costs by aggregating token usage reveals a well-engineered pipeline that transforms raw LLM consumption into actionable financial metrics. This article breaks down the complete data flow from runtime emission to UI display, citing the exact source files and functions that make it work.


Runtime Emission: Where Token Tracking Begins

Every AI-agent execution in Paperclip starts with precise measurement. The Tool Runtime Metrics service (server/src/services/tool-runtime-metrics.ts) emits an ACP UsageUpdate message for each agent run. This message contains:

  • inputTokens – tokens sent to the LLM
  • outputTokens – tokens received from the LLM
  • used – total bytes consumed
  • costUsd – derived monetary cost

These fields form the raw data layer for all downstream cost calculations. The runtime captures usage at the moment of inference, ensuring no token goes uncounted.


Persisting Usage Events to the Database

Once emitted, usage data lands in the Run-Log Store (server/src/services/run-log-store.ts). This service writes a row to the cost_events table on every heartbeat of a running job.

Key columns in cost_events include:

Column Type Purpose
inputTokens integer Tokens sent to the model
outputTokens integer Tokens received from the model
costCents integer Cost stored as integer cents for precision
companyId string Organization grouping for aggregations
recordedAt timestamp When the usage occurred

Storing cost in cents as integers avoids floating-point rounding errors—a critical detail for financial accuracy at scale.


SQL Aggregation: Computing Cost Summaries

The Status-Cards service (server/src/services/status-cards.ts) performs the heavy lifting of aggregating token usage into meaningful metrics. It uses SQL SUM() operations to compute totals across multiple dimensions.

Per-Day Aggregation

// server/src/services/status-cards.ts
export async function getDailyCost(companyId: string) {
  const rows = await db
    .select({
      tokens: sql<number>`coalesce(sum(${costEvents.inputTokens} + ${costEvents.outputTokens}), 0)::int`,
      costCents: sql<number>`coalesce(sum(${costEvents.costCents}), 0)::int`,
    })
    .from(costEvents)
    .where(eq(costEvents.companyId, companyId))
    .groupBy(sql`date_trunc('day', ${costEvents.recordedAt})`);
  return rows;
}

This query:

  • Sums inputTokens + outputTokens for total token consumption
  • Sums costCents for total spend
  • Groups results by calendar day using PostgreSQL's date_trunc

The same pattern extends to per-run and per-company aggregations that feed the Cost Summary APIs.


REST API Layer: Typed Cost Endpoints

Aggregated data surfaces through the Costs API (server/src/api/costs.ts), consumed by the UI via ui/src/api/costs.ts. The API returns strongly-typed objects:

  • CostSummary – high-level spend overview
  • CostByAgent – usage broken down by individual agents
  • FinanceSummary – billing-ready totals

Fetching Cost Data Client-Side

import { costsApi } from '@/api/costs';

// Get the cost-summary for a company over the last 30 days
const summary = await costsApi.summary('company-123', {
  from: '2024-07-01',
  to: '2024-07-31',
});
console.log(summary); // → { tokens: 123456, costCents: 487, … }

The API accepts date ranges, enabling flexible reporting periods for dashboards and invoices.


UI Display: Formatting and Daily Cap Enforcement

The final layer transforms raw numbers into human-readable metrics. The Status Cards formatting module (ui/src/pages/StatusCards/format.ts) provides two essential helpers:

  • formatTokens() – converts token counts to compact notation (e.g., 96,000 → "96.0k")
  • formatCents() – converts cents to dollar strings (e.g., 48 → "$0.48")

Displaying Token/Cost Pairs

import { formatTokens, formatCents } from '@/pages/StatusCards/format';

const tokens = 96_000;               // from the API
const cents  = 48;                  // $0.48
const label = `${formatCents(cents)} · ${formatTokens(tokens)}`;
// label => "$0.48 · 96.0k tok"

This concise format appears throughout Paperclip's dashboards, giving users immediate cost visibility.

Daily Token Cap Enforcement

Paperclip also enforces spending limits at the UI layer. It checks aggregated daily totals against configured caps and pauses auto-updates when thresholds are reached. The test file ui/src/pages/StatusCards/format.test.ts validates this cap logic alongside formatting functions.


Key Source Files in the Cost Pipeline

Component File Path Role in Cost Tracking
Runtime metrics emission server/src/services/tool-runtime-metrics.ts Emits ACP UsageUpdate with token counts and USD cost
Event persistence server/src/services/run-log-store.ts Writes to cost_events table
SQL aggregation server/src/services/status-cards.ts Computes daily/company totals with SUM()
REST API server/src/api/costs.ts Exposes typed cost endpoints
UI API client ui/src/api/costs.ts Calls server cost-summary endpoints
Formatting utilities ui/src/pages/StatusCards/format.ts Renders tokens and cents for display
Cap enforcement tests ui/src/pages/StatusCards/format.test.ts Validates daily token limit logic

Summary

Paperclip's cost tracking system demonstrates a clear separation of concerns across five pipeline stages:

  • Capture – Runtime metrics service records every token at inference time
  • Persist – Run-Log Store writes normalized cost events to PostgreSQL
  • Aggregate – Status-Cards service uses SQL SUM() for efficient grouping
  • Serve – Costs API exposes typed endpoints for flexible querying
  • Display – UI formatting helpers render readable metrics with cap enforcement

This architecture scales from individual agent runs to enterprise billing reports while maintaining cent-level financial precision throughout.


Frequently Asked Questions

How does Paperclip avoid rounding errors in cost calculations?

Paperclip stores all monetary values as integer cents in the costCents column rather than floating-point dollars. This approach eliminates rounding errors during aggregation and ensures billing accuracy. The conversion to display format ($0.48) only happens at the UI layer.

Can I query cost data for custom date ranges?

Yes. The Costs API accepts from and to parameters in ISO date format. The costsApi.summary() method in ui/src/api/costs.ts passes these directly to the server endpoint, enabling arbitrary reporting periods for dashboards or invoices.

What happens when a company hits its daily token cap?

The UI enforces caps by checking aggregated daily totals against configured limits. When thresholds are reached, auto-updates pause to prevent additional spend. This logic is tested in ui/src/pages/StatusCards/format.test.ts alongside the formatting utilities.

Where does the initial USD cost value come from?

The costUsd field originates in the Tool Runtime Metrics service (server/src/services/tool-runtime-metrics.ts), which calculates cost based on model-specific pricing at runtime. This derived value is then converted to integer cents before database storage.

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 →