Codex Desktop hook repro on Windows
Summary
I reproduced two Codex hook lifecycle issues while testing context-mode with Codex Desktop on Windows:
SessionStart and PreToolUse fire reliably.
PostToolUse fires for successful Bash tool calls, but does not fire for failing Bash tool calls with non-zero exit codes.
- The hook payload can carry a stale
session_id and transcript_path from an older session.
Because PostToolUse does not fire for failing Bash calls, context-mode cannot record the expected error_tool event for those failures.
This is different from #225. On this machine the dispatcher path works and successful Bash calls do produce PostToolUse; the remaining problem is that failing Bash calls do not.
Environment
- OS: Windows
- Client: Codex Desktop
- Model shown in hook payload:
gpt-5.4
- Permission mode shown in hook payload:
bypassPermissions
context-mode version: 1.0.89
- Project cwd used in repro:
C:\Users\admin\Documents\CodexPlayground
Hook configuration used
Working command form for this machine:
{
"hooks": {
"PreToolUse": [
{
"hooks": [
{
"type": "command",
"command": "C:\\Windows\\System32\\cmd.exe /d /c C:\\Users\\admin\\AppData\\Roaming\\npm\\context-mode.cmd hook codex pretooluse"
}
]
}
],
"PostToolUse": [
{
"hooks": [
{
"type": "command",
"command": "C:\\Windows\\System32\\cmd.exe /d /c C:\\Users\\admin\\AppData\\Roaming\\npm\\context-mode.cmd hook codex posttooluse"
}
]
}
],
"SessionStart": [
{
"hooks": [
{
"type": "command",
"command": "C:\\Windows\\System32\\cmd.exe /d /c C:\\Users\\admin\\AppData\\Roaming\\npm\\context-mode.cmd hook codex sessionstart"
}
]
}
]
}
}
For diagnosis I replaced those commands with wrapper scripts that:
- read the raw hook stdin
- forward stdin to
context-mode.cmd hook codex <mode>
- record stdin/stdout/stderr/exit code to files
The wrappers did not change the forwarded payload or returned output.
Repro steps
- Enable
codex_hooks = true.
- Configure
SessionStart, PreToolUse, and PostToolUse for context-mode.
- Start Codex Desktop in
C:\Users\admin\Documents\CodexPlayground.
- Run a successful Bash command:
Write-Output 'controlled-success-test'
- Wait about 1 second.
- Run a failing Bash command:
$ErrorActionPreference='Continue'; Write-Error 'controlled-failure-test'; exit 13
- Wait at least 5 seconds.
Observed behavior
A. SessionStart works
After restart, a new sessionstart wrapper log is written and context-mode creates a new session row in the project DB.
Example captured payload:
{
"session_id": "019da370-60bd-7c63-8c93-97fd35b5def2",
"transcript_path": "C:\\Users\\admin\\.codex\\sessions\\2026\\04\\19\\rollout-2026-04-19T09-52-24-019da370-60bd-7c63-8c93-97fd35b5def2.jsonl",
"cwd": "C:\\Users\\admin\\Documents\\CodexPlayground",
"hook_event_name": "SessionStart",
"model": "gpt-5.4",
"permission_mode": "bypassPermissions",
"source": "resume"
}
B. Successful Bash call fires both PreToolUse and PostToolUse
Captured PreToolUse payload:
{
"session_id": "019da370-60bd-7c63-8c93-97fd35b5def2",
"turn_id": "019da38f-ac6a-7640-8839-0cf7add93766",
"cwd": "C:\\Users\\admin\\Documents\\CodexPlayground",
"hook_event_name": "PreToolUse",
"tool_name": "Bash",
"tool_input": {
"command": "$ErrorActionPreference='Stop'; Write-Output 'controlled-success-test'"
}
}
Captured PostToolUse payload:
{
"session_id": "019da370-60bd-7c63-8c93-97fd35b5def2",
"turn_id": "019da38f-ac6a-7640-8839-0cf7add93766",
"cwd": "C:\\Users\\admin\\Documents\\CodexPlayground",
"hook_event_name": "PostToolUse",
"tool_name": "Bash",
"tool_input": {
"command": "$ErrorActionPreference='Stop'; Write-Output 'controlled-success-test'"
},
"tool_response": "controlled-success-test\r\n"
}
PostToolUse arrived with a small delay, around 0.7 seconds after PreToolUse.
C. Failing Bash call fires PreToolUse only
Captured PreToolUse payload:
{
"session_id": "019da370-60bd-7c63-8c93-97fd35b5def2",
"turn_id": "019da38f-ac6a-7640-8839-0cf7add93766",
"cwd": "C:\\Users\\admin\\Documents\\CodexPlayground",
"hook_event_name": "PreToolUse",
"tool_name": "Bash",
"tool_input": {
"command": "$ErrorActionPreference='Continue'; Write-Error 'controlled-failure-test'; exit 13"
}
}
Observed after waiting more than 5 seconds:
- a new
pretooluse.* log exists
- no matching
posttooluse.* log exists
- no new
error_tool event is written to the context-mode session DB
Additional issue: stale session metadata
Both the successful and failing Bash hook payloads above used the same old:
session_id = 019da370-60bd-7c63-8c93-97fd35b5def2
transcript_path = C:\Users\admin\.codex\sessions\2026\04\19\rollout-2026-04-19T09-52-24-019da370-60bd-7c63-8c93-97fd35b5def2.jsonl
But the actual latest context-mode session DB row for the project had already advanced to a newer session, for example:
session_id = 019da38c-a001-7fb1-80df-beea02017957
started_at = 2026-04-19 02:23:17
So the hook payload appears to be using stale session metadata even while new sessions are being created.
Expected behavior
PostToolUse should fire for both successful and failing Bash tool invocations.
- Failing Bash commands should still produce a
PostToolUse payload so downstream tools like context-mode can record error events.
session_id and transcript_path in hook payloads should match the current active session, not an older one.
Actual behavior
- Successful Bash:
PreToolUse + delayed PostToolUse
- Failing Bash:
PreToolUse only, no PostToolUse
- Hook payload session metadata can be stale
Why this matters for context-mode
context-mode can tolerate delay, but it cannot recover from a missing PostToolUse because:
- no
tool_response arrives for failed Bash calls
- no
error_tool event can be extracted
- session continuity and event analytics become incomplete
Local evidence files
Wrapper logs used for proof:
C:\Users\admin\.codex\hook-debug\logs\20260419-022356-766-sessionstart.stdin.json
C:\Users\admin\.codex\hook-debug\logs\20260419-022729-654-pretooluse.stdin.json
C:\Users\admin\.codex\hook-debug\logs\20260419-022730-329-posttooluse.stdin.json
C:\Users\admin\.codex\hook-debug\logs\20260419-022836-053-pretooluse.stdin.json
Project session DB:
C:\Users\admin\.codex\context-mode\sessions\f9ad9d0a70d1bd89.db
Codex Desktop hook repro on Windows
Summary
I reproduced two Codex hook lifecycle issues while testing
context-modewith Codex Desktop on Windows:SessionStartandPreToolUsefire reliably.PostToolUsefires for successfulBashtool calls, but does not fire for failingBashtool calls with non-zero exit codes.session_idandtranscript_pathfrom an older session.Because
PostToolUsedoes not fire for failingBashcalls,context-modecannot record the expectederror_toolevent for those failures.This is different from #225. On this machine the dispatcher path works and successful
Bashcalls do producePostToolUse; the remaining problem is that failingBashcalls do not.Environment
gpt-5.4bypassPermissionscontext-modeversion:1.0.89C:\Users\admin\Documents\CodexPlaygroundHook configuration used
Working command form for this machine:
{ "hooks": { "PreToolUse": [ { "hooks": [ { "type": "command", "command": "C:\\Windows\\System32\\cmd.exe /d /c C:\\Users\\admin\\AppData\\Roaming\\npm\\context-mode.cmd hook codex pretooluse" } ] } ], "PostToolUse": [ { "hooks": [ { "type": "command", "command": "C:\\Windows\\System32\\cmd.exe /d /c C:\\Users\\admin\\AppData\\Roaming\\npm\\context-mode.cmd hook codex posttooluse" } ] } ], "SessionStart": [ { "hooks": [ { "type": "command", "command": "C:\\Windows\\System32\\cmd.exe /d /c C:\\Users\\admin\\AppData\\Roaming\\npm\\context-mode.cmd hook codex sessionstart" } ] } ] } }For diagnosis I replaced those commands with wrapper scripts that:
context-mode.cmd hook codex <mode>The wrappers did not change the forwarded payload or returned output.
Repro steps
codex_hooks = true.SessionStart,PreToolUse, andPostToolUseforcontext-mode.C:\Users\admin\Documents\CodexPlayground.Observed behavior
A. SessionStart works
After restart, a new
sessionstartwrapper log is written andcontext-modecreates a new session row in the project DB.Example captured payload:
{ "session_id": "019da370-60bd-7c63-8c93-97fd35b5def2", "transcript_path": "C:\\Users\\admin\\.codex\\sessions\\2026\\04\\19\\rollout-2026-04-19T09-52-24-019da370-60bd-7c63-8c93-97fd35b5def2.jsonl", "cwd": "C:\\Users\\admin\\Documents\\CodexPlayground", "hook_event_name": "SessionStart", "model": "gpt-5.4", "permission_mode": "bypassPermissions", "source": "resume" }B. Successful Bash call fires both PreToolUse and PostToolUse
Captured
PreToolUsepayload:{ "session_id": "019da370-60bd-7c63-8c93-97fd35b5def2", "turn_id": "019da38f-ac6a-7640-8839-0cf7add93766", "cwd": "C:\\Users\\admin\\Documents\\CodexPlayground", "hook_event_name": "PreToolUse", "tool_name": "Bash", "tool_input": { "command": "$ErrorActionPreference='Stop'; Write-Output 'controlled-success-test'" } }Captured
PostToolUsepayload:{ "session_id": "019da370-60bd-7c63-8c93-97fd35b5def2", "turn_id": "019da38f-ac6a-7640-8839-0cf7add93766", "cwd": "C:\\Users\\admin\\Documents\\CodexPlayground", "hook_event_name": "PostToolUse", "tool_name": "Bash", "tool_input": { "command": "$ErrorActionPreference='Stop'; Write-Output 'controlled-success-test'" }, "tool_response": "controlled-success-test\r\n" }PostToolUsearrived with a small delay, around 0.7 seconds afterPreToolUse.C. Failing Bash call fires PreToolUse only
Captured
PreToolUsepayload:{ "session_id": "019da370-60bd-7c63-8c93-97fd35b5def2", "turn_id": "019da38f-ac6a-7640-8839-0cf7add93766", "cwd": "C:\\Users\\admin\\Documents\\CodexPlayground", "hook_event_name": "PreToolUse", "tool_name": "Bash", "tool_input": { "command": "$ErrorActionPreference='Continue'; Write-Error 'controlled-failure-test'; exit 13" } }Observed after waiting more than 5 seconds:
pretooluse.*log existsposttooluse.*log existserror_toolevent is written to thecontext-modesession DBAdditional issue: stale session metadata
Both the successful and failing Bash hook payloads above used the same old:
session_id = 019da370-60bd-7c63-8c93-97fd35b5def2transcript_path = C:\Users\admin\.codex\sessions\2026\04\19\rollout-2026-04-19T09-52-24-019da370-60bd-7c63-8c93-97fd35b5def2.jsonlBut the actual latest
context-modesession DB row for the project had already advanced to a newer session, for example:session_id = 019da38c-a001-7fb1-80df-beea02017957started_at = 2026-04-19 02:23:17So the hook payload appears to be using stale session metadata even while new sessions are being created.
Expected behavior
PostToolUseshould fire for both successful and failing Bash tool invocations.PostToolUsepayload so downstream tools likecontext-modecan record error events.session_idandtranscript_pathin hook payloads should match the current active session, not an older one.Actual behavior
PreToolUse+ delayedPostToolUsePreToolUseonly, noPostToolUseWhy this matters for context-mode
context-modecan tolerate delay, but it cannot recover from a missingPostToolUsebecause:tool_responsearrives for failed Bash callserror_toolevent can be extractedLocal evidence files
Wrapper logs used for proof:
C:\Users\admin\.codex\hook-debug\logs\20260419-022356-766-sessionstart.stdin.jsonC:\Users\admin\.codex\hook-debug\logs\20260419-022729-654-pretooluse.stdin.jsonC:\Users\admin\.codex\hook-debug\logs\20260419-022730-329-posttooluse.stdin.jsonC:\Users\admin\.codex\hook-debug\logs\20260419-022836-053-pretooluse.stdin.jsonProject session DB:
C:\Users\admin\.codex\context-mode\sessions\f9ad9d0a70d1bd89.db