[Hooks] SubagentStart and SubagentStop are not dispatched for project-defined custom subagents on Windows
What version of Codex CLI is running?
codex-cli 0.144.1 and codex-cli 0.144.4
What subscription do you have?
Not applicable to this probe (custom Responses-compatible API provider).
Which model were you using?
gpt-5.6-sol (custom Responses-compatible API provider)
What platform is your computer?
Microsoft Windows NT 10.0.19043.0 x64 (Windows 10 Pro, build 19043)
What terminal emulator and version are you using (if applicable)?
Windows PowerShell 5.1.19041.1023
Codex doctor report
{
"status": "not_collected",
"reason": "The completed isolated probes did not collect a Codex doctor report; no additional probe was run."
}
What issue are you seeing?
Trusted and active SubagentStart and SubagentStop command hooks are not invoked when a real project-defined custom subagent starts and completes. The custom subagent itself is created successfully and returns the expected result, but the hook handler process is never launched.
This was reproduced in three isolated repositories/runs with Codex CLI 0.144.1 and 0.144.4. The final 0.144.4 run used the wildcard matcher .*, so the result is not explained by the earlier exact matcher.
The current Codex Hooks documentation documents both lifecycle events, says their matcher is applied to the subagent type, and states that project-local hooks load for trusted projects after the hook definitions are reviewed and trusted.
The custom agent starts, returns exactly HOOK_PROBE_WORKER_COMPLETE, and completes, but every real run records:
SubagentStarthandler process launches: 0SubagentStophandler process launches: 0- raw lifecycle payload rows: 0
- hook command errors shown by Codex: none
The handler writes and flushes a process-start record before reading or parsing stdin. Therefore, zero process-start rows means the configured command handler was not launched; this is not merely a payload parsing failure.
Because no real hook payload exists, the opaque runtime agent_id, payload agent_type, parent session_id, transcript_path, and agent_transcript_path are unavailable. The selected project profile is known to be hook_probe_worker, but the payload's runtime agent_type is not inferred or invented.
Codex_Subagent_Hook_Issue_Package.zip
What steps can reproduce the bug?
Sanitized equivalent of the tested configuration
The tested fixture contained both command and commandWindows, with the absolute handler path quoted because the real path contained spaces.
.codex/hooks.json:
{
"hooks": {
"SubagentStart": [
{
"matcher": ".*",
"hooks": [
{
"type": "command",
"command": "\"C:\\absolute path\\fixture_repo\\hooks\\raw_hook_probe.cmd\" SubagentStart",
"commandWindows": "\"C:\\absolute path\\fixture_repo\\hooks\\raw_hook_probe.cmd\" SubagentStart",
"timeout": 10
}
]
}
],
"SubagentStop": [
{
"matcher": ".*",
"hooks": [
{
"type": "command",
"command": "\"C:\\absolute path\\fixture_repo\\hooks\\raw_hook_probe.cmd\" SubagentStop",
"commandWindows": "\"C:\\absolute path\\fixture_repo\\hooks\\raw_hook_probe.cmd\" SubagentStop",
"timeout": 10
}
]
}
]
}
}
.codex/agents/hook_probe_worker.toml:
name = "hook_probe_worker"
description = "Read-only native lifecycle Hook probe."
sandbox_mode = "read-only"
developer_instructions = """
Do not read any file.
Do not execute any command.
Do not write any file.
Do not create or invoke another agent.
Do not call any tool.
Return exactly this single line and nothing else:
HOOK_PROBE_WORKER_COMPLETE
"""
The attached raw_hook_probe.py writes handler_process_start.jsonl before it reads stdin, then records the raw input and JSON parse status in raw_hook_invocations.jsonl. The .cmd wrapper invokes that script with the event name.
Reproduction steps
- Create an isolated Git repository on Windows.
- Add the custom agent, lifecycle hooks, and recorder from the sanitized fixture.
- Replace the placeholder with the quoted absolute path to
raw_hook_probe.cmd. - Start Codex from the repository root with an isolated
CODEX_HOME. - Trust the repository.
- Review and trust both hooks in
/hooks. - Confirm both hooks are active and have no pending review.
- Start exactly one project custom agent of type
hook_probe_worker. - Wait for it to return
HOOK_PROBE_WORKER_COMPLETE. - Check
evidence/real/handler_process_start.jsonlandevidence/real/raw_hook_invocations.jsonl.
Do not pre-create the two evidence files. If the handler launches, it creates them itself.
What is the expected behavior?
When hook_probe_worker starts, Codex should launch the matching SubagentStart command hook and send the lifecycle JSON object to its stdin.
When the same subagent completes, Codex should launch the matching SubagentStop command hook and send the corresponding lifecycle JSON object to its stdin.
Additional information
Environment
- OS: Microsoft Windows 10 Pro, 64-bit, version 10.0.19043 (build 19043)
- Shell: Windows PowerShell 5.1.19041.1023
- Codex CLI versions tested: 0.144.1 and 0.144.4
- 0.144.4 executable SHA-256:
51398051C2332B6AFE08DC3B9DBB4056085C197F35CA57A307EE303D450CADA5 - Model:
gpt-5.6-sol - Model provider: custom Responses-compatible API provider
- Custom agent profile:
hook_probe_worker - Hook source: project-local
.codex/hooks.json - Repository trust: confirmed in the UI
- Hook trust: both hooks manually reviewed, trusted, and shown as active
- Windows sandbox: initialized successfully
The custom provider may be relevant, but custom-agent creation and completion worked normally in every run. No claim is made that the provider is or is not causal.
Reproduction matrix
| Codex version | Matcher | Agent completed | SubagentStart | SubagentStop | Handler launches |
| --- | --- | ---: | ---: | ---: | ---: |
| 0.144.1 | ^hook_probe_worker$ | Yes | No | No | 0 |
| 0.144.4 | ^hook_probe_worker$ | Yes | No | No | 0 |
| 0.144.4 | .* | Yes | No | No | 0 |
Each row represents exactly one real custom-agent run. No additional agent was started or resumed in a run.
Controls and causes already checked
- The custom agent was selected and returned the exact expected result.
- The repository and both hook definitions were trusted, and the hooks were shown as active.
- The 0.144.4 wildcard run rules out the tested exact matcher as the explanation.
- The command used a quoted absolute Windows path.
- The same
.cmdwrapper and Python recorder launch successfully with controlled synthetic lifecycle input. - The recorder logs process startup before stdin parsing, so malformed or missing JSON would still produce a process-start row.
- The real runs showed no hook launch error.
- The probes were isolated from the production project integration.
Current diagnosis boundary
The first unobserved boundary is upstream of the handler process. The evidence narrows the issue to one of these areas but does not distinguish between them:
- native subagent lifecycle event generation/dispatch; or
- loading or inheritance of trusted project-local lifecycle hooks for the custom-agent runtime.
The evidence does not establish a source-level root cause, and it does not establish that the custom model provider is irrelevant.
The unresolved boundary is runtime lifecycle dispatch or project-hook inheritance/loading.
Related but not duplicate: #21753 is an umbrella Hook parity tracker; #26383 reports all repo hooks missing under codex exec 0.137.0 on macOS. This report is specifically about trusted and Active custom-subagent lifecycle hooks in the interactive native Windows CLI across 0.144.1 and 0.144.4.
Questions
- Are
SubagentStartandSubagentStopexpected to run for project-defined custom subagents on native Windows Codex CLI? - Should trusted project-local hooks participate in custom-subagent lifecycle dispatch?
- Is lifecycle hook dispatch intended to be independent of the configured model provider?
- Is there a supported runtime trace or developer logging option that shows event generation, matcher evaluation, and hook loading for these events?
Sanitized attachments
- minimal wildcard fixture (
.codex/hooks.json, custom-agent TOML,.cmdwrapper, and Python recorder) - three-run comparison
- result summaries and SHA-256 references for the original local evidence archives
- no API keys, authentication files, cookies, sessions, transcripts,
CODEX_HOME, or unrelated project files
Attachment SHA-256: BC900DA45B9C57B0EE1E2CF750FF7B665D11533921791B0FBB749CD3FF6AA1E7.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗