Summary
PreToolUse hooks registered for Write, Edit, and Bash matchers never fire when the Codex agent edits files, because the agent uses an internal patch tool that is not exposed as a matchable tool name.
Reproduction
- Build a minimal Codex plugin with a PreToolUse hook:
{
"hooks": {
"PreToolUse": [
{"matcher": "Write", "hooks": [{"type": "command", "command": "$PLUGIN_ROOT/hooks/block.sh"}]},
{"matcher": "Edit", "hooks": [{"type": "command", "command": "$PLUGIN_ROOT/hooks/block.sh"}]},
{"matcher": "Bash", "hooks": [{"type": "command", "command": "$PLUGIN_ROOT/hooks/block.sh"}]}
]
}
}
Where block.sh writes a marker file and exits 2.
-
Install the plugin via local marketplace (codex plugin add).
-
Launch Codex TUI:
codex --no-alt-screen --dangerously-bypass-hook-trust \
-s workspace-write \
"Write the text 'TEST' to test.txt using the Write tool. Then stop."
- Observe:
- The agent responds: "I don't have a tool named Write in this environment, so I'll make the requested file edit with the available patch tool."
- The file is modified (
Added test.txt (+1 -0))
- The marker file is never created — the hook never fired
- This happens in both
-s workspace-write and --dangerously-bypass-approvals-and-sandbox modes
Expected behavior
PreToolUse hooks should fire for the internal patch/edit tool, or a new matcher name (e.g., Patch, ApplyPatch, or FileEdit) should be documented so plugins can match it.
Actual behavior
The internal patch tool bypasses all PreToolUse hook matchers. There is no documented matcher name for it.
Impact
Plugins that rely on PreToolUse hooks for safety enforcement (e.g., blocking writes to protected files) cannot intercept file edits made by the Codex agent. The only remaining enforcement path is post-validation after the agent commits.
Environment
- Codex CLI: v0.137.0
- OS: Linux
- Plugin hooks feature: enabled and working for Stop hooks (confirmed via marker files)
Notes
- Stop hooks work correctly — confirmed with marker-based control tests (hook starts, times out as expected)
- PreToolUse hooks work for Bash when the model explicitly uses the Bash tool (e.g.,
echo > file), but the model prefers the internal patch tool for file edits
- The
--dangerously-bypass-hook-trust flag is used; the issue is not about hook trust but about matcher coverage
Summary
PreToolUse hooks registered for
Write,Edit, andBashmatchers never fire when the Codex agent edits files, because the agent uses an internal patch tool that is not exposed as a matchable tool name.Reproduction
{ "hooks": { "PreToolUse": [ {"matcher": "Write", "hooks": [{"type": "command", "command": "$PLUGIN_ROOT/hooks/block.sh"}]}, {"matcher": "Edit", "hooks": [{"type": "command", "command": "$PLUGIN_ROOT/hooks/block.sh"}]}, {"matcher": "Bash", "hooks": [{"type": "command", "command": "$PLUGIN_ROOT/hooks/block.sh"}]} ] } }Where
block.shwrites a marker file and exits 2.Install the plugin via local marketplace (
codex plugin add).Launch Codex TUI:
codex --no-alt-screen --dangerously-bypass-hook-trust \ -s workspace-write \ "Write the text 'TEST' to test.txt using the Write tool. Then stop."Added test.txt (+1 -0))-s workspace-writeand--dangerously-bypass-approvals-and-sandboxmodesExpected behavior
PreToolUse hooks should fire for the internal patch/edit tool, or a new matcher name (e.g.,
Patch,ApplyPatch, orFileEdit) should be documented so plugins can match it.Actual behavior
The internal patch tool bypasses all PreToolUse hook matchers. There is no documented matcher name for it.
Impact
Plugins that rely on PreToolUse hooks for safety enforcement (e.g., blocking writes to protected files) cannot intercept file edits made by the Codex agent. The only remaining enforcement path is post-validation after the agent commits.
Environment
Notes
echo > file), but the model prefers the internal patch tool for file edits--dangerously-bypass-hook-trustflag is used; the issue is not about hook trust but about matcher coverage