Skip to content

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

Open

Description

@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
  2. Put simple lifecycle hooks in hooks.json, for example SessionStart, UserPromptSubmit, Stop, each running a command that writes a file under /tmp or $HOME.
  3. Install/enable the plugin normally so it is present under ~/.codex/plugins/cache/<marketplace>/<plugin>/local and enabled in ~/.codex/config.toml.
  4. 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.

Activity

  1. added
    bugSomething isn't working
    CLIIssues related to the Codex CLI
    on Apr 1, 2026
  2. added
    agentIssues related to the core agent loop
    and removed
    CLIIssues related to the Codex CLI
    on Apr 2, 2026
  3. andre-menutole commented on Apr 10, 2026

    @andre-menutole

    A bit of additional technical framing that may help here:

    Plugins already act as a packaging/composition boundary for reusable Codex capabilities. Today, an enabled plugin can contribute:

    • skills
    • MCP servers
    • apps

    From that perspective, hooks look like a missing runtime capability in the same composition model. Right now, a plugin can package the tools and instructions for a workflow, but not the lifecycle behavior that should accompany that workflow.

    That is why this feels more like an incomplete plugin boundary than just a docs mismatch.

    A minimal implementation path seems to be:

    1. resolve hooks in plugin manifest loading, alongside skills / mcpServers / apps
    2. expose effective hook config paths for enabled, healthy plugins
    3. pass those paths into the existing hooks discovery/runtime
    4. keep ordering deterministic: config-layer hooks first, plugin hooks after

    That would preserve current global/workspace behavior while allowing plugins to package lifecycle behavior together with the rest of the plugin bundle.

  4. added
    configIssues involving config.toml, config keys, config merging, or config updates
    and removed
    agentIssues related to the core agent loop
    on Apr 11, 2026
  5. zorkary commented on May 3, 2026

    @zorkary

    Adding a current-version confirmation: I can still reproduce this on Codex 0.128.0-alpha.1 on macOS, specifically in codex exec.

    I tested while packaging a small local plugin with both:

    • a stdio MCP server
    • a UserPromptSubmit hook

    Results:

    • direct config-level UserPromptSubmit hook works
    • direct MCP registration works
    • plugin-packaged MCP works when present in the installed plugin cache
    • plugin-packaged UserPromptSubmit hook does not execute

    I used a marker-file test for the hook command, so this was not just “the model didn’t see the additionalContext”; the plugin hook command itself did not run.

    I also tried:

    • hooks/hooks.json with top-level { "hooks": { ... } }
    • bare top-level { "UserPromptSubmit": [...] }
    • manifest hooks field present / absent
    • relative and absolute hook commands
    • [features] codex_hooks = true

    All plugin-bundled hook variants failed in codex exec.

    One related install-path note: codex plugin marketplace add <local path> registers the marketplace in config but does not appear to install/activate local plugin components by itself; codex plugin marketplace upgrade <name> rejects local marketplaces because it expects a Git marketplace.

  6. oalanicolas commented on May 8, 2026

    @oalanicolas

    Confirming reproduction on 0.128.0 (release) on macOS — same setup as @zorkary's report (.codex-plugin/plugin.json with explicit hooks: "./hooks/hooks.json" + hooks/hooks.json + marketplace registered via codex plugin marketplace add . + plugin enabled + [features] codex_hooks = true).

    Plugin hooks silent. Same exact command moved to top-level [[hooks.SessionStart]] / [[hooks.UserPromptSubmit]] in ~/.codex/config.toml fires immediately. Marker-file test confirms the hook command never runs from the plugin path — not a "model didn't see additionalContext" issue, the process itself isn't spawned.

    @andre-menutole's 4-step plan upthread looks correct to me.

    Use case context: filed #21675 for the broader rule-cache proposal that this bug currently blocks distributing as a plugin. Once hooks discovery from plugin manifests works, the entire workaround collapses to a single --uninstall command.

  7. srbryers commented on May 16, 2026

    @srbryers

    Confirming this is still a blocker on Codex CLI 0.130.0 on macOS.

    Use case: packaging SLOPE lifecycle guards as a Codex plugin. SLOPE can generate a .codex-plugin/plugin.json and package the guard dispatcher/scripts cleanly, but the lifecycle hooks still need to live in a config-layer .codex/hooks.json or ~/.codex/hooks.json to be discovered and reviewed by /hooks.

    Observed locally:

    • codex features list reports hooks as stable/true
    • plugin_hooks is present but under development/false
    • /hooks discovers config-layer project hooks from ~/Development/fathoms/.codex/hooks.json
    • plugin-local hooks are not available as a usable trust/review surface, so a plugin alone cannot activate the guards

    This means a clean slope hook add --level=full --harness=codex implementation currently has to install a shim into global/project hook config rather than shipping lifecycle behavior entirely inside the plugin bundle. The desired fix from @andre-menutole above would resolve that: plugin manifests should expose effective hook config paths to the existing hook discovery/runtime.

  8. 19 remaining items

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingconfigIssues involving config.toml, config keys, config merging, or config updates

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions