🔍 Problem Description
Archiving an OpenCode session does not currently close its corresponding Engram session. This leaves the Engram session open after the user has archived the conversation, requiring separate lifecycle management.
In the inspected OpenCode adapter, plugin/opencode/engram.ts handles session.created and session.deleted; deletion only cleans local maps. There is no archive-to-session-close integration. The adapter already registers the native OpenCode session ID unchanged and excludes subagents, so the integration should retain that identity boundary rather than infer a session from a project name or title.
💡 Proposed Solution
Handle OpenCode session archival in the thin Engram OpenCode adapter and request closure of the exact, already-registered matching Engram session. Upstream documentation/source indicates archival is represented by session.updated with time.archived, not a dedicated session.archived event. Verify the installed SDK/runtime payload contract during implementation; this issue does not claim that contract has been tested locally.
Acceptance criteria:
- Detect archival through the verified OpenCode event payload. Ignore ordinary session updates and unrelated, subagent, or unregistered sessions. Do not synthesize an Engram session solely to close it.
- Use the existing native OpenCode session identity. Keep event translation in the plugin and closure semantics in the Engram core.
- Make closure idempotent and summary-preserving in the core, including repeated archive events and retries. The current
POST /sessions/{id}/end path calls Store.EndSession; an empty payload can overwrite an existing summary with NULL, repeated calls can rewrite the close timestamp, and an unknown ID currently produces no error. Do not blindly forward an empty close request without addressing those safeguards.
- Establish and test an inactive-state check or an explicit safe policy for archival while a session is busy; an archive update must not silently terminate active work.
- Explicitly define and document unarchive/resume behavior. Re-registering the same ID currently does not clear
ended_at; do not silently assume that registration reopens a session or introduce reopening as an incidental side effect.
- Preserve observations and prompts. Archival is session closure, not data deletion, and must not fabricate or automatically generate a summary.
- Add focused plugin and core tests for the installed event payload, ordinary updates, identity isolation, excluded sessions, repeated events/retries, summary preservation, unknown IDs, busy-session handling, and the chosen unarchive/resume policy. Update the relevant plugin/lifecycle documentation.
Keep this scoped to the archive integration and the safeguards needed to make it safe, not a broad lifecycle redesign.
📦 Affected Area
Other
🔄 Alternatives Considered
No response
📎 Additional Context
Related closed reports: #48, #1083 and #1131 concern missing session closure or accumulated open sessions; #972 concerns re-registering an already-ended session. The reviewed bodies do not describe handling OpenCode archival through session.updated / time.archived. This request specifically tracks that archive-triggered integration and its safety requirements.
Relevant implementation locations from the inspected checkout: plugin/opencode/engram.ts, internal/server/server.go, and internal/store/store.go. Existing sync application preserves a prior ended_at when an incoming value is null, which must be considered when defining resume behavior. No implementation is included in this request.
Delivery slices
- PR #1250 — Core closure semantics (383 changed lines).
- Issue #1259 — Delayed closure sync.
- Issue #1263 — OpenCode archive-to-idle feature (may require a maintainer-approved
size:exception).
- Issue #1264 — Archive lifecycle hardening.
- Issue #1235 — Later adapter-to-core refactor.
Sequential main-target PR order: #1250, then a PR for #1259, then a PR for #1263, then a PR for #1264, and then a PR for #1235.
🔍 Problem Description
Archiving an OpenCode session does not currently close its corresponding Engram session. This leaves the Engram session open after the user has archived the conversation, requiring separate lifecycle management.
In the inspected OpenCode adapter,
plugin/opencode/engram.tshandlessession.createdandsession.deleted; deletion only cleans local maps. There is no archive-to-session-close integration. The adapter already registers the native OpenCode session ID unchanged and excludes subagents, so the integration should retain that identity boundary rather than infer a session from a project name or title.💡 Proposed Solution
Handle OpenCode session archival in the thin Engram OpenCode adapter and request closure of the exact, already-registered matching Engram session. Upstream documentation/source indicates archival is represented by
session.updatedwithtime.archived, not a dedicatedsession.archivedevent. Verify the installed SDK/runtime payload contract during implementation; this issue does not claim that contract has been tested locally.Acceptance criteria:
POST /sessions/{id}/endpath callsStore.EndSession; an empty payload can overwrite an existing summary with NULL, repeated calls can rewrite the close timestamp, and an unknown ID currently produces no error. Do not blindly forward an empty close request without addressing those safeguards.ended_at; do not silently assume that registration reopens a session or introduce reopening as an incidental side effect.Keep this scoped to the archive integration and the safeguards needed to make it safe, not a broad lifecycle redesign.
📦 Affected Area
Other
🔄 Alternatives Considered
No response
📎 Additional Context
Related closed reports: #48, #1083 and #1131 concern missing session closure or accumulated open sessions; #972 concerns re-registering an already-ended session. The reviewed bodies do not describe handling OpenCode archival through
session.updated/time.archived. This request specifically tracks that archive-triggered integration and its safety requirements.Relevant implementation locations from the inspected checkout:
plugin/opencode/engram.ts,internal/server/server.go, andinternal/store/store.go. Existing sync application preserves a priorended_atwhen an incoming value is null, which must be considered when defining resume behavior. No implementation is included in this request.Delivery slices
size:exception).Sequential main-target PR order: #1250, then a PR for #1259, then a PR for #1263, then a PR for #1264, and then a PR for #1235.