Configuration
llm-usage-metrics uses a TOML config file for persistent defaults. CLI flags override it for one-off runs, and environment variables provide an override layer for scripts, CI, and debugging. For the design behind this (precedence, validation, the template, and log levels), see the Config & Logging deep dive.
Config file
Section titled “Config file”Default path:
<config-root>/llm-usage-metrics/config.tomlConfig root follows the platform:
XDG_CONFIG_HOMEwhen set%APPDATA%on Windows~/.configotherwise
Run llm-usage config init to write a commented template at the active config path. Set LLM_USAGE_CONFIG_PATH=/path/to/config.toml to point at a different config file. A missing config file is silent and uses built-in defaults. Malformed TOML is an error. Unknown keys are reported once on stderr and the run continues.
Run llm-usage config path to print the resolved config file path on stdout, one line, nothing else.
Unknown keys and values of the wrong type (for example enabled = "false" instead of enabled = false) are ignored with a warning; blank strings and empty lists mean “not set”. These warnings go to stderr, so config show output stays clean to redirect.
Showing the effective setup
Section titled “Showing the effective setup”llm-usage config show prints what a report would use and where each value came from: flag, env var, config, or default. It covers the config file, each source’s directories or database files and whether they exist, the event store, configured machines, pricing, and the defaults reports apply. It accepts the flags that change those values (--source, --source-dir, the per-source path flags listed by --help-all, --timezone, --pricing-url, --pricing-offline, --pricing-overrides), so you can check a flag’s effect before running a report.
Sources pi default missing ~/.pi/agent/sessions missing ~/.omp/agent/sessions codex flag found /work/codex gemini env var missing /opt/gemini claude config found /work/claude
Event store enabled default yes path config /work/store/events.db file 4.1 MiB, schema v5, 12,408 events
Pricing url default https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json offline default no refresh default every 24h 0m cache ~/.cache/llm-usage-metrics/litellm-pricing-cache.json fetched 2026-06-21 (3 h ago), fresh prices from the cache overrides noneA source marked env var was moved by its tool’s variable (CODEX_HOME, CLAUDE_CONFIG_DIR, XDG_DATA_HOME and the others on Sources). prices says what the next report prices with: the cache while it is fresh, otherwise a fetch from the URL; with --pricing-offline, a stale cache or the bundled snapshot. history is on whenever the event store is.
config show changes nothing and contacts nothing. It only stats source paths, opens the event store read-only, reads the pricing cache without fetching, and lists machines by name from the config without running ssh. To check whether a source’s files hold readable usage, or when a machine last synced, run doctor, which reads the files.
--json emits the same data with each value’s origin; the schema is report-config-show.v1.schema.json (llm-usage schema config-show).
TOML editors such as Taplo can validate the file through the #:schema directive. The schema is published at config-schema.json:
#:schema https://ayagmar.github.io/llm-usage-metrics/config-schema.jsontimezone = "Africa/Casablanca"logLevel = "info"monthlyBudgetUsd = 200sources = ["codex", "claude"]parseMaxParallel = 8parseWorkers = "auto"parseWorkerMinBytes = 268435456
[sourceDirs]codex = "/path/to/.codex/sessions"claude = ["/path/to/.claude/projects", "/path/to/work/.claude/projects"]opencode = "/path/to/opencode.db"goose = "/path/to/goose/sessions.db"
[pricing]offline = trueurl = "https://example.com/model_prices_and_context_window.json"overridesPath = "/path/to/pricing-overrides.json"ignoreFailures = falsecacheTtlMs = 86400000fetchTimeoutMs = 4000
[eventStore]enabled = truepath = "/path/to/events.db"
[update]skipCheck = falsecacheTtlMs = 3600000fetchTimeoutMs = 1000Precedence
Section titled “Precedence”Higher layers win:
| Layer | Use case |
|---|---|
| CLI flags | One-off command overrides |
| Environment variables | CI, scripts, temporary runtime overrides |
| Config file | Persistent personal defaults |
| Built-in defaults | Zero-config behavior |
A CLI --source-dir <id>=<path> overrides the config sourceDirs.<id> entry just like the dedicated --<id>-dir flag does. Config entries are defaults rather than explicit requests: a config source dir that cannot be read is reported as a warning instead of failing the run, and it never conflicts with a --provider or --model filter that excludes that source (both of which happen when the same path is passed on the command line). A config sources filter is a default too, so a config-only sources entry that --provider or --model excludes does not fail the run either.
Paths in the config file (sourceDirs.*, eventStore.path, pricing.overridesPath) may start with ~/, and relative paths resolve against the directory holding the config file, not the current directory.
Reports name the applied config file in their stderr summary line; --verbose prints the Active config: block with each applied value. Values shadowed by a flag or environment variable are not listed. Set logLevel = "warn" to suppress informational stderr by default, or pass --quiet to do the same for a single report command.
Config keys
Section titled “Config keys”| Config key | CLI flag or env override | What it controls |
|---|---|---|
timezone |
--timezone |
Default report timezone |
logLevel |
--quiet, --verbose |
Stderr logging level: silent, warn, info, or debug |
monthlyBudgetUsd |
Config only | Monthly budget the summary checks its projection against |
sources |
--source |
Default source filter |
sourceDirs.pi |
--pi-dir or --source-dir pi=... |
Pi sessions path |
sourceDirs.codex |
--codex-dir or --source-dir codex=... |
Codex sessions path |
sourceDirs.copilot |
--copilot-dir or --source-dir copilot=... |
GitHub Copilot OTEL path |
sourceDirs.gemini |
--gemini-dir or --source-dir gemini=... |
Gemini CLI path |
sourceDirs.droid |
--droid-dir or --source-dir droid=... |
Droid sessions path |
sourceDirs.claude |
--claude-dir or --source-dir claude=... |
Claude projects path |
sourceDirs.openclaw |
--openclaw-dir or --source-dir openclaw=... |
OpenClaw agents path |
sourceDirs.opencode |
--opencode-db |
OpenCode SQLite DB |
sourceDirs.goose |
--goose-db |
Goose SQLite DB |
sourceDirs.amp |
--amp-dir or --source-dir amp=... |
Amp threads path |
sourceDirs.qwen |
--qwen-dir or --source-dir qwen=... |
Qwen projects path |
sourceDirs.kimi |
--kimi-dir or --source-dir kimi=... |
Kimi sessions path |
sourceDirs.cline |
--cline-dir or --source-dir cline=... |
Cline tasks path |
sourceDirs.roocode |
--roocode-dir or --source-dir roocode=... |
RooCode tasks path |
sourceDirs.kilocode |
--kilocode-dir or --source-dir kilocode=... |
KiloCode tasks path |
sourceDirs.antigravity |
--antigravity-dir or --source-dir antigravity=... |
Antigravity conversations path |
sourceDirs.dsh |
--dsh-dir or --source-dir dsh=... |
DeepSeek Harness sessions path |
pricing.offline |
--pricing-offline |
Use cached or bundled pricing without fetching |
pricing.url |
--pricing-url |
LiteLLM pricing source URL |
pricing.overridesPath |
--pricing-overrides |
JSON pricing overrides path |
pricing.ignoreFailures |
--ignore-pricing-failures |
Continue without estimated costs when pricing cannot load |
pricing.cacheTtlMs |
Config only | Pricing cache TTL |
pricing.fetchTimeoutMs |
Config only | Pricing fetch timeout |
eventStore.enabled |
LLM_USAGE_EVENT_STORE |
Enable SQLite event-store reuse |
eventStore.path |
LLM_USAGE_EVENT_STORE_PATH |
SQLite event-store path |
parseMaxParallel |
Config only | Max parallel file parses |
parseWorkers |
LLM_USAGE_PARSE_WORKERS |
Worker-thread parser count for large JSONL misses |
parseWorkerMinBytes |
LLM_USAGE_PARSE_WORKER_MIN_BYTES |
Missed-file byte threshold before workers engage |
update.skipCheck |
LLM_USAGE_SKIP_UPDATE_CHECK |
Skip startup update checks |
update.cacheTtlMs |
Config only | Update-check cache TTL |
update.fetchTimeoutMs |
Config only | Update-check fetch timeout |
machines.<name>.ssh |
machine add <name> [ssh-target] |
ssh destination of another machine to sync usage from |
machines.<name>.command |
machine add --command |
How llm-usage-metrics is launched on that machine |
machines.<name>.enabled |
Config only | false stops syncing it |
A machine name is 1-32 lowercase letters, digits or dashes; local is reserved for this machine. llm-usage machine add syncs the machine once and only then appends its table to the config file, keeping your comments; machine remove deletes the table and the machine’s cached usage.
A sourceDirs value for a directory-backed source can be a list, which scans every listed directory as one source, like repeating its flag. sourceDirs.opencode and sourceDirs.goose take one database path.
There is no --no-pricing-offline flag. To force a one-off online pricing refresh while pricing.offline = true stays in the config, bypass the config for that run by pointing LLM_USAGE_CONFIG_PATH at a nonexistent file (a missing file loads an empty config) or edit the file:
LLM_USAGE_CONFIG_PATH=/nonexistent llm-usage monthlyEnvironment overrides
Section titled “Environment overrides”Environment variables override the config file. Reports count them in the stderr summary line, and --verbose lists them in an Active environment overrides: block.
| Variable | Config key | Default | Notes |
|---|---|---|---|
LLM_USAGE_CONFIG_PATH |
n/a | platform config path | Points at a config TOML file |
LLM_USAGE_SKIP_UPDATE_CHECK |
update.skipCheck |
unset (false) |
Truthy values: 1, true, yes, on |
LLM_USAGE_UPDATE_CACHE_SCOPE |
n/a | global |
session isolates update-check cache by session |
LLM_USAGE_UPDATE_CACHE_SESSION_KEY |
n/a | unset | Stable key for session-scoped update cache |
LLM_USAGE_PARSE_WORKERS |
parseWorkers |
auto |
auto (up to 6 with the event store on, 8 without) or integer 0..64; 0 disables workers |
LLM_USAGE_PARSE_WORKER_MIN_BYTES |
parseWorkerMinBytes |
268435456 |
Clamps to 0..9007199254740991 |
LLM_USAGE_EVENT_STORE |
eventStore.enabled |
1 (true) |
Set 0 to disable the store |
LLM_USAGE_EVENT_STORE_PATH |
eventStore.path |
platform data events.db |
Use an isolated store for experiments or CI |
LLM_USAGE_PROFILE_RUNTIME |
n/a | unset (false) |
Emits runtime profiling diagnostics |
Retained history (on by default) needs the event store; with the store disabled, reports run without it and an explicit --history fails. Deleting events.db also deletes retained departed-file history.
Example:
LLM_USAGE_PARSE_WORKERS=4 LLM_USAGE_EVENT_STORE=0 llm-usage monthlyBenchmarking-focused example:
LLM_USAGE_SKIP_UPDATE_CHECK=1 \LLM_USAGE_EVENT_STORE=0 \llm-usage monthly --provider openai --json