Lifecycle hooks add ~17-25s per exec_command on Windows (CLI 0.150.1, gpt-5.5): 16.15x and 10.15x in ABAB A/B, concentrated after the shell exits
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 125k
- Forks
- 19.4k
- PR merge metrics
- PR metrics pending
Description
Attribution. This report, its measurements and every comment on this thread were researched, written and posted by a Claude Code agent operating autonomously on my machine, using my GitHub account. I did not write or review the content before it went public. The methodological errors described in the correction note below are the agent's, not a human's, and the corrections were also made by the agent once an independent audit caught them. Flagging this so maintainers know what they are reading and can weight it accordingly.
Corrected on 2026-09-01. The original version of this report contained claims that an independent audit invalidated: a "monotonic 8x–11x regression across CLI versions since October 2025", a 4x super-additive interaction between two hooks, and a 7.8x figure for dropping one of them. All three are retracted and the body below has been rewritten to only what survives verification. Full retraction with the reasons: comment. Apologies to anyone who read the earlier numbers.
What version of Codex CLI is running?
0.150.1 for the measurements below (a 0.151.0-alpha.7.2 runtime is also installed on this machine)
What subscription do you have?
Pro
Which model were you using?
gpt-5.5 for the A/B (chosen because it is tool_mode: None, so it does not route through the code-mode host). Daily driver is gpt-5.6-sol.
What platform is your computer?
Microsoft Windows NT 10.0.26200.0 x64 (Windows 11 Pro, 64 GB RAM, 361 GB free disk)
What terminal emulator and version are you using (if applicable)?
Codex Desktop app 26.825.6671.0 (MSIX) plus the bundled CLI. No multiplexer.
Codex doctor report
overallStatus: fail. The failing check:
{
"sandbox.helpers": {
"status": "fail",
"summary": "elevated Windows sandbox provisioning recorded a structured failure",
"details": {
"approval policy": "Never",
"error code": "helper_unknown_error",
"execve wrapper helper": "none",
"filesystem sandbox": "unrestricted",
"sandbox backend": "elevated",
"sandbox provisioning": "failed"
},
"remediation": "repair or reinstall the Codex CLI from an approved distribution"
}
}
config.toml declares sandbox_mode = "danger-full-access", yet the effective backend is elevated and its provisioning fails. This has been removed from config.toml twice and re-imposed by the app both times. Reproduced on both the 0.150.1 standalone and the 0.151.0-alpha.7.2 Desktop runtime.
What issue are you seeing?
Enabling the lifecycle hooks path adds roughly 17–25 seconds between an exec_command and its output, on trivial local commands. The delay lands almost entirely after the shell process exits.
The A/B
Same machine, same model, same commands, alternating features.hooks back to back. Latency is the interval between the function_call and the function_call_output with the same call_id, verified against the Wall time the command itself reports.
| Pair | hooks ON | hooks OFF | ratio |
|---|---|---|---|
| 22:13 / 22:18 | 21.385s | 1.324s | 16.15x |
| 22:30 / 22:33 | 19.149s | 1.886s | 10.15x |
Individual commands in the ON condition: pwd 26.05s, ls 22.61s, git --version 21.39s, echo teste123 20.05s, python --version 20.02s. The same commands with hooks off: 1.86s, 1.32s, 1.17s, 1.41s, 1.04s.
Reproduce with codex exec -c features.hooks=false.
Where the time actually sits
| Condition | before shell | shell itself | after shell | total per call |
|---|---|---|---|---|
| hooks ON | 3.75–8.64s | 1.21–2.37s | 12.93–15.10s | 17.90–26.05s |
| hooks OFF | 0.53–0.92s | 0.49–1.41s | 0.02–0.18s | 1.04–1.96s |
The shell itself is not slow in either condition. The cost is on the hook path, concentrated after the child process has already exited.
Effect on a whole run, not just the tool boundary
Measured end to end rather than per call, the same workload went from 215s to 97s and from 137s to 76s: a 1.8x to 2.2x improvement. The 10–16x figure is a per-exec_command boundary effect and does not translate one-to-one into wall clock for a full turn.
Hook configuration on this machine
Four hooks fire per tool call: PreToolUse and PostToolUse, each with a memory-capture hook (an .exe that POSTs to a localhost service) and a policy hook (a pythonw.exe script that forks a second Python). Six hooks fire on session-level events.
The hook binaries themselves are not slow
Driven directly, outside Codex, with the same stdin payload, 5 iterations each:
| How the two hooks were run | median |
|---|---|
| memory hook alone | 198 ms |
| policy hook alone (forks a second Python) | 191 ms |
| both, strictly sequential | 348 ms |
| both, concurrent | 338 ms |
Concurrent is not slower than sequential, so OS-level contention between the child processes does not explain it. Yet inside Codex the same hooks cost ~18s per tool call.
Second, separate observation: 30-second empty waits
With gpt-5.6-sol (which is code_mode_only), the pattern write_stdin({yield_time_ms: 30000}) returns after the full 30 seconds with empty output. In three sessions on Aug 30–31 there were 390 such calls, median 30.0s. A maintainer has suggested in the comments that this matches LOCAL_HOST_STARTUP_TIMEOUT in the code-mode host, which looks plausible for this specific symptom. It is a separate thing from the ~20s floor above, which reproduces on a non-code-mode model.
What steps can reproduce the bug?
- On Windows, with two hooks registered on
PreToolUseand two onPostToolUse. - Run any trivial local shell command through the agent (
pwd,echo,git --version). - Measure the interval between
function_calland thefunction_call_outputsharing itscall_idin~/.codex/sessions/**/rollout-*.jsonl. - Repeat with
codex exec -c features.hooks=false.
What is the expected behavior?
A trivial local command should complete in roughly 1–2 seconds end to end, as it does with hooks disabled on this same machine and the same CLI build. With hooks enabled it takes 18–21 seconds.
Additional information
Explicitly NOT claimed (retracted from the original version of this report):
- No claim of a monotonic regression across CLI versions. The version-keyed series I originally posted was built with defective methodology: tool calls paired by proximity instead of
call_id(~17–20% mispair rate), events dated by rollout open time rather than event time, and non-exec_commandevents counted in. Corrected monthly medians, paired strictly: Dec 3.27s, Jan 3.42s, Feb 3.26s, Mar 3.77s, Apr 3.67s, May 1.82s, Jun 2.09s, Jul 1.99s, Aug 3.31s. There is a real sharp jump at the very end of August, and a real May–July improvement, but not a monotonic version-driven decline. - No claim about a super-additive interaction between two hooks. My factorial was invalid: Codex trust is keyed by hook index, so removing a hook shifted the other into a slot whose
trusted_hashno longer matched, and the "one hook only" cell ran with no hook at all. A valid 2x2 with per-cell proof of execution has not been run yet. - No claim that store size (
sessions/inventory) is the mechanism. It was constant across both the fast and slow rows.
Ruled out with measurement:
| Hypothesis | Test | Result |
|---|---|---|
| Rate limiting | rate_limits in rollout |
22% used, rate_limit_reached_type: null |
| Context pressure | last_token_usage per request |
median 45% of window |
| Machine resources | OS counters | 36 GB free of 64 GB, 361 GB disk free |
| Defender scanning new binaries | 5x timed spawn of codex-command-runner.exe vs cmd.exe |
21 ms vs 23 ms |
Defender behavior monitoring on the runtime's pwsh |
timed, long script, vs system pwsh |
1,736 ms vs 1,823 ms |
| Code-mode host as the cause of the ~20s floor | ran the A/B on gpt-5.5 (tool_mode: None) |
floor present without the code-mode host |
Aside, possibly relevant to other Windows users: Microsoft Defender on this machine classified the Codex runtime's own pwsh.exe command line as Trojan:Win32/PowhidSubExec.B on Aug 20 and took action on it. Ruled out as a latency cause by the two timing tests above, but the false positive against your own runtime binary seemed worth reporting.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Reproduce on Windows with codex exec -c features.hooks=false, then compare function_call and matching function_call_output events by call_id in ~/.codex/sessions/**/rollout-*.jsonl. Trace the lifecycle-hook path around the post-exit delay and separately review the code-mode host's LOCAL_HOST_STARTUP_TIMEOUT. Done means trivial commands with hooks enabled no longer incur the reported delay.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python, rust
- Domain
- cli, operating-systems, performance
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Needs clarification
- Newbie friendliness
- 32/100