Skip to content

feat(plugins): Plugin-scoped control over unprefixed skill aliases in autocomplete #50488

@e1024kb

Description

@e1024kb

Feature request: plugin-scoped control over unprefixed skill aliases in autocomplete

Context

I maintain a plugin (xx) in a marketplace where every skill is intended to be invoked only via its namespaced form — /xx:add-project, /xx:help, /xx:migrate. The namespace is part of the plugin's public contract: it signals "this is a XX workflow command" and it's what the docs and CONTRIBUTING.md teach users to type.

Observed behaviour

When I type /add in a session that has the plugin installed, autocomplete offers:

/add-project (xx) Register a XX project directory i.e. the unprefixed form of the skill name appears alongside the namespaced form. The bare form appears to be a convenience alias Claude Code adds when the skill name doesn't conflict with another installed skill.

Problem

I can't turn this off. The docs describe two user-scoping frontmatter flags:

  • disable-model-invocation: true — blocks Claude from auto-invoking. Already set.
    Doesn't affect autocomplete.
  • user-invocable: false — hides from the / menu, but the docs don't clarify whether
    the namespaced form still works when it's set. Setting it risks making the skill entirely
    unreachable, which defeats the purpose.

Neither gives me what I want: "appear in autocomplete only under /xx:<skill>, never
under bare /<skill>."
There is also no plugin-level knob in plugin.json for this.

Why this matters for plugin authors

  1. The namespace is a branding and discoverability signal. Showing skills unprefixed
    breaks the /<plugin>:... mental model the docs themselves promote ("Plugin skills are
    always namespaced to prevent conflicts").
  2. Autocomplete clutter: every plugin a user installs can add N bare aliases to the global
    slash menu. With multiple plugins, this gets noisy fast.
  3. "No conflict today" is a fragile basis for aliasing. The bare form can start
    conflicting later when another plugin ships a same-named skill — behaviour changes without
    the user touching anything.
  4. For plugins that orchestrate internal workflows, users calling bare /migrate instead
    of /xx:migrate is a footgun: they might invoke a different plugin's /migrate by
    accident once conflicts arise.

Proposed solutions

Any one of these would address the problem, in order of preference:

  1. Per-skill frontmatter flag: namespace-only: true. Skill appears in autocomplete
    only as /<plugin>:<skill>, never as bare /<skill>. Typing the bare form is either
    rejected or falls through to non-plugin skills.
  2. Plugin-wide setting in plugin.json: "namespaceOnly": true. Applies to every
    skill in the plugin — simpler for plugin authors who want the policy uniform.
  3. Clarify user-invocable: false semantics in the docs and guarantee that namespaced
    invocation (/<plugin>:<skill>) still works when it's set. That turns it into a usable
    workaround even without a new flag.

Happy to test a preview if any of this lands. Thanks!

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions