anomalyco / anomalyco/opencode
Session load parses summary.diffs patches from message rows; hundreds of MB of JSON per session, multi-GB heap spike on resume
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 209k
- Forks
- 27.5k
- PR merge metrics
- PR metrics pending
Description
opencode 1.18.30, macOS (Apple Silicon, 36 GB). Bun runtime.
With snapshot tracking on, each user message stores summary.diffs[].patch: the full
unified diff of every working-tree change since the previous turn. In a large working
tree the patches get enormous. One session of 68 messages holds 390 MB of message JSON;
a single message is 330 MB (24,444 file diffs: other agents sharing the same working
directory were unpacking archives during that turn). Across my store, 48 messages hold
2.2 GB (33 sessions); the part table for the same sessions is ~7 MB.
Effect: resuming a session (opencode --session <id>) parses all of it. Measured with
vmmap: 53 MB at start, 5.7 GB resident at 61 s, peak footprint 5.0 GB, settling to ~0.7 GB
after GC while idle. Sending one prompt in that session took the process to 8.2 GB.
With 13 restored sessions resuming together the machine jetsammed (44 GB across opencode
processes).
Related: the event table grows without bound (30.6 GB, 83k rows; message.updated and
message.part.updated copy the full message/part JSON per update), and a 6 h session
wrote 550 GB via WAL checkpoints.
Workarounds that hold: "snapshot": false in config stops new patches; deleting
summary.diffs from the oversized rows (json_remove) and VACUUM took the store from
2.4 GB to 220 MB with the session still exporting intact; the same session then peaks
at 750 MB instead of 5.0 GB.
Suggestions: cap or truncate stored patches (or store diffs out of the message row and
load them lazily), and bound the event table (compact or drop replayed events).
Code paths (v1.18.30 tag; same at HEAD ebb7b76)
packages/opencode/src/session/summary.tssummarize(): loads every message of the
session (sessions.messages, line 116) on each turn, computessnapshot.diffFull(from, to)
(line 98) and writes the result into the user message (target.info.summary = {..., diffs},
line 125) viasessions.updateMessage. Nothing bounds the number of files or the total size.packages/opencode/src/snapshot/index.tsdiffFull:git showof the before and after
content for every added/deleted/modified file between the two snapshot hashes. The only
guard is the per-filelimit = 2 * 1024 * 1024(line 24) at tracking time, so a turn that
touches thousands of files stores thousands of full-content patches.packages/opencode/src/session/session.tsupdateMessage(line 631): publishes
SessionV1.Event.MessageUpdatedwith the wholeinfoobject, diffs included, so the event
store persists a full copy of the payload on every update.packages/opencode/src/cli/cmd/export.ts(lines 173, 207) is the only reader of
summary.diffsbesides the UI "changes" chip; the model request never uses it, which is
why lazy-loading it out of the message row is safe.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reading packages/opencode/src/session/summary.ts and packages/opencode/src/session/session.ts, then trace snapshot.diffFull in packages/opencode/src/snapshot/index.ts. Inspect packages/opencode/src/cli/cmd/export.ts to understand the summary.diffs reader. Done means resuming large sessions no longer causes the reported memory spike while session export remains intact and event growth is addressed.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- git, typescript
- Domain
- backend, databases, performance
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Needs clarification
- Newbie friendliness
- 30/100