Plugin docs/examples imply plugin-local hooks, but runtime only executes global hooks.json
Summary
Codex plugin docs/examples imply that plugin-local hooks.json is a supported plugin surface, but the current runtime appears to only load hooks from config-layer hooks.json files (for example ~/.codex/hooks.json).
In practice, an installed plugin can contribute skills / .mcp.json / .app.json, but its plugin-local hooks.json does not seem to run.
Environment
- Codex CLI:
v0.118.0 - OS: Linux
Repro
- Create or install a local plugin with this shape:
.codex-plugin/plugin.jsonhooks.jsonscripts/runtime-hook.cjs
- Put simple lifecycle hooks in
hooks.json, for exampleSessionStart,UserPromptSubmit,Stop, each running a command that writes a file under/tmpor$HOME. - Install/enable the plugin normally so it is present under
~/.codex/plugins/cache/<marketplace>/<plugin>/localand enabled in~/.codex/config.toml. - Start a new Codex session.
Expected
If plugin-level hooks are supported, the installed plugin's hooks.json should be discovered and executed.
Actual
The plugin installs and can be enabled, but its lifecycle hooks do not run.
If I place the exact same hooks into ~/.codex/hooks.json, they immediately start working.
Why this looks inconsistent
There are several signals that suggest plugin-local hooks are intended to work:
- The plugins docs/examples mention
hooks.jsonas a plugin companion surface. - The public plugin examples include plugin folders with
hooks.json. - Example manifests include a
hooksfield pointing at./hooks.json.
But the current runtime code seems to say otherwise:
codex-rs/core/src/plugins/manifest.rsparses plugin manifests and recognizesskills,mcpServers, andapps, but nothooks.codex-rs/hooks/src/engine/discovery.rsdiscovers hooks by scanning config-layer folders forhooks.json, not installed plugin roots.
So right now the observed behavior is:
- plugin install/load path: plugin capabilities work for skills/MCP/apps
- hook runtime path: only config-layer
hooks.jsonis actually executed
Request
Could you clarify which of these is intended?
- Plugin-local
hooks.jsonis supposed to work, and this is a runtime bug. - Plugin-local
hooks.jsonis not supported yet, and the docs/examples should be updated to avoid implying support.
If plugin-local hooks are intended to be supported, that would make plugin packaging much cleaner because lifecycle hooks could live inside the plugin bundle instead of requiring a second global ~/.codex/hooks.json installation path.
This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗