Skip to content

OpenCode Source

  • SQLite database. OpenCode V1 stores messages in the message table. OpenCode V2 stores them in session_message, one row per model step, with the session’s directory in session_v2
  1. explicit --opencode-db

  2. the default directories, in this order:

    • Linux: $XDG_DATA_HOME/opencode (default ~/.local/share/opencode), then ~/.opencode
    • macOS: ~/Library/Application Support/opencode, then ~/.opencode
    • Windows: %APPDATA%\opencode (or under %LOCALAPPDATA%), then ~/.opencode

    Per directory, the adapter looks for opencode.db first, then opencode-<channel>.db variants sorted by name, then db.sqlite. OpenCode keeps one database per release channel, so every readable opencode.db and opencode-<channel>.db in the first directory that has one is read; db.sqlite is read only when neither exists there

    opencode-next.db is skipped. It is the pre-release V2 database, which OpenCode 2 imports into opencode.db on start, so reading both would count its sessions twice. Passed with --opencode-db, it fails with an error that points at opencode.db

Terminal window
llm-usage daily --source opencode --opencode-db /path/to/opencode.db
  • database is opened in read-only mode
  • assistant message rows are parsed into normalized events; an OpenCode V2 database gives one event per step, each with its own tokens and cost
  • OpenCode V2 migrates a V1 database in place: it copies each message into session_message under the same id and keeps the old tables. Such a message is read once, from message, so its history parses as it did before the upgrade
  • a V1 message stores the tokens of its last model step but the cost of all its steps. A message with more than one step-finish part gives one event per part instead, each with that step’s tokens, cost and time, so every step is priced as its own request
  • a database with neither layout fails with a schema drift error
  • reasoningTokens is a subset of outputTokens. OpenCode releases since April 2026 store tokens.output without reasoning while the SDK tokens.total includes it; the adapter adds tokens.reasoning back when the total shows reasoning outside the stored buckets, and leaves older rows (output already inclusive, or no total at all) unchanged. Gemini rows written before February 2026 stored thoughts outside output; they are corrected only when the stored output is smaller than the reasoning count. OpenCode V2 rows always store tokens.output without reasoning and have no total, so reasoning is always added back. A positive tokens.total is kept as the event total; otherwise the buckets are summed.
  • a positive cost on a row is kept as its explicit cost; the provider comes from providerID (model.providerID in V2), and repoRoot from the row’s path.root, path.cwd or cwd, or for V2 from the session’s directory
  • malformed rows are skipped and surfaced in diagnostics
  • busy/locked DB errors use bounded retry before failing with actionable guidance