Skip to content

[Feature request] Extend PreToolUse hooks beyond Bash + implement updatedInput rewrite #18491

Description

@claudioemmanuel

Summary

The PreToolUse hook in ~/.codex/hooks.json currently fires for Bash/shell tool calls only. Two related requests that together unlock full-parity middleware integrations:

  1. Expand PreToolUse to all tool calls — specifically read_file and grep, which are the other high-volume tools with the highest potential to overflow context when left unconstrained (apply_patch is now fixed — see progress below)
  2. Implement updatedInput in the hook response — the runtime currently rejects it with "PreToolUse hook returned unsupported updatedInput". Implementing this would let hooks enforce programmatic budgets (e.g. cap limit on a file read, cap head_limit on a grep) rather than relying on model compliance

Motivation

I'm the author of squeez, an external compression middleware that integrates with Claude Code, Copilot CLI, OpenCode, Gemini CLI, and Codex CLI via their respective hook systems.

For Codex specifically, I can compress Bash output via the existing PreToolUse + PostToolUse hooks — that part works today. But read_file / grep results routinely push sessions past the context budget, and without a hook surface on those tools the only fallback is a prose hint in AGENTS.md, which the model may or may not honour.

If the hook surface expanded, middleware could uniformly enforce output-size budgets across every tool call, the same way Claude Code's PreToolUse + tool-input rewrite does today.

Progress

✅ Fixed in 0.123.0 (PR #18391, 2026-04-23)

  • apply_patch now emits PreToolUse and PostToolUse hook events
  • tool_name in hook stdin is now handler-supplied (no longer always "Bash")

❌ Still blocked

  • read_file and grep have no ToolHandler with pre_tool_use_payload/post_tool_use_payload — only test files exist, no hook dispatch
  • updatedInput is explicitly rejected by output_parser.rs:
    if output.updated_input.is_some() {
        Some("PreToolUse hook returned unsupported updatedInput".to_string())
    }
    

Suggested acceptance criteria

  • PreToolUse fires for read_file and grep in addition to Bash/shell and apply_patch
  • A hook emitting {"decision":"allow","updatedInput":{...}} has the rewritten input passed to the tool
  • Documentation updated to reflect both

Downstream tracker

squeez CodexCliAdapter stays at BUDGET_SOFT (prose hints in AGENTS.md) until both remaining items land. Will flip to BUDGET_HARD once confirmed. Happy to test a dev branch.

Additional context

Related discussion: #2150

Activity

  1. added
    enhancementNew feature or request
    CLIIssues related to the Codex CLI
    hooksIssues related to event hooks
    tool-callsIssues related to tool calling
    on Apr 18, 2026
  2. claudioemmanuel commented on May 5, 2026

    @claudioemmanuel
    Author

    Status update — 2026-05-05

    Following up with findings from a detailed audit of the upstream source and release history.

    What shipped

    #18391 (merged 2026-04-22, released in 0.123.0 on 2026-04-23) fixed apply_patch:

    • ApplyPatchHandler now implements pre_tool_use_payload() and post_tool_use_payload()
    • tool_name in hook stdin is now handler-supplied instead of always hardcoded as "Bash"
    • Hooks registered with ".*" or "apply_patch" matchers will now fire for apply_patch calls

    This is a real, meaningful improvement — thank you to @fcoury-oai and the reviewers.

    What is still blocked

    Two of the three asks in the original issue remain unresolved:

    1. read_file and grep hook surface — these tools still have no ToolHandler implementation with pre_tool_use_payload/post_tool_use_payload. Only test files exist (read_file_tests.rs, grep_files_tests.rs); no hook dispatch for these tools.

    2. updatedInput rewrite — output_parser.rs explicitly rejects this today:

      if output.updated_input.is_some() {
          Some("PreToolUse hook returned unsupported updatedInput".to_string())
      }
      

      So a hook emitting {"decision":"allow","updatedInput":{...}} will produce an error, not a rewrite. This is the critical gate for hard budget enforcement on input parameters (e.g. capping limit on a file read).

    Downstream impact

    The squeez CodexCliAdapter remains at BUDGET_SOFT — prose hints in AGENTS.md — because updatedInput + read_file/grep hooks are still needed to flip to BUDGET_HARD. The adapter comments have been updated to reflect the current upstream state accurately (including the 0.123.0 apply_patch win).

    Leaving this issue open until both remaining items land. Happy to test a dev branch when available.

  3. oxysoft commented on May 8, 2026

    @oxysoft

    Indexed this hook ticket in the umbrella tracker: #21753

    Goal: collect the scattered Codex hook requests and bugs into one parity matrix for Full Claude Code Hook Parity (29+), while preserving this issue as the detailed thread for its specific behavior.

  4. 3 remaining items

  5. danzaio commented on Jul 9, 2026

    @danzaio

    Please we need this asap

  6. claudioemmanuel commented on Jul 9, 2026

    @claudioemmanuel
    Author

    Status update — 2026-07-09

    Re-audited against current main (Codex v0.144.0, released today) by reading the shipped source directly, since I don't have a working local Codex install to test live right now (unrelated broken npm vendor binary on my end).

    Both blockers from the original issue appear resolved upstream

    1. updatedInput rewrite — no longer rejected for PreToolUse.

    • Support PreToolUse updatedInput rewrites #20527 ("Support PreToolUse updatedInput rewrites", merged 2026-05-12) generalizes updatedInput beyond Bash: Bash-like tools, apply_patch, and MCP tools now all accept the rewrite.
    • Default function tools into tool hooks #23757 ("Default function tools into tool hooks", merged 2026-05-23) goes further — CoreToolRuntime now provides a default pre_tool_use_payload / post_tool_use_payload / with_updated_hook_input implementation for every ordinary local function tool, not just the ones with bespoke wiring. Explicit exceptions are hosted tools and code-mode wait/write_stdin.
    • Confirmed in current codex-rs/hooks/src/engine/output_parser.rs: the validation for PreToolUse only rejects updatedInput when it's not paired with hookSpecificOutput.permissionDecision: "allow" — the exact combination the issue originally needed now round-trips cleanly. The literal error string quoted in this issue's original report ("PreToolUse hook returned unsupported updatedInput") no longer exists for PreToolUse in current source (a similarly-worded rejection still exists for the separate PermissionRequest hook type, which is a different code path).

    2. read_file / grep hook surface — the premise may be moot rather than fixed.

    I went looking for the read_file/grep tool handlers this issue originally referenced (read_file_tests.rs, grep_files_tests.rs) in codex-rs/core/src/tools/ on current main and couldn't find them — there's no dedicated read_file or grep model-facing tool in the current tree. File access appears to route through the shell/exec tool (hooked since day one) or through MCP servers (hooked since #20527/#23757). If those handlers existed back in April and were since removed/consolidated, or if I'm missing something, please correct me — but as far as I can tell reading main today, this specific gap doesn't reproduce.

    What I haven't done

    I have not runtime-tested this — only static-read the source. If someone can confirm live that a PreToolUse hook with hookSpecificOutput.permissionDecision: "allow" + updatedInput actually rewrites a non-Bash/non-apply_patch/non-MCP local tool call end-to-end on a current build, that would close the loop.

    Downstream

    @danzaio — the fix you're waiting on has very likely already shipped (0.131.0–0.133.0 range, currently at 0.144.0). Worth updating and retesting on your end.

    For squeez: I'm holding off flipping CodexCliAdapter from BUDGET_SOFT to BUDGET_HARD until I get a live confirmation (my local Codex install is broken and unrelated to this issue). Will close this out once that's confirmed, either by me or by anyone else who can verify on a working install.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requesthooksIssues related to event hookstool-callsIssues related to tool calling

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions