← All guidesWorkflow

Claude Code skills: what makes one actually fire

A Claude Code skill is a directory containing a SKILL.md file: YAML frontmatter, then markdown instructions. That is the whole format. The part that trips people up is not writing one, it is getting it to fire, because more than twenty frontmatter fields exist and exactly one of them decides whether Claude ever reaches for your skill. If you are configuring these alongside hooks, they share a home in your settings.json.

Where a skill lives

The location sets the scope, and nothing else about the file changes:

ScopePathLoads in
Personal~/.claude/skills/<name>/SKILL.mdEvery project on your machine
Project.claude/skills/<name>/SKILL.mdThis repo. Commit it to share with the team
Nested<subdir>/.claude/skills/<name>/SKILL.mdSessions in or below that subdirectory
Plugin<plugin>/skills/<name>/SKILL.mdWherever the plugin is enabled, as /plugin-name:skill-name
Session onlyany directory passed with --add-dirThat session

When names collide, enterprise beats personal beats project, and your own skill replaces a bundled one of the same name. A project skill and a nested one both load, because they get different names: /deploy and /apps/web:deploy.

The only field that decides anything

Claude never sees your skill's body until it invokes it. What sits in context permanently is the description, and that single string is the entire basis for the routing decision. Progressive disclosure is the whole design: descriptions always loaded, bodies loaded on demand, paid for once.

So a description that says what the skill is will lose to one that says when to reach for it. Compare a vague one:

---
name: seo-guide
description: Guidelines for writing guides.
---

with the shape that actually triggers, taken from a skill shipped in the official marketplace:

---
name: writing-hookify-rules
description: This skill should be used when the user asks to "create a hookify rule", "write a hook rule", "configure hookify", "add a hookify rule", or needs guidance on hookify rule syntax and patterns.
version: 0.1.0
---

Quoted trigger phrases, in the words a user would actually type. The cap is 1,536 characters, shared with the optional when_to_use field, which is appended to the description and counts toward the same budget.

What real skills look like

Measured on this site's repository, which has seven project skills in daily use with Claude Code 2.1.269:

Range across the 7 skills
Description length407 to 711 characters
Body length58 to 209 lines
Frontmatter fields usedname, description, and version on three of them

Two things stand out. Descriptions land around a quarter to a half of the allowed budget, so the cap is not the constraint, clarity is. And three fields out of more than twenty carry all seven skills: the long list below is opt-in, not a checklist to fill.

Keep the body under 500 lines, and push detail into sibling files that the body links to. Supporting scripts go in a scripts/ subfolder and are addressed with ${CLAUDE_SKILL_DIR}:

python3 ${CLAUDE_SKILL_DIR}/scripts/setup.py

The fields worth knowing

FieldWhy you would set it
disable-model-invocation: trueClaude can never auto-invoke it. Use it for anything with side effects: deploys, sending messages, commits
user-invocable: falseHides it from the / menu. Background knowledge Claude may use, that you never type
context: forkRuns the skill in a subagent instead of the main conversation. Good for long, isolated jobs like a code review
agentWhich subagent type a forked skill uses: Explore, Plan, or one of your own
allowed-toolsPre-approves tools for that turn only. The grant clears on your next message
pathsA glob. The skill auto-loads only when matching files are in play, which keeps it out of unrelated context
model, effortForce a model or an effort level while the skill is active
argumentsNamed positional arguments, so /fix-issue 123 substitutes $issue in the body

Turning one off without deleting it

skillOverrides in .claude/settings.json controls visibility per skill, which is how you silence a noisy one without removing the file:

{
  "skillOverrides": {
    "deploy": "off",
    "legacy-context": "name-only",
    "internal-guide": "user-invocable-only"
  }
}

off hides it from both Claude and the menu, name-only leaves it in the menu but strips the description from Claude's context, and user-invocable-only keeps it typeable while hiding it from Claude entirely.

Injecting live context

A line prefixed with ! runs before the skill content reaches Claude, and its output is pasted in as literal text:

## Current changes
!`git diff HEAD`

Three behaviours are worth knowing before you rely on it. Commands run in the session's working directory. Each has a two minute timeout. And a non-zero exit code aborts the entire skill invocation, so a grep that legitimately finds nothing will take the whole skill down with it. Guard those with || true.

The part you cannot see from the terminal

context: fork is where this gets interesting and where visibility drops off. A forked skill runs in a subagent, in the background by default, so you type /code-review, get your prompt back, and the work happens somewhere you are not looking. Run two or three of those at once, across several sessions, and the terminal genuinely cannot tell you what is still running.

Blooby puts that back in view: one mascot per session on your taskbar, with a badge that counts the subagents a session has in flight, so a forked skill finishing is something you see rather than something you go and check.

See it for yourself

download Get Blooby free