# How CodexBar Scans for Codex and Claude Cost Usage: A Technical Deep Dive

> Learn how CodexBar scans Codex and Claude cost usage with its layered pipeline. Discover data aggregation and unified token snapshots to manage your AI expenses effectively.

- Repository: [Peter Steinberger/CodexBar](https://github.com/steipete/CodexBar)
- Tags: deep-dive
- Published: 2026-07-07

---

**CodexBar aggregates cost and token usage data through a layered pipeline orchestrated by `CostUsageFetcher`, which validates providers, refreshes model pricing, executes heavy-weight log scans, and merges Pi session data to generate a unified `CostUsageTokenSnapshot`.**

CodexBar is an open-source macOS menu bar application that monitors AI coding assistant costs in real time. The engine powering its cost tracking is `CostUsageFetcher`, a Swift class located in [`Sources/CodexBarCore/CostUsageFetcher.swift`](https://github.com/steipete/CodexBar/blob/main/Sources/CodexBarCore/CostUsageFetcher.swift) that systematically scans local log files, session caches, and Pi cost data to calculate spending for Codex, Claude, and other providers.

## The Scanning Pipeline

### Provider Validation and Time Window Configuration

The process begins in `CostUsageFetcher.loadTokenSnapshot`, which validates that the requested provider is one of `.codex`, `.claude`, `.vertexai`, or `.bedrock`. It calculates a `since`-`until` date range representing a 30-day rolling window by default (configurable via `historyDays`). This method is defined at lines 22-31 of [`CostUsageFetcher.swift`](https://github.com/steipete/CodexBar/blob/main/CostUsageFetcher.swift).

### Scanner Options and Cache Configuration

Before scanning, the method constructs a `CostUsageScanner.Options` instance. For Codex scans, this includes the explicit `codexHomePath` to locate the `sessions` folder; for Claude, it configures `claudeLogProviderFilter` appropriately. These options are initialized between lines 43-66 of [`CostUsageFetcher.swift`](https://github.com/steipete/CodexBar/blob/main/CostUsageFetcher.swift).

### Background Pricing Refresh

If the provider is Codex or Claude, `ModelsDevPricingPipeline.refreshIfNeeded` is invoked (lines 52-60) to ensure the latest per-model pricing is available. This runs either on a detached utility task or synchronously before the scan begins, guaranteeing that cost calculations use current rates.

### Heavy-Weight Scan Execution

The `CostUsageScanExecutor.run` method bridges Swift concurrency cancellation into the synchronous scanner. Inside this closure, defined in [`CostUsageScanExecutor.swift`](https://github.com/steipete/CodexBar/blob/main/CostUsageScanExecutor.swift), three main actions occur:

- **Load raw daily logs**: `CostUsageScanner.loadDailyReportCancellable` reads the provider's log files or JSONL data for the calculated window.
- **Load Codex project caches**: When the provider is Codex, `CostUsageCacheIO.load` reads pre-computed scan caches and feeds them to `CostUsageScanner.buildCodexProjectBreakdownsFromCache`.
- **Load Pi session cost data**: For Codex and Claude, `PiSessionCostScanner.loadDailyReportCancellable` fetches session-level cost information (tokens and USD). The Pi report is merged with the raw daily report via `CostUsageDailyReport.merged`.

This execution block spans lines 84-95 in [`CostUsageFetcher.swift`](https://github.com/steipete/CodexBar/blob/main/CostUsageFetcher.swift).

### Project Breakdown Aggregation

After the raw scan completes, Codex-specific project breakdowns are merged by `mergedProjectBreakdowns` in [`CostUsageFetcher.swift`](https://github.com/steipete/CodexBar/blob/main/CostUsageFetcher.swift). This yields a unified list of `CostUsageProjectBreakdown` objects sorted by cost, token count, and name.

### Snapshot Generation

The `tokenSnapshot` method synthesizes a `CostUsageTokenSnapshot` containing:
- **Session-level** tokens and cost for the current day (the entry whose local day contains `now`)
- **30-day totals** derived from the daily report summary, or summed from entries if absent
- **Per-project** breakdowns

### Caching Layer

To avoid redundant disk scans, `loadCachedCodexTokenSnapshot` (lines 36-49) attempts to read a persisted `CachedCodexTokenSnapshotResult` from disk via `CostUsageCacheIO`. If a valid cache exists and covers the requested window, the snapshot returns instantly without file system traversal.

### Bedrock Special Handling

When the provider is `.bedrock`, the scanner delegates to `BedrockCredentialResolver` and `BedrockUsageFetcher.fetchDailyReport`, bypassing the generic log-parsing flow used for Codex and Claude.

## Key Implementation Files

- **[`Sources/CodexBarCore/CostUsageFetcher.swift`](https://github.com/steipete/CodexBar/blob/main/Sources/CodexBarCore/CostUsageFetcher.swift)**: Orchestrates the entire scan pipeline, creates scanner options, runs the executor, and builds the final `CostUsageTokenSnapshot`.
- **[`Sources/CodexBarCore/CostUsageScanner.swift`](https://github.com/steipete/CodexBar/blob/main/Sources/CodexBarCore/CostUsageScanner.swift)**: Parses raw provider logs into `CostUsageDailyReport` objects and defines the `Options` struct controlling cache paths, filters, and refresh intervals.
- **[`Sources/CodexBarCore/CostUsageScanExecutor.swift`](https://github.com/steipete/CodexBar/blob/main/Sources/CodexBarCore/CostUsageScanExecutor.swift)**: Supplies the cancellable bridge `run { checkCancellation in … }` allowing Swift concurrency to cancel long-running synchronous scans.
- **[`Sources/CodexBarCore/CostUsageCacheIO.swift`](https://github.com/steipete/CodexBar/blob/main/Sources/CodexBarCore/CostUsageCacheIO.swift)**: Handles on-disk caching of Codex scan results to avoid re-scanning large session archives.
- **[`Sources/CodexBarCore/PiSessionCostScanner.swift`](https://github.com/steipete/CodexBar/blob/main/Sources/CodexBarCore/PiSessionCostScanner.swift)**: Reads Pi session-cost JSON files (produced by internal tools) for Codex and Claude, returning a `CostUsageDailyReport` merged with the main report.
- **[`Sources/CodexBarCore/ModelsDevPricingPipeline.swift`](https://github.com/steipete/CodexBar/blob/main/Sources/CodexBarCore/ModelsDevPricingPipeline.swift)**: Refreshes per-model pricing data from OpenAI's dev-pricing endpoint.
- **[`Sources/CodexBarCore/BedrockCredentialResolver.swift`](https://github.com/steipete/CodexBar/blob/main/Sources/CodexBarCore/BedrockCredentialResolver.swift)** and **[`BedrockUsageFetcher.swift`](https://github.com/steipete/CodexBar/blob/main/BedrockUsageFetcher.swift)**: Provider-specific path for AWS Bedrock usage.
- **[`Sources/CodexBarCLI/CLICostCommand.swift`](https://github.com/steipete/CodexBar/blob/main/Sources/CodexBarCLI/CLICostCommand.swift)**: CLI entry point that instantiates `CostUsageFetcher` and prints the cost snapshot.
- **[`Sources/CodexBarCLI/CLIServeCommand.swift`](https://github.com/steipete/CodexBar/blob/main/Sources/CodexBarCLI/CLIServeCommand.swift)**: Runs the fetcher in the background for the menu-bar UI, updating the status item with current cost information.

## Code Examples

### Fetching Usage from Swift

```swift
import CodexBarCore

let fetcher = CostUsageFetcher()
do {
    // Request Codex usage for the past 30 days with auto-refresh pricing
    let codexSnapshot = try await fetcher.loadTokenSnapshot(
        provider: .codex,
        now: Date(),
        historyDays: 30,
        forceRefresh: false,
        allowVertexClaudeFallback: false)

    print("Session cost: $\(codexSnapshot.sessionCostUSD ?? 0)")
    print("30-day total: $\(codexSnapshot.last30DaysCostUSD ?? 0)")
    if let project = codexSnapshot.projects?.first {
        print("Top project '\(project.name)' spent $\(project.totalCostUSD ?? 0)")
    }
} catch {
    print("Failed to fetch usage: \(error)")
}

```

### CLI Invocation

```bash
$ codexbar cost --provider codex

# Output:

#   Session: $0.12   (1,234 tokens)

#   30-day total: $9.45

#   Projects:

#     • my-project   $4.20  (2,500 tokens)

```

### Leveraging the Cache

```swift
let cached = await fetcher.loadCachedCodexTokenSnapshot(
    now: Date(),
    codexHomePath: "/Users/me/.codex",
    historyDays: 30)

if let snapshot = cached {
    // Use cached version - no disk scan performed
    print("Cached 30-day cost: $\(snapshot.last30DaysCostUSD ?? 0)")
}

```

## Summary

- **CodexBar** uses `CostUsageFetcher` to orchestrate cost scanning for Codex, Claude, and other providers through a unified pipeline.
- The scanner validates providers, refreshes pricing data via `ModelsDevPricingPipeline`, and executes heavy-weight log parsing via `CostUsageScanExecutor`.
- Session-level cost data from **Pi** tools is merged with daily reports using `CostUsageDailyReport.merged` to produce accurate `CostUsageTokenSnapshot` objects.
- A caching layer via `CostUsageCacheIO` prevents redundant scans of large session archives, with `loadCachedCodexTokenSnapshot` providing instant access to recent data.
- The implementation supports both programmatic Swift APIs and CLI interfaces through [`CLICostCommand.swift`](https://github.com/steipete/CodexBar/blob/main/CLICostCommand.swift).

## Frequently Asked Questions

### How does CodexBar handle different AI providers in the same codebase?

The `CostUsageFetcher.loadTokenSnapshot` method accepts a provider enum (`.codex`, `.claude`, `.vertexai`, or `.bedrock`) and configures scanner options accordingly. For Bedrock, it delegates to `BedrockCredentialResolver` and `BedrockUsageFetcher.fetchDailyReport`, bypassing the generic log-parsing flow used for Codex and Claude.

### What is the default time window for cost scanning?

By default, CodexBar calculates a 30-day rolling window through the `loadTokenSnapshot` method, creating `since` and `until` date ranges based on the `historyDays` parameter (defaulting to 30). This window determines which log files and session data are scanned.

### How does CodexBar ensure cost calculations use current pricing?

Before scanning, the pipeline invokes `ModelsDevPricingPipeline.refreshIfNeeded` for Codex and Claude providers. This updates the per-model pricing cache from OpenAI's dev-pricing endpoint, ensuring that token counts are converted to accurate USD amounts.

### Can the scan process be interrupted or cancelled?

Yes. The `CostUsageScanExecutor.run` method provides a cancellation bridge that allows Swift concurrency to signal cancellation to the underlying synchronous scanner. This prevents long-running file system operations from blocking app termination or UI updates in the menu bar interface.