codex - 💡(How to fix) Fix Inconsistent PreToolUse hook coverage across tool handlers (most tools never emit hook events) [3 comments, 3 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openai/codex#20204Fetched 2026-04-30 06:32:02
View on GitHub
Comments
3
Participants
3
Timeline
7
Reactions
0
Timeline (top)
commented ×3labeled ×3unlabeled ×1

codex-rs/core/src/tools/registry.rs dispatches PreToolUse / PermissionRequest / PostToolUse generically: any handler that returns Some(payload) from pre_tool_use_payload will surface a hook event. Today only shell (Bash), unified_exec, apply_patch, and mcp opt in. Every other tool handler in core/src/tools/handlers/ falls back to the trait default (None), so hooks never fire for those tools.

The result is that the hooks system, which is otherwise a clean general purpose interception mechanism, behaves as if it were shell and edit-only. Anyone building tooling on top of Codex hooks (observability, audit logging, policy enforcement, telemetry, debugging instrumentation, third-party integrations) silently loses coverage on a large portion of the agent's tool surface.

Root Cause

Codex hooks are a public extension point. Their value depends on coverage being consistent across tools. With today's gaps:

  • Observability tools cannot record what files the agent listed or what plans it updated.
  • Audit logs are incomplete: apply_patch is logged, but the update_plan that decided to apply the patch is not.
  • Policy / safety tooling cannot enforce constraints on agent reasoning surface (update_plan, goal) or on multi-agent orchestration.
  • Telemetry / debugging instrumentation has blind spots on the same boundaries.

This is a consistency gap in an existing public API surface.

Fix Action

Fix / Workaround

codex-rs/core/src/tools/registry.rs dispatches PreToolUse / PermissionRequest / PostToolUse generically: any handler that returns Some(payload) from pre_tool_use_payload will surface a hook event. Today only shell (Bash), unified_exec, apply_patch, and mcp opt in. Every other tool handler in core/src/tools/handlers/ falls back to the trait default (None), so hooks never fire for those tools.

The asymmetry between apply_patch (file edits: emits hooks) and list_dir / view_image (file reads: silent) is particularly noticeable for any tool that wants a complete view of agent activity.

  • Observability tools cannot record what files the agent listed or what plans it updated.
  • Audit logs are incomplete: apply_patch is logged, but the update_plan that decided to apply the patch is not.
  • Policy / safety tooling cannot enforce constraints on agent reasoning surface (update_plan, goal) or on multi-agent orchestration.
  • Telemetry / debugging instrumentation has blind spots on the same boundaries.
RAW_BUFFERClick to expand / collapse

Summary

codex-rs/core/src/tools/registry.rs dispatches PreToolUse / PermissionRequest / PostToolUse generically: any handler that returns Some(payload) from pre_tool_use_payload will surface a hook event. Today only shell (Bash), unified_exec, apply_patch, and mcp opt in. Every other tool handler in core/src/tools/handlers/ falls back to the trait default (None), so hooks never fire for those tools.

The result is that the hooks system, which is otherwise a clean general purpose interception mechanism, behaves as if it were shell and edit-only. Anyone building tooling on top of Codex hooks (observability, audit logging, policy enforcement, telemetry, debugging instrumentation, third-party integrations) silently loses coverage on a large portion of the agent's tool surface.

Affected handlers (don't currently emit hook events)

From codex-rs/core/src/tools/handlers/:

  • Filesystem reads: list_dir, view_image
  • MCP resource access: mcp_resource (asymmetric with mcp tool calls, which do emit)
  • Agent task plan / objectives: plan (update_plan), goal (create_goal / update_goal / get_goal)
  • Batch sub-agent orchestration: agent_jobs (spawn_agents_on_csv)
  • Tool discovery: tool_search, tool_suggest
  • Per-agent control: multi_agents/* (5 sub-handlers), multi_agents_v2/* (7 sub-handlers)
  • Web search: no handler implementation in core/src/web_search.rs

The asymmetry between apply_patch (file edits: emits hooks) and list_dir / view_image (file reads: silent) is particularly noticeable for any tool that wants a complete view of agent activity.

Why this matters

Codex hooks are a public extension point. Their value depends on coverage being consistent across tools. With today's gaps:

  • Observability tools cannot record what files the agent listed or what plans it updated.
  • Audit logs are incomplete: apply_patch is logged, but the update_plan that decided to apply the patch is not.
  • Policy / safety tooling cannot enforce constraints on agent reasoning surface (update_plan, goal) or on multi-agent orchestration.
  • Telemetry / debugging instrumentation has blind spots on the same boundaries.

This is a consistency gap in an existing public API surface.

Proposed change

Add pre_tool_use_payload implementations to the handlers above. The pattern is already established in apply_patch.rs:317-322 and mcp.rs. Each addition is 5 to 15 lines of Rust.

A working PoC is available on a fork branch:

The PoC covers 8 of the missing handlers:

  • list_dir.rs
  • view_image.rs
  • mcp_resource.rs
  • plan.rs
  • goal.rs
  • agent_jobs.rs
  • tool_search.rs
  • tool_suggest.rs

For handlers that wrap multiple sub-tools (mcp_resource, goal), the raw function arguments are forwarded as JSON. For handlers with a single args schema (list_dir, view_image, tool_search), the parsed fields are surfaced explicitly.

Diff size: 16 files changed, 503 insertions, 0 deletions (8 handler patches plus 8 test additions).

Tests: 10 new unit tests cover the new pre_tool_use_payload paths, asserting each handler returns the expected PreToolUsePayload shape (and None for non-Function payloads where applicable). Pattern follows apply_patch_tests.rs. Full codex-core lib test count: 1641 to 1651, all passing on the patched branch (after rebasing on current main).

Live verification: Built cargo build -p codex-cli --release and ran the patched binary in Codex Desktop. Captured a PreToolUse tool=update_plan hook event for the first time, confirming the dispatch path is correct end-to-end. Without this patch, update_plan calls go through silently.

Out of scope

Two pieces are intentionally deferred to keep the first PR reviewable:

  1. multi_agents/* (5 sub-handlers) and multi_agents_v2/* (7 sub-handlers) for fine-grained agent control. The big-picture orchestration entry (spawn_agents_on_csv) is already covered via agent_jobs.rs in this PR. Per-agent control can land in a focused follow-up.
  2. web_search: no handler implementation exists today; needs a new handler skeleton in core/src/web_search.rs. Better as its own issue + PR.

Tested against

  • openai/codex main (current head as of filing).
  • Codex CLI 0.125.0 baseline plus patched build.
  • Codex Desktop on macOS (Apple Silicon).

Open questions

  1. Is there an internal roadmap for hook coverage that this overlaps with?
  2. Are there any handlers on the deferred list (multi_agents, web_search) where you'd prefer not to emit hooks for design reasons (privacy, operational noise, etc.)?
  3. Preference on PR shape: single PR for all 8, or split by category?
  4. Naming convention for hook payloads: should update_plan's HookToolName be "update_plan" or pulled from the canonical tool registry name?

Happy to iterate on the design before any code lands.

extent analysis

TL;DR

Implement pre_tool_use_payload for the affected handlers to ensure consistent hook event coverage across tools.

Guidance

  • Review the proposed change and the provided proof-of-concept (PoC) branch to understand the implementation details.
  • Evaluate the affected handlers and their respective pre_tool_use_payload implementations to ensure they meet the requirements.
  • Consider the out-of-scope items, such as multi_agents and web_search, and plan for their implementation in follow-up issues and PRs.
  • Test the changes thoroughly to ensure hook events are emitted correctly for all affected handlers.

Example

// Example implementation for list_dir handler
impl ToolHandler for ListDir {
    fn pre_tool_use_payload(&self, _args: &ToolArgs) -> Option<PreToolUsePayload> {
        // Return the payload shape for list_dir
        Some(PreToolUsePayload {
            tool: "list_dir".to_string(),
            // Add relevant fields for list_dir
        })
    }
}

Notes

The proposed change aims to address the consistency gap in hook coverage across tools. However, it's essential to review and test the changes carefully to ensure they meet the requirements and do not introduce any regressions.

Recommendation

Apply the workaround by implementing pre_tool_use_payload for the affected handlers, as proposed in the issue. This will ensure consistent hook event coverage across tools, addressing the identified consistency gap.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

codex - 💡(How to fix) Fix Inconsistent PreToolUse hook coverage across tool handlers (most tools never emit hook events) [3 comments, 3 participants]