Hooks: PostToolUse is missing for tools that complete via exec session / polling path
Summary
Codex emits PreToolUse for shell tools started via exec_command, but in some cases it never emits the matching PostToolUse.
This appears to happen specifically when the command does not complete on the initial exec_command call and instead completes later through the long-running session / polling path.
Expected behavior
Every tool call that emits PreToolUse should emit exactly one matching PostToolUse when the tool finishes, regardless of whether it:
- completes immediately on the initial tool call, or
- completes later through the session continuation / polling flow
Actual behavior
PostToolUse is emitted for commands that complete immediately, but is missing for commands that:
- start via
exec_command - return a running session
- later complete through the session / polling path
Evidence
In one reproduced case, a single turn produced:
7PreToolUse2PostToolUse
The transcript for that same turn showed that the missing tool calls did in fact complete successfully later, including exit codes and output, but no PostToolUse event was emitted for them.
The missing cases were long-running shell commands that first returned a session and later completed through polling. The two cases that did get PostToolUse were commands that completed directly on the initial exec_command path.
Impact
Consumers that rely on hooks to model tool lifecycle get incomplete traces:
- tools appear to start but never finish
- duration and status are missing
- downstream systems cannot reliably pair pre/post tool events
Root-cause hypothesis
The hook integration appears to emit PostToolUse only for the immediate completion path, but not for tool completion that happens later through the exec session continuation / polling path.
Suggested fix
Emit PostToolUse when the tool actually completes, regardless of whether completion happens:
- during the initial
exec_command, or - during later session polling / continuation
The emitted event should use the original tool call ID so consumers can pair it with the earlier PreToolUse.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗