Claude Code Skills·Claude Skills·The open SKILL.md registry for Claude
HomeLearn › Installing Claude Code Skills: From Catalog to Working Session

Installing Claude Code Skills: From Catalog to Working Session

Published 31 May 2026 · 11 min read · By a long-time Claude Code practitioner

Installing a Claude Code skill is, on paper, a one-line operation: drop a SKILL.md into ~/.claude/skills/<slug>/, restart, done. In practice there's a small but real surface area of gotchas — silent YAML parse failures, project-local vs global precedence rules, mid-session reload behavior that surprises people, and a handful of "why isn't Claude picking this up?" failure modes that all look the same on the surface.

This is the guide I wish I'd had after the third or fourth time I installed a skill and couldn't figure out why Claude wasn't using it. We'll walk through how auto-discovery actually works under the hood, the three install methods you'll encounter, the difference between project-local and global skills (with the precedence rule that catches teams off-guard), and a troubleshooting section for the failure modes that bite in practice.

In this guide

How skill discovery actually works

Claude Code's skill loader is mechanically simple, and understanding it cleans up most of the confusion downstream. At the start of a session, Claude Code scans ~/.claude/skills/ (and the project-local equivalent — more on that in a moment), reads the SKILL.md file in each subdirectory, parses the YAML frontmatter at the top, and registers two fields into its internal skill index: name and description.

That's it. The body of the SKILL.md — the actual instructions Claude follows when invoking the skill — is not loaded into context at startup. It's only read when Claude decides to invoke that specific skill. This is why descriptions matter so much: that one-line description: field is the entire signal Claude uses to decide whether your skill is relevant to the current conversation. If it doesn't describe the trigger conditions clearly, your skill won't fire.

The discovery scan happens once per session, at startup. This is the single most important thing to remember:

There's no /reload-skills command. Some people have asked for one, and it might land eventually, but the current contract is: restart on every change. The good news is that Claude Code's startup is fast enough (sub-second on most machines) that this isn't actually a real friction once you internalize it.

You can verify what Claude has actually loaded with the /skills slash command inside a session. It lists every registered skill by name and description. If you installed something and it's not in /skills, the loader didn't see it — almost always a path problem, a YAML problem, or a forgot-to-restart problem.

The skill index in memory

Internally Claude maintains the skill index as a name → description map, with the file path cached alongside. When a skill fires, Claude reads the body of the SKILL.md fresh from disk. This means if you edit the body of a SKILL.md mid-session (not the frontmatter), the changes do apply on the next invocation — the body is re-read every time. It's only the frontmatter (name/description) that's frozen at startup. This is a useful detail for iterating on skill instructions without restart cycles.

Manual install: curl + restart

The canonical install flow is three shell commands. Every skill on the catalog has a stable URL at https://claudskills.com/skills/<slug>/SKILL.md that returns the raw markdown.

mkdir -p ~/.claude/skills/<slug>
curl -fsSL https://claudskills.com/skills/<slug>/SKILL.md \
  -o ~/.claude/skills/<slug>/SKILL.md
# restart Claude Code

A few notes on the flags. -f makes curl exit non-zero on HTTP errors (otherwise a 404 gets silently written into the file as HTML and Claude Code chokes on the YAML parse). -s suppresses progress meters. -L follows redirects, which matters because the catalog serves SKILL.md files through a CDN rewrite. And -o with an explicit path avoids the curl habit of dumping the file in your current working directory.

If you're installing several skills at once, just loop:

for slug in conventional-comments code-review-rubric pr-summarizer; do
  mkdir -p ~/.claude/skills/$slug
  curl -fsSL https://claudskills.com/skills/$slug/SKILL.md \
    -o ~/.claude/skills/$slug/SKILL.md
done

The directory name should match the slug, but Claude Code actually doesn't care — the loader keys off the name: field in the frontmatter, not the directory name. That said, mismatched names create confusion when you're grepping later. Keep them aligned.

Verifying the install

After restart, two checks confirm everything worked:

  1. Run /skills in a Claude Code session. Your new skill should appear by name with its description.
  2. Trigger a conversation that matches the description. The skill should fire — Claude will mention it explicitly or you'll see its instructions reflected in the response.

If /skills shows it but Claude isn't invoking it for relevant queries, the description is probably too narrow or too generic. See Writing a SKILL.md File for how to dial that in. If /skills doesn't show it at all, jump to the troubleshooting section below.

Why not git clone?

Some skills are part of larger repositories with multiple files (helper scripts, reference documents, example configs). For those, a git clone into ~/.claude/skills/<slug>/ is the right move — Claude Code will still find the SKILL.md at the top level and the supporting files become available as references in the skill body. The catalog's individual SKILL.md endpoint is for the common case where the skill is self-contained in a single file.

The ClaudSkills desktop app

If you're installing more than a handful of skills, the curl loop gets old fast. The desktop app at claudskills.com/install/ handles the file-write and restart-prompt for you, plus it keeps track of what you've installed so you can see deltas the next time a skill updates.

The flow is straightforward: browse the catalog inside the app, click Install on any skill, the app writes the SKILL.md to ~/.claude/skills/<slug>/SKILL.md using the same path convention as the manual flow, then prompts you to restart Claude Code. There's no proprietary install format — what the app produces on disk is byte-identical to what you'd get from curl. You can mix and match: install some skills via the app, others via curl, and Claude Code treats them all the same.

The app's main practical advantage besides the click reduction is the Pro Collections feature — bundled installs where one click drops 10-20 thematically related skills at once. If you're setting up a new machine and want, say, the full code-review toolkit or the data-engineering bundle, that's the fastest path. The bundle is just a list of slugs; under the hood it's the same per-skill install flow run in a loop.

A few non-obvious details:

The app is free for browsing and installing individual skills. The catalog itself — every SKILL.md, every category, every search — is fully usable without the app via curl and the website. The app is convenience, not gatekeeping.

Plugin-bundled skills

A growing pattern is shipping multiple related skills as a single plugin — a directory tree rooted at .claude-plugin/ with a plugin.json manifest and a skills/ subdirectory containing one folder per skill. Plugins exist because some toolkits are genuinely multi-skill — a code-review plugin might ship five complementary skills that share helper scripts and reference docs.

The manifest at .claude-plugin/plugin.json looks roughly like this:

{
  "name": "service-graph",
  "version": "1.2.0",
  "description": "B2B service provider lookup toolkit",
  "author": "nostrband",
  "skills": [
    "find-law-firm",
    "find-cpa-firm",
    "find-marketing-agency"
  ]
}

The skills array enumerates which subdirectories under skills/ are actual SKILL.md-bearing skills. The plugin manager uses this for install/uninstall accounting — it knows which directories to create and which to clean up when you remove the plugin.

Installing a plugin

Plugin install lands the entire .claude-plugin/ tree at ~/.claude/plugins/<plugin-name>/, and Claude Code's skill loader knows to also scan ~/.claude/plugins/*/skills/ in addition to ~/.claude/skills/. From Claude's perspective, plugin-bundled skills and standalone skills are equivalent at runtime — same discovery, same invocation, same precedence rules.

If you cloned a plugin repo manually:

git clone https://github.com/<author>/<plugin-name>.git \
  ~/.claude/plugins/<plugin-name>

Restart, and Claude Code picks up every skill enumerated in the manifest.

When to ship as a plugin vs as individual skills

If you're authoring something and trying to decide, the rough rule: plugin if the skills genuinely share dependencies (helper modules, reference data, shared prompts) or if they're cohesive enough that users will always want them together. Individual skills if they're independent and a user might want one without the others. Plugins are heavier to install and update; individual skills are simpler to mix and match. Most things should be individual skills.

Plugin-aware tooling is still maturing

Worth flagging: the plugin ecosystem is newer than the skill ecosystem, and not every tool that lists skills is plugin-aware yet. The ClaudSkills catalog indexes plugin-bundled skills individually (each appears as its own catalog entry), which works fine but doesn't currently surface the plugin grouping in the UI. If you're maintaining a plugin, list it by its individual skill slugs in any documentation pointing at the catalog.

Project-local vs global skills

Claude Code looks in two places for skills: ~/.claude/skills/ (your global toolkit, available in every session) and ./.claude/skills/ at the root of your current project (available only when you're working in that project). Both follow the same SKILL.md convention.

The precedence rule, and this is the one that catches teams off-guard: project-local wins on name collision. If your global toolkit has a skill called code-review and the project you're working in also has a .claude/skills/code-review/, the project version takes precedence for that session. Claude Code logs which version it loaded at startup if you're paying attention, but most people aren't, and they end up confused when a skill behaves differently in one repo than another.

When to put a skill in the project

The pattern that works well: global for general toolkit, project-local for team-specific overrides and context.

The project-local approach also means new team members get the skills automatically when they clone the repo — no per-developer onboarding step. This is the most undervalued part of the system. If your team has institutional knowledge that ends up in skill bodies (which it should), checking the .claude/skills/ directory into git turns Claude Code into a vehicle for distributing that knowledge.

Discovery scope

One subtlety: project-local skills are discovered based on your current working directory when Claude Code starts. If you launch Claude Code from a parent directory, the project-local skills won't be picked up. This is rarely a problem in practice — most people work from a project root — but it's worth knowing if you're scripting Claude Code startup.

The .gitignore question

People sometimes ask whether to gitignore .claude/skills/ in their projects. The answer depends on intent. If the skills capture team-shared context and conventions, check them in — that's the value. If they're per-developer scratch space (someone's experimental skill they're iterating on locally), gitignore them. I lean toward checking them in by default and gitignoring specific files only when there's a reason. Skills are documentation that happens to be machine-readable; documentation belongs in the repo.

Updating a skill

There's no version-aware update mechanism in Claude Code itself. Updating a skill is the same operation as installing it: overwrite the SKILL.md with the new version and restart. The manual flow is identical to install:

curl -fsSL https://claudskills.com/skills/<slug>/SKILL.md \
  -o ~/.claude/skills/<slug>/SKILL.md
# restart Claude Code

The desktop app can flag known-updated skills — it tracks the version you installed against the catalog's current version and shows an indicator when there's drift. You can also diff manually if you're curious what changed:

diff ~/.claude/skills/<slug>/SKILL.md \
  <(curl -fsSL https://claudskills.com/skills/<slug>/SKILL.md)

Versioning is honor-system

The version: frontmatter field is optional and not enforced by the loader. Some skill authors bump it on every change; many don't bump it at all. The catalog's lastmod dates (visible on each skill's page) are the most reliable signal of when a skill actually changed. The catalog stores a content hash and only bumps lastmod when the SKILL.md content actually differs — so a skill that hasn't moved in three months legitimately hasn't moved.

Don't auto-update from scripts

I'd push back gently on the temptation to run a nightly cron that re-pulls every skill in your library. Skill authors occasionally make breaking changes — tighter trigger conditions, removed features, reworded descriptions that now collide with another skill you have installed. Updates should be conscious. Skim the diff, decide whether the change is good, then apply.

If you really want batch updates, the desktop app's bulk-update flow shows you a per-skill diff and lets you pick which ones to apply. The same logic could be scripted, but the diff-then-decide step is the part worth preserving.

Customized skills are stickier

If you've edited a SKILL.md locally — common pattern: tightened the description to avoid a collision with another skill, or added a project-specific note in the body — pulling a new version overwrites your edits. There's no merge tool. The workarounds are either: copy the upstream file fresh and reapply your changes, or fork the skill (give it a new slug like code-review-mycompany) so upstream updates don't touch your version. The second approach scales better for anything more than a one-line tweak.

Removing a skill cleanly

Removing a skill is a directory delete plus a restart:

rm -rf ~/.claude/skills/<slug>/
# restart Claude Code

That's the whole operation. The next session start won't see the skill in its discovery scan, won't register it in the skill index, and won't invoke it.

One quirk worth knowing: removed skills can still appear in transcripts and Claude's memory of prior sessions. If you ask Claude something like "what skills do you have access to?" right after removing one, the answer should be correct (it reflects the current session's index). But if you're continuing a long conversation that started before the removal, Claude may still reference the old skill by name from its conversation context. This isn't a bug exactly — it's how the conversation history works — but it can be confusing the first time you see it. Starting a fresh session resolves it.

Same caveat applies to in-flight skill invocations. If a skill is mid-execution when you delete its directory, the invocation completes (the body was already read into the working context). Subsequent invocations fail because the file is gone.

Disabling without removing

Sometimes you want a skill out of the index temporarily without deleting it (you're debugging a collision, or you want to A/B between two versions). The simplest approach: rename the directory so the loader skips it.

mv ~/.claude/skills/<slug> ~/.claude/skills/<slug>.disabled

The loader looks for SKILL.md inside each subdirectory of ~/.claude/skills/ — it doesn't enforce a particular directory naming scheme, but anything that doesn't contain a readable SKILL.md is skipped silently. The .disabled suffix is just a convention; you could use any name. Restart, the skill is gone from the index. Rename it back, restart, it's loaded again.

Bulk removal

Reset to zero skills:

rm -rf ~/.claude/skills/*

This deletes every installed skill but preserves the parent directory. Restart Claude Code afterward. The desktop app, if you use it, will notice the skills are gone and offer to reinstall the ones you previously had. This can be useful as a clean-slate troubleshooting step if Claude Code is behaving strangely and you suspect a corrupted skill.

Troubleshooting: 7 failure modes

These are the failure modes I've hit most often. Each starts with the symptom, then the diagnostic step, then the fix.

1. Claude doesn't pick up the skill at all

Symptom: You installed it, restarted, and /skills doesn't show it.

Diagnose: Check the file actually exists at the path the loader expects: ls ~/.claude/skills/<slug>/SKILL.md. Check the YAML frontmatter parses: head -20 ~/.claude/skills/<slug>/SKILL.md and confirm the first line is ---, there's a closing --- a few lines down, and both name: and description: are present and non-empty.

Fix: Most common cause is the curl wrote an HTML 404 page into the SKILL.md because the URL was wrong and you didn't use the -f flag. Re-curl with -f, verify the file starts with ---, restart.

2. Claude picks the wrong skill

Symptom: A skill fires when you didn't intend it to, or the wrong skill fires for an obvious query.

Diagnose: Look at the descriptions of the conflicting skills via /skills. If two skills have similar or overlapping descriptions, Claude has to guess.

Fix: Tighten the description on at least one of them — add explicit "use when X" and "do not use when Y" language. See the frontmatter fields guide for description patterns that disambiguate well.

3. Skill file exists but doesn't show in /skills

Symptom: ls confirms the file is there, but Claude doesn't see it.

Diagnose: Almost always a YAML parse error. Run a YAML linter on the frontmatter, or just pipe the first 20 lines through yq or python -c 'import yaml,sys; yaml.safe_load(sys.stdin)'. Common offenders: unescaped colons in description values, mismatched quotes, tabs instead of spaces.

Fix: Wrap description in double quotes if it contains colons. Use spaces consistently. Restart.

4. Works on my machine, not my teammate's

Symptom: A skill works for you but not for someone else on the team.

Diagnose: Check whether the skill is in ~/.claude/skills/ (global, per-user) or ./.claude/skills/ (project-local, in repo). Global skills aren't shared — every developer installs their own.

Fix: If it should be shared with the team, move it to the project's .claude/skills/ directory and commit. Everyone gets it on next pull.

5. Uninstalled but Claude still mentions it

Symptom: You deleted the skill directory, but Claude is still referencing the skill in the current session.

Diagnose: Expected behavior. Conversation context outlives the discovery scan.

Fix: Start a fresh session. The reference will be gone.

6. Description includes a colon, YAML breaks

Symptom: Frontmatter looks fine to a human, loader skips the skill silently.

Diagnose: Unquoted strings containing : followed by a space are parsed as nested mappings in YAML. The line description: Use this when: you want X parses as a broken mapping, not a string.

Fix: Wrap in double quotes: description: "Use this when: you want X".

7. Skill runs but ignores its body

Symptom: Claude invokes the skill (you can see it fire), but the response doesn't follow the instructions in the SKILL.md body.

Diagnose: This usually means the body instructions are at odds with the user's request, or the body is structured in a way Claude can't parse cleanly (huge unstructured wall of text, no clear sections).

Fix: Restructure the body with clear headings and short paragraphs. Treat it like instructions to a smart but new colleague.

Patterns for team setups

A few patterns I've seen work for teams running Claude Code together:

The shared-skills repo

One team I know maintains a private company-skills repo that gets cloned to ~/.claude/skills-shared/ on every developer's machine, and they've symlinked or copy-installed those into ~/.claude/skills/ via a setup script. A weekly cron updates the clone. This gives them version control over their shared skill library without depending on the catalog or any third-party install path.

The setup script is roughly:

#!/bin/bash
repo=~/.claude/skills-shared
if [ ! -d "$repo" ]; then
  git clone [email protected]:company/skills.git "$repo"
else
  git -C "$repo" pull --ff-only
fi
for skill in "$repo"/skills/*/; do
  slug=$(basename "$skill")
  ln -sfn "$skill" ~/.claude/skills/"$slug"
done

Symlinks instead of copies mean a git pull is enough to update everyone's skills — no manual sync step. Restart Claude Code afterward.

Layered approach

Another pattern: keep general-purpose skills in the shared repo (linked into ~/.claude/skills/) and put project-specific overrides in each project's ./.claude/skills/. Because project-local wins precedence, a team member working in the auth-service repo gets the auth-service-specific code review skill; a member working in the billing repo gets the billing-specific one. Both inherit the same shared skills for everything not overridden.

This layering scales surprisingly well. The shared library captures "how this company writes code" in skill form. The project-local overrides capture "how this specific service is different." New team members get the full setup automatically when they clone repos.

Audit what's loaded before sharing a session

If you're pair-programming in a Claude Code session or sharing a transcript, run /skills first and skim what's loaded. A teammate's skills can drastically change Claude's behavior, and "why is Claude doing this weird thing?" often resolves to a skill the other person installed that you didn't know about.

Don't over-install

One pattern that doesn't work as well as people expect: installing every skill that looks remotely useful, on the theory that more options is better. Claude Code's skill-selection logic gets worse as the index gets noisier — more skills with overlapping descriptions means more chances of the wrong one firing. Lean libraries with tight descriptions beat sprawling libraries with loose descriptions, every time.

I keep my global library to roughly 20-30 skills I actually use. Project-local libraries are usually 3-10 skills tuned to that codebase. Anything beyond those numbers and you're paying a selection-noise tax for skills you rarely invoke. If a skill hasn't fired in a month, uninstall it. You can always reinstall from the catalog in three commands.

Frequently asked questions

Where does Claude Code look for installed skills?
Two locations: ~/.claude/skills/ for global per-user skills available in every session, and ./.claude/skills/ at the root of your current project for project-local skills available only when you're working in that project. Both follow the same SKILL.md convention.
Do I have to restart Claude Code after installing a skill?
Yes. The discovery scan that reads each SKILL.md's frontmatter and registers skills into Claude's internal index runs once at session startup. Adding a new skill, editing a description, or removing a skill mid-session won't take effect until you restart.
What happens if a global and project-local skill have the same name?
The project-local version wins. This is intentional — it lets teams override general skills with project-specific tuned versions. The pattern: keep your general toolkit global, override with project-local versions in repos that need custom behavior.
Can I edit a SKILL.md after installing it?
Yes. The body of the SKILL.md is re-read every time Claude invokes the skill, so body changes take effect on the next invocation without a restart. Frontmatter changes (name, description) only take effect after restart because the loader caches them at startup.
How do I update a skill to a newer version?
Same as installing: overwrite the SKILL.md with the new version and restart. There's no built-in version-aware update. The desktop app can flag known-updated skills, or you can diff manually against the catalog's current version. Avoid auto-update scripts — read the diff and decide.
Why doesn't Claude see my skill even though the file is there?
Almost always a YAML parse error in the frontmatter or a missing required field. Common offenders: unescaped colons in description values, mismatched quotes, empty name field. Run the frontmatter through a YAML linter to confirm it parses, and verify both name and description are present and non-empty.
Should I check ./.claude/skills/ into git?
Generally yes, if the skills capture team-shared context like conventions, playbooks, or project-specific knowledge. That's the highest-value use of project-local skills — they distribute institutional knowledge to every team member automatically on clone. Gitignore only specific files that are per-developer scratch space.

Found a bug or want a topic covered? Email [email protected] or open an issue via GitHub.