OpenCode¶
OpenCode is a SQLite-backed conversation backend. agentgrep reconstructs turns
from the relational session/message/part tables. No searched store carries a
fast prompt log, so --exhaustive is required for user text; assistant and
reasoning parts additionally require conversation scope. Targeted effort
cannot route this backend.
OpenCode does write a prompt-history log, but outside its data root — at
${XDG_STATE_HOME:-~/.local/state}/opencode/prompt-history.jsonl — and no
store row covers that path yet, so it does not shorten the search today.
Base path: ~/.local/share/opencode (env overrides: XDG_DATA_HOME, OPENCODE_DB).
observed_version: opencode v1.18.15 (observed 2026-08-08).
OpenCode (anomalyco/opencode) stores conversations in a single SQLite
database, opencode.db, under its XDG data directory
(${XDG_DATA_HOME:-~/.local/share}/opencode). Non-stable install
channels use opencode-<channel>.db, and OPENCODE_DB can relocate the
database (an absolute path is used directly).
Stores¶
- Role:
primary_chat- Format:
sqlite- Coverage:
default_search- Adapter:
opencode.db_sqlite.v1
- Role:
primary_chat- Format:
json_object- Coverage:
catalog_only- Adapter:
-
- Role:
prompt_history- Format:
jsonl- Coverage:
catalog_only- Adapter:
-
- Role:
app_state- Format:
json_object- Coverage:
catalog_only- Adapter:
-
- Role:
app_state- Format:
json_object- Coverage:
private- Adapter:
-
- Role:
source_tree- Format:
opaque- Coverage:
catalog_only- Adapter:
-
- Role:
cache- Format:
opaque- Coverage:
catalog_only- Adapter:
-
- Role:
app_state- Format:
text- Coverage:
catalog_only- Adapter:
-
- Role:
cache- Format:
text- Coverage:
catalog_only- Adapter:
-
opencode.db¶
SQLite store (Drizzle). Tables session (id, project_id, directory = working dir, title, version, time_created/updated, model, cost, tokens_*), message (id, session_id FK, data JSON with role/time; assistant messages carry top-level modelID/providerID/path.cwd, while user messages nest the selected model under model.modelID), and part (id, message_id FK, session_id, data JSON with type + payload). Searchable text lives in part.data: type text/reasoning -> text, subtask -> prompt. A conversation turn is reconstructed by joining part -> message -> session. Channel installs use opencode-<channel>.db; OPENCODE_DB overrides the path (also :memory:/absolute). The same file also carries the v2 event-sourced tables session_input, session_message, event/event_sequence, and todo; event is now populated on stable installs and mirrors the part transcript text, so it is left unsearched to avoid duplicate hits — the canonical transcript stays in session/message/part. Secret-bearing account, account_state, control_account, and credential tables are present but never enumerated — the adapter reads only text-bearing part rows.
- Agent:
OpenCode
- Role:
primary_chat- Format:
sqlite- Coverage:
default_search- Path:
${XDG_DATA_HOME or ${HOME}/.local/share}/opencode/opencode.db- Adapter:
opencode.db_sqlite.v1- Data version:
-- Version strategies:
-- Observed:
opencode v1.18.15 (2026-08-08)
- Default search:
yes
SQLite tables observed (1.18.15, 2026-08-08)
- __drizzle_migrations columns:
id,hash,created_at,name,applied_at- account columns:
id,email,url,access_token,refresh_token,token_expiry,time_created,time_updated- account_state columns:
id,active_account_id,active_org_id- control_account columns:
email,url,access_token,refresh_token,token_expiry,active,time_created,time_updated- credential columns:
id,integration_id,label,value,connector_id,method_id,active,time_created,time_updated- data_migration columns:
name,time_completed- event columns:
id,aggregate_id,seq,type,data- event_sequence columns:
aggregate_id,seq,owner_id- message columns:
id,session_id,time_created,time_updated,data- migration columns:
id,time_completed- part columns:
id,message_id,session_id,time_created,time_updated,data- permission columns:
id,project_id,action,resource,time_created,time_updated- project columns:
id,worktree,vcs,name,icon_url,icon_color,time_created,time_updated,time_initialized,sandboxes,commands,icon_url_override- project_directory columns:
project_id,directory,type,strategy,time_created- session columns:
id,project_id,parent_id,slug,directory,title,version,share_url,summary_additions,summary_deletions,summary_files,summary_diffs,revert,permission,time_created,time_updated,time_compacting,time_archived,workspace_id,path,agent,model,cost,tokens_input,tokens_output,tokens_reasoning,tokens_cache_read,tokens_cache_write,metadata- session_context_epoch columns:
session_id,baseline,snapshot,baseline_seq- session_input columns:
id,session_id,prompt,delivery,admitted_seq,promoted_seq,time_created- session_message columns:
id,session_id,type,time_created,time_updated,data,seq- session_share columns:
session_id,id,secret,url,time_created,time_updated- todo columns:
session_id,content,status,priority,position,time_created,time_updated- workspace columns:
id,type,name,branch,directory,extra,project_id,time_used
The sole searchable OpenCode store. kind is derived from the joined message role (user -> prompt, else history).
opencode.storage_legacy¶
Pre-migration on-disk layout: one JSON file per session/message/part. A startup migration folds these into opencode.db; migrated installs keep a storage/session_diff/ of small per-session [] marker files and a storage/migration marker, with no searchable session/message/part JSON left. Documentary — relevant only to older, un-migrated installs.
- Agent:
OpenCode
- Role:
primary_chat- Format:
json_object- Coverage:
catalog_only- Path:
${XDG_DATA_HOME or ${HOME}/.local/share}/opencode/storage/{session,message,part}/**/*.json- Adapter:
-
- Data version:
-- Version strategies:
-- Observed:
opencode v1.18.15 (2026-08-08)
- Default search:
no
opencode.prompt_history¶
Recalled prompt log, one JSON object per line with the key set {input, parts, mode}. input is the prompt text, parts holds {type, text, source} entries, and mode was only ever observed as normal. There is no timestamp and no session id, so a record here cannot be joined to a session in opencode.db. Not a duplicate of that database either: prompts present here can be absent from it entirely. Documented pending an adapter; wiring it would give OpenCode the fast prompt path it currently lacks.
- Agent:
OpenCode
- Role:
prompt_history- Format:
jsonl- Coverage:
catalog_only- Path:
${XDG_STATE_HOME or ${HOME}/.local/state}/opencode/prompt-history.jsonl- Adapter:
-
- Data version:
-- Version strategies:
catalog_observation- Observed:
opencode v1.18.15 (2026-08-08)
- Default search:
no
opencode.config¶
Application config (opencode.json/opencode.jsonc): providers, agents, plugins, commands, UI settings. Configuration, not chat.
- Agent:
OpenCode
- Role:
app_state- Format:
json_object- Coverage:
catalog_only- Path:
${XDG_CONFIG_HOME or ${HOME}/.config}/opencode/opencode.{json,jsonc}- Adapter:
-
- Data version:
-- Version strategies:
-- Observed:
opencode v1.18.15 (2026-08-08)
- Default search:
no
opencode.auth¶
Provider API keys and OAuth tokens. Documented but never enumerated.
- Agent:
OpenCode
- Role:
app_state- Format:
json_object- Coverage:
private- Path:
${XDG_DATA_HOME or ${HOME}/.local/share}/opencode/auth.json- Adapter:
-
- Data version:
-- Version strategies:
-- Observed:
opencode v1.18.15 (2026-08-08)
- Default search:
no
opencode.snapshots¶
Per-project git repositories holding session file snapshots.
- Agent:
OpenCode
- Role:
source_tree- Format:
opaque- Coverage:
catalog_only- Path:
${XDG_DATA_HOME or ${HOME}/.local/share}/opencode/snapshot/- Adapter:
-
- Data version:
-- Version strategies:
-- Observed:
opencode v1.18.15 (2026-08-08)
- Default search:
no
opencode.repos¶
Cache of cloned git repositories referenced during sessions.
- Agent:
OpenCode
- Role:
cache- Format:
opaque- Coverage:
catalog_only- Path:
${XDG_DATA_HOME or ${HOME}/.local/share}/opencode/repos/- Adapter:
-
- Data version:
-- Version strategies:
-- Observed:
opencode v1.18.15 (2026-08-08)
- Default search:
no
opencode.logs¶
Timestamped application logs. Diagnostics, not chat content.
- Agent:
OpenCode
- Role:
app_state- Format:
text- Coverage:
catalog_only- Path:
${XDG_DATA_HOME or ${HOME}/.local/share}/opencode/log/- Adapter:
-
- Data version:
-- Version strategies:
-- Observed:
opencode v1.18.15 (2026-08-08)
- Default search:
no
opencode.tool_output¶
Overflow storage for large tool output that exceeds inline limits.
- Agent:
OpenCode
- Role:
cache- Format:
text- Coverage:
catalog_only- Path:
${XDG_DATA_HOME or ${HOME}/.local/share}/opencode/tool-output/- Adapter:
-
- Data version:
-- Version strategies:
-- Observed:
opencode v1.18.15 (2026-08-08)
- Default search:
no
Record schema¶
Conversation database¶
opencode.db is a relational session → message → part schema
(Drizzle). A conversation turn is reconstructed by joining a part row up to
its message (for the role) and session (for the title and working
directory). User text parts participate in prompt scope under --exhaustive;
assistant and reasoning parts require --scope conversations or
--scope all.
session table — one row per session:
Column |
Type |
Description |
|---|---|---|
|
TEXT |
Session id (primary key) |
|
TEXT |
Git remote/root hash, or |
|
TEXT |
Working directory, stored verbatim |
|
TEXT |
Session title |
|
INTEGER |
Unix milliseconds |
message table — id, session_id (FK), and a data JSON column.
Assistant messages carry a top-level modelID/providerID/path.cwd;
user messages instead nest the selected model under model.modelID, so
agentgrep reads modelID and falls back to model.modelID:
{"role": "assistant", "modelID": "...", "providerID": "...",
"time": {"created": 1779999665000}, "path": {"cwd": "..."}}
part table — id, message_id (FK), session_id, and a data JSON
column holding one content part. The searchable text lives here:
Part |
Searchable field |
|---|---|
|
|
|
|
|
|
A part’s kind is derived from the joined message role (user →
prompt, otherwise history). Tool, file, snapshot, patch, and step-marker
parts are metadata and stay outside default search. Message timestamps
are unix-milliseconds and are normalized to ISO-8601.
The same opencode.db file also carries OpenCode’s v2 event-sourced
tables — session_input, session_message, event/event_sequence,
and todo. The event table is now populated on stable installs and
mirrors the part transcript text, so agentgrep leaves it unsearched to
avoid duplicate hits; the canonical transcript stays in
session/message/part. The secret-bearing account,
account_state, control_account, and credential tables are present
but never enumerated — the adapter reads only text-bearing part rows.
The legacy pre-migration layout (one JSON file per session, message, and
part under storage/) is documented but no longer searched — current
installs migrate it into opencode.db on startup.