π Bug Description
The Pi adapter (plugin/pi/index.ts, published as gentle-engram) creates a sessions row on session_start but never closes it. Its session_shutdown handler clears three in-memory maps and returns; it never calls POST /sessions/{id}/end.
On main today (f60fd0b6):
// plugin/pi/index.ts:1331
pi.on("session_shutdown", async (_event: unknown, ctx: SessionContext) => {
const sessionId = observeRuntimeSessionID(ctx);
if (!sessionId) return;
toolCounts.delete(sessionId);
forgetKnownSession(sessionId);
forgetSelfHealContext(sessionId);
});
Grepping /end across that file returns exactly one hit β line 1180, inside the mem_session_end tool handler. So closure is reachable only when the model voluntarily calls the tool; there is no lifecycle path.
This is the same defect class as #1083 (OpenCode), #1118 (Claude Code) and #48, and it produces the failure in #1101. Pi is the client that every one of those audits missed:
| Issue |
Clients in scope |
Pi included? |
| #48 |
Claude Code, OpenCode, Gemini CLI, Codex |
No β absent from the table |
| #1118 |
plugin/claude-code vs plugin/codex |
No |
| #1131 (open) |
OpenCode |
No β Agent / Client: OpenCode |
This repeats the pattern #1031 called out: a defect fixed for one client while another keeps reproducing it.
Pi's own extension documentation states the contract being violated: "Register an idempotent session_shutdown handler to close any session-scoped resources you start." The adapter registers the handler, so it is aware of the contract, and then closes nothing store-side.
Side note: this form's Agent / Client dropdown has no Pi option, which is arguably the same blind spot in reporting form.
π Steps to Reproduce
- Use Pi with the
gentle-engram package (npm:gentle-engram@0.1.12, current latest).
- Start a Pi session in a project directory, then exit it cleanly so
session_shutdown fires.
- Repeat at least twice in the same directory.
- Query the store:
SELECT id, started_at, ended_at FROM sessions
WHERE directory = '<project-dir>' AND ended_at IS NULL;
- Observe every Pi row still has
ended_at IS NULL.
- Call
mem_save without an explicit session_id from that directory.
Pi session ids are UUIDv7 (01a0β¦), which makes them easy to separate from Claude Code's UUIDv4 rows when auditing.
β
Expected Behavior
The session_shutdown handler should close the store-side session, mirroring what plugin/codex/scripts/session-end.sh does for Codex β i.e. POST /sessions/{id}/end for the shutting-down session id, idempotent as Pi's docs require, before the in-memory cleanup.
β Actual Behavior
Pi rows accumulate with ended_at = NULL indefinitely. Measured closure rate by client on one store, for sessions started after 2026-08-01, bucketed by session-id shape:
| Client (id shape) |
Sessions |
Closed |
| Claude Code (UUIDv4) |
196 |
61.2% |
| Manually named |
195 |
45.1% |
Pi / OpenCode (UUIDv7 01a0*) |
176 |
1.1% |
engram-generated (ses_*) |
69 |
0% |
Store-wide this reached 1996 of 2380 rows open (84%), and a single project directory accumulated 16 open rows, which made mem_save fail closed until the rows were closed manually via POST /sessions/{id}/end.
Operating System
macOS
Engram Version
2.0.0-rc.9
Agent / Client
Other
π Relevant Logs
multiple active runtime sessions match the current project and directory; provide session_id or end other active matching sessions before retrying
π‘ Additional Context
Verified the defect is in the published package, not in one local install:
- Installed
gentle-engram is 0.1.12, which is npm latest.
- The installed
index.ts is byte-identical to a pristine npm pack gentle-engram@0.1.12 tarball β SHA256 96dc8896c4dbdc5433eacb8c4a519df63fcab14f21d6398b96bcb87f015b006a for both.
- The same handler is present in the pristine tarball, in
plugin/pi/index.ts at ebf1228, and on main at f60fd0b6. It is not fixed upstream.
gentle-pi (main) contains no reference to closing engram sessions, so nothing else compensates.
Two related observations, both consistent with #1131's expected-behavior points 1 and 2 rather than new claims:
ActiveRuntimeSessions applies no recency bound and no live-process check, so a single unclosed row is permanent. That is documented intent ("rejects ambiguity rather than selecting by recency"), but it means any client that leaks one row eventually hard-fails mem_save for that directory.
engram doctor does not flag orphaned ended_at IS NULL rows whose owning process is gone. During this investigation it reported the affected project as ok on every session check while mem_save was failing.
One further data point for whoever picks this up: two rows could not be closed through the HTTP route at all and still hold real observations (46 and 3). One has an empty id, the other has id manual-save-/ with project /; both break the /sessions/{id}/end path. These look like the residue of #630.
π Bug Description
The Pi adapter (
plugin/pi/index.ts, published asgentle-engram) creates asessionsrow onsession_startbut never closes it. Itssession_shutdownhandler clears three in-memory maps and returns; it never callsPOST /sessions/{id}/end.On
maintoday (f60fd0b6):Grepping
/endacross that file returns exactly one hit β line 1180, inside themem_session_endtool handler. So closure is reachable only when the model voluntarily calls the tool; there is no lifecycle path.This is the same defect class as #1083 (OpenCode), #1118 (Claude Code) and #48, and it produces the failure in #1101. Pi is the client that every one of those audits missed:
plugin/claude-codevsplugin/codexAgent / Client: OpenCodeThis repeats the pattern #1031 called out: a defect fixed for one client while another keeps reproducing it.
Pi's own extension documentation states the contract being violated: "Register an idempotent
session_shutdownhandler to close any session-scoped resources you start." The adapter registers the handler, so it is aware of the contract, and then closes nothing store-side.Side note: this form's
Agent / Clientdropdown has noPioption, which is arguably the same blind spot in reporting form.π Steps to Reproduce
gentle-engrampackage (npm:gentle-engram@0.1.12, currentlatest).session_shutdownfires.ended_at IS NULL.mem_savewithout an explicitsession_idfrom that directory.Pi session ids are UUIDv7 (
01a0β¦), which makes them easy to separate from Claude Code's UUIDv4 rows when auditing.β Expected Behavior
The
session_shutdownhandler should close the store-side session, mirroring whatplugin/codex/scripts/session-end.shdoes for Codex β i.e.POST /sessions/{id}/endfor the shutting-down session id, idempotent as Pi's docs require, before the in-memory cleanup.β Actual Behavior
Pi rows accumulate with
ended_at = NULLindefinitely. Measured closure rate by client on one store, for sessions started after 2026-08-01, bucketed by session-id shape:01a0*)ses_*)Store-wide this reached 1996 of 2380 rows open (84%), and a single project directory accumulated 16 open rows, which made
mem_savefail closed until the rows were closed manually viaPOST /sessions/{id}/end.Operating System
macOS
Engram Version
2.0.0-rc.9
Agent / Client
Other
π Relevant Logs
multiple active runtime sessions match the current project and directory; provide session_id or end other active matching sessions before retryingπ‘ Additional Context
Verified the defect is in the published package, not in one local install:
gentle-engramis0.1.12, which is npmlatest.index.tsis byte-identical to a pristinenpm pack gentle-engram@0.1.12tarball β SHA25696dc8896c4dbdc5433eacb8c4a519df63fcab14f21d6398b96bcb87f015b006afor both.plugin/pi/index.tsatebf1228, and onmainatf60fd0b6. It is not fixed upstream.gentle-pi(main) contains no reference to closing engram sessions, so nothing else compensates.Two related observations, both consistent with #1131's expected-behavior points 1 and 2 rather than new claims:
ActiveRuntimeSessionsapplies no recency bound and no live-process check, so a single unclosed row is permanent. That is documented intent ("rejects ambiguity rather than selecting by recency"), but it means any client that leaks one row eventually hard-failsmem_savefor that directory.engram doctordoes not flag orphanedended_at IS NULLrows whose owning process is gone. During this investigation it reported the affected project asokon every session check whilemem_savewas failing.One further data point for whoever picks this up: two rows could not be closed through the HTTP route at all and still hold real observations (46 and 3). One has an empty
id, the other hasidmanual-save-/withproject/; both break the/sessions/{id}/endpath. These look like the residue of #630.