📝 Bug Description
On native Windows, plugin/codex/scripts/run-bash-hook.ps1 (v2.2.1) waits for its stdout and stderr copy tasks after bash exits: $process.WaitForExit(), then [System.Threading.Tasks.Task]::WaitAll(@($stdoutTask, $stderrTask)). Those tasks complete only at EOF.
A native Windows process that the hook script starts in the background inherits the redirected pipe handles, even when the script redirects the child's own stdout and stderr. session-start.sh starts the server exactly that way when it is not running (line 45):
ENGRAM_CLOUD_AUTOSYNC=1 engram serve > /dev/null 2>> "$ENGRAM_SERVE_ERR_LOG" &
The wrapper therefore waits until Codex's hook timeout (10 s here), and Codex drops the SessionStart output. The first session after a cold start gets no memory context.
🔄 Steps to Reproduce
Isolated repro; no Engram server needed.
- Copy
plugin/codex/scripts/run-bash-hook.ps1 from v2.2.1 into an empty directory.
- Next to it, create
session-start.sh. The wrapper runs only approved script names that sit next to it.
#!/usr/bin/env bash
ping -n 6 127.0.0.1 > /dev/null 2>> "$(dirname "$0")/child.err.log" &
printf '%s\n' '{"context":"repro"}'
exit 0
- Run
powershell.exe -NoProfile -ExecutionPolicy Bypass -File <dir>\run-bash-hook.ps1 -HookScript <dir>\session-start.sh with stdin closed, and time it.
- For the control, run the same script without the
ping line.
✅ Expected Behavior
The wrapper returns when bash exits, in about the time the control takes.
❌ Actual Behavior
- With the background child, the wrapper took 5,362 ms, which is the lifetime of
ping -n 6.
- The control took 281 ms.
- With
engram serve as the child, the wait lasts until the hook timeout, so Codex discards the context block.
Operating System
Windows
Engram Version
2.2.0. The repro above used the v2.2.1 wrapper, unchanged.
Agent / Client
Other: Codex CLI 0.157.0, official Engram Codex plugin
📋 Relevant Logs
A real Codex 0.157.0 session on this host showed the same pattern:
serve.err.log recorded "listening" in the same second the session started.
- The Codex log was silent for 10.55 s before the first model request.
- The rollout contained no Engram block.
A later session, with the server already running, received the block after 1.5 s.
Versions: Windows 11 Pro 10.0.26200 x64, Windows PowerShell 5.1.26100.9444, Git for Windows bash 5.3.15.
💡 Additional Context
Either of these would fix it:
- Start the server detached from the hook's handles, through a path that does not inherit the redirected handles.
- Bound the drain after
WaitForExit(): wait for the copy tasks with a short timeout, then exit with the process exit code.
Possibly related: #1454, which has a different trigger but the same symptom: the lifecycle HTTP server is unavailable while MCP still works.
📝 Bug Description
On native Windows,
plugin/codex/scripts/run-bash-hook.ps1(v2.2.1) waits for its stdout and stderr copy tasks after bash exits:$process.WaitForExit(), then[System.Threading.Tasks.Task]::WaitAll(@($stdoutTask, $stderrTask)). Those tasks complete only at EOF.A native Windows process that the hook script starts in the background inherits the redirected pipe handles, even when the script redirects the child's own stdout and stderr.
session-start.shstarts the server exactly that way when it is not running (line 45):The wrapper therefore waits until Codex's hook timeout (10 s here), and Codex drops the SessionStart output. The first session after a cold start gets no memory context.
🔄 Steps to Reproduce
Isolated repro; no Engram server needed.
plugin/codex/scripts/run-bash-hook.ps1from v2.2.1 into an empty directory.session-start.sh. The wrapper runs only approved script names that sit next to it.powershell.exe -NoProfile -ExecutionPolicy Bypass -File <dir>\run-bash-hook.ps1 -HookScript <dir>\session-start.shwith stdin closed, and time it.pingline.✅ Expected Behavior
The wrapper returns when bash exits, in about the time the control takes.
❌ Actual Behavior
ping -n 6.engram serveas the child, the wait lasts until the hook timeout, so Codex discards the context block.Operating System
Windows
Engram Version
2.2.0. The repro above used the v2.2.1 wrapper, unchanged.
Agent / Client
Other: Codex CLI 0.157.0, official Engram Codex plugin
📋 Relevant Logs
A real Codex 0.157.0 session on this host showed the same pattern:
serve.err.logrecorded "listening" in the same second the session started.A later session, with the server already running, received the block after 1.5 s.
Versions: Windows 11 Pro 10.0.26200 x64, Windows PowerShell 5.1.26100.9444, Git for Windows bash 5.3.15.
💡 Additional Context
Either of these would fix it:
WaitForExit(): wait for the copy tasks with a short timeout, then exit with the process exit code.Possibly related: #1454, which has a different trigger but the same symptom: the lifecycle HTTP server is unavailable while MCP still works.