OpenCode¶
OpenCode is a SQLite-backed conversation backend. agentgrep reconstructs turns
from the relational session/message/part tables, and reads OpenCode’s
prompt-history log for the fast prompt path, so plain agentgrep search
reaches OpenCode prompts without --exhaustive. Assistant and reasoning parts
require conversation scope. Targeted effort cannot route this backend.
Base path: ~/.local/share/opencode (env overrides: XDG_DATA_HOME,
OPENCODE_DB); prompt history under ~/.local/state/opencode (env override:
XDG_STATE_HOME).
observed_version: opencode v1.19.4 (observed 2026-10-25).
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:
default_search- Adapter:
opencode.prompt_history_jsonl.v1
- 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.19.4 (2026-10-25)
- Default search:
yes
SQLite tables observed (1.19.4, 2026-10-25)
- __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.19.4 (2026-10-25)
- 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 as typed, with a placeholder such as [Pasted ~43 lines] where text was pasted; each parts entry holds that pasted text and a source.text span (start, end, value) locating its placeholder. 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.
- Agent:
OpenCode
- Role:
prompt_history- Format:
jsonl- Coverage:
default_search- Path:
${XDG_STATE_HOME or ${HOME}/.local/state}/opencode/prompt-history.jsonl- Adapter:
opencode.prompt_history_jsonl.v1- Data version:
-- Version strategies:
catalog_observation- Observed:
opencode v1.19.4 (2026-10-25)
- Default search:
yes
Record keys observed (1.19.4, 2026-10-25)
- Keys:
input,mode,parts
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.19.4 (2026-10-25)
- 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.19.4 (2026-10-25)
- 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.19.4 (2026-10-25)
- 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.19.4 (2026-10-25)
- 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.19.4 (2026-10-25)
- 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.19.4 (2026-10-25)
- 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.
Prompt history¶
opencode.prompt_history is OpenCode’s recall log, one JSON
object per line:
{"input": "Review [Pasted ~43 lines]", "mode": "normal",
"parts": [{"type": "text", "text": "...",
"source": {"text": {"start": 7, "end": 25,
"value": "[Pasted ~43 lines]"}}}]}
input is the prompt as typed. A pasted block shows there as a placeholder,
and its parts entry holds the pasted text with the placeholder’s span;
agentgrep splices the paste back in, so pasted text is searchable. mode is
kept as metadata.
The log has no timestamp and no session id, and agentgrep invents neither. Its
records sort after dated ones, a date filter excludes them, and
has:timestamp is false for them. Plain search reads this log alone, so a
prompt appears once. Under --exhaustive or --scope all,
opencode.db is read too, and a prompt present in both
appears once per store, the same way Codex’s prompt history stands beside its
session transcripts and Claude Code’s history.jsonl beside its project
transcripts. The log is not a copy of the database: prompts recalled there can
be absent from opencode.db entirely.
Changes by version¶
Each entry brackets a change between the observation that first saw it and the last one that did not; see Observed record shapes.
1.19.4¶
Observed 2026-10-25: no store changes since 1.18.30 (2026-09-11).
1.18.30¶
Observed 2026-09-11: no store changes since 1.18.15 (2026-08-08).