Skip to content

Add PreToolUse and PostToolUse hook events for code quality enforcement #14754

@NavinAgrawal

Description

@NavinAgrawal

Summary

Codex v0.114.0 added experimental hooks with SessionStart and Stop events (PR #13276). This is a great foundation, but the two most impactful hook events are missing: PreToolUse and PostToolUse.

Without these, it is impossible to enforce code quality gates, block destructive commands, or validate tool outputs - capabilities that are production-critical for teams with shared coding standards.

What I need

Event Purpose Example
PreToolUse Validate/block BEFORE a tool runs Block rm -rf ~/, git push --force main, git reset --hard. Block commits with secrets. Require plan approval before exiting plan mode.
PostToolUse Validate/block AFTER a tool runs Block shallow test patterns (assert True, XCTAssertTrue(true)). Block f-string loggers in Python. Warn about console.log in JS/TS.

Real hooks I have ready to go

I have 5 production enforcement hooks written and working in Claude Code that I cannot use in Codex:

  1. block-shallow-tests.sh - PostToolUse on Write/Edit of test files. Catches 15+ worthless test patterns across Python, Swift, and TypeScript. Blocks the edit with exit code 2.
  2. block-fstring-loggers.sh - PostToolUse on Write/Edit of .py files. Catches logger.info(f"...") (should use %s lazy format) and datetime.utcnow() (deprecated). Blocks the edit.
  3. block-dangerous-bash.sh - PreToolUse on Bash. Blocks rm -rf ~/, git push --force main/master, git reset --hard, git clean -f. Exit code 2.
  4. commit-guard.sh - PreToolUse on Bash git commit. Scans staged files for hardcoded secrets, http:// URLs, console.log. Hard-blocks on secrets (exit 2), warns on others.
  5. require-plan-approval.sh - PreToolUse on ExitPlanMode. Blocks auto-exit from plan mode so user can review.

These all use the same JSON stdin/stdout protocol as the existing SessionStart/Stop hooks. The matcher syntax from Claude Code (tool == "Bash" && tool_input.command matches "^git\\s+commit") would be ideal but even a simple tool-name matcher would work.

Proposed schema additions

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "tool == \"Bash\"",
        "hooks": [
          {
            "type": "command",
            "command": "/path/to/block-dangerous-bash.sh",
            "timeout": 5
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "tool == \"Write\" && tool_input.file_path matches \"test_\"",
        "hooks": [
          {
            "type": "command",
            "command": "/path/to/block-shallow-tests.sh",
            "timeout": 10
          }
        ]
      }
    ]
  }
}

Input schema for PreToolUse would need tool_name and tool_input fields. Output schema needs a decision field with "allow" or "block" values. Exit code 2 = block is the Claude Code convention and works well.

Why this matters

  • Codex runs with sandbox_mode = "danger-full-access" for trusted projects. Without PreToolUse hooks, there is no safety net for destructive commands.
  • Code quality enforcement (test patterns, logging standards) currently only works in Claude Code. Teams using both tools get inconsistent quality.
  • The hooks engine infrastructure from PR start of hooks engine #13276 already supports the pattern - this is adding two new event types to an existing framework.

Environment

  • Codex CLI: 0.114.0
  • macOS 15.4 (Darwin 25.3.0)
  • 5 enforcement hooks ready, tested in Claude Code, waiting for Codex support

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requesthooksIssues related to event hooks

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions