Skip to content

Cost Tracking

cost-tracker.ts (323 lines) is an often-overlooked but pervasive cross-cutting concern. It’s not just “recording how much was spent” — it’s a complete 7-dimension session-level metering system.

Core Question

Every API call, every tool execution, every code change an AI agent makes has a cost. Users need to know “how much did this session cost,” the system needs to know “how much can still be spent,” and operations needs to know “where anomalous consumption occurred.”

Cost tracking is not an add-on but infrastructure for sustainable agent operation.

7-Dimension Metering

DimensionDescription
Token meteringInput tokens, output tokens, cache creation tokens, cache read tokens tracked separately
Time decompositionTotal elapsed, API call time, retry-excluded API time, tool execution time computed independently
Code changesLines added and lines deleted, continuously accumulated
Multi-model splitUsage bucketed by model name, queryable via getUsageForModel()
Cost estimationcalculateUSDCost() based on model pricing tables for real-time USD cost
Web SearchIndependent web search request count tracking
State persistencesetCostStateForRestore() / resetCostState() for session resume and reset

Architecture

    flowchart LR
    subgraph Input ["Event Sources"]
        API["API Calls<br/>token metering"]
        Tool["Tool Execution<br/>time metering"]
        Code["Code Changes<br/>line counting"]
        Web["Web Search<br/>request counting"]
    end

    subgraph Tracker ["cost-tracker.ts"]
        State["Global State Atom<br/>bootstrap/state.js"]
        Model["Multi-Model Bucketing<br/>getUsageForModel()"]
        USD["Cost Estimation<br/>calculateUSDCost()"]
    end

    subgraph Output ["Consumers"]
        UI["Status Bar<br/>real-time cost display"]
        Persist["Session Persistence<br/>resume/reset"]
        Telemetry["Telemetry Pipeline<br/>logEvent()"]
    end

    API --> State
    Tool --> State
    Code --> State
    Web --> State
    State --> Model
    State --> USD
    USD --> UI
    State --> Persist
    USD --> Telemetry
  

Global State Atom

The cost tracker uses a global state atom in bootstrap/state.js. Any module can read current session cost via getTotalCostUSD() without passing counter references. This is a typical cross-cutting concern globalization design — cost information needs to be simultaneously available in the UI layer (status bar), runtime layer (budget checks), and telemetry layer (reporting).

Two Token Counting Methods

MethodScenarioPrecision
CanonicalFrom API response usage fieldExact
Rough estimationPre-request estimation, image/document estimationApproximate

Rough estimation rules:

  • Plain text: 4 bytes/token
  • JSON format: 2 bytes/token (dense formats need more conservative estimation)
  • Images/documents: Conservative 2,000 tokens (actual formula: width × height / 750)

Multi-Model Bucketing

When a session involves multiple models (primary model + sub-agent model + YOLO classifier model), the cost tracker buckets by model name. getUsageForModel() supports per-model usage queries.

Relationship to Runtime

Cost tracking is not an isolated recorder but interacts with multiple runtime subsystems:

Interaction TargetRelationship
Auto compressionCompression decisions consider current token consumption rate
Token budgetMAX_TOOL_RESULTS_PER_MESSAGE_CHARS = 200K prevents single-tool flooding
TelemetryAPI three-event model (query/success/error) + TTFT/TTLT performance metrics
Session resumesetCostStateForRestore() restores accumulated cost on resume
Status barReal-time display of current session USD cost

Observability Connection

Cost tracking is one data source in Claude Code’s 5-layer telemetry system. After each API call, logEvent() reports token usage, timing, and cost to the telemetry pipeline, which flows through PII filtering to Datadog and internal data lakes.

Key metrics:

  • TTFT (Time to First Token): First token latency
  • TTLT (Time to Last Token): Last token latency
  • Cache hit rate: cacheReadTokens / totalInputTokens

Lessons for Agent Builders

PatternDescription
Cross-cutting meteringCost tracking should be as ubiquitous as logging, not bolted on later
Multi-dimensional bucketingDon’t just track total tokens — bucket by model, time, and change type
Conservative estimationWhen precise data is unavailable, use conservative fallbacks (JSON at 2 bytes/token)
Session persistenceCost state must survive resume, otherwise users see discontinuous billing
Globally readableGlobal state atoms let any module read cost without manual parameter passing

Path Evidence

PathRole
src/cost-tracker.tsCore cost tracker (323 lines)
src/bootstrap/state.jsGlobal state atom
src/utils/modelCost.tsModel pricing table
src/services/analytics/Telemetry pipeline
src/components/Status bar display

Further Reading

  1. Runtime Loop — Where cost tracking sits in queryLoop
  2. Architecture Map — Cross-cutting concern system positioning
  3. Memory System — Compression and cost relationship