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

default store
default store
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

catalog store
catalog store
Role:

app_state

Format:

json_object

Coverage:

catalog_only

Adapter:

-

private store
private store
Role:

app_state

Format:

json_object

Coverage:

private

Adapter:

-

catalog store
catalog store
Role:

source_tree

Format:

opaque

Coverage:

catalog_only

Adapter:

-

catalog store
catalog store
Role:

cache

Format:

opaque

Coverage:

catalog_only

Adapter:

-

catalog store
catalog store
Role:

app_state

Format:

text

Coverage:

catalog_only

Adapter:

-

Role:

cache

Format:

text

Coverage:

catalog_only

Adapter:

-

opencode.db

opencode.db
default store
default store
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

opencode.storage_legacy
catalog store
catalog store
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

opencode.prompt_history
default store
default store
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

opencode.config
catalog store
catalog store
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

opencode.auth
private store
private store
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

opencode.snapshots
catalog store
catalog store
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

opencode.repos
catalog store
catalog store
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

opencode.logs
catalog store
catalog store
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

opencode.tool_output
catalog store
catalog store
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

id

TEXT

Session id (primary key)

project_id

TEXT

Git remote/root hash, or global

directory

TEXT

Working directory, stored verbatim

title

TEXT

Session title

time_created / time_updated

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 type

Searchable field

text

text (user prompts and assistant replies)

reasoning

text (model thinking)

subtask

prompt

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).