You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I have verified this feature I'm about to request hasn't been suggested before.
Describe the enhancement you want to request
Problem
OpenCode sessions grow unboundedly. There is no TTL, no auto-cleanup, no storage cap, and no post-compaction reclamation. Over time this leads to significant disk usage that users have reported across multiple issues.
Real-world data from 3 weeks of active use:
Metric
Value
Database size (opencode.db)
774 MB
Sessions
1,812 (248 root, 1,564 child)
Messages
50,818
Parts (PartTable rows)
176,596 (626 MB = 81% of DB)
Archived sessions
0 (no auto-archival exists)
Pruned parts still retaining full output
2,689 (14.15 MB wasted)
86% of all sessions are child sessions (from task() calls), and they hold 75% of total part storage.
Scope: DB growth vs. filesystem artifacts
This issue focuses on SQLite database growth (opencode.db + WAL/SHM). Filesystem-level storage leaks like tmp_pack_* file accumulation (#8749, #14811) are a separate problem with different root causes (snapshot system). Both contribute to disk pressure, but they require different solutions.
Current State
OpenCode has some building blocks, but they don't form a complete lifecycle:
Capability
Exists?
Gap
Prune (mark old tool outputs)
✅ compaction.ts:59-99
Sets time.compacted on ToolStateCompleted parts but never clears output or attachments — data stays in DB
Compaction (LLM summarization)
✅
Summary is tiny (~0.07 MB for 166 compactions) but pre-compaction parts are never reclaimed
Archive (mark session archived)
✅ Session.setArchived() + REST API
Not surfaced in TUI or CLI — users can't archive sessions without hitting the API directly
Remove (delete session + cascade children)
✅ Session.remove()
Manual only, no batch/auto cleanup
Auto-cleanup / TTL
❌
Nothing exists
Child session lifecycle
❌
No independent cleanup; only cascade-deleted with parent
Storage statistics / management UI
❌
No way to see DB size or per-session storage usage
SQLite VACUUM
❌
Never called — deleted/cleared data doesn't free disk space (passive WAL checkpoint exists at startup but only flushes, does not truncate WAL or reclaim row space)
Related Issues
This problem has surfaced across many issues, each addressing a piece:
None of these take a holistic view. This issue aims to unify them under a coherent session lifecycle management design.
Proposal
1. Post-Compaction Storage Reclamation
After compaction produces a summary, the original parts before the compaction point have served their purpose — the summary is usually sufficient for the model to continue.
The reclamation target is ToolStateCompleted parts — specifically their output (string) and attachments (FilePart[]) fields, which make up the vast majority of storage. Part rows and metadata (tool name, input args, timestamps) would be preserved.
Two levels of reclamation:
Conservative: Clear output and attachments from tool parts that already have time.compacted set. This is a natural extension of the current prune logic — prune already identifies these parts as disposable and the rendering layer already checks time.compacted (see message-v2.ts:637-638), it just doesn't follow through on clearing the stored content.
Aggressive: After compaction completes, clear output and attachments from allToolStateCompleted parts before the compaction point — not just the pruned ones. The compaction summary usually captures the full context needed to continue. This approach is proven in practice by oh-my-opencode's compaction strategy, which produces comprehensive summaries including child session records, task state, and key discoveries — and the model continues working effectively.
Whether to apply conservative or aggressive reclamation could be a user-configurable option, extending the existing config.compaction namespace (which already has auto and prune booleans).
In my database, parts account for 626 MB (81% of 774 MB). The compaction summaries total just 0.07 MB. The potential savings are orders of magnitude.
2. Auto-Archival for Inactive Sessions
Sessions that haven't been active for N days could be auto-archived. The time_archived column already exists in the schema but is never set automatically.
This would require adding a new configuration key (e.g., in the config.compaction or a new config.session namespace) since no session lifecycle config exists today. The auto-archive check could run at startup or on a periodic interval.
3. Child Session Lifecycle
Child sessions (86% of all sessions in my database) are created by task() and hold 75% of storage. Once a child session completes and returns its result to the parent, its detailed parts are rarely needed again.
Note: the parent session already captures the child's result in its own tool part output. The child's SubtaskPart only holds input metadata (prompt, description, agent) — the actual result lives in the parent's tool output. This means the child's full part history is largely redundant once the parent acknowledges the result.
Suggestion: Completed child sessions could have their parts reclaimed after a configurable retention period (e.g., 24h or N days). This preserves the ability to inspect recent child sessions for debugging while reclaiming storage from older ones. Immediate deletion is too aggressive — users may want to review child session details shortly after completion.
4. Session Management Tooling
Users currently have no visibility into storage usage and limited management options:
archive — supported via Session.setArchived() + REST API, but not surfaced in CLI or TUI — should be exposed as opencode session archive and a TUI action
No storage statistics — a command like opencode session stats could show DB size, session count, largest sessions
No VACUUM — SQLite does not automatically reclaim disk space from deleted rows. After batch cleanup, running VACUUM would reclaim disk space. Optionally, PRAGMA wal_checkpoint(TRUNCATE) could also be offered to shrink a large WAL file when the DB is idle. (Currently OpenCode only runs a passive checkpoint at startup via db.ts:83, which flushes WAL contents but does not truncate the file.)
Non-goals / Invariants
Preserve recent transcript UX — reclamation should not affect sessions the user is actively viewing or recently used. A retention window ensures users can still scroll back and inspect recent tool outputs.
Preserve task_id resume capability — child session data should be retained long enough for task_id-based resume to work. The retention period in Proposal feat: model config persistence #3 addresses this.
Don't VACUUM during active sessions — VACUUM requires exclusive access. It should only be triggered by explicit user action or at shutdown.
Reclamation is opt-in or gradual — start with the conservative approach; let users opt into aggressive reclamation.
Expose archive in TUI/CLI — small surface area change, high user impact.
Add opencode session stats — give users visibility into storage before asking them to manage it.
Add checkpoint/VACUUM to cleanup flow — ensure deleted data actually frees disk space.
Then iterate — auto-archival, child session lifecycle, and aggressive reclamation can build on this foundation.
Background
I discovered this problem while building a plugin that reads session history across projects for weekly work summaries. The 774 MB database (3 weeks, 10 projects) made it clear that session storage needs active lifecycle management. The plugin use case also highlighted that Session.listGlobal() is only accessible via an experimental API route — cross-project session access could benefit from first-class support.
Summary
The core ask is: sessions should have a lifecycle, not just a birth. The building blocks exist (prune, archive, remove, compaction) but they aren't connected into a coherent lifecycle. Adding post-compaction reclamation, auto-archival, child session cleanup, and management tooling would address the storage growth problem systematically rather than piecemeal.
Feature hasn't been suggested before.
Describe the enhancement you want to request
Problem
OpenCode sessions grow unboundedly. There is no TTL, no auto-cleanup, no storage cap, and no post-compaction reclamation. Over time this leads to significant disk usage that users have reported across multiple issues.
Real-world data from 3 weeks of active use:
opencode.db)86% of all sessions are child sessions (from
task()calls), and they hold 75% of total part storage.Scope: DB growth vs. filesystem artifacts
This issue focuses on SQLite database growth (
opencode.db+ WAL/SHM). Filesystem-level storage leaks liketmp_pack_*file accumulation (#8749, #14811) are a separate problem with different root causes (snapshot system). Both contribute to disk pressure, but they require different solutions.Current State
OpenCode has some building blocks, but they don't form a complete lifecycle:
compaction.ts:59-99time.compactedonToolStateCompletedparts but never clearsoutputorattachments— data stays in DBSession.setArchived()+ REST APISession.remove()Related Issues
This problem has surfaced across many issues, each addressing a piece:
More related issues and PRs
Storage growth (filesystem-level, separate root cause):
Related open PRs:
feat(cli): add session prune commandfeat: prune old tool outputs before compactionfix: clear tool output and attachments when pruningfeat: pluggable session storage backendsfix: add TTL, LRU eviction, ring buffersNone of these take a holistic view. This issue aims to unify them under a coherent session lifecycle management design.
Proposal
1. Post-Compaction Storage Reclamation
After compaction produces a summary, the original parts before the compaction point have served their purpose — the summary is usually sufficient for the model to continue.
The reclamation target is
ToolStateCompletedparts — specifically theiroutput(string) andattachments(FilePart[]) fields, which make up the vast majority of storage. Part rows and metadata (tool name, input args, timestamps) would be preserved.Two levels of reclamation:
Conservative: Clear
outputandattachmentsfrom tool parts that already havetime.compactedset. This is a natural extension of the current prune logic — prune already identifies these parts as disposable and the rendering layer already checkstime.compacted(seemessage-v2.ts:637-638), it just doesn't follow through on clearing the stored content.Aggressive: After compaction completes, clear
outputandattachmentsfrom allToolStateCompletedparts before the compaction point — not just the pruned ones. The compaction summary usually captures the full context needed to continue. This approach is proven in practice by oh-my-opencode's compaction strategy, which produces comprehensive summaries including child session records, task state, and key discoveries — and the model continues working effectively.Whether to apply conservative or aggressive reclamation could be a user-configurable option, extending the existing
config.compactionnamespace (which already hasautoandprunebooleans).In my database, parts account for 626 MB (81% of 774 MB). The compaction summaries total just 0.07 MB. The potential savings are orders of magnitude.
2. Auto-Archival for Inactive Sessions
Sessions that haven't been active for N days could be auto-archived. The
time_archivedcolumn already exists in the schema but is never set automatically.This would require adding a new configuration key (e.g., in the
config.compactionor a newconfig.sessionnamespace) since no session lifecycle config exists today. The auto-archive check could run at startup or on a periodic interval.3. Child Session Lifecycle
Child sessions (86% of all sessions in my database) are created by
task()and hold 75% of storage. Once a child session completes and returns its result to the parent, its detailed parts are rarely needed again.Note: the parent session already captures the child's result in its own tool part
output. The child'sSubtaskPartonly holds input metadata (prompt, description, agent) — the actual result lives in the parent's tool output. This means the child's full part history is largely redundant once the parent acknowledges the result.Suggestion: Completed child sessions could have their parts reclaimed after a configurable retention period (e.g., 24h or N days). This preserves the ability to inspect recent child sessions for debugging while reclaiming storage from older ones. Immediate deletion is too aggressive — users may want to review child session details shortly after completion.
4. Session Management Tooling
Users currently have no visibility into storage usage and limited management options:
archive— supported viaSession.setArchived()+ REST API, but not surfaced in CLI or TUI — should be exposed asopencode session archiveand a TUI actionopencode session statscould show DB size, session count, largest sessionsopencode session prune(see PR feat(cli): add session prune command for cleanup #12631) for removing old/archived sessions and reclaiming part storageVACUUMwould reclaim disk space. Optionally,PRAGMA wal_checkpoint(TRUNCATE)could also be offered to shrink a large WAL file when the DB is idle. (Currently OpenCode only runs a passive checkpoint at startup viadb.ts:83, which flushes WAL contents but does not truncate the file.)Non-goals / Invariants
task_idresume capability — child session data should be retained long enough fortask_id-based resume to work. The retention period in Proposal feat: model config persistence #3 addresses this.MVP Path
A practical incremental path:
opencode session stats— give users visibility into storage before asking them to manage it.Background
I discovered this problem while building a plugin that reads session history across projects for weekly work summaries. The 774 MB database (3 weeks, 10 projects) made it clear that session storage needs active lifecycle management. The plugin use case also highlighted that
Session.listGlobal()is only accessible via an experimental API route — cross-project session access could benefit from first-class support.Summary
The core ask is: sessions should have a lifecycle, not just a birth. The building blocks exist (prune, archive, remove, compaction) but they aren't connected into a coherent lifecycle. Adding post-compaction reclamation, auto-archival, child session cleanup, and management tooling would address the storage growth problem systematically rather than piecemeal.