Skip to content

Caching

llm-usage-metrics uses caching to keep runs fast, stable offline, and predictable.

  • reduce repeated network calls (pricing + update checks)
  • avoid reparsing unchanged source files on every run
  • keep deterministic behavior when the network is unavailable
Cache Purpose Default TTL Location
update-check cache avoids querying npm on every startup 1 hour <platform-cache-root>/llm-usage-metrics/update-check.json
pricing cache stores normalized LiteLLM pricing data 24 hours <platform-cache-root>/llm-usage-metrics/litellm-pricing-cache.json
event store stores parsed file diagnostics/events and retained departed-file history no TTL <platform-data-root>/llm-usage-metrics/events.db
machine caches one event store per other machine, filled by sync refreshed by reports after 10 minutes <platform-data-root>/llm-usage-metrics/machines/<name>.db

On Linux with no XDG_CACHE_HOME, <platform-cache-root> defaults to ~/.cache. The event store is a ledger rather than a cache, so it lives under <platform-data-root>: ~/.local/share when XDG_DATA_HOME is unset (Linux and macOS), %LOCALAPPDATA% on Windows. A ledger left in the cache directory by an older version is copied there once, on the next report; the old file stays until you delete it.

  • read cached npm version if still fresh
  • otherwise perform a bounded fetch (default 1s timeout) for the latest version so the update hint stays consistent across commands
  • on fetch failure, fallback to previous cached version when available
  • optional session-scoped mode creates a per-shell cache file
  • skipped entirely for --help, --version, npx, and direct source/development runs

Relevant config keys/env vars:

  • LLM_USAGE_SKIP_UPDATE_CHECK
  • LLM_USAGE_UPDATE_CACHE_SCOPE (global or session)
  • LLM_USAGE_UPDATE_CACHE_SESSION_KEY
  • update.cacheTtlMs
  • update.fetchTimeoutMs
  • tries fresh cache first
  • if cache is stale and network is enabled, fetches LiteLLM pricing and rewrites cache
  • if network fails, falls back to stale cache when possible
  • for the default LiteLLM URL, falls back to the bundled snapshot when cache and network are unavailable
  • with --pricing-offline, skips network and uses fresh cache, stale cache, or the bundled snapshot

Relevant options/config:

  • --pricing-offline
  • --pricing-url
  • pricing.cacheTtlMs
  • pricing.fetchTimeoutMs
  • enabled by default
  • key is (source, file path)
  • validity requires matching dependency fingerprints
  • stores parse diagnostics and normalized events, and for claude, codex and pi each file’s tool calls and messages (never message text), which tools and session --timeline read
  • dependency fingerprints include the primary file and any adapter-declared sidecar inputs; for SQLite sources that means the -wal and -journal files, not -shm, which every read rewrites
  • fingerprints also include a parser version, so upgrading to a release with parser fixes re-parses stored files once
  • persisted as SQLite with per-file replace-on-change writes, batched into one transaction per source
  • with --since, file-per-session sources skip files whose newest mtime (including sidecars) is more than a day before the window; with the store on, only files the store already holds are skipped, so the ledger still ingests older files
  • reports include usage from files that no longer exist on disk by default; --no-history leaves it out. tools and session --timeline include those files’ tool calls and messages, except for files that departed before the store kept them
  • files only ever read through a directory flag (--claude-dir ./export, --source-dir) are cached but never served as history by a report on the usual directories; once such a report finds the file in the usual location, it is history like any other file. Files stored this way by older versions are not recognized; prune --departed-before can delete them, but it also selects departed files from the usual directories, so preview without --apply first
  • moved, renamed, and copied files are suppressed by content hash to avoid double counting; a departed file that only partly overlaps counted usage is served without the overlapping events
  • llm-usage prune previews or deletes departed-file rows explicitly
  • first run after a store schema upgrade migrates the database in place and may take a few seconds
  • deleting the database file deletes retained local history and starts a new ledger on the next run; a ledger once copied from the old cache-directory location is not copied again (a legacy-ledger-copied marker beside the ledger records the copy), so delete that old file yourself to reclaim its space
  • legacy JSON cache shards are ignored and safe to delete manually

Prune is dry-run by default:

Terminal window
llm-usage prune --suppressed

Selectors:

  • --suppressed selects departed files that --history already suppresses as moved or duplicated. Applying this selector does not change report output. Only live files a report has read in their current state vouch for a departed copy, so run a report first after files change or an upgrade.
  • --departed-before YYYY-MM-DD selects departed files whose newest event timestamp is strictly older than that UTC date. Applying this selector permanently deletes retained history for those files.

Apply selected candidates:

Terminal window
llm-usage prune --suppressed --apply
llm-usage prune --departed-before 2026-01-01 --apply

After an applying run, the CLI deletes selected rows, runs SQLite VACUUM, and reports reclaimed database/WAL bytes.

Relevant env vars:

  • LLM_USAGE_EVENT_STORE (0 disables it)
  • LLM_USAGE_EVENT_STORE_PATH
  • parseMaxParallel
  • LLM_USAGE_PARSE_WORKERS
  • LLM_USAGE_PARSE_WORKER_MIN_BYTES

Avoid network pricing fetches:

Terminal window
llm-usage monthly --pricing-offline

Increase parsing throughput:

parseMaxParallel = 16
parseWorkers = 4

Shorten pricing cache TTL to 2 hours:

[pricing]
cacheTtlMs = 7200000
  • When pricing uses the bundled snapshot, stderr shows its snapshot date; run once without --pricing-offline to refresh the cache.
  • Custom --pricing-url values use their matching cache or network source and do not fall back to the bundled default snapshot.
  • For stale reports after source file changes, verify source files updated mtime. Deleting <platform-data-root>/llm-usage-metrics/events.db starts a fresh ledger, but it also deletes retained history used by --history.
  • To force update checks every run, set update.cacheTtlMs = 0 in the config file.