openai / openai/codex

A root plugin.json silently disables all of a plugin's hooks

Open
#39,895 3 comments 2 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug CLI hooks skills
Dominant language
Rust
Stars
125k
Forks
19.4k
PR merge metrics
PR metrics pending

Description

A root plugin.json silently disables all of a plugin's hooks

What happens

When a plugin directory contains a root plugin.json (the
Agent Plugins 1.0.0 manifest), Codex loads it through
the Agent Plugins loader — and that loader has no hook support. The hooks field
in .codex-plugin/plugin.json is never read, so every hook the plugin declares
stops running
, with no warning, error, or log line.

Shipping both manifests is a reasonable thing to want: .codex-plugin/plugin.json
for Codex, the root manifest so the same directory loads in Cursor and other spec
clients. Today those two goals are mutually exclusive, and choosing one silently
costs you the other.

Why it is hard to notice

The failure is invisible from every surface a user would check:

  • The TUI still prints hook: SessionStart / hook: SessionStart Completed
    lines — for other plugins' hooks. The count looks plausible.
  • ~/.codex/config.toml keeps its [hooks.state] entries for the affected
    plugin with valid trusted_hash values, so the hooks appear registered.
  • codex doctor has no hooks section.
  • Nothing is logged.

Two of our plugins were dead for a week before anyone noticed, and locating the
cause took a long bisect against an installed cache.

Reproduction

Codex 0.149.0, Linux (WSL2), plugin installed from a git marketplace.

Plugin layout:

condux/
  .codex-plugin/plugin.json     # { ..., "hooks": "./hooks/codex-hooks.json" }
  .claude-plugin/plugin.json
  plugin.json                   # Agent Plugins 1.0.0 manifest
  hooks/codex-hooks.json        # SessionStart + Stop
  hooks/session-start.mjs
  skills/...

hooks/codex-hooks.json:

{
  "hooks": {
    "SessionStart": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "node \"${PLUGIN_ROOT}/hooks/session-start.mjs\" --codex",
            "additionalContextLimit": 4000
          }
        ]
      }
    ]
  }
}

With a tracer added to the body of session-start.mjs (editing the command
string instead would invalidate the trusted hash and prompt), run
codex exec "hi" twice — once with the root plugin.json present, once with it
moved aside. Nothing else changes.

root plugin.json SessionStart hooks fired Tracer
present 2 (both from an unrelated plugin) never runs
removed 3 runs

A second plugin in the same install reproduces it identically, including a
UserPromptSubmit hook that goes from absent to firing. And a third plugin that
ships no root manifest has its hooks working throughout — which is what
isolates the manifest as the cause.

What we tried
Attempt Result
hooks field on the root manifest ignoring unknown Agent Plugins manifest field
extensions only namespace com.openai is read, keys default_tools_approval_mode / enabled_tools / disabled_tools / tools. No hooks slot
conventional hooks/hooks.json alongside also suppressed
move the manifest to .cursor-plugin/plugin.json hooks return — but that is a Cursor Plugin manifest, a different format

So there is no supported way to be a spec-conformant Agent Plugin and keep
Codex hooks. We shipped the removal, which costs those two plugins their spec
conformance.

Suggested fix

Either of these would resolve it:

  1. Precedence — when .codex-plugin/plugin.json is present, let it keep
    authority over host-specific fields (hooks, and presumably interface)
    even if a root manifest also exists. This matches the documented resolution
    order .codex-plugin/.claude-plugin/.cursor-plugin/, which the
    Agent Plugins loader currently bypasses entirely.
  2. A hooks slot under extensions — e.g.
    extensions["com.openai"].hooks, keeping the root manifest inside its
    closed schema.

Failing either, a warning would have saved the week: something like
plugin <name> declares hooks in .codex-plugin/plugin.json but ships a root plugin.json; hooks are disabled at load time. Right now the mode is entirely
silent.

Environment
  • Codex CLI 0.149.0 (npm, linux-x86_64), Ubuntu 24.04 on WSL2
  • [features] hooks = true
  • Plugins installed from a git marketplace source

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Trace the Agent Plugins loader and the .codex-plugin/plugin.json versus root plugin.json resolution path, then reproduce the issue with codex exec "hi" using the supplied manifest layout. Done means hooks from .codex-plugin/plugin.json still fire when a root manifest is present, or the conflicting configuration produces a clear warning.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
cli
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
56/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.