Codex

Codex hooks: hooks.json, PreToolUse allow/deny, exit code 2 and config.toml [hooks]

How do I run a script before or after Codex uses a tool, and how do I block a command with a hook?

Codex hooks are on by default. Put them in ~/.codex/hooks.json or <repo>/.codex/hooks.json, or as [hooks] tables in config.toml. Each event, such as PreToolUse, takes a list of matcher groups with command handlers. Codex sends the event as JSON on stdin. To block a tool call, exit 2 with the reason on stderr, or print hookSpecificOutput.permissionDecision "deny". Project hooks run only after the project's .codex/ folder is trusted.

Compare: hooks in every AI coding agent →

Codex settings change often

Get one email a week when a setting, flag or permission rule changes, checked against the vendor docs.

Where Codex reads hooks

  • ~/.codex/hooks.json or inline [hooks] tables in ~/.codex/config.toml (user).
  • <repo>/.codex/hooks.json or <repo>/.codex/config.toml (project). Project hooks load only when that .codex/ layer is trusted.
  • Enabled plugins, through hooks/hooks.json or a hooks entry in .codex-plugin/plugin.json.
  • Managed hooks for an organization, through [hooks] in requirements.toml.
  • Higher-precedence layers do not replace hooks from lower ones; they add to them. Hooks that are not managed must be reviewed and trusted before they run.
  • Hooks are enabled by default. Turn them off with hooks = false under [features] in config.toml (codex_hooks is a deprecated alias).

Events

  • SessionStart: a session or subagent starts. The matcher filters on the source: startup, resume, clear, compact or fork.
  • UserPromptSubmit: before your prompt is sent.
  • PreToolUse: before a tool call, covering Bash, apply_patch, MCP tools and other local function tools.
  • PermissionRequest: when Codex is about to ask you for approval.
  • PostToolUse: after a supported tool produces output.
  • PreCompact and PostCompact: before and after the conversation is compacted (matcher: manual or auto).
  • SubagentStop, Stop, Interrupt (an active main-thread turn is interrupted) and SessionEnd (the main thread ends).

Block a shell command

.codex/hooks.json

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "python3 .codex/hooks/check_bash.py",
            "timeout": 30,
            "statusMessage": "Checking command"
          }
        ]
      }
    ]
  }
}

The hook gets JSON on stdin with session_id, cwd, hook_event_name, model and, for tool events, tool_name and tool_input. To block, exit 2 and write the reason to stderr, or exit 0 and print a decision:

PreToolUse hook output (stdout)

{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "deny",
    "permissionDecisionReason": "git push is not allowed from Codex"
  }
}

Matchers, handlers and timeouts

  • matcher is a regex. "*", an empty string or no matcher matches everything. It is ignored for UserPromptSubmit, Stop and Interrupt.
  • For PreToolUse, PostToolUse and PermissionRequest the matcher is the tool name. For apply_patch you can also match Edit or Write.
  • Handler types: command and mcp_tool (server, tool, input). prompt and agent handlers are parsed but skipped.
  • commandWindows (command_windows in TOML) overrides the command on Windows. async: true runs the command in the background.
  • timeout is in seconds and defaults to 600. SessionEnd and Interrupt default to 1 second and allow at most 3.
  • additionalContextLimit caps the context a hook can add (default 2500 tokens; 0 passes the full context).

Exit codes and JSON output

  • Exit 0 with no output: success, Codex continues.
  • Exit 2: blocks on events that support it, such as PreToolUse, UserPromptSubmit, Stop and SubagentStop, with the reason taken from stderr. On PostToolUse it sends feedback.
  • PreToolUse: permissionDecision is allow or deny. ask is not supported yet. updatedInput rewrites the tool input and works only with allow.
  • PermissionRequest: hookSpecificOutput.decision with behavior allow or deny (and a message). Deny wins over allow.
  • UserPromptSubmit, PostToolUse, SubagentStop and Stop: top-level decision "block" with a reason. On Stop, block does not reject the turn.
  • On every event: continue, stopReason and systemMessage. additionalContext in hookSpecificOutput is added as developer context.

Get Codex settings changes by email

When a setting, flag or permission rule in this guide changes, it goes in the weekly AgentAtlas update, checked against the vendor docs. One email a week.

Sources

More on Codex

More Codex guides

Other guides

How to allow Cursor to run all commands: Run Everything, allowlist and sandboxHow to allow Claude Code to run all commands: permission modes, allow rules and skip permissionsClaude Code permissions: allow, ask and deny rules, rule syntax and allowed toolsGemini CLI: YOLO mode, auto_edit and allowing specific shell commandsCursor Privacy Mode: telemetry, training and data retentionClaude Code telemetry and data retention: what is sent and how to turn it offGemini CLI: turn off usage statistics and telemetryCLAUDE.md: where it goes, how it loads, and how it works with AGENTS.mdClaude Code hooks: all events, exit codes, PreToolUse allow/deny JSON and examplesClaude Code subagents: create one, limit its tools, and call itAdd MCP servers to Cursor with mcp.json: Keep files out of Cursor with .cursorignore: Configure Gemini CLI with settings.json: Add MCP servers to Claude Code (claude mcp add, .mcp.json, scopes): Claude Code custom slash commands and skills (SKILL.md): GitHub Copilot custom instructions: Adding MCP servers to GitHub Copilot: Claude Code settings.json: file locations, precedence, and key settingsClaude Code plugins and marketplaces: install, create, and shareGemini CLI extensions and custom commands: Configuring OpenCode with opencode.json: Cline Rules: workspace, global, and conditional rulesKiro steering files: .kiro/steering, inclusion modes, and AGENTS.mdZed agent: instruction files, MCP servers, tool permissions, and ACP agentsCursor CLI: install, headless mode, permissions and CIAider: CONVENTIONS.md, .aider.conf.yml and API keysJunie guidelines, MCP and the Action Allowlist: Amp AGENTS.md, settings.json and MCP: Configure Goose extensions, hints, recipes and permissions: Customize OpenHands with skills, AGENTS.md, setup.sh and MCP: Configure Factory Droid CLI: AGENTS.md, settings.json, autonomy, custom droids and MCPConfigure Qwen Code: settings.json, providers, QWEN.md, MCP and approval modesCursor hooks: hooks.json, beforeShellExecution, afterFileEdit and exit codesCursor sandbox: sandbox.json, network allowlist and run modesCursor settings: settings.json, Cursor Settings and the ~/.cursor config filesCursor browser agent: @browser, browser automation and approval modesCursor subagents: .cursor/agents, frontmatter, built-in Explore and BrowserCursor telemetry and OpenTelemetry export (Privacy Mode, OTLP, Analytics API): Cursor rules setup: project, user and Team Rules, .mdc frontmatter, globs and AGENTS.mdClaude Code headless mode: claude -p, --output-format json, --bare and CI flagsClaude Code statusline: custom status bar in settings.json with context %, cost and git branchClaude Code /model: switch models, aliasesClaude Code /cost and /usage: check token spend, usage limits and reduce costsClaude Code VS Code extension: install, shortcuts, settings and /ideGEMINI.md in Gemini CLI: context file locations, imports and /memoryGemini CLI MCP servers: gemini mcp add and mcpServers in settings.jsonGemini CLI custom slash commands: TOML files, {{args}}, !{shell} and @{file}Gemini CLI headless mode: gemini -p, JSON output and exit codes for scripts and CIGemini CLI sandbox: enable Docker, Podman, macOS Seatbelt or gVisorcopilot-setup-steps.yml: set up the GitHub Copilot cloudGitHub Copilot CLI permissions: --allow-tool, --deny-tool, --allow-all-tools and trusted directoriesGitHub Copilot custom agents: .github/agents/*.agent.md profiles, tools and frontmatterGitHub Copilot code review settings: automatic PR reviews, rulesets, effort level and approvalsOpenCode MCP Server Setup: Local and Remote Servers in opencode.jsonOpenCode Permissions: Allow, Ask or Deny Bash, Edit and WebfetchOpenCode Custom Agents and Subagents: Markdown Files, Modes and @ MentionsCline MCP Setup: cline_mcp_settings.json for Local and Remote ServersCline Auto Approve and YOLO Mode: Run Commands and Edits Without PromptsCline Skills: SKILL.md Location, Format and Slash Command UseAmp MCP Setup: amp mcp add, amp.mcpServers and Workspace ApprovalAmp AGENTS.md: File Locations, @ Mentions and Glob-Scoped GuidanceAmp Skills: SKILL.md Folders, amp skill add and Search OrderKiro MCP Setup: .kiro/settings/mcp.json, autoApprove and OAuthKiro Hooks: .kiro/hooks JSON, PreToolUse, PostFileSave and StopKiro Permissions: permissions.yaml Allow, Ask and Deny RulesFactory Droid MCP Setup: droid mcp add, mcp.json Locations and /mcpFactory Droid Hooks: hooks.json, PreToolUse Matchers and Exit CodesFactory Droid Custom Droids (Subagents): .factory/droids Markdown FilesJunie MCP Setup: .junie/mcp/mcp.json for CLI and /mcp CommandJunie Brave Mode and Action Allowlist: Auto-Approve Commands in Junie CLIJunie Custom Slash Commands: .junie/commands Markdown Files and Argumentsgoose .goosehints and AGENTS.md: Global and Project Instructionsgoose Permission Modes: GOOSE_MODE auto, approve, smart_approve and chatgoose Recipes: recipe.yaml Format, Parameters and goose run --recipeZed Agent Tool Permissions: Auto-Approve Terminal Commands with tool_permissionsUse Claude, Codex and Gemini CLI in Zed: External Agents and agent_serversZed with Ollama, LM Studio and llama.cpp: Local Model Setup and Context LengthMCP 2026-07-28 Migration Guide: Stateless Protocol, No Sessions, server/discover, MRTR, and SDK v2 UpgradeSubagents and Custom Agents Compared: Claude Code vs Codex vs Cursor vs Gemini CLI vs GitHub CopilotAllow all commands in any AI coding agent: Cursor, Claude Code, Codex, Gemini CLI, Copilot CLI and 7 moreAdd an MCP server to any AI coding agent: Claude Code, Cursor, Codex, Gemini CLI, VS Code and 8 moreSettings file locations for every AI coding agent: Claude Code, Cursor, Codex, Gemini CLI, OpenCode, Qwen Code, Amp and Factory DroidRules and instruction files in every AI coding agent: .cursor/rules, CLAUDE.md, AGENTS.md, GEMINI.md, Copilot instructions and moreGemini CLI hooks: settings.json, BeforeTool, AfterTool, exit codes and /hooksGitHub Copilot hooks: .github/hooks/*.json for Copilot CLI and the cloud agentHooks in every AI coding agent: Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, Kiro and Factory DroidAgent Skills (SKILL.md) in every AI coding agent: Claude Code, Codex, Cline, Amp and OpenHandsHow to deploy a remote MCP server (Streamable HTTP): Cloudflare Workers, Vercel, Railway and moreHeadless mode in every AI coding agent: claude -p, codex exec, gemini -p, Cursor agent -p and copilot -p for scripts and CIClaude Code sandbox: /sandbox, sandbox.enabled, allowedDomains, excludedCommands and strict modeSandbox modes in every AI coding agent: Claude Code, Cursor, Codex and Gemini CLI comparedCustom slash commands in every AI coding agent: file locations, arguments and examplesMigrate from Gemini CLI to Antigravity CLI (2026): Config, MCP, Skills, FlagsRun GitHub Copilot CLI with copilot -p in scripts and CI (2026): Agent Loops 2026: Ralph Loop, /loop, /goal and Headless Loops for AI Coding AgentsWeb Scraping MCP Servers Compared (2026): Bright Data, Firecrawl, Apify, Tavily and BrowserbaseCursor skills and custom slash commands: .cursor/skills SKILL.md, .cursor/commands and /migrate-to-skills

Reviewed Oct 20, 2026. Settings change often; the linked vendor docs are the source of truth.