How CodexBar Scans for Codex and Claude Cost Usage: A Technical Deep Dive
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 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.
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.
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, three main actions occur:
- Load raw daily logs:
CostUsageScanner.loadDailyReportCancellablereads the provider's log files or JSONL data for the calculated window. - Load Codex project caches: When the provider is Codex,
CostUsageCacheIO.loadreads pre-computed scan caches and feeds them toCostUsageScanner.buildCodexProjectBreakdownsFromCache. - Load Pi session cost data: For Codex and Claude,
PiSessionCostScanner.loadDailyReportCancellablefetches session-level cost information (tokens and USD). The Pi report is merged with the raw daily report viaCostUsageDailyReport.merged.
This execution block spans lines 84-95 in CostUsageFetcher.swift.
Project Breakdown Aggregation
After the raw scan completes, Codex-specific project breakdowns are merged by mergedProjectBreakdowns in 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: Orchestrates the entire scan pipeline, creates scanner options, runs the executor, and builds the finalCostUsageTokenSnapshot.Sources/CodexBarCore/CostUsageScanner.swift: Parses raw provider logs intoCostUsageDailyReportobjects and defines theOptionsstruct controlling cache paths, filters, and refresh intervals.Sources/CodexBarCore/CostUsageScanExecutor.swift: Supplies the cancellable bridgerun { checkCancellation in … }allowing Swift concurrency to cancel long-running synchronous scans.Sources/CodexBarCore/CostUsageCacheIO.swift: Handles on-disk caching of Codex scan results to avoid re-scanning large session archives.Sources/CodexBarCore/PiSessionCostScanner.swift: Reads Pi session-cost JSON files (produced by internal tools) for Codex and Claude, returning aCostUsageDailyReportmerged with the main report.Sources/CodexBarCore/ModelsDevPricingPipeline.swift: Refreshes per-model pricing data from OpenAI's dev-pricing endpoint.Sources/CodexBarCore/BedrockCredentialResolver.swiftandBedrockUsageFetcher.swift: Provider-specific path for AWS Bedrock usage.Sources/CodexBarCLI/CLICostCommand.swift: CLI entry point that instantiatesCostUsageFetcherand prints the cost snapshot.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
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
$ 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
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
CostUsageFetcherto 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 viaCostUsageScanExecutor. - Session-level cost data from Pi tools is merged with daily reports using
CostUsageDailyReport.mergedto produce accurateCostUsageTokenSnapshotobjects. - A caching layer via
CostUsageCacheIOprevents redundant scans of large session archives, withloadCachedCodexTokenSnapshotproviding instant access to recent data. - The implementation supports both programmatic Swift APIs and CLI interfaces through
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.
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 →