skillOverrides silently ignored for plugin-provided skills — runtime hard-codes source==="plugin" to "on" while the /skills UI implies overrides work
Summary
skillOverrides (name-only / off / user-invocable-only) is silently ignored for plugin-provided skills: the runtime resolver hard-codes them to "on" before any key lookup. Meanwhile the /skills UI reads and displays override state for plugin skills as if the setting works — so users can set overrides that never take effect, with no warning.
Environment
- Claude Code 2.1.205 (npm global, macOS 15 / Darwin 25.5)
- Reproduced with marketplace plugins (
expo@claude-plugins-official,sentry-cli@claude-plugins-official,commit-commands@claude-plugins-official)
Repro
- Enable any marketplace plugin that ships skills (e.g.
expo@claude-plugins-official). - In
~/.claude/settings.json, set overrides for its skills — any key form:
``json``
"skillOverrides": {
"expo:building-native-ui": "name-only",
"sentry-cli:sentry-cli": "name-only"
}
- Also set a user-scope skill (from
~/.claude/skills/) toname-onlyas a control. - Start a new session and inspect the model's skill listing.
Expected: plugin skills render name-only (or hidden for off), same as user-scope skills.
Actual: plugin skills always render with their full (200-char-capped) descriptions; the user-scope control skill correctly renders name-only. Verified with 29 plugin-qualified name-only entries — none have any effect, while every bare user-scope key works.
Root cause (from the 2.1.205 bundle)
The effective-override resolver short-circuits on plugin source before any settings lookup:
function e9e(e){
if (e.type !== "prompt" || e.source === "plugin") return "on";
let t = Bn(), r = t.skillOverrides,
n = r?.[e.name] ?? (e.unqualifiedName != null ? r?.[e.unqualifiedName] : void 0) ?? "on";
...
}
This one function feeds the name-only listing set, the off invocation gate (WY), and model-invocability (iDo) — so all override modes are dead for plugin skills, regardless of key format.
The mismatch: the /skills panel's override logic does read user/project/local skillOverrides for plugin skills and renders the chosen state, so the UI implies support the runtime doesn't have. If the exclusion is intentional, the UI should refuse or warn; if not, the resolver should drop the source === "plugin" short-circuit.
Impact
There is currently no way to trim plugin skill descriptions from the per-turn skill listing short of disabling the entire plugin. Plugins with large skill sets (expo ships 15 skills ≈ 2.5k chars of listing) consume a big share of the ~1% listing budget, and past the budget, entries get truncated and skill routing degrades — so per-skill name-only on plugins is exactly the tool users reach for, and it silently does nothing.
Related
- #15281 — requested exactly this, but was auto-closed as a duplicate of #13954, which is about project-vs-user rules precedence, not plugin skill overrides; it's locked, hence this new issue.
- #50631 — earlier report that
skillOverrideswas ignored entirely (stub resolver). That's since been fixed for user/project skills, which is why bare keys now work; the plugin-source exclusion remains. - #22345 — adjacent: plugin skills also don't support
disable-model-invocationfrontmatter, closing off the author-side workaround too.
---
Investigated and drafted with Claude Code (binary-verified against 2.1.205); posted by the account owner.
Showing cached comments. Read the full discussion on GitHub ↗
3 Comments
Two additions from an independent repro on 2.1.212 (macOS, native install), 39 plugin-qualified
"off"entries, none effective:1. For whoever drops the
source === "plugin"short-circuit: plugin skills register under BOTH qualified and bare names, and the two behave as separate entries — the fix needs to treat them as one unit./contextlists some plugin skills twice, as separate listing entries with separate token costs — e.g.vercel:bootstrap(~70 tok) and barebootstrap(~100 tok) in the same session.skillUsagetelemetry likewise records invocations of the same plugin skill under both forms — e.g.remember9× vsremember:remember109×.The current non-plugin lookup is
r?.[e.name] ?? r?.[e.unqualifiedName]per entry. If the bare-name listing entry carries the bare name as itse.name, a user who keys overrides qualified-form only (the form/skillswrites) would still leak the bare duplicate after the short-circuit is removed — and vice versa. Override matching should resolve both registrations of a plugin skill together.2. Still reproduces on 2.1.212, and no settings tier reaches plugin skills — including the
--settingsflag.Same payload, plugin skill vs bundled skill:
Notable: the 2.1.212 bundle has a second resolver that checks
policySettingsthenflagSettingsbefore the plugin short-circuit — but it only appears to feed the/skillsUI lock display, not the model-facing listing. So the UI/runtime mismatch described in the report extends to the policy and flag tiers as well: the UI implies even IT-managed overrides work on plugin skills, and none do.(Prior report of the user/project-tier variant for bundled skills was #50631, now closed and locked.)
Isn't this mentioned in official document as expected behaviour, sorry I was a bit confused.
Plugin skills are not affected by skillOverrides. Manage those through /plugin instead.https://code.claude.com/docs/en/skills#override-skill-visibility-from-settings
Reproduced on v2.1.233 (macOS) — the runtime behavior, not the UI mismatch.
Steps:
myplugin/.claude-plugin/plugin.json+myplugin/skills/zebra-widget/SKILL.md) and a project skill.claude/skills/user-control/SKILL.mdas a control..claude/settings.json:{"skillOverrides":{"myplugin:zebra-widget":"off","zebra-widget":"off","user-control":"off"}}claude -p --plugin-dir ./myplugin "Is there a skill named exactly 'myplugin:zebra-widget' in your skills listing? YES or NO"→YES. Same question foruser-control→NO./skillsin an interactive session shows:``
``🔒 on myplugin:zebra-widget · plugin · locked by plugin
✘ off user-control · project
Plugin skills are managed via /plugin
Observed:
skillOverrideshas no effect on plugin skills in any settings tier; the/skillspanel shows them as locked rather than letting you set an override.Expected (per the report):
name-only/offapplies to individual plugin skills.Assessment: This is working as designed and documented. The skills docs say "Plugin skills are not affected by
skillOverrides. Manage those through/plugininstead" (https://code.claude.com/docs/en/skills#override-skill-visibility-from-settings), and the/skillspanel on 2.1.233 marks plugin skills as locked with that same pointer, so there is no UI/runtime mismatch on the current version. The intended model is: plugin skills are enabled or disabled as a unit via/plugin; per-skill visibility overrides only apply to user, project, and built-in skills. The underlying ask — trimming individual plugin skills from the listing without disabling the whole plugin — is a reasonable feature request, but it is not a bug.🤖 Generated with Claude Code