Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Codex CLI Hooks Reference

Disclaimer: This document reflects our current understanding of Codex CLI’s hook system. It is a working reference for symposium development, not a substitute for the official docs. Details may be outdated or incomplete — always consult the primary sources.

Primary sources: Hooks · GitHub repo

OpenAI’s Codex CLI implements a shell-command hook system configured in hooks.json. It is experimental (disabled by default, not available on Windows) and first shipped in v0.114 (March 2026).

Enabling

Add to ~/.codex/config.toml:

[features]
codex_hooks = true

Configuration

FileScope
~/.codex/hooks.jsonUser-global
<repo>/.codex/hooks.jsonProject-scoped

Both are additive — all matching hooks from all files run. Project hooks follow the untrusted-project trust model.

Configuration structure

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

Only handler type is "command". matcher is a regex string; omit or use "" / "*" to match everything. Default timeout: 600 seconds, configurable via timeout or timeoutSec.

Events

EventTriggerMatcher filters onCan block?
SessionStartSession starts or resumessource ("startup" or "resume")Yes (continue: false)
PreToolUseBefore tool executiontool_name (currently only "Bash")Yes
PostToolUseAfter tool executiontool_name (currently only "Bash")Yes (continue: false)
UserPromptSubmitUser submits a promptN/AYes (continue: false)
StopAgent turn completesN/AYes (deny → continuation prompt)

Input Schema (stdin)

Base fields (all events)

{
  "session_id": "string",
  "transcript_path": "string|null",
  "cwd": "string",
  "hook_event_name": "string",
  "model": "string"
}

Turn-scoped events (PreToolUse, PostToolUse, UserPromptSubmit, Stop) add turn_id.

PreToolUse additions

  • tool_name: string
  • tool_use_id: string
  • tool_input: object with command field

PostToolUse additions

  • tool_name, tool_use_id, tool_input (same as PreToolUse)
  • tool_response: string

UserPromptSubmit additions

  • prompt: string

Stop additions

  • stop_hook_active: boolean
  • last_assistant_message: string

Output Schema (stdout)

Deny/block (two equivalent methods)

Method 1 — JSON output:

{ "decision": "block", "reason": "Destructive command blocked" }

or:

{
  "hookSpecificOutput": {
    "permissionDecision": "deny",
    "permissionDecisionReason": "Destructive command blocked"
  }
}

Method 2 — Exit code 2 with reason on stderr.

Inject context

{
  "hookSpecificOutput": {
    "additionalContext": "Extra info for the agent"
  }
}

Plain text on stdout also works for SessionStart and UserPromptSubmit (ignored for PreToolUse, PostToolUse, Stop).

Stop session

{ "continue": false, "stopReason": "Session terminated by hook" }

Supported on SessionStart, UserPromptSubmit, PostToolUse, Stop.

System message (UI warning)

{ "systemMessage": "Warning text shown to user" }

Stop event special behavior

For the Stop event, { "decision": "block", "reason": "Run tests again" } tells Codex to create a continuation prompt — it does not reject the turn.

Exit Codes

CodeMeaning
0Success; stdout parsed. No output = continue normally.
2Block/deny; stderr used as reason
OtherNon-blocking warning

Execution Behavior

  • Multiple matching hooks run concurrently — no ordering guarantees.
  • Commands run with session cwd as working directory.
  • Shell expansion works.

Parsed but Not Yet Implemented

These fields are accepted but fail open (no effect): suppressOutput, updatedInput, updatedMCPToolOutput, permissionDecision: "allow", permissionDecision: "ask".

Current Limitations

  • Only Bash tool events fire PreToolUse/PostToolUse — no file-write or MCP tool hooks.
  • PreToolUse can only deny, not modify tool input.
  • No async hook mode.
  • Stop event requires JSON output (plain text is invalid).

Environment Variables

No dedicated environment variables are set during hook execution (unlike Claude Code’s CLAUDE_PROJECT_DIR). All context is passed via stdin JSON. The cwd field serves as the project directory equivalent. CODEX_HOME (defaults to ~/.codex) controls where Codex stores config and state.

Custom Instructions

ScopePath
Global~/.codex/AGENTS.md (or AGENTS.override.md)
ProjectAGENTS.md (or AGENTS.override.md) at each directory level from git root to CWD

The project_doc_fallback_filenames config option in ~/.codex/config.toml allows alternative filenames. Max combined size: 32 KiB (project_doc_max_bytes).

Skills

ScopePath
Repository.agents/skills/<name>/SKILL.md (each dir from CWD up to repo root)
User~/.agents/skills/<name>/SKILL.md
Admin/etc/codex/skills/<name>/SKILL.md
SystemBundled with Codex

Skills use SKILL.md with YAML frontmatter (name, description) and may include scripts/, references/, assets/, and agents/openai.yaml.

MCP Server Configuration

Configured in ~/.codex/config.toml or .codex/config.toml under [mcp_servers.<name>]:

[mcp_servers.my-server]
command = "path/to/executable"
args = ["--arg1"]
env = { API_KEY = "value" }
startup_timeout_sec = 10
tool_timeout_sec = 60

Supports stdio (command/args) and streamable HTTP (url/bearer_token_env_var). CLI management: codex mcp add <name> ....

MCP Server Registration

In addition to hooks, symposium registers itself as an MCP server in the agent’s config file. This provides an alternative integration path alongside the hook-based approach.

Configuration structure

The MCP server entry is added under [mcp_servers] in the TOML config:

[mcp_servers.symposium]
command = "/path/to/cargo-agents"
args = ["mcp"]
  • Project-level: .codex/config.toml
  • User-level: ~/.codex/config.toml

Registration is idempotent — if the entry already exists with the correct values, no changes are made. If the entry exists but has stale values (e.g. the binary moved), it is updated in place.

Other Extensibility

  • notify in config.toml (fire-and-forget on agent-turn-complete)
  • Execpolicy command-level rules
  • Subagents
  • Slash commands