Architecture

Tokfuel is a SwiftUI menu-bar app with no server component. Every number it shows comes from parsing files that Claude Code, Cursor, and Codex CLI already keep on your Mac.

SPM layers

App code under App/ is split into SPM targets. Dependencies flow UI → Store → sources; the Tokfuel executable wires the concrete types.

Tokfuel SPM layer architecture Dependency flow UI to Store to sources. The Tokfuel executable wires concrete types. Settings, Analytics, and Core sit beside the main stack. Tokfuel executable · DI / wiring TokfuelUI Popover · Settings · About · presentation depends on TokfuelStore UsageStore · shape / aggregate for UI depends on TokfuelClaude retok · transcripts TokfuelCursor dashboard · pricing TokfuelCodex CLI sessions TokfuelBudget thresholds · alerts Shared · settings · diagnostics TokfuelSettings AppSettings · UserDefaults TokfuelAnalytics opt-in · Crashlytics (dist) TokfuelCore shared types only Local data on disk ? sources fetch ? Store shapes ? UI presents. Prompts never leave the Mac. Arrow direction = import / depends-on (UI ? Store ? sources).
  • TokfuelUI — popover, Settings, About, and other presentation

  • TokfuelStore — aggregation and UI-facing shaping (UsageStore)

  • TokfuelClaude / TokfuelCursor / TokfuelCodex / TokfuelBudget — fetch and domain sources

  • TokfuelSettings / TokfuelAnalytics / TokfuelCore — settings, opt-in Analytics, shared types

Data flows fetch → shape / aggregate → present. The decision record is ADR-0002; the repository README has the same dependency diagram.

UsageStore: the single source of truth

UsageStore (in TokfuelStore) is the one @MainActor object every view reads from. It owns the current cost totals, charts, and per-model breakdown, and refreshes them on a timer — every 10 minutes when idle, stepping up to once a minute for 5 minutes after cost moves. PopoverView and the rest of the UI stay pure display layers; settings live separately in AppSettings, backed by UserDefaults.

RetokService: reading Claude Code's own transcripts

RetokService (in TokfuelClaude) shells out to the bundled retok script (© Daiki Matsudate, MIT, kept unmodified) to parse the ~/.claude/projects/ transcripts Claude Code writes on its own — no hooks, no extra install, nothing to configure. python3 is an optional dependency; without it, cost analysis degrades but the rest of the app keeps working.

BudgetMonitor

BudgetMonitor (in TokfuelBudget) watches UsageStore's totals against the monthly and daily limits in AppSettings, and fires a heads-up exactly once each time a threshold is crossed. The alert window itself is assembled by the App / UI side.

Per-source services

  • CursorDashboardService — when Cursor is installed and signed in, calls Cursor's own dashboard usage API using the session token Cursor already keeps in its local state.vscdb. Falls back to a local SQLite token snapshot when signed out or offline.

  • CursorPricingService — fetches Cursor's own published price table once a day to price fallback-path usage. Never guesses a rate for an unpriced model; it's counted as $0 instead.

  • ExchangeRateService — fetches the USD→JPY rate from Frankfurter once a day, only when JPY display is enabled.

  • UpdateChecker — polls GitHub Releases for a newer version at launch and then every 24 hours; downloads only when you click Update.

  • CSVExportService — turns the current period's data already in the retok report into daily or monthly CSV, entirely on-device.

  • AnalyticsService — the single surface for opt-in, distribution-build-only Firebase Analytics events; a no-op everywhere else.

Each source is kept independent and labeled — Cursor and Codex costs are never silently merged into the Claude total.

The App/ tree

Per ADR-0001, app-related trees live under App/. Site, Docs, and Scripts stay outside. Verification artifacts sit in App/Tests/ beside the SPM layer packages (App/Tokfuel*).

  • App/Tokfuel* — executable and libraries (UI / Store / sources)

  • App/Tests/UnitTests — what swift test runs

  • App/Tests/{IntegrationTests,E2E,TestDocs} — integration, end-to-end, and scenario docs (see Testing)

Related docs