[Hooks] SubagentStart and SubagentStop are not dispatched for project-defined custom subagents on Windows

Open 💬 1 comment Opened Jul 14, 2026 by cufudjxnxjxj-art

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:

  • SubagentStart handler process launches: 0
  • SubagentStop handler 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

  1. Create an isolated Git repository on Windows.
  2. Add the custom agent, lifecycle hooks, and recorder from the sanitized fixture.
  3. Replace the placeholder with the quoted absolute path to raw_hook_probe.cmd.
  4. Start Codex from the repository root with an isolated CODEX_HOME.
  5. Trust the repository.
  6. Review and trust both hooks in /hooks.
  7. Confirm both hooks are active and have no pending review.
  8. Start exactly one project custom agent of type hook_probe_worker.
  9. Wait for it to return HOOK_PROBE_WORKER_COMPLETE.
  10. Check evidence/real/handler_process_start.jsonl and evidence/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 .cmd wrapper 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:

  1. native subagent lifecycle event generation/dispatch; or
  2. 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

  1. Are SubagentStart and SubagentStop expected to run for project-defined custom subagents on native Windows Codex CLI?
  2. Should trusted project-local hooks participate in custom-subagent lifecycle dispatch?
  3. Is lifecycle hook dispatch intended to be independent of the configured model provider?
  4. 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, .cmd wrapper, 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.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗