Skip to content

Where opencode stores session history ​

The opencode layout supported here stores sessions in a SQLite database at ~/.local/share/opencode/opencode.db, or $XDG_DATA_HOME/opencode/opencode.db when configured:

~/.local/share/opencode/opencode.db

It follows the XDG base directory spec, so $XDG_DATA_HOME/opencode/opencode.db wins if that variable is set. That applies on macOS too, where most apps would use ~/Library/Application Support.

In this supported layout, sessions are database rows rather than individual JSONL files. Query SQLite to inspect them instead of assuming a recursive text search can extract a conversation. Older file-based layouts are outside this adapter's scope.

The four tables that matter ​

sql
project  -- id (sha1), worktree (the project directory), vcs, time_*
session  -- id ("ses_…"), project_id, parent_id, slug, title, directory,
         -- model (JSON), tokens_* (5 columns), cost, time_created,
         -- time_updated, time_archived
message  -- id ("msg_…"), session_id, time_created, data (JSON envelope)
part     -- id ("prt_…"), message_id, session_id, time_created, data (JSON body)

The database has more tables (workspace, todo, permission, event, credential and migration bookkeeping), but a transcript is session → message → part.

message.data is a JSON envelope: role, modelID, providerID, tokens{input,output,reasoning,cache{read,write}}, cost, time{created,completed}. part.data is the body, with a type of text, reasoning, tool, file, step-start, step-finish and others.

Sub-agent sessions ​

A session with a non-null parent_id is a sub-agent run spawned by another session. The viewer hides these from the ordinary history list but includes their recorded work in statistics. They can contain usage and costs; a local model, provider pricing or missing fields can yield zero recorded cost. A sub-agent run is not proof of a separately billed API call.

Open it read-only ​

opencode's TUI may be writing while you inspect the database. Use a read-only connection to avoid accidental writes; busy or changing databases can still require retrying after activity settles. The command also respects a configured XDG data root:

bash
sqlite3 "file:${XDG_DATA_HOME:-$HOME/.local/share}/opencode/opencode.db?mode=ro" ".tables"

Reading an opencode transcript with SQL ​

List sessions with their project and cost, newest first:

sql
SELECT s.id, p.worktree, s.title, s.cost,
       datetime(s.time_created/1000, 'unixepoch') AS created
FROM session s
JOIN project p ON p.id = s.project_id
WHERE s.parent_id IS NULL
ORDER BY s.time_created DESC
LIMIT 20;

Print one session's text, in order:

sql
SELECT json_extract(m.data, '$.role') AS role,
       json_extract(pt.data, '$.text') AS text
FROM message m
JOIN part pt ON pt.message_id = m.id
WHERE m.session_id = 'ses_...'
  AND json_extract(pt.data, '$.type') = 'text'
ORDER BY m.time_created, pt.time_created;

Sum session-recorded costs per project:

sql
SELECT p.worktree, ROUND(SUM(s.cost), 2) AS usd, COUNT(*) AS sessions
FROM session s JOIN project p ON p.id = s.project_id
GROUP BY p.worktree ORDER BY usd DESC;

The last query includes sub-agent rows on purpose. It sums session.cost, which is a stored value, not a provider invoice. Desktop statistics instead read assistant-message costs; the two aggregations need not agree if records are missing or inconsistent.

Why cost has to come from the database ​

opencode can use different providers or local models, so a price table keyed only by model name may not reflect that setup. The viewer reads modelID, tokens and cost from assistant-message records rather than repricing them with its catalog. Missing numeric message costs currently default to zero; this means unmeasured cost, not verified free work. Recorded cost is not an independently verified invoice. Compare financial decisions with the provider's actual usage report; see usage and cost boundaries.

How do I resume this session? ​

Run opencode --session SESSION_ID from the project's directory with opencode installed. The app offers terminal resume, not in-app opencode chat.

Install Sessions Viewer, select opencode, then choose a project to read its supported SQLite sessions. Use ⌘⇧F (macOS) or Ctrl+Shift+F (Windows/Linux) for session titles and saved user prompts across opencode projects, or switch to ID mode. This does not search assistant answers or tool output; see search scope.

Export Markdown, HTML or parsed-message JSON after reviewing private content; keep the native database for archival needs. Export limits include external/unreadable images. Continuing uses the installed opencode CLI in a terminal, not an opencode in-app chat. Sessions Viewer is an independent open-source project, not an official opencode product. Check privacy before resuming or sharing.

Source and limitations ​

Path, recorded-cost and viewer-operation wording reviewed on 2026-10-06 against the 0.6.0 opencode adapter and search implementation. This is source review and synthetic-test scope, not CLI runtime certification. Upstream: opencode documentation.

Reference scope: checked against the Sessions Viewer 0.6.0 adapters on 2026-10-05, not a compatibility guarantee for every CLI release. Shell examples use macOS/Linux paths and require jq (or sqlite3 for opencode). Replace placeholders with real values and use your configured data root. Text extraction does not replay tools, images or the active branch of a session tree. Command regressions use downloadable synthetic samples, not private sessions. Check the capability and evidence matrix for tested scope. Browsing is distinct from resuming or editing data; see privacy and data handling.

SQL examples target the database schema described above; they do not cover older file-based layouts. Read-only queries are distinct from explicit rename/trash/restore actions that write to the database. See missing-session troubleshooting.

Or open it in an app ​

Sessions Viewer queries this database read-only, hides sub-agent sessions from the list while still counting them in the stats, and shows opencode conversations next to your JSONL-based agents in the same view. It also reads Claude Code, Codex, Grok Build, Kimi Code, Pi and Antigravity CLI.