English · 简体中文
A desktop tool to visually browse and clean old OpenCode conversations, orphan
snapshot directories and stale session_diff files — as a terminal (TUI) and a GUI
application, written in C++17 for Windows.
- Browse all OpenCode sessions, snapshot directories and their sizes.
- Works with both opencode database layouts. v1 keeps sessions in
sessionand messages inmessage+part, with an append-onlyeventlog; v2 moved them tosession_v2andsession_messageand retired the event log. The tool resolves the right tables per database, so nothing created after an upgrade goes missing (and a v2 session'ssession_diffis never mistaken for an orphan). When the event log is gone the database view says so instead of offering a compaction that has nothing to act on. - Both front ends share the same feature set and the same filter/sort code
(
session_view.cpp), so they cannot drift apart. - Sessions view: id, title, project / worktree, message count, created & updated.
- Snapshots view: marked
in use(a session still references that project) orno session(orphan), with directory size. - Select multiple items and remove them, with a confirmation dialog that lists exactly what goes.
- Nothing is deleted outright: files are sent to the Windows Recycle Bin by default.
- Live search across id / title / project / path, sortable columns, and an "orphans only" filter.
- Per row: copy the resume command
opencode -s <id>, jump to resume the session in a new console (in its worktree when it still exists), dir / open to reveal the folder in Explorer. - Snapshot sizes are measured a few directories at a time, so neither front end stalls on a large data directory.
- Chinese/CJK font support (loads Microsoft YaHei etc. automatically), DPI-aware on scaled displays and when dragging between monitors.
- Orphan
session_diff/*.jsoncleanup, either on demand or (opt-in) on exit. - Database view: where the disk space actually goes, and the safe ways to get it back — orphan event rows, event-log compaction, VACUUM, and the files that live next to the database (the text log, and leftover tool output a deleted session left behind). On a real 4.4 GB database this reclaimed 4.5 GB.
- Session preview (the tail of the conversation) and JSON export of selected sessions.
- Rule based selection:
--older-than,--max-messages, then "select matching" and delete. - A headless CLI for everything the UI does, so the tool is scriptable and testable.
- Removals use
SHFileOperation(FOF_ALLOWUNDO), i.e. the Recycle Bin, so a wrong click is recoverable. SetOPENCODE_SM_NO_RECYCLE=1(or pass--no-recycleto the TUI) to delete permanently instead. - The "cleanup on exit" behaviour is off by default in both front ends; use the checkbox, the
Clean orphan diffsbutton, or--cleanup. - Deleting a session also removes the rows that belong to it (
message,part,session_message,session_input,todo, ...). opencode's schema declares foreign keys for only a couple of these tables, so the tool also treats "any table with asession_idcolumn" as session-scoped. - The delete runs in a single transaction with a 5 second busy timeout, and reports failures instead of pretending it worked (for example when opencode is holding the database).
- Windows (paths and console behaviour are Windows-specific).
- MinGW-w64
g++with C++17 (tested with GCC 8.1). - sqlite3 dev lib (
C:\MinGW\optin the defaults below). - The TUI also needs
ncursesw. - Dear ImGui is bundled in this repo (
imgui/).
rem TUI (terminal app) -> dist\opencode-session-manager.exe
build.bat
rem GUI (Win32 + OpenGL3 + ImGui) -> dist\opencode-session-manager-gui.exe
build_gui.bat
rem data layer tests -> dist\test_data.exe (+ runs them)
build_tests.batThe GUI is a single file, no bundled DLLs (only Windows system libraries such as
opengl32.dll).
If your toolchain lives somewhere else, override it — the scripts are no longer hard-wired to
C:\MinGW:
set MINGW_ROOT=D:\msys64\ucrt64
set MINGW_OPT=D:\msys64\ucrt64\opt
build_gui.batWith mingw32-make installed, the Makefile does the same:
mingw32-make rem TUI + GUI + tests
mingw32-make gui
mingw32-make test rem builds and runs the tests
mingw32-make cleanThe version compiled into the executables comes from a single file, version.h, which resource.rc
and the C++ sources both include.
build_tests.bat (or mingw32-make test) builds and runs tests/test_data.cpp, which covers the
things that are easy to get wrong and impossible to notice by clicking around:
- non-ASCII paths (a Chinese
%USERPROFILE%, worktree and snapshot directory), - the delete cascade against a schema shaped like the real one (child tables that carry a
session_idwithout declaring a foreign key), - a locked database (the delete must fail loudly, not silently),
- the shared view model: filtering (including CJK and ASCII case folding), every sort field and direction, tie-break determinism, and that building a view never mutates its input,
- the database maintenance module: the space report, the compaction plan (and that planning is read-only), orphan event removal, applying a plan, VACUUM, session preview and JSON export,
- orphan diff cleanup, UTF-8 safe truncation, and the resume-command argument guard.
133 checks, 0 failed
GitHub Actions builds the TUI, the GUI and the tests on every push (.github/workflows/build.yml).
A helper mode is available for inspecting a real database:
dist\test_data.exe --delete <path\to\opencode.db> <session-id> [<session-id> ...]The tool reads the same data as OpenCode:
- Windows data dir:
%USERPROFILE%\.local\share\opencode
Override it for testing:
set OPENCODE_DATA_DIR=C:\some\opencode\data
dist\opencode-session-manager-gui.exeOther environment variables:
| Variable | Effect |
|---|---|
OPENCODE_DATA_DIR |
Data directory to read (opencode.db, storage/, snapshot/) |
OPENCODE_SM_NO_RECYCLE |
1 = delete permanently instead of using the Recycle Bin |
Settings (currently just the text size) are stored per user in
%APPDATA%\opencode-session-manager\settings.ini.
| Key | Action |
|---|---|
up/down / j / k |
Move cursor |
PgUp / PgDn, Home / End |
Page up/down, first/last row |
Space |
Toggle selection |
Ctrl+A |
Select all visible rows |
Ctrl+D |
Clear selection |
Tab |
Switch view (Sessions / Snapshots / Database) |
F5 |
Reload data |
/ |
Filter (live, Enter applies, Esc cancels) |
s / S |
Cycle the sort field / reverse the direction |
d or Enter |
Remove selected (confirm with y, cancel with n) |
c |
Copy the resume command opencode -s <id> |
o |
Resume the cursor session in a new console |
r |
Reveal the worktree / snapshot folder in Explorer |
O |
Snapshots view: orphan directories only |
p |
Sessions view: preview the tail of the session |
e |
Export the selected sessions to JSON |
x |
Clean orphan session_diff files now |
Ctrl+E |
Toggle cleanup-on-exit |
Esc |
Clear the filter, or quit when there is none |
q |
Quit |
Database view keys: r scan, c analyse the event log (dry run), x clean orphan events,
b compact (backs up first), v VACUUM, j/k/PgUp/PgDn scroll.
The header line shows the filtered/total row count, the active sort and how much space the orphan
snapshot directories hold. Snapshot sizes are measured a few directories at a time, so the UI stays
responsive on large data directories; while that runs, a progress bar on the line under the tab bar
shows the percentage and how many directories are left (... marks rows whose size is not known yet).
The same load/filter/sort pipeline is available without the UI, which makes the tool scriptable:
rem the 10 biggest orphan snapshot directories
opencode-session-manager.exe --list --snapshots --orphans --limit 10
rem sessions mentioning a project, sorted by message count
opencode-session-manager.exe --list --filter nixStats --sort msgs| Option | Effect |
|---|---|
--list |
print the current view and exit |
--snapshots |
list snapshot directories instead of sessions |
--orphans |
--snapshots: only directories no session references |
--filter <text> |
match id / title / project / worktree (or path / name) |
--sort <field> |
created, updated, msgs, size, status, id, name, project |
--asc |
sort ascending (default: descending) |
--limit <n> |
print at most n rows |
--older-than <days> |
only sessions older than that |
--max-messages <n> |
only sessions with at most n messages |
--preview <id> |
print the tail of a session |
--export <dir> |
write the listed sessions to JSON files |
--cleanup |
also clean orphan session_diff files after the UI exits |
--no-recycle |
delete permanently instead of using the Recycle Bin |
--version |
print the version and exit |
Everything above cleans sessions, snapshots and diffs — which on a real machine is only a few MB. The Database view exists because the file is usually somewhere else entirely:
$ opencode-session-manager --db-report
database file : 4.4G (1141873 pages x 4096 bytes)
free pages : 214M <- reclaimable by VACUUM
largest tables (estimated from content bytes when dbstat is unavailable):
event 3.6G
part 57.6M
...
event log 3.6G (232110 rows) by type:
message.part.updated.1 191168 rows 3.6G
message.updated.1 31481 rows 86.4M
event is opencode's append-only event log, and message.part.updated.1 stores a complete
snapshot of a message part on every update — one part in the database above has 87,121
versions, which is 2.8 GB on its own. Deleting a session does not touch those rows, which is why
the file never shrinks.
Three operations, in increasing order of daring:
| Operation | What it does | Safety |
|---|---|---|
--clean-orphan-events |
Removes event rows whose session no longer exists | Safe: the aggregate is gone, nothing can replay it |
--compact-events |
Keeps only the newest version of each part | Rewrites the event log. Dry run by default; a backup is mandatory to apply |
--vacuum |
Rewrites the file so free pages go back to the filesystem | Needs temp space ≈ the file size and a few minutes; close opencode first |
--clean-aux |
Removes log files and tool-output/ files no session references |
Never touches a file a session still points at (those are part of the conversation) |
rem see where the space goes (read-only)
opencode-session-manager.exe --db-report
rem reclaim what is provably dead, then compact, then shrink the file
opencode-session-manager.exe --clean-orphan-events --yes
opencode-session-manager.exe --compact-events rem dry run
opencode-session-manager.exe --compact-events --yes --backup D:\opencode.db.bak
opencode-session-manager.exe --vacuum --yesNotes on compaction, since it is the one that rewrites opencode's data:
- It is a dry run unless you pass
--yes, and--yesadditionally requires--backup <file>. The GUI always takes a backup before applying. - Rows whose part id cannot be read (oversized ones) are never deleted.
- It keeps the newest version by
seq, so the final state of every part is preserved. Whether opencode's replay is happy with the older versions gone can only be proven by running opencode against the result — which is exactly why the backup is not optional. - Both front ends share one implementation and run these as background jobs with progress, so a multi-minute VACUUM never freezes the window.
- The space scan is one sequential pass over the event log with the folding done in C++ instead
of SQL.
GROUP BY typehas no index to lean on in opencode's schema, and SQLite's fallback sorter carries the wholedatacolumn: measured on a 4.4 GB database that query took ~80 s and churned ~34 GB of temporary files (SQLite unlinks them immediately, but Windows only returns the space when the last handle closes, so the system drive appears to be filling up while it runs). The streaming version takes ~15 s, peaks at a few hundred MB and creates no temporary files.
- View buttons switch between Sessions / Snapshots / Database; the menu bar shows the totals and how much space the orphan snapshot directories hold.
- Toolbar: Refresh, Select All, Clear Sel, Delete Selected, Clean orphan diffs,
a Cleanup on exit checkbox, a search box, an Orphans only filter, the rule based selection
(
Older than [n] days,max msgs, Select matching), a Preview toggle and the text size control. - Click a column header to sort (by default: sessions by creation date, snapshots by size — largest first, which is the usual reason to open this tool).
- Keyboard:
F5refresh,Delremove selected,Ctrl+Aselect all,Ctrl+Dclear selection,Ctrl+Ffocus the search box,Ctrl++/Ctrl+-/Ctrl+0text size,Escclear the search / selection. - Per row actions: copy (resume command), jump (resume in a new console), dir / open (reveal in Explorer).
- The Database tab has a scan button plus the three maintenance operations, each behind a confirmation dialog, and runs them in the background with a progress bar.
- Text size is adjustable from the toolbar (
Text: 24 px - + reset); the setting is saved to%APPDATA%\opencode-session-manager\settings.ini. The default reproduces the size earlier builds rendered at — see the note below.
Dear ImGui 1.92 computes GetFontSize() as
style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi. Earlier builds passed an
already-DPI-scaled pixel size to the font atlas and set FontScaleDpi, so text always rendered at
scale² — 36px on a 150% display instead of 24px. That is fixed (the monitor scale is applied once),
which on its own makes the text look smaller than people were used to, so the text size became a
setting whose default matches the old appearance. Ctrl+0 / reset returns to that default;
keep pressing Ctrl+- to reach the size a plain 16px UI would use at 100%.
Column widths are derived from the live font metrics, so the action buttons cannot be clipped at any text size.
Bundled third-party libs keep their own licenses: Dear ImGui is MIT. sqlite3 is public domain.