| name | opencode-session-recovery |
|---|---|
| description | Recover lost opencode conversations after folder rename/move. Auto-relinks stale session.directory pointers via project_id (git root commit hash). Supports --check, --relink, and manual --old/--new remap. Verified on Windows; designed for macOS/Linux. |
Recovers conversation history that becomes inaccessible after renaming or moving a project folder.
opencode stores conversations in ~/.local/share/opencode/opencode.db. Each session has a directory field pointing to the project root at creation time. When you rename the folder, opencode can't find old sessions because the path doesn't match.
But session.project_id references project.id — a git root commit hash (git rev-list --max-parents=0 --all) that stays the same across renames. This skill uses that stable relationship to relink sessions to the new path, no guessing required.
python scripts/recover_sessions.py --check# Preview
python scripts/recover_sessions.py --relink --dry-run
# Execute
python scripts/recover_sessions.py --relinkPhase 1 uses project_id matching (safe, deterministic). Phase 2 falls back to path heuristic (requires manual confirmation).
When you know both the old and new paths:
python scripts/recover_sessions.py --old "path/to/old-name" --new "path/to/new-name" --dry-run
python scripts/recover_sessions.py --old "path/to/old-name" --new "path/to/new-name"Move the N most recent sessions from one project to another, updating both directory and project_id:
# Preview
python scripts/recover_sessions.py --migrate --old "path/to/source" --new "path/to/target" --count 3 --dry-run
# Execute (migrate 5 latest sessions, default)
python scripts/recover_sessions.py --migrate --old "path/to/source" --new "path/to/target"
# Execute (migrate 2 latest)
python scripts/recover_sessions.py --migrate --old "path/to/source" --new "path/to/target" --count 2Sessions that already belong to the target project are skipped automatically. Output distinguishes subagent sessions ([subagent] tag) from top-level conversations.
python scripts/recover_sessions.py --check| Argument | Description |
|---|---|
--check |
List sessions whose directory no longer exists |
--relink |
Auto-match stale sessions to current worktrees |
--migrate |
Migrate N latest sessions from --old to --new (updates directory + project_id) |
--count N |
Number of latest sessions to migrate (default: 5, only with --migrate) |
--old |
Old / stale project path (manual or migrate mode) |
--new |
New / current project path (manual or migrate mode) |
--dry-run |
Preview only — do not modify database |
The session table stores directory at creation time and never updates it. The project table, however, is kept current. When you rename a folder:
project.worktreeis updated (or a new project row is created with the sameproject_id)session.directorystill points to the old path- opencode's UI queries sessions by
directory, so old conversations are hidden
This skill simply does UPDATE session SET directory = project.worktree WHERE session.project_id = project.id — exactly what opencode itself could, but currently doesn't, do.
project_id is derived from the git root commit hash, not the HEAD commit. It is stable during normal development but changes in these scenarios:
| Scenario | project_id Changes? | Recovery Method |
|---|---|---|
| Rename folder (git repo) | No | --relink (auto) |
| Move folder (git repo) | No | --relink (auto) |
git init on non-git dir |
Yes | --old / --new (manual) |
| Root commit changes (orphan branch, subtree merge) | Yes | --old / --new (manual) |
Delete .git and re-init |
Yes | --old / --new (manual) |
| Non-git directory rename | Yes | --old / --new (manual) |
When two separate git repos share a lineage (e.g. old CST_MCP renamed to cst-runtime-cli vs. new cst-runtime-cli-dev), sessions have different project_id values. The --old/--new mode updates only directory, leaving the session bound to the old project. The --migrate mode fixes both directory and project_id, making sessions fully visible under the target project.
Sessions spawned by subagents (agent field = explore, general, etc.) have a non-null parent_id linking them to their parent session. These sub-sessions are not displayed as independent entries in opencode's UI. --migrate output marks them with a [subagent] tag and shows their parent title, so you know which sessions will actually appear as top-level conversations.
| Table | Key column | Purpose |
|---|---|---|
project |
id |
Git root commit hash (stable across renames) |
project |
worktree |
Current project root path |
session |
project_id → project.id |
Links session to git identity |
session |
directory |
Path at session creation (can become stale) |
session |
parent_id |
Non-null = subagent session (hidden from main list) |
session |
agent |
Agent type (build, explore, general, etc.) |