| name | hook-development |
| description | Use when the user wants to create Codex workflow hooks (pre/post run gates, tool-use validators, stop checks) or needs guidance on hook scripts and hooks.json configuration. |
Hook Development (Codex)
Overview
Codex CLI does not provide Claude-style hook events. To replicate hook behavior, implement a hook runner (wrapper script or CI job) that:
- Runs hook scripts before/after
codex exec. - Optionally parses
codex exec --jsonoutput to detect tool usage. - Applies a
hooks.jsonconfiguration to decide which hooks to run.
This skill defines a Codex hook contract and provides utilities for validating, testing, and linting hooks.
This repository ships a reference runner at scripts/codex-hook-runner (installed by install.sh) that implements the contract described below. Hooks are enabled by default in codex-autonomous; set CODEX_DISABLE_HOOKS=1 to disable.
Hook Types
Prompt Hooks (LLM-driven)
Use an LLM (Codex or another model) to make contextual decisions.
{
"type": "prompt",
"prompt": "Validate this operation. Return approve|deny with a reason."
}
Command Hooks (Deterministic)
Use shell scripts for fast, repeatable checks.
{
"type": "command",
"command": "bash ${CODEX_HOOK_ROOT}/scripts/validate-write.sh",
"timeout": 30
}
Hook Configuration (hooks.json)
Define hooks in a single hooks.json. This format is consumed by your hook runner.
{
"hooks": {
"PreToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "bash ${CODEX_HOOK_ROOT}/scripts/validate-write.sh"
}
]
}
],
"Stop": [
{
"matcher": "*",
"hooks": [
{
"type": "prompt",
"prompt": "Review transcript at $TRANSCRIPT_PATH. Block if tests were not run after code changes."
}
]
}
]
}
}
If your runner prefers a direct format, you can omit the hooks wrapper and use events at top level. scripts/validate-hook-schema.sh supports both.
Hook Events (Codex Mapping)
Your hook runner chooses which events to emit. Recommended events:
SessionStart: before running CodexUserPromptSubmit: after prompt is assembled but before executionPreToolUse: before a tool call (requires--jsonparsing)PostToolUse: after a tool call (requires--jsonparsing)Stop: before accepting the final responseSessionEnd: after the run completesSubagentStop: for worker processes spawned byworker-dispatch
Hook Script Contract
Hook scripts receive JSON on stdin and return decisions via exit code:
- Exit 0: allow / continue
- Exit 2: block (stderr message is surfaced)
Recommended output shape for decision hooks:
{
"decision": "allow|deny|ask",
"reason": "short explanation",
"systemMessage": "optional context for the main agent"
}
Input Fields (Suggested)
{
"event": "PreToolUse",
"hook_event_name": "PreToolUse",
"tool_name": "Write",
"tool_input": {"file_path": "..."},
"tool_result": {"stdout": "..."},
"session_id": "...",
"transcript_path": "...",
"cwd": "...",
"approval_policy": "on-request",
"sandbox_mode": "workspace-write"
}
Your runner may add additional fields as needed.
Environment Variables
The hook runner should set:
CODEX_PROJECT_ROOT: repository rootCODEX_HOOK_ROOT: directory containinghooks.jsonand scriptsCODEX_ENV_FILE: path to a file for exporting environment variables (optional)
Utilities
Use these helper scripts while developing hooks:
scripts/validate-hook-schema.sh: validatehooks.jsonstructurescripts/hook-linter.sh: lint hook scriptsscripts/test-hook.sh: run hooks with sample inputs
References
references/patterns.mdfor common hook patternsreferences/advanced.mdfor advanced techniquesreferences/migration.mdfor migrating from script-only gates to prompt-based hooksexamples/for sample hooks