OpenCode Source
Data format
Section titled “Data format”- SQLite database. OpenCode V1 stores messages in the
messagetable. OpenCode V2 stores them insession_message, one row per model step, with the session’s directory insession_v2
Path selection
Section titled “Path selection”-
explicit
--opencode-db -
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.dbfirst, thenopencode-<channel>.dbvariants sorted by name, thendb.sqlite. OpenCode keeps one database per release channel, so every readableopencode.dbandopencode-<channel>.dbin the first directory that has one is read;db.sqliteis read only when neither exists thereopencode-next.dbis skipped. It is the pre-release V2 database, which OpenCode 2 imports intoopencode.dbon start, so reading both would count its sessions twice. Passed with--opencode-db, it fails with an error that points atopencode.db - Linux:
llm-usage daily --source opencode --opencode-db /path/to/opencode.dbParsing notes
Section titled “Parsing notes”- 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_messageunder the same id and keeps the old tables. Such a message is read once, frommessage, 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-finishpart 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
reasoningTokensis a subset ofoutputTokens. OpenCode releases since April 2026 storetokens.outputwithout reasoning while the SDKtokens.totalincludes it; the adapter addstokens.reasoningback 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 outsideoutput; they are corrected only when the stored output is smaller than the reasoning count. OpenCode V2 rows always storetokens.outputwithout reasoning and have no total, so reasoning is always added back. A positivetokens.totalis kept as the event total; otherwise the buckets are summed.- a positive
coston a row is kept as its explicit cost; the provider comes fromproviderID(model.providerIDin V2), andrepoRootfrom the row’spath.root,path.cwdorcwd, or for V2 from the session’sdirectory - malformed rows are skipped and surfaced in diagnostics
- busy/locked DB errors use bounded retry before failing with actionable guidance