Plugin docs/examples imply plugin-local hooks, but runtime only executes global hooks.json

Open 💬 4 comments Opened Apr 1, 2026 by isCopyman

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

  1. Create or install a local plugin with this shape:
  • .codex-plugin/plugin.json
  • hooks.json
  • scripts/runtime-hook.cjs
  1. Put simple lifecycle hooks in hooks.json, for example SessionStart, UserPromptSubmit, Stop, each running a command that writes a file under /tmp or $HOME.
  2. Install/enable the plugin normally so it is present under ~/.codex/plugins/cache/<marketplace>/<plugin>/local and enabled in ~/.codex/config.toml.
  3. 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.json as a plugin companion surface.
  • The public plugin examples include plugin folders with hooks.json.
  • Example manifests include a hooks field pointing at ./hooks.json.

But the current runtime code seems to say otherwise:

  • codex-rs/core/src/plugins/manifest.rs parses plugin manifests and recognizes skills, mcpServers, and apps, but not hooks.
  • codex-rs/hooks/src/engine/discovery.rs discovers hooks by scanning config-layer folders for hooks.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.json is actually executed

Request

Could you clarify which of these is intended?

  1. Plugin-local hooks.json is supposed to work, and this is a runtime bug.
  2. Plugin-local hooks.json is 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.

View original on GitHub ↗

This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗