Opencode session recovery
Public agent skills for OpenCode, Claude Code, Cursor, and other agent runtimes
npx -y skills add mvarge/agent-skills --skill opencode-session-recoveryAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- 27 days oldThe repository was created 27 days ago. New is not bad, but a brand new repository carrying a familiar-sounding name is the shape a typosquat arrives in, and there has been no time for anyone else to find a problem with it.
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Find, search, and resume past OpenCode sessions by querying the local SQLite session store directly. Auto-load whenever the user asks "which session was that", "find the session where we discussed X", "what did we do about Y last time", "resume the X session", "list my recent OpenCode sessions", or otherwise wants to locate or continue prior OpenCode work. Do not ask the user to click around the TUI picker — query the DB instead.
SKILL.md
7.7 KB, ~1.9k tokens by cl100k_base, as published. Nobody here has run it
OpenCode session recovery
OpenCode stores every session in a local SQLite database. When the user asks to find or resume a past session, do NOT tell them to open the session picker in the TUI — query the DB or use the helper scripts bundled with this skill. The built-in picker is title-only and doesn't support content search, which is usually what the user actually needs ("the session where we discussed the load balancer", not "the session titled exactly X").
Where the data lives
- DB path:
~/.local/share/opencode/opencode.db— SQLite, safe to read while OpenCode is running. sqlite3on the CLI is the simplest way in; anything that speaks SQLite works.- Session titles are auto-generated by whatever the user has configured as their
small_model. If titles look likeNew session - <ISO timestamp>for every session, title generation is silently failing — see the "Titles broken" section at the bottom.
Schema cheat sheet
Three tables matter:
session— one row per session.id(text, e.g.ses_0ae748691ffeKYezWOjxug2Ure)title(text, human-readable; may beNew session - …if untitled)directory(text, absolute path of the cwd when the session started)time_created,time_updated(integers, milliseconds since epoch — divide by 1000 beforedatetime())time_archived(integer or NULL — filterIS NULLfor live sessions)
message— one row per message.id,session_iddata(JSON blob;rolelives inside as$.role)
part— the actual content chunks.message_id,session_iddata(JSON blob; text parts are{"type":"text","text":"…"})
To search message text, LIKE against part.data. It's JSON, but plain-text substring match works fine for keyword hunting since the text is embedded verbatim.
The three helper scripts (preferred)
This skill bundles three scripts in scripts/. The user should symlink them into their PATH (e.g. ln -s $PWD/scripts/oc-* ~/bin/) — do this once during install. They're tuned for the common cases; use them before hand-writing SQL.
oc-ls — list recent sessions
oc-ls # sessions whose directory starts with cwd
oc-ls -a # all sessions everywhere
oc-ls -p ~/Projects/foo # sessions for a specific path prefix
oc-ls -n 50 # bump the row limit (default 30)
oc-ls moon # keyword filter (case-insensitive, slug/title/dir)
oc-ls -a "load balancer" # combine with -a/-p/-n; multi-word joins as one substring
Columns: slug | title | updated | dir | session_id. session_id is what you feed to oc-resume or opencode -s. Slugs (like neon-moon) are OpenCode's short human handles for sessions and are usable directly with oc-resume.
oc-grep — search sessions by message content
oc-grep "load balancer weekly"
oc-grep -p ~/Projects/foo "release"
oc-grep -n 5 "supabase migration"
Searches part.data for the substring across all sessions (or filtered by path prefix). Same output columns as oc-ls.
oc-resume — resume by slug, title fragment, or ID
oc-resume neon-moon # exact slug match (case-insensitive)
oc-resume "load balancer" # substring on slug OR title; if unambiguous, drops into that session
oc-resume ses_0b40615a5ffe... # by explicit ID
oc-resume -l "release" # list matches instead of resuming
Resolution order: (1) exact slug match on session.slug, (2) fall back to substring on slug OR title. If either pass returns more than one row, oc-resume refuses and prints the candidates so you can pick by ID. Under the hood it just runs opencode -s <id>.
Raw SQL when the scripts aren't enough
For anything the scripts don't cover (grouping, joining, custom time ranges), query the DB directly.
How many sessions did I have on a specific date?
sqlite3 ~/.local/share/opencode/opencode.db "
SELECT COUNT(*) FROM session
WHERE date(time_updated/1000, 'unixepoch', 'localtime') = '2026-07-10'
AND time_archived IS NULL;
"
Sessions per project, most active first:
sqlite3 -header -column ~/.local/share/opencode/opencode.db "
SELECT directory, COUNT(*) AS n
FROM session WHERE time_archived IS NULL
GROUP BY directory ORDER BY n DESC LIMIT 20;
"
Find the first user message of a specific session (great for "what was I asking about?"):
sqlite3 ~/.local/share/opencode/opencode.db "
SELECT substr(p.data, 1, 300)
FROM part p JOIN message m ON m.id = p.message_id
WHERE p.session_id = 'ses_XXX'
AND json_extract(m.data, '$.role') = 'user'
ORDER BY p.rowid ASC LIMIT 1;
"
SQLite's json_extract works fine on both message.data and part.data.
Resuming a session from the CLI
opencode -s <session_id>— drop into the TUI on that session (this is whatoc-resumedoes).opencode run --session <session_id> "your continuation prompt"— one-shot headless, useful when the user just wants to fire a follow-up without opening the TUI.opencode run --continue "…"— continue the most recent session, no ID needed.- Add
--forkto any of the above to branch off a copy instead of appending to the original.
Safe-query hygiene
- Read-only by default. Never
UPDATE,DELETE, orINSERTonopencode.dbwithout explicit permission — this file is the user's entire session history. Back up first (cp opencode.db opencode.db.bak.$(date -u +%Y%m%dT%H%M%SZ)) if you must mutate. - Escape single quotes in user input by doubling them (
'→'') when interpolating into SQL. The helper scripts already do this. - Full-text scans of
part.dataare fine — the DB is typically a few hundred MB and stays snappy.
Titles broken (triage playbook)
If a bunch of recent sessions come back titled New session - <ISO>, the small_model is failing to generate titles and OpenCode is swallowing the error.
- Tail the log for title/summary/HTTP errors:
tail -200 ~/.local/share/opencode/log/opencode.log | grep -iE 'title|summar|400|401|429|error' - Common causes seen in the wild:
- Anthropic thinking-mode conflict: if the small model has extended thinking enabled AND
temperature != 1, Anthropic returns a 400. Either setreasoning: falseon that model in~/.config/opencode/opencode.json, or leave temperature at its default. Titles need a low temperature, soreasoning: falseis usually the right fix. - Auth / rate limit: 401 or 429 from the provider — check credentials or quota.
- Model not available: provider returns 404 or the model id has been renamed.
- Anthropic thinking-mode conflict: if the small model has extended thinking enabled AND
- Fix the underlying cause; new sessions will get titles again. Existing "New session - …" rows stay untitled — either accept it, or write a small backfill script that reads the first user message from
partand calls your small-model API to generate a title, thenUPDATE session SET title = ? WHERE id = ?. Back up the DB before you run it.
When NOT to use this skill
- If the user asks about a session in a different tool (Claude Code, ChatGPT, Cursor) — this skill only knows OpenCode.
- For real-time state of the current session — that's just conversation memory, not the DB.
What ships with it: 3 files
7.7 KB alongside SKILL.md, 3 of them executable