codex - 💡(How to fix) Fix Plugin manifests define `hooks`, but plugin hooks are not loaded into the Codex hooks runtime [2 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openai/codex#17331Fetched 2026-04-11 06:17:34
View on GitHub
Comments
2
Participants
2
Timeline
8
Reactions
0
Timeline (top)
labeled ×4commented ×2closed ×1renamed ×1

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

Root Cause

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.

Code Example

{
  "hooks": "./hooks.json"
}
RAW_BUFFERClick to expand / collapse

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.

extent analysis

TL;DR

The proposed solution involves extending plugin manifest loading to resolve the hooks path and passing effective plugin hook paths into the hooks discovery/runtime layer to enable plugin-scoped hook support.

Guidance

  • Review the plugin manifest loading and aggregation code in codex-rs/core/src/plugins/manifest.rs and codex-rs/core/src/plugins/manager.rs to understand how plugin components are currently resolved and loaded.
  • Extend the plugin manifest loading to resolve the hooks path in the same way as other plugin component paths, and update the plugin load aggregation to expose effective hook config paths for enabled/healthy plugins.
  • Update the hooks discovery/runtime layer to accept and process plugin hook paths, ensuring deterministic execution order with config-layer hooks first and plugin hooks after.
  • Validate the proposed solution against the suggested semantics, including only enabled plugins contributing hooks, resolving hook file paths relative to plugin root, and preserving existing hook event schemas and runtime semantics.

Example

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

This example plugin manifest declares a hooks field, which should be resolved and loaded into the active hooks runtime if the proposed solution is implemented.

Notes

The proposed solution aims to provide a minimal and backward-compatible approach to enabling plugin-scoped hook support. However, the implementation details and potential edge cases should be carefully reviewed and discussed with the maintainers before proceeding with a pull request.

Recommendation

Apply the proposed workaround by extending plugin manifest loading and updating the hooks discovery/runtime layer to enable plugin-scoped hook support, as it provides a clear and backward-compatible solution to the current limitation.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING