opencode-memory
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseOpenCode Memory Browser
OpenCode 记忆浏览器
Lightweight, read-only access to your local OpenCode history. No injection, no bloat — just the ability to look things up when it would help.
This skill is specifically about OpenCode data stored on the local machine. It is not for ChatGPT history, Claude cloud history, generic browser history, or external memory products.
All data lives in a local SQLite database and plain files. You query them directly using via bash. No bundled scripts or external dependencies needed.
sqlite3轻量级、只读方式访问你的本地OpenCode历史记录。无注入、无冗余——仅在需要时提供查询能力。
该功能专门针对存储在本地设备上的OpenCode数据,不适用于ChatGPT历史、Claude云端历史、通用浏览器历史或其他外部记忆产品。
所有数据都存储在本地SQLite数据库和纯文本文件中。你可以通过bash使用直接查询,无需捆绑脚本或外部依赖。
sqlite3When to Use
使用场景
Auto-trigger (agent decides)
自动触发(由Agent决定)
- You are resuming work on a project and suspect prior sessions exist.
- The user references something done previously ("we did this before", "last time", "that plan we made").
- A recurring issue suggests checking if it was encountered before.
- The user asks about the state of plans, past decisions, or previous approaches.
- You need context that might exist in history but is not in the current session.
- 你正在恢复某个项目的工作,且怀疑存在过往会话记录。
- 用户提及之前做过的事情(如“我们之前做过这个”、“上次”、“我们制定的那个计划”)。
- 遇到重复出现的问题,需要检查之前是否遇到过。
- 用户询问计划状态、过往决策或之前的解决方案。
- 你需要当前会话中没有的、可能存在于历史记录中的上下文信息。
User-triggered (explicit request)
用户触发(明确请求)
- "Check my history"
- "What did we do in the last session?"
- "Show me my plans"
- "Search for when we discussed X"
- "What projects have I worked on?"
- "Look at previous conversations about Y"
- “查看我的历史记录”
- “我们上次会话做了什么?”
- “展示我的计划”
- “搜索我们讨论X的记录”
- “我都做过哪些项目?”
- “查看关于Y的过往对话”
Do NOT use when
请勿使用的场景
- The task is clearly brand new with no relevant history.
- Fresh repo context (files, git log) is sufficient.
- The user explicitly says they don't care about prior work.
- 任务是全新的,无相关历史记录。
- 最新的仓库上下文(文件、git日志)已足够回答问题。
- 用户明确表示不关心过往工作内容。
Storage Locations
存储位置
Database: ${XDG_DATA_HOME:-$HOME/.local/share}/opencode/opencode.db
Plans: ${XDG_DATA_HOME:-$HOME/.local/share}/opencode/plans/*.md
Session diffs: ${XDG_DATA_HOME:-$HOME/.local/share}/opencode/storage/session_diff/<session-id>.json
Prompt history: ${XDG_STATE_HOME:-$HOME/.local/state}/opencode/prompt-history.jsonlThe database path respects if set (default: ).
$XDG_DATA_HOME~/.local/shareDatabase: ${XDG_DATA_HOME:-$HOME/.local/share}/opencode/opencode.db
Plans: ${XDG_DATA_HOME:-$HOME/.local/share}/opencode/plans/*.md
Session diffs: ${XDG_DATA_HOME:-$HOME/.local/share}/opencode/storage/session_diff/<session-id>.json
Prompt history: ${XDG_STATE_HOME:-$HOME/.local/state}/opencode/prompt-history.jsonl数据库路径遵循环境变量(默认路径:)。
$XDG_DATA_HOME~/.local/shareDatabase Schema (what matters)
数据库架构(关键内容)
- project — (text PK),
id(path),worktree(often NULL, derive from worktree basename)name - session — (text, e.g.
id),ses_xxx(FK),project_id(NULL = main session, set = subagent),parent_id,title,summary,time_createdtime_updated - message — ,
id(FK),session_id(JSON withdata=$.roleor"user"),"assistant"time_created - part — ,
id(FK),message_id(FK),session_id(JSON withdata=$.typeand"text"= content)$.text
Timestamps are Unix milliseconds. Use to display them.
datetime(col/1000, 'unixepoch', 'localtime')- project — (文本类型主键)、
id(路径)、worktree(通常为NULL,可从worktree的basename推导)name - session — (文本类型,例如
id)、ses_xxx(外键)、project_id(NULL表示主会话,有值表示子Agent会话)、parent_id、title、summary、time_createdtime_updated - message — 、
id(外键)、session_id(JSON格式,data值为$.role或"user")、"assistant"time_created - part — 、
id(外键)、message_id(外键)、session_id(JSON格式,data值为$.type,"text"为内容)$.text
时间戳为Unix毫秒格式。使用进行格式转换显示。
datetime(col/1000, 'unixepoch', 'localtime')Ready-to-Use Queries
即用型查询语句
All queries use in read-only mode. Always run via bash.
sqlite3Shorthand used below:
DATA_ROOT="${XDG_DATA_HOME:-$HOME/.local/share}/opencode"
STATE_ROOT="${XDG_STATE_HOME:-$HOME/.local/state}/opencode"
DB="$DATA_ROOT/opencode.db"
DB_URI="file:${DB}?mode=ro"所有查询均使用的只读模式,始终通过bash执行。
sqlite3以下使用简写变量:
DATA_ROOT="${XDG_DATA_HOME:-$HOME/.local/share}/opencode"
STATE_ROOT="${XDG_STATE_HOME:-$HOME/.local/state}/opencode"
DB="$DATA_ROOT/opencode.db"
DB_URI="file:${DB}?mode=ro"Quick summary
快速概览
bash
sqlite3 "$DB_URI" "
SELECT 'projects', COUNT(*) FROM project
UNION ALL SELECT 'sessions (main)', COUNT(*) FROM session WHERE parent_id IS NULL
UNION ALL SELECT 'sessions (total)', COUNT(*) FROM session
UNION ALL SELECT 'messages', COUNT(*) FROM message
UNION ALL SELECT 'todos', COUNT(*) FROM todo;
"bash
sqlite3 "$DB_URI" "
SELECT 'projects', COUNT(*) FROM project
UNION ALL SELECT 'sessions (main)', COUNT(*) FROM session WHERE parent_id IS NULL
UNION ALL SELECT 'sessions (total)', COUNT(*) FROM session
UNION ALL SELECT 'messages', COUNT(*) FROM message
UNION ALL SELECT 'todos', COUNT(*) FROM todo;
"List projects
列出项目
bash
sqlite3 "$DB_URI" "
SELECT
COALESCE(p.name, CASE WHEN p.worktree = '/' THEN '(global)' ELSE REPLACE(p.worktree, RTRIM(p.worktree, REPLACE(p.worktree, '/', '')), '') END) AS name,
p.worktree,
(SELECT COUNT(*) FROM session s WHERE s.project_id = p.id AND s.parent_id IS NULL) AS sessions
FROM project p
ORDER BY p.time_updated DESC
LIMIT 10;
"bash
sqlite3 "$DB_URI" "
SELECT
COALESCE(p.name, CASE WHEN p.worktree = '/' THEN '(global)' ELSE REPLACE(p.worktree, RTRIM(p.worktree, REPLACE(p.worktree, '/', '')), '') END) AS name,
p.worktree,
(SELECT COUNT(*) FROM session s WHERE s.project_id = p.id AND s.parent_id IS NULL) AS sessions
FROM project p
ORDER BY p.time_updated DESC
LIMIT 10;
"List recent sessions
列出近期会话
bash
sqlite3 "$DB_URI" "
SELECT
s.id,
COALESCE(s.title, 'untitled') AS title,
COALESCE(p.name, CASE WHEN p.worktree = '/' THEN '(global)' ELSE REPLACE(p.worktree, RTRIM(p.worktree, REPLACE(p.worktree, '/', '')), '') END) AS project,
datetime(s.time_updated/1000, 'unixepoch', 'localtime') AS updated,
(SELECT COUNT(*) FROM message m WHERE m.session_id = s.id) AS msgs
FROM session s
LEFT JOIN project p ON p.id = s.project_id
WHERE s.parent_id IS NULL
ORDER BY s.time_updated DESC
LIMIT 10;
"bash
sqlite3 "$DB_URI" "
SELECT
s.id,
COALESCE(s.title, 'untitled') AS title,
COALESCE(p.name, CASE WHEN p.worktree = '/' THEN '(global)' ELSE REPLACE(p.worktree, RTRIM(p.worktree, REPLACE(p.worktree, '/', '')), '') END) AS project,
datetime(s.time_updated/1000, 'unixepoch', 'localtime') AS updated,
(SELECT COUNT(*) FROM message m WHERE m.session_id = s.id) AS msgs
FROM session s
LEFT JOIN project p ON p.id = s.project_id
WHERE s.parent_id IS NULL
ORDER BY s.time_updated DESC
LIMIT 10;
"Sessions for a specific project
特定项目的会话
Replace the worktree path with the actual project path:
bash
sqlite3 "$DB_URI" "
SELECT s.id, COALESCE(s.title, 'untitled'),
datetime(s.time_updated/1000, 'unixepoch', 'localtime')
FROM session s
JOIN project p ON p.id = s.project_id
WHERE p.worktree = '/path/to/project'
AND s.parent_id IS NULL
ORDER BY s.time_updated DESC
LIMIT 10;
"To find the worktree for the current directory:
git rev-parse --show-toplevel将工作树路径替换为实际项目路径:
bash
sqlite3 "$DB_URI" "
SELECT s.id, COALESCE(s.title, 'untitled'),
datetime(s.time_updated/1000, 'unixepoch', 'localtime')
FROM session s
JOIN project p ON p.id = s.project_id
WHERE p.worktree = '/path/to/project'
AND s.parent_id IS NULL
ORDER BY s.time_updated DESC
LIMIT 10;
"获取当前目录的工作树路径:
git rev-parse --show-toplevelRead messages from a session
读取会话中的消息
Replace the session ID:
bash
sqlite3 "$DB_URI" "
SELECT
json_extract(m.data, '$.role') AS role,
datetime(m.time_created/1000, 'unixepoch', 'localtime') AS time,
GROUP_CONCAT(json_extract(p.data, '$.text'), char(10)) AS text
FROM message m
LEFT JOIN part p ON p.message_id = m.id
AND json_extract(p.data, '$.type') = 'text'
WHERE m.session_id = 'SESSION_ID_HERE'
GROUP BY m.id
ORDER BY m.time_created ASC
LIMIT 50;
"替换会话ID:
bash
sqlite3 "$DB_URI" "
SELECT
json_extract(m.data, '$.role') AS role,
datetime(m.time_created/1000, 'unixepoch', 'localtime') AS time,
GROUP_CONCAT(json_extract(p.data, '$.text'), char(10)) AS text
FROM message m
LEFT JOIN part p ON p.message_id = m.id
AND json_extract(p.data, '$.type') = 'text'
WHERE m.session_id = 'SESSION_ID_HERE'
GROUP BY m.id
ORDER BY m.time_created ASC
LIMIT 50;
"Search across all conversations
跨所有对话搜索
Replace the search term:
bash
sqlite3 "$DB_URI" "
SELECT
s.id AS session_id,
COALESCE(s.title, 'untitled') AS title,
json_extract(m.data, '$.role') AS role,
datetime(m.time_created/1000, 'unixepoch', 'localtime') AS time,
substr(json_extract(p.data, '$.text'), 1, 200) AS snippet
FROM part p
JOIN message m ON m.id = p.message_id
JOIN session s ON s.id = m.session_id
WHERE s.parent_id IS NULL
AND json_extract(p.data, '$.type') = 'text'
AND json_extract(p.data, '$.text') LIKE '%SEARCH_TERM%'
ORDER BY m.time_created DESC
LIMIT 10;
"替换搜索关键词:
bash
sqlite3 "$DB_URI" "
SELECT
s.id AS session_id,
COALESCE(s.title, 'untitled') AS title,
json_extract(m.data, '$.role') AS role,
datetime(m.time_created/1000, 'unixepoch', 'localtime') AS time,
substr(json_extract(p.data, '$.text'), 1, 200) AS snippet
FROM part p
JOIN message m ON m.id = p.message_id
JOIN session s ON s.id = m.session_id
WHERE s.parent_id IS NULL
AND json_extract(p.data, '$.type') = 'text'
AND json_extract(p.data, '$.text') LIKE '%SEARCH_TERM%'
ORDER BY m.time_created DESC
LIMIT 10;
"List saved plans
列出已保存的计划
bash
ls -lt "$DATA_ROOT"/plans/*.md 2>/dev/null | head -20To read a specific plan:
bash
cat "$DATA_ROOT"/plans/FILENAME.mdbash
ls -lt "$DATA_ROOT"/plans/*.md 2>/dev/null | head -20读取特定计划:
bash
cat "$DATA_ROOT"/plans/FILENAME.mdShow recent prompt history
显示近期提示词历史
bash
tail -20 "$STATE_ROOT"/prompt-history.jsonlEach line is a JSON object. The user's input is typically in the or field.
inputtextbash
tail -20 "$STATE_ROOT"/prompt-history.jsonl每行是一个JSON对象。用户输入通常位于或字段中。
inputtextWorkflow
工作流程
Quick recall (most common)
快速调取(最常用)
- Run the summary query to see what's available.
- If you need sessions for the current project, get the worktree with , then run the project sessions query.
git rev-parse --show-toplevel - If you need a specific topic, run the search query.
- If you need full conversation detail, run the messages query with the session ID.
- 运行概览查询,查看可用的历史记录。
- 如果需要当前项目的会话记录,使用获取工作树路径,然后运行特定项目会话查询。
git rev-parse --show-toplevel - 如果需要特定主题的内容,运行搜索查询。
- 如果需要完整对话细节,使用会话ID运行消息查询。
Plan review
计划回顾
- List plans with .
ls -lt "$DATA_ROOT"/plans/*.md - Read a plan with .
cat "$DATA_ROOT"/plans/<filename>.md
- 使用列出所有计划。
ls -lt "$DATA_ROOT"/plans/*.md - 使用读取指定计划。
cat "$DATA_ROOT"/plans/<filename>.md
Deep investigation
深度调查
- Run projects to see all tracked repos.
- Run sessions for a specific project.
- Run messages for full conversation content.
- Cross-reference with search across all projects.
- 运行项目列表查询,查看所有被追踪的仓库。
- 运行特定项目的会话列表查询。
- 运行消息查询获取完整对话内容。
- 结合跨项目搜索查询进行交叉参考。
Critical Rules
重要规则
- Read-only. Never write to or modify the database or any OpenCode files.
- Use bash + sqlite3. Do not try to read with the Read tool — it is a binary file. Always query via
opencode.dbin bash.sqlite3 - Don't dump everything. Use and
LIMITto keep output focused. The database can contain tens of thousands of messages.LIKE - Summarize for the user. After retrieving data, distill the relevant parts. Don't paste raw query output.
- Respect privacy. Session history may contain sensitive data. Only surface what is relevant to the current task.
- Set path variables first. At the start of any memory lookup, set ,
DATA_ROOT,STATE_ROOT, andDBexactly as shown above so the commands work on XDG and non-XDG setups and keep SQLite access read-only.DB_URI
- 只读模式。绝不能写入或修改数据库或任何OpenCode文件。
- 使用bash + sqlite3。不要尝试用读取工具直接读取——它是二进制文件。始终通过bash中的
opencode.db进行查询。sqlite3 - 不要导出全部数据。使用和
LIMIT语句聚焦输出内容。数据库可能包含数万条消息。LIKE - 为用户总结内容。获取数据后,提炼相关部分。不要直接粘贴原始查询输出。
- 尊重隐私。会话历史可能包含敏感数据。仅展示与当前任务相关的内容。
- 先设置路径变量。在进行任何记忆查询前,严格按照上述示例设置、
DATA_ROOT、STATE_ROOT和DB变量,确保命令在XDG和非XDG环境下都能正常工作,并保持SQLite的只读访问模式。DB_URI
Fallback: Web UI
备选方案:Web界面
If the user needs visual dashboards or a browsable interface:
- Check if OpenCode web is running:
curl -s http://127.0.0.1:4096/api/health 2>/dev/null || echo "not running" - If running, direct the user to .
http://127.0.0.1:4096 - If not running, suggest .
opencode web - Note: only works with mDNS enabled (
opencode.local). Don't assume it exists.opencode web --mdns
如果用户需要可视化仪表盘或可浏览的界面:
- 检查OpenCode Web服务是否运行:
curl -s http://127.0.0.1:4096/api/health 2>/dev/null || echo "not running" - 如果正在运行,引导用户访问。
http://127.0.0.1:4096 - 如果未运行,建议用户执行启动服务。
opencode web - 注意:仅在启用mDNS时可用(执行
opencode.local),不要默认假设它存在。opencode web --mdns
Deep Reference
深度参考
See references/storage-format.md for the full storage layout, all table schemas, and additional query examples.
查看references/storage-format.md获取完整存储布局、所有表结构以及更多查询示例。