hooks
codex-hooks installs, removes, trusts, diagnoses, and wraps Codex lifecycle hooks.
It supports two backends:
- installed: merge command hooks into
$CODEX_HOME/hooks.json, preserve foreign hooks, and write trusted hook hashes to$CODEX_HOME/config.toml. - session-flags: build
codex execargv fragments such as-c hooks.SessionStart=[...]for one invocation.
install
Section titled “install”npm install -g @codex-modules/hooksOr from source:
npm installnpm run buildUse --codex-home DIR or CODEX_HOME=DIR for sandboxed installs. The library never needs another module at runtime.
Create a hookset.json:
{ "SessionStart": [ { "matcher": "startup|resume", "hooks": [ { "type": "command", "command": "/path/to/hook.sh", "commandWindows": "py -3 C:\\path\\to\\hook.py", "timeout": 5, "async": false, "statusMessage": "Starting hook", "additionalContextLimit": 5000 } ] } ], "SessionEnd": [ { "matcher": "other", "hooks": [ { "type": "command", "command": "/path/to/session-end.sh", "timeout": 3 } ] } ], "Stop": [ { "hooks": [ { "type": "command", "command": "/path/to/hook.sh", "timeout": 5 } ] } ]}Installed backend:
codex-hooks plan --hooks hookset.json --codex-home /tmp/codex-homecodex-hooks apply --hooks hookset.json --codex-home /tmp/codex-homecodex-hooks trust --codex-home /tmp/codex-homecodex-hooks status --codex-home /tmp/codex-homeWrapper backend:
codex-hooks exec-args --hooks hookset.json# Copy the printed argv after `codex exec`, then add your prompt.For scripts, prefer JSON and pass the returned array directly:
codex-hooks exec-args --hooks hookset.json --jsonBy default exec-args keeps Codex hook trust enforcement enabled. For one-off automation that has independently reviewed every hook source, explicitly pass --bypass-trust to add --dangerously-bypass-hook-trust.
The current lifecycle events are PreToolUse, PermissionRequest, PostToolUse, PreCompact, PostCompact, SessionStart, SessionEnd, UserPromptSubmit, SubagentStart, SubagentStop, and Stop. Command handlers support commandWindows (or the command_windows input alias), timeout, async, statusMessage, and additionalContextLimit. Codex currently parses async, but does not run asynchronous command hooks.
how it works
Section titled “how it works”The installed backend reads $CODEX_HOME/hooks.json, validates the PascalCase Codex hook events, and appends only missing command hooks. Foreign hooks are preserved. Re-running apply is idempotent for the same event, matcher, and command.
Installed entries are tracked in $CODEX_HOME/.codex-hooks-manifest.json. Manifest v3 records the complete command handler and distinguishes handlers created by codex-hooks from matching pre-existing handlers that were only adopted for trust/status tracking. remove deletes exactly one matching created handler and never deletes or replaces an adopted handler, then removes the managed trust block from config.toml. Ambiguous v1 ownership migrates fail-safe as adopted.
When codex-hooks creates the entire hooks.json, manifest v3 also records a SHA-256 fingerprint of the complete file. remove --delete-created-file deletes the whole file only while that fingerprint still matches. Any later foreign hook, top-level description, metadata, or even unrecognized file edit disables whole-file deletion; owned handlers are still removed selectively. Fingerprint-less v1/v2 manifests never authorize whole-file deletion.
trust calls Codex app-server method hooks/list with { cwds }, consumes the current { data: [{ cwd, hooks, warnings, errors }] } response, reads each installed hook key and currentHash, and writes:
[hooks.state."<key>"]trusted_hash = "sha256:..."enabled = trueThose TOML entries are contained in a managed block owned by codex-hooks, then validated before writing. Discovery errors stop trust before config.toml is changed; status and doctor report both discovery warnings and errors. Trust matches the current app-server metadata exactly: matcher, command handler type, effective timeout, status message, and additional-context limit must all be present and unambiguous. Trust is all-or-nothing by default when a manifest hook is missing. Use trust --allow-partial only when writing the discovered subset is intentional.
Version matrix:
| Codex version | installed backend | session-flags backend |
|---|---|---|
| 0.139.x | hooks/list discovery and hooks.state trust verified; exec firing was not observed | warn: exec-path firing unverified/broken (measured: 0.139 no-fire) |
| 0.142-0.146 | legacy compatibility only; some contracts differ from current documentation | session flag firing was measured on 0.142.5 |
| 0.147+ | current hooks/list shape and lifecycle hook contract | current supported contract |
doctor reports the Codex binary, version, hooks feature state, hooks/list availability, discovered hooks, and the session-flags version gate.
uninstall-rollback
Section titled “uninstall-rollback”Every change to hooks.json and config.toml is backed up before writing. Backups live next to the target file under .codex-kit-backups/, for example:
$CODEX_HOME/.codex-kit-backups/hooks.json.2026-07-05T00-00-00-000Z.12345.bakRemove managed entries:
codex-hooks remove --codex-home "$CODEX_HOME"If codex-hooks originally created hooks.json and no hooks remain, delete it during removal:
codex-hooks remove --codex-home "$CODEX_HOME" --delete-created-fileManual rollback from a backup:
cp "$CODEX_HOME/.codex-kit-backups/hooks.json.<stamp>.bak" "$CODEX_HOME/hooks.json"cp "$CODEX_HOME/.codex-kit-backups/config.toml.<stamp>.bak" "$CODEX_HOME/config.toml"Attribution
Section titled “Attribution”The merge and ownership patterns are based on the MIT-licensed plastic-labs/codex-honcho project: https://github.com/plastic-labs/codex-honcho
The trust automation pattern is based on the MIT-licensed aannoo/hcom project: https://github.com/aannoo/hcom
The local configuration helper code in src/kit/ is adapted from this repository’s modules/config-kit package.