Regression: apply_patch custom tool calls do not fire PostToolUse hooks in 0.136.0

Resolved 💬 2 comments Opened Jun 6, 2026 by trotsky1997 Closed Jun 6, 2026

Summary

apply_patch does not appear to emit PostToolUse hooks in a Codex CLI 0.136.0 session, despite project hooks being enabled/trusted and despite apply_patch hook support being documented and previously reported as fixed in #16732 / #17794.

The observable symptom is stronger than "additionalContext did not render": a hook wrapper that writes a debug log at process start is never invoked after real apply_patch calls.

Related issues:

  • #16732: ApplyPatchHandler did not emit hooks; reported fixed in 0.123.0.
  • #17794: file write operations / functions.apply_patch did not fire hooks.
  • #20204: broader hook coverage gaps across handlers.

This issue is for a current regression or uncovered surface in 0.136.0 where model-visible custom_tool_call entries named apply_patch do not run the configured project PostToolUse hook.

Environment

  • Codex CLI: codex-cli 0.136.0
  • Install method: npm package @openai/codex
  • Platform: Windows 11 / windows-x86_64
  • Source: interactive CLI / TUI session (originator: codex-tui, source: cli in rollout metadata)
  • Repo trust: project is trusted via user config:
  • [projects.'c:\users\trots\openlsp'] trust_level = "trusted"
  • Hooks feature: enabled:
  • [features] hooks = true
  • Hook trust: project hook has a trusted hash in [hooks.state]

Hook configuration

Project .codex/config.toml:

[[hooks.PostToolUse]]
matcher = "Edit|Write|apply_patch|mcp__.*"

[[hooks.PostToolUse.hooks]]
type = "command"
command = "sh \"$(git rev-parse --show-toplevel)/.codex/hooks/openlsp-codex-hook.sh\""
command_windows = "powershell -NoProfile -ExecutionPolicy Bypass -Command \"& { $root = (git rev-parse --show-toplevel).Trim(); & (Join-Path $root '.codex/hooks/openlsp-codex-hook.ps1') }\""
timeout = 30
statusMessage = "Checking OpenLSP diagnostics"

The Windows wrapper starts by appending to .codex/hook-debug.log, before running any project-specific logic. That makes it easy to distinguish these cases:

  1. Hook runner invoked wrapper, but wrapper produced no findings.
  2. Hook runner never invoked wrapper.

Reproduction

  1. Configure and trust the PostToolUse hook above.
  2. Ensure the wrapper writes to .codex/hook-debug.log immediately on startup.
  3. Clear .codex/hook-debug.log.
  4. Ask Codex to create a syntactically invalid TypeScript file, which causes a real apply_patch call. Example observed tool entry from the rollout file:
{
  "type": "custom_tool_call",
  "name": "apply_patch",
  "input": "*** Begin Patch\n*** Add File: src/openlsp-hook-final-smoke.ts\n+export const openLspHookFinal =\n*** End Patch\n"
}
  1. Check .codex/hook-debug.log.

Actual behavior

  • apply_patch succeeds and modifies the file.
  • .codex/hook-debug.log remains empty.
  • No hook additionalContext is returned to the agent.

This indicates the configured hook wrapper was not invoked at all for the apply_patch tool call.

Expected behavior

PostToolUse should fire for the apply_patch tool call and invoke the configured wrapper. At minimum, .codex/hook-debug.log should contain a start/end entry from the wrapper.

If the hook prints valid JSON like this:

{
  "hookSpecificOutput": {
    "hookEventName": "PostToolUse",
    "additionalContext": "...diagnostics..."
  }
}

then that additionalContext should become available to the agent according to the hook contract.

Control checks

These controls all passed in the same repo/session environment:

  1. Manually invoking the wrapper with a synthetic PostToolUse stdin event writes .codex/hook-debug.log and exits 0.
  2. Manually invoking the wrapper with the same invalid file returns valid hookSpecificOutput.additionalContext JSON.
  3. Running the diagnostics command directly on the invalid file reports the expected syntax error.
  4. The project hook is trusted and hooks are enabled according to user config / codex features list.

Example manual wrapper output:

{"hookSpecificOutput":{"hookEventName":"PostToolUse","additionalContext":"OpenLSP found issues in 1 check(s):\n\n[diagnostics] openlsp-hook-final-smoke.ts (ok)\n\nERROR [1:1] Syntax error near 'export const openLspHookFinal ='"}}

Because the debug log remains empty only after the real apply_patch, this looks like the hook runner is not being called for this custom_tool_call apply_patch path in 0.136.0.

Notes

The hook consumer initially only parsed patch text under tool_input.command; that has been fixed locally to also parse raw string tool_input / patch text. The failure described here is independent of that parser issue: the wrapper's first debug-log write does not run at all after real apply_patch calls.

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗