Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,22 @@ $ uvx --from 'agentgrep' --prerelease allow python

<!-- END PLACEHOLDER - ADD NEW CHANGELOG ENTRIES BELOW THIS LINE -->

### What's new

#### OpenCode backend (#30)

agentgrep now searches [OpenCode](https://github.com/anomalyco/opencode)
(formerly `sst/opencode`). OpenCode keeps conversations in a single
SQLite database (`opencode.db`) under `~/.local/share/opencode`, so it
joins the relational `session → message → part` tables and surfaces each
text-bearing part — user prompts, assistant replies, model reasoning,
and subtask prompts — with the session title, working directory, and
model attached. Discovery honours `XDG_DATA_HOME` and the `OPENCODE_DB`
override, and every other on-disk store (the legacy JSON layout, config,
snapshots, the repo cache, logs, and tool output) is catalogued for
completeness, with `auth.json` documented but never indexed. See
{doc}`/backends/opencode` for details.

## agentgrep 0.1.0a12 (2026-05-31)

agentgrep 0.1.0a12 adds Pi (the earendil-works "Pi Agent Harness") as
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)

Read-only search for local AI agent prompts and history across Codex,
Claude Code, Cursor, Gemini, Grok, and Pi.
Claude Code, Cursor, Gemini, Grok, Pi, and OpenCode.

`agentgrep` provides a CLI and an MCP server over the same discovery + parsing layer:

Expand Down
7 changes: 7 additions & 0 deletions docs/backends/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,12 @@ Grok CLI prompt history, session transcripts, memory, logs, and config.
Pi (earendil-works) session transcripts, settings, prompts, and managed extensions.
:::

:::{grid-item-card} OpenCode
:link: opencode
:link-type: doc
OpenCode (anomalyco) SQLite session store, config, snapshots, and caches.
:::

::::

## Coverage levels
Expand Down Expand Up @@ -91,4 +97,5 @@ cursor-ide
gemini
grok
pi
opencode
```
63 changes: 63 additions & 0 deletions docs/backends/opencode.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
(backend-opencode)=

# OpenCode

Base path: `~/.local/share/opencode` (env overrides: `XDG_DATA_HOME`, `OPENCODE_DB`).

`observed_version`: `opencode v1.15.11` (observed 2026-05-30).

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). This makes OpenCode a
SQLite backend, like Grok's `session_search` and Cursor's `state.vscdb`,
rather than a JSONL-transcript backend.

## Stores

```{storage:agent} opencode
```

## Record schema

### opencode.db

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

`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:

```json
{"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 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.
2 changes: 1 addition & 1 deletion docs/dev/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Cross-commit `hyperfine` sweeps across HEAD, trunk, ranges, lookback, tags, or e
:::{grid-item-card} Storage catalogue
:link: storage-catalog
:link-type: doc
On-disk store layouts for Codex, Claude Code, Cursor, Gemini CLI, Grok CLI, and Pi — useful for adapter authors and anyone tracing why a record was or wasn't found.
On-disk store layouts for Codex, Claude Code, Cursor, Gemini CLI, Grok CLI, Pi, and OpenCode — useful for adapter authors and anyone tracing why a record was or wasn't found.
:::

:::{grid-item-card} Architecture decisions
Expand Down
28 changes: 28 additions & 0 deletions docs/dev/storage-catalog.md
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,34 @@ Documentary-only entries cover settings, auth (private credentials),
models, themes, tools, managed binaries, prompt templates, the debug
log, and the npm extension install root.

### OpenCode

`observed_version`: ``opencode v1.15.11`` (observed 2026-05-30).

OpenCode (anomalyco/opencode) stores conversations in a single SQLite
database under `${XDG_DATA_HOME or ${HOME}/.local/share}/opencode/`,
unlike the JSONL-transcript backends:

- `opencode.db_sqlite.v1` parses the `opencode.db` SQLite database. It
joins the relational `part → message → session` tables: each
text-bearing `part` row becomes a record whose `kind` comes from the
joined message `role` (`user` → prompt, else history). Searchable text
is `part.data` of type `text`/`reasoning` (the `text` field) and
`subtask` (the `prompt`); the session `title`, `directory`, and the
message `model`/timestamp are attached. Message times are
unix-milliseconds, normalized to ISO-8601.

Discovery resolves the data root via `XDG_DATA_HOME` (default
`~/.local/share`) plus the `opencode` segment and finds `opencode.db` by
filename — not a glob, so the binary SQLite file bypasses the text
prefilter. An absolute `OPENCODE_DB` value is discovered as that exact
file, so channel installs are reachable by pointing `OPENCODE_DB` at
their `opencode-<channel>.db`.

Documentary-only entries cover the legacy per-file JSON layout, config,
auth (private credentials), snapshots, the repo cache, logs, and tool
output.

## Adding or updating a store

1. Edit `src/agentgrep/store_catalog.py`. Stamp `observed_version`
Expand Down
2 changes: 1 addition & 1 deletion docs/getting-started/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Use `--agent` one or more times to limit search or discovery:
$ uv run agentgrep grep "cache" --agent codex
```

Supported agents are `codex`, `claude`, `cursor-cli`, `cursor-ide`, `gemini`, `grok`, and `pi`. Omitting `--agent` searches all supported agents.
Supported agents are `codex`, `claude`, `cursor-cli`, `cursor-ide`, `gemini`, `grok`, `pi`, and `opencode`. Omitting `--agent` searches all supported agents.

## Search type

Expand Down
2 changes: 1 addition & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

# agentgrep

Read-only search for local AI agent prompts and history across Codex, Claude Code, Cursor, Gemini, Grok, and Pi.
Read-only search for local AI agent prompts and history across Codex, Claude Code, Cursor, Gemini, Grok, Pi, and OpenCode.

```{warning}
**Pre-alpha.** APIs may change. [Feedback welcome](https://github.com/tony/agentgrep/issues).
Expand Down
2 changes: 1 addition & 1 deletion docs/mcp/resources.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ used to interpret that source.
```{fastmcp-resource-template} agentgrep_sources_by_agent
```

Read `agentgrep://sources/codex`, `agentgrep://sources/claude`, `agentgrep://sources/cursor-cli`, `agentgrep://sources/cursor-ide`, `agentgrep://sources/gemini`, `agentgrep://sources/grok`, or `agentgrep://sources/pi` to filter discovery by agent.
Read `agentgrep://sources/codex`, `agentgrep://sources/claude`, `agentgrep://sources/cursor-cli`, `agentgrep://sources/cursor-ide`, `agentgrep://sources/gemini`, `agentgrep://sources/grok`, `agentgrep://sources/pi`, or `agentgrep://sources/opencode` to filter discovery by agent.

## Store catalog

Expand Down
2 changes: 1 addition & 1 deletion docs/tui/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# TUI

The `agentgrep ui` command launches the interactive Textual explorer
over the same Codex, Claude Code, Cursor, Gemini, Grok, and Pi stores the rest
over the same Codex, Claude Code, Cursor, Gemini, Grok, Pi, and OpenCode stores the rest
of the CLI walks. It is read-only — agentgrep never mutates the
source stores. Bare `agentgrep` prints the directory of choices, so
the explorer always needs the explicit `ui` subcommand.
Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[project]
name = "agentgrep"
version = "0.1.0a12"
description = "Read-only search for local AI agent prompts and history (Codex, Claude Code, Cursor, Gemini, Grok, Pi)"
description = "Read-only search for local AI agent prompts and history (Codex, Claude Code, Cursor, Gemini, Grok, Pi, OpenCode)"
requires-python = ">=3.14,<4.0"
authors = [
{name = "Tony Narlock", email = "tony@git-pull.com"}
Expand All @@ -21,7 +21,7 @@ classifiers = [
"Typing :: Typed",
]

keywords = ["ai", "codex", "claude", "cursor", "gemini", "grok", "pi", "mcp", "search", "agent-history"]
keywords = ["ai", "codex", "claude", "cursor", "gemini", "grok", "pi", "opencode", "mcp", "search", "agent-history"]
readme = "README.md"
packages = [
{ include = "*", from = "src" },
Expand Down
Loading
Loading