Explicit-only skills need a visible, reliable explicit invocation contract

Resolved 💬 3 comments Opened Apr 26, 2026 by jkaunert Closed Apr 26, 2026

What version of Codex is running?

Current main after policy.allow_implicit_invocation and explicit skill
mentions landed.

What issue are you seeing?

policy.allow_implicit_invocation: false provides the important policy split
requested in #10585: a skill can be enabled without being eligible for broad
implicit task matching. That part appears to be in place.

The remaining gap is the end-to-end contract for explicit-only skills. Today,
explicit-only skills can be excluded from broad task matching, but they are not
discoverable or invokable enough to be reliable explicit targets.

Current upstream already supports useful substrate:

  • structured UserInput::Skill selections
  • linked skill paths
  • $skill token mentions
  • parsing policy.allow_implicit_invocation

But the remaining behavior still looks split:

  • the model-visible skill list is built from implicit-eligible skills, so an

explicit-only skill can be omitted from the visible instructions

  • plain-text skill names are not explicit mentions unless the user uses the

$skill form or a structured selection

  • namespaced plugin skills are hard to invoke naturally because users and other

model-visible instructions often refer to the base skill name, while the
installed skill name may be namespace-qualified

  • plugin names have a similar issue: linked plugin://... mentions work, but

plain-text plugin config/display names are not treated as explicit plugin
mentions

The result is that an explicit-only skill can be enabled and intentionally
excluded from automatic routing, while still being unreliable as an explicit
target in normal user text or model-visible routing instructions.

Minimal repro shape

  1. Define an enabled skill with policy.allow_implicit_invocation: false.
  2. Start a fresh Codex session where the skill is available.
  3. Ask for the skill by normal explicit text, for example use review-helper

rather than a structured skill chip or $review-helper.

  1. For a plugin-contributed skill, use a base name such as review-helper while

the installed skill name is namespace-qualified, for example
example-plugin:review-helper.

Expected: the skill remains excluded from broad implicit task matching, but is
visible as an explicit-only skill and can be selected by an unambiguous explicit
plain-text name or base-name reference.

Observed: the skill can be absent from the visible skill list and the plain-text
name/base-name reference does not reliably resolve to a skill injection.

Expected behavior

Explicit-only skills should remain excluded from broad implicit matching, but
should still be reliable explicit targets.

A workable contract would be:

  • render explicit-only skills in a separate model-visible section with narrower

trigger guidance

  • keep them out of automatic task matching
  • allow explicit matching by structured selection, fully qualified name, and

unambiguous plain-text or plugin base-name references where safe

  • preserve ambiguity checks so unrelated skills or connectors are not selected

by accident

Why this is separate from #10585

#10585 asked for the policy switch. That part appears to be partially
implemented now.

This issue is about the follow-through contract after that switch exists:
explicit-only skills need to be visible and invokable enough to function as
explicit tools without re-opening broad implicit routing.

Implementation direction

I would avoid replacing the current budgeted/aliased skill rendering design.
Instead, extend that surface so explicit-only skills can be rendered separately
from implicit-eligible skills, with separate trigger text.

For matching, keep the existing structured and linked path behavior, then add
safe plain-text matching for unambiguous skill names and namespaced plugin skill
base names.

The important constraint is that this should not re-enable broad implicit
matching. It should only make explicit-only skills discoverable and invokable
when the user or another active instruction names them directly.

View original on GitHub ↗

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