Local Plugin UI Containment Bug in Codex App

Open 💬 4 comments Opened Apr 3, 2026 by jkaunert

What version of the Codex App are you using (From “About Codex” dialog)?

Version 26.325.31654 (1272)

What subscription do you have?

Pro

What platform is your computer?

Darwin 24.6.0 arm64 arm

What issue are you seeing?

A local skill-bearing plugin installs cleanly and the CLI/runtime surface is
namespaced correctly, but the Codex Electron app still exposes plugin-owned
skills as directly invokable items in the picker and Skills UI. The same app
also renders local marketplace metadata differently from the curated
Build iOS Apps plugin.

The core issue is that local plugin-owned skills are not visually contained
behind the plugin entrypoint in Electron, even though the runtime itself is
cleanly namespaced.

What is already proven clean:

  1. plugin-managed runtime install is proven through installed cache, enabled

config state, and fresh-session visibility

  1. local plugin source is a materialized directory at

~/plugins/apple-appdev-workflow

  1. plugin payload no longer ships node_modules/
  2. CLI skill listing is namespaced and clean, for example:
  • apple-appdev-workflow:apple-product-surface-orchestrator
  • apple-appdev-workflow:apple-persistence-orchestrator
  • apple-appdev-workflow:apple-swiftdata-review
  1. explicit plugin-entry controls are green for both product-surface and

persistence brigades

Remaining Electron-only defects:

  1. plugin-owned skills still surface outside the plugin entrypoint in

picker/Skills UI

  1. plugin card metadata uses local marketplace name in the Category row

instead of marketplace interface.displayName

  1. local plugin presentation differs from curated plugin presentation even when

plugin-level and skill-level metadata are aligned closely with
Build iOS Apps

Exact text error encountered during local marketplace metadata testing:

Failed to load plugin
invalid marketplace name: only ASCII letters, digits, '_', and '-' are allowed

Exact prompt examples used during validation:

Use [@apple-appdev-workflow](plugin://apple-appdev-workflow@LocalAppleWorkflow) to review the SwiftData model and migration approach for saved reference captures, and recommend what should change first to reduce rollout and data-loss risk.
Review the SwiftData model and migration approach for saved reference captures, and recommend what should change first to reduce rollout and data-loss risk.
Use apple-product-surface-orchestrator to review this SwiftUI app's main product surface and recommend what should change first so the navigation, empty states, and on-screen copy feel more coherent and production-ready.

Representative CLI validation commands:

python3 ./scripts/probe_plugin_managed_runtime.py --repo-root .
codex exec -C /tmp --skip-git-repo-check "List the available plugins in this session by name only."
codex exec -C /tmp --skip-git-repo-check "List the available skills in this session by name only."

Representative clean runtime conclusion:

plugin-managed runtime is proven for the target plugin through installed cache, enabled config state, and fresh-session visibility

Electron-specific text clues observed in app-side logging / Sentry scope:

Skills/list missing short_description ...
method=plugin/read

Why this appears platform-side rather than bundle-side:

  1. first-party Build iOS Apps is also a real skills plugin
  2. its installed cache includes skills/ and skill-level agents/openai.yaml
  3. CLI exposes those skills as namespaced runtime skills
  4. the local plugin runtime is also namespaced cleanly in CLI
  5. the exposed/duplicate behavior persists primarily in Electron UI surfaces

rather than in the runtime listing itself

What steps can reproduce the bug?

  1. Create or use a local plugin marketplace with a local skill-bearing plugin.

In my case:

  • marketplace name: LocalAppleWorkflow
  • marketplace display name: Local Apple Workflow
  • plugin id: apple-appdev-workflow
  1. Install the plugin from the local marketplace in the Codex Electron app.
  2. Confirm the runtime itself is healthy:
  • run python3 ./scripts/probe_plugin_managed_runtime.py --repo-root .
  • confirm the probe concludes:

plugin-managed runtime is proven for the target plugin through installed cache, enabled config state, and fresh-session visibility

  1. Confirm CLI runtime namespacing is clean:
  • run codex exec -C /tmp --skip-git-repo-check "List the available plugins in this session by name only."
  • run codex exec -C /tmp --skip-git-repo-check "List the available skills in this session by name only."
  • confirm only namespaced skill entries appear for the local plugin
  1. Open the plugin card, picker, and Skills tab in the Electron app.
  2. Observe that plugin-owned skills are exposed as directly invokable UI items

outside the plugin entrypoint, and that the plugin card Category row uses the
marketplace slug-style name rather than the human-facing marketplace
interface.displayName.

What is the expected behavior?

For local skill-bearing plugins, Electron should either:

  1. preserve plugin containment rules consistently with curated plugins
  2. or document that local skill-bearing plugins are intentionally exposed as

standalone picker/Skills items

Expected metadata behavior:

  1. human-facing marketplace labels should use marketplace

interface.displayName

  1. slug-style marketplace name should remain an internal identifier and not

leak into the plugin card Category row

Instead, I see:

  1. The local plugin runtime is clean in CLI, but Electron still exposes

plugin-owned skills as standalone invokable items in picker/Skills UI.

  1. The plugin card Category row uses the marketplace slug-style identifier

instead of the human-facing display name.

  1. Curated Build iOS Apps is presented differently in Electron despite both

plugins being real skill-bearing plugins with runtime-visible skills/.

Representative local plugin runtime entries:

apple-appdev-workflow:apple-product-surface-orchestrator
apple-appdev-workflow:apple-persistence-orchestrator
apple-appdev-workflow:apple-swiftdata-review

Representative curated plugin cache root:

~/.codex/plugins/cache/openai-curated/build-ios-apps/...

Additional information

PII-redacted path examples:

/Users/<redacted>/.codex/plugins/cache/LocalAppleWorkflow/apple-appdev-workflow/local/skills/apple-product-surface-orchestrator/SKILL.md
/Users/<redacted>/.codex/plugins/cache/openai-curated/build-ios-apps/...

The local plugin and curated plugin both have:

  1. skills/
  2. plugin-level agents/openai.yaml
  3. skill-level agents/openai.yaml

I did not find an explicit allow_implicit_invocation: false in the curated
plugin files I inspected, so the different Electron presentation does not look
like a simple manifest-field difference.

View original on GitHub ↗

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