skillOverrides silently ignored for plugin-provided skills — runtime hard-codes source==="plugin" to "on" while the /skills UI implies overrides work

Status Fixed / completed
Reported on v2.1.205
Maintainer reply ✓ Yes — bcherny
Activity 4 comments · opened Jul 9, 2026 · closed Aug 17, 2026
💡 Likely answer: A maintainer (bcherny, collaborator) responded on this thread — see the highlighted reply below.

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

  1. Enable any marketplace plugin that ships skills (e.g. expo@claude-plugins-official).
  2. 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"
}
``

  1. Also set a user-scope skill (from ~/.claude/skills/) to name-only as a control.
  2. 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 skillOverrides was 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-invocation frontmatter, closing off the author-side workaround too.

---

Investigated and drafted with Claude Code (binary-verified against 2.1.205); posted by the account owner.

View original on GitHub ↗

3 Comments

glopezjr · 1 month ago

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.

  • /context lists some plugin skills twice, as separate listing entries with separate token costs — e.g. vercel:bootstrap (~70 tok) and bare bootstrap (~100 tok) in the same session.
  • skillUsage telemetry likewise records invocations of the same plugin skill under both forms — e.g. remember 9× vs remember:remember 109×.

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 its e.name, a user who keys overrides qualified-form only (the form /skills writes) 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 --settings flag.

Same payload, plugin skill vs bundled skill:

$ claude -p --settings '{"skillOverrides":{"vercel:ai-sdk":"off"}}' \
    "Is there a skill named exactly 'vercel:ai-sdk' in your skills listing? YES or NO only."
YES

$ claude -p --settings '{"skillOverrides":{"deep-research":"off"}}' \
    "Is there a skill named exactly 'deep-research' in your skills listing? YES or NO only."
NO

Notable: the 2.1.212 bundle has a second resolver that checks policySettings then flagSettings before the plugin short-circuit — but it only appears to feed the /skills UI 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.)

tim-hub · 1 month ago

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

bcherny collaborator · 15 days ago

Reproduced on v2.1.233 (macOS) — the runtime behavior, not the UI mismatch.

Steps:

  1. Create a local plugin with one skill (myplugin/.claude-plugin/plugin.json + myplugin/skills/zebra-widget/SKILL.md) and a project skill .claude/skills/user-control/SKILL.md as a control.
  2. In .claude/settings.json: {"skillOverrides":{"myplugin:zebra-widget":"off","zebra-widget":"off","user-control":"off"}}
  3. claude -p --plugin-dir ./myplugin "Is there a skill named exactly 'myplugin:zebra-widget' in your skills listing? YES or NO"YES. Same question for user-controlNO.
  4. /skills in an interactive session shows:

``
🔒 on myplugin:zebra-widget · plugin · locked by plugin
✘ off user-control · project
Plugin skills are managed via /plugin
``

Observed: skillOverrides has no effect on plugin skills in any settings tier; the /skills panel shows them as locked rather than letting you set an override.
Expected (per the report): name-only/off applies 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 /plugin instead" (https://code.claude.com/docs/en/skills#override-skill-visibility-from-settings), and the /skills panel 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

Showing cached comments. Read the full discussion on GitHub ↗