Skip to content

Plugin manifests define hooks, but plugin hooks are not loaded into the Codex hooks runtime #17331

Description

@andre-menutole

Summary

Plugin manifests appear to support a hooks field, but plugin-defined hooks are not actually loaded into the runtime hook system. As a result, plugins can contribute skills, MCP servers, and apps, but not lifecycle hooks, even though the plugin spec and scaffolding suggest that they can.

This creates a mismatch between:

  • plugin manifest/spec expectations
  • plugin scaffolding/templates
  • actual runtime behavior

Current Behavior

Today, Codex lifecycle hooks are loaded from hooks.json discovered through config layers, via the hooks engine/runtime.

At the same time, plugin manifests and plugin scaffolding suggest support for plugin-scoped hooks:

  • plugin sample/spec includes a hooks field
  • plugin scaffolding includes optional hook-related structure

However, in the runtime:

  • plugin loading resolves skills, MCP servers, and apps
  • plugin manifests do not appear to contribute hook configs to the active codex-hooks engine
  • enabled plugins therefore cannot activate lifecycle hooks as part of the plugin bundle

Why This Matters

A plugin already acts as a packaging and composition unit for reusable Codex capabilities. If a plugin can include:

  • skills
  • MCP servers
  • apps

but not:

  • lifecycle hooks

then the plugin boundary is incomplete. The plugin can package the tools and instructions for a workflow, but not the runtime lifecycle behavior that should accompany that workflow.

Example use cases:

  • a repo/workflow plugin that blocks unsafe shell commands before execution
  • a plugin that injects context after specific tool calls
  • a plugin that enforces stop-time continuation prompts for a narrow workflow
  • a plugin that adds session-start checks when the plugin is enabled

Without plugin-scoped hooks, these behaviors must live in global/workspace hook config, which weakens encapsulation and portability.

Reproduction / Evidence

From local inspection of the repository:

1. Plugin spec/scaffolding suggests hooks are supported

The plugin sample/spec includes a hooks field:

  • codex-rs/skills/src/assets/samples/plugin-creator/references/plugin-json-spec.md

The plugin creator scaffold also references hooks:

  • codex-rs/skills/src/assets/samples/plugin-creator/scripts/create_basic_plugin.py

2. Runtime plugin loading does not appear to load hooks

Plugin manifest loading in:

  • codex-rs/core/src/plugins/manifest.rs

Plugin loading/aggregation in:

  • codex-rs/core/src/plugins/manager.rs
  • codex-rs/plugin/src/load_outcome.rs

These paths load/aggregate:

  • skills
  • MCP server config
  • apps

but not hook config paths.

3. Hooks runtime is separate and only discovers config-layer hooks

Hook discovery/runtime is implemented under:

  • codex-rs/hooks/src/engine/discovery.rs
  • codex-rs/hooks/src/registry.rs
  • codex-rs/core/src/hook_runtime.rs

The active handlers are discovered from config layers, not from enabled plugins.

4. Product/UI copy also reflects the current limitation

Plugin render text currently describes plugins as bundles of:

  • skills
  • MCP servers
  • apps

which is consistent with current runtime behavior, but inconsistent with the plugin spec.

Expected Behavior

If a plugin manifest declares:

{
  "hooks": "./hooks.json"
}

and the plugin is enabled, then that hook config should be loaded into the active hooks runtime for the session.

A plugin should be able to contribute lifecycle hooks the same way it contributes other capabilities.

Proposed Solution

Minimal approach:

  1. Treat hooks as another plugin-contributed runtime capability, alongside:

    • skills
    • mcpServers
    • apps
  2. Extend plugin manifest loading to resolve the hooks path in the same way it resolves the other plugin component paths.

  3. Extend plugin load aggregation to expose effective hook config paths for enabled/healthy plugins.

  4. Pass those effective plugin hook paths into the hooks discovery/runtime layer.

  5. Keep execution order deterministic:

    • config-layer hooks first
    • plugin hooks after

This seems like the lowest-risk behavior because it preserves existing global/workspace policy while allowing plugins to layer additional behavior.

Suggested Semantics

  • Only enabled plugins contribute hooks.
  • Plugins with load errors should not contribute hooks.
  • Hook file paths should be resolved relative to plugin root and validated with the same safety rules used for other plugin manifest paths.
  • Existing hook event schemas and runtime semantics do not need to change.
  • No need to introduce new hook types initially; type: "command" support is enough.

Compatibility / Risk

This should be backward-compatible:

  • existing global/workspace hooks continue to work unchanged
  • plugins without hooks are unaffected
  • plugin-scoped hooks simply become active when present

Potential questions to decide explicitly:

  • ordering between global and plugin hooks
  • whether duplicate hook files should be deduplicated
  • whether plugin hooks should always be active when the plugin is enabled, or only when the plugin is explicitly invoked/mentioned

My recommendation:

  • active whenever the plugin is enabled
  • deduplicate by resolved path
  • run after config-layer hooks

Requested Outcome

I am not asking for unsolicited code review here.

I am mainly asking:

  1. Is plugin-scoped hook support intended?
  2. If yes, would the maintainers accept an invited PR implementing the minimal wiring above?
  3. If not, should the plugin spec/scaffolding be updated to stop advertising hooks support?

If helpful, I can also provide a more concrete implementation outline based on the current Rust crate boundaries.

Activity

  1. changed the title [-]Plugin manifests define , but plugin hooks are not loaded into the Codex hooks runtime[/-] [+]Plugin manifests define `hooks`, but plugin hooks are not loaded into the Codex hooks runtime[/+] on Apr 10, 2026
  2. added
    bugSomething isn't working
    CLIIssues related to the Codex CLI
    hooksIssues related to event hooks
    skillsIssues related to skills
    on Apr 10, 2026
  3. github-actions commented on Apr 10, 2026

    @github-actions
    Contributor

    Potential duplicates detected. Please review them and close your issue if it is a duplicate.

    Powered by Codex Action

  4. andre-menutole commented on Apr 10, 2026

    @andre-menutole
    Author

    Closing as duplicate of #16430.

  5. oxysoft commented on May 8, 2026

    @oxysoft

    Indexed this hook ticket in the umbrella tracker: #21753

    Goal: collect the scattered Codex hook requests and bugs into one parity matrix for Full Claude Code Hook Parity (29+), while preserving this issue as the detailed thread for its specific behavior.

  6. andre-menutole commented on Jun 1, 2026

    @andre-menutole
    Author

    Indexed this hook ticket in the umbrella tracker: #21753

    Goal: collect the scattered Codex hook requests and bugs into one parity matrix for Full Claude Code Hook Parity (29+), while preserving this issue as the detailed thread for its specific behavior.

    ty

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

    CLIIssues related to the Codex CLIbugSomething isn't workinghooksIssues related to event hooksskillsIssues related to skills

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions