A settings-level switch for skill visibility
Every skill controls its own visibility through two frontmatter fields: disable-model-invocation stops Claude from invoking it automatically, and user-invocable: false stops you from invoking it directly. Both live inside the skill's own SKILL.md, which works fine when the skill is yours to edit. It doesn't work when the skill isn't, a skill checked into a shared team repository you don't want to fork just to silence locally, a plugin-adjacent skill, or one you only want quiet for a single testing session without leaving a change in a file someone else might commit.
skillOverrides is Claude Code's answer to that gap: a setting, not a frontmatter field, that controls whether a specific skill is listed, described, or invocable at all, from outside the skill file entirely. It's documented directly in Claude Code's skills reference, and the fastest way to set it doesn't involve touching JSON by hand.
The four states
skillOverrides is a map: each key is a skill name, each value is one of four states.
| Value | Listed to Claude | In / menu |
|---|---|---|
"on" | Name and description | Yes |
"name-only" | Name only | Yes |
"user-invocable-only" | Hidden | Yes |
"off" | Hidden | Hidden |
A skill absent from skillOverrides entirely is treated as "on", the default, fully-listed state. You only need an entry for a skill you want to change.
Read the table by what each state actually removes:
"on": no change from default. Claude sees the full description and can invoke it; you can invoke it from the/menu too."name-only": Claude still sees the skill exists, by name, but not its description. It stays invocable from the/menu for you directly. This is the state to reach for when a skill is taking up context budget it doesn't need, covered in more detail below."user-invocable-only": hidden from Claude entirely, so it can't be triggered automatically, but still runnable by you from the/menu. Functionally close to settingdisable-model-invocation: truein frontmatter, without editing the file."off": hidden everywhere. Not listed to Claude, not in the/menu, and invoking it directly returns theskillOverrideserror instead of running.
Setting it from the /skills menu
You rarely need to hand-write the JSON. Run /skills, highlight a skill, press Space to cycle through its four states, then Enter to save. The menu writes the change to .claude/settings.local.json, the project-scoped local settings file, and labels the "user-invocable-only" state user-only in its display, which is worth knowing if you go looking for that exact string and don't find it.
To set it by hand instead, the shape is a flat object under the skillOverrides key:
{
"skillOverrides": {
"legacy-context": "name-only",
"deploy": "off"
}
}
This example collapses legacy-context to a bare name (Claude knows it exists, doesn't see what it does unless invoked) and hides deploy completely.
Why the settings file location matters
skillOverrides lives in your settings files, and Claude Code layers settings by scope: user, project, project-local, and managed policy. The /skills menu specifically writes to .claude/settings.local.json, the project-local tier that's typically gitignored, which is precisely why the feature exists in the first place. If a skill is checked into a shared repository and you want it quiet on your own machine without changing what your teammates see, a project-local override is the correct place for that change to live: it's yours, not committed, and it doesn't touch the skill file itself.
If you want the same override applied for the whole team, set it in .claude/settings.json (committed, shared) instead of .claude/settings.local.json. Nothing about the skillOverrides key itself changes between the two files, only which settings tier you write it into and whether it's shared.
When to reach for skillOverrides instead of frontmatter
Three cases where the settings-level control genuinely beats editing SKILL.md directly:
A shared or third-party skill you can't edit cleanly. A skill checked into a monorepo other people maintain, or one installed from a plugin marketplace, isn't yours to modify without either forking it or sending a change nobody asked for. Setting it to "off" or "name-only" locally leaves the file untouched for everyone else.
A temporary state for testing. Comparing Claude's output with and without a skill available is the core technique behind testing an agent skill before you ship it. Toggling skillOverrides to "off" for the duration of a baseline comparison, then back once you're done, avoids a throwaway frontmatter edit that risks being committed by accident.
Freeing context budget without deleting anything. Claude Code's skill listing has a character budget, covered in full in why Claude Code shortens or drops your skill's description. Setting a low-priority skill to "name-only" removes its description from that budget entirely while keeping the skill installed and manually runnable, which is a more deliberate way to manage a crowded listing than hoping the automatic truncation drops the right ones.
skillOverrides vs frontmatter, side by side
Frontmatter (disable-model-invocation, user-invocable) | skillOverrides | |
|---|---|---|
| Where it lives | Inside the skill's own SKILL.md | In your settings, outside the skill file |
| Requires editing the skill | Yes | No |
| States available | Two booleans, roughly equivalent to on and user-invocable-only | Four states, including name-only and full off |
| Good for | A skill you author and maintain | A skill you don't own, or a temporary local change |
| Set from | A text editor | The /skills menu, or hand-edited JSON |
They aren't mutually exclusive. A skill's frontmatter sets its default behaviour for everyone who installs it; skillOverrides lets any individual installation change that behaviour locally without forking the skill.
What changed in v2.1.199
As of Claude Code v2.1.199, the "off" state extended beyond the terminal. Before that release, setting a skill to "off" hid it from Claude and from the / menu, but it could still surface through other surfaces. Since v2.1.199, "off" also hides the skill from the command lists advertised to Remote Control clients and to Agent SDK callers, so a skill you've turned off stays off consistently whether you're looking at it from the terminal, a phone connected over Remote Control, or a program built on the Agent SDK. Invoking a hidden skill by its full name still returns the skillOverrides error rather than running it, regardless of which surface the invocation came from.
The one exception: plugin skills
skillOverrides explicitly does not touch skills that ship inside a plugin. If you want to change a plugin skill's availability, that's a /plugin operation, enabling, disabling, or uninstalling the plugin itself, not a skillOverrides entry. Trying to hide a plugin-bundled skill through skillOverrides won't do anything; the setting simply doesn't apply to that category of skill.
A worked example: quieting a noisy shared skill
Say your team keeps a legacy-migration-notes skill in a shared monorepo, written months ago for a migration that's long finished. Nobody's deleted it, because a couple of people still reference it occasionally, but it keeps surfacing in Claude's suggestions for unrelated work because its description is broad. You don't maintain that skill, and rewriting its description to be narrower risks breaking it for the two people who still use it deliberately.
The settings-only fix is a single local override:
{
"skillOverrides": {
"legacy-migration-notes": "user-invocable-only"
}
}
Saved to your own .claude/settings.local.json, this hides the skill from Claude's automatic consideration entirely on your machine, while leaving it fully invocable with /legacy-migration-notes for you or anyone else who still wants it. Nobody else's setup changes, the file in the shared repo is untouched, and if the team later agrees the skill really should retire for everyone, that's a disable-model-invocation: true edit to the actual SKILL.md, made deliberately rather than worked around individually by each person who noticed the noise.
skillOverrides vs disableBundledSkills
It's worth distinguishing skillOverrides from a related but coarser setting: disableBundledSkills. Setting disableBundledSkills: true turns off every one of Claude Code's own bundled skills at once, things like /code-review and /debug, except /doctor, which stays typable even with the flag on. That's an all-or-nothing switch for Anthropic's built-in skills specifically. skillOverrides is the opposite in scope: it targets one named skill at a time, works on personal, project and plugin-adjacent skills alike (with the plugin exception noted above), and offers four graduated states rather than one binary toggle. Reach for disableBundledSkills when you want a leaner built-in skill set across the board; reach for skillOverrides when the problem is one specific skill, bundled or not, behaving in a way you want to change locally.
Troubleshooting
A skillOverrides entry doesn't seem to be taking effect. Confirm the skill name in your skillOverrides map matches the skill's actual name exactly, and confirm you're not trying to override a plugin skill, which the setting ignores entirely. Also check which settings file the entry landed in; a .claude/settings.local.json entry only applies on the machine that file lives on.
A skill set to "off" still shows up somewhere. If you're on a version before v2.1.199, "off" didn't yet extend to Remote Control or Agent SDK surfaces, only the terminal / menu and Claude's own context. Upgrading resolves this for anyone still seeing the gap.
You can't find the state labelled user-invocable-only in the /skills menu. The menu displays it as user-only, a shorter label for the same underlying value. Look for that string instead.
You edited skillOverrides by hand and the JSON won't parse. Malformed settings JSON is a common source of confusing skill behaviour generally, not just for skillOverrides. Run with --debug to surface the parse error, or use the /skills menu instead of hand-editing, since it always writes valid JSON.
Rolling an override out to a whole team
Everything above assumes a personal, local change, the common case, and the reason skillOverrides written by the /skills menu lands in .claude/settings.local.json by default. If the whole team should see the same override, not just you, move the same key into the committed .claude/settings.json instead. The skillOverrides object itself is identical either way; only the file it lives in changes, and that choice is really a question of scope rather than mechanism. A skill you personally find noisy belongs in your local file. A skill the team has agreed shouldn't auto-trigger for anyone, perhaps one that's been superseded but isn't worth deleting yet, belongs in the shared one, committed alongside the rest of the project's settings so a fresh clone inherits the same behaviour without anyone having to set it up by hand.
Where to go next
For the full frontmatter reference, including disable-model-invocation and user-invocable, see the SKILL.md format explained. For the character budget that decides which skill descriptions Claude actually sees, see why Claude Code shortens or drops your skill's description. For using this setting specifically to run a fair before-and-after comparison, see how to test an agent skill before you ship it. Browse the current catalogue at getclaudeskills.com/platforms/claude-code.
