Guide
How to install Claude Code skills — both ecosystems, end to end
There are two skill ecosystems for Claude Code, with two different installers, and
almost every guide describes only one of them. Official plugins come from marketplaces
via claude plugin install; plain-git skills come from any public repo via
npx skills add. They write to different directories, they cannot see each other's
installs, and the advice that works in one does not transfer to the other. Everything below was
run on a real machine in August 2026 against Claude Code 2.1.221 and the
skills CLI 1.5.22. If you only want the two commands:
# Ecosystem 1 — a plugin from a marketplace
claude plugin marketplace add anthropics/claude-plugins-official
claude plugin install code-simplifier@claude-plugins-official
# Ecosystem 2 — one skill from any public git repo, installed globally
npx skills add vercel-labs/agent-skills -g -y -s vercel-optimize -a claude-code The rest of this page is the part that actually costs people an afternoon: where the files land, how to see what you already have, how to write your own, how to remove one cleanly, and the pinning trap that makes "just pin your skills" bad advice for most of the ecosystem. If you are still deciding what you need rather than how to install it, start with skills vs plugins vs MCP; if you have not installed the agent yet, start with how to install Claude Code.
Ecosystem 1: official plugins
A plugin is a bundle. It can carry skills, subagents, hooks, MCP servers and LSP servers in one
package, which is why claude plugin install is the heavier of the two mechanisms.
You add a marketplace once, then install from it by id:
claude plugin marketplace add anthropics/claude-plugins-official
claude plugin install code-simplifier@claude-plugins-official
The official marketplace is normally configured already, in which case the first line is a
harmless no-op — it prints Marketplace 'claude-plugins-official' already on disk and
changes nothing. The install prints
Successfully installed plugin: code-simplifier@claude-plugins-official (scope: user)
and drops the bundle at
~/.claude/plugins/cache/claude-plugins-official/code-simplifier/1.0.0/. Note the
version in the path: plugins are cached per version, so an update leaves the old tree in place
until it is pruned.
To see the catalogue, machine-readable:
claude plugin list --available --json
That returns a JSON object with two arrays, installed and available. On
the day of writing available held 281 plugins — 278 from
claude-plugins-official plus 3 from a second marketplace I had added for the test.
Each entry carries a source object with the upstream repo, a ref and a
resolved sha, and an installCount. The top five by installs were
frontend-design (1,017,241), superpowers (913,876),
code-review (404,331), context7 (392,837) and
skill-creator (347,481). Expect all of those numbers to have moved by the time you
read this; the shape of the output is the durable part.
The trap: you add by repo, but install by declared name
marketplace add takes an owner/repo, a URL or a local path — but the
marketplace registers under the name declared inside its own manifest, which is often
not the repo name. Adding anthropics/skills printed:
✔ Successfully added marketplace: anthropic-agent-skills (declared in user settings)
So the plugins from it are example-skills@anthropic-agent-skills, not
…@skills, and removing it is
claude plugin marketplace remove anthropic-agent-skills. If a
plugin install fails with "not found in marketplace", check
claude plugin marketplace list for the real name before you debug anything else.
Check the cost before you install
This subcommand deserves to be better known. claude plugin details prints a
component inventory and a projected token cost:
claude plugin details code-simplifier Component inventory
Skills (0)
Agents (1) code-simplifier
Hooks (0)
MCP servers (0)
Projected token cost
Always-on: ~64 tok added to every session
Sixty-four tokens is nothing. But run the same command against a big bundle and the arithmetic
gets real — a 32-skill plugin on the same machine reported
Always-on: ~3,060 tok added to every session, with per-component
on-invoke costs from ~1.1k to ~25.4k tokens. That is the honest answer to "why not just install
forty skills": every installed skill's description is loaded into every session so the model can
decide whether to use it. Skills are cheap individually and expensive in bulk. Check
details before you add a bundle you were only going to use once.
Ecosystem 2: plain-git skills via npx skills
The second installer is skills (from vercel-labs/skills), backed by the
registry at skills.sh. It
installs a single skill folder out of any public git repo, and it is deliberately
agent-agnostic — the same skill can be installed for Claude Code, Cursor, Codex, OpenCode, Gemini
CLI and others, which is what the -a flag selects.
Look before you leap
The single most useful flag is -l, which lists a repo's skills with their
descriptions and installs nothing:
npx skills add vercel-labs/agent-skills -l
That printed Found 9 skills with a description for each. The same command against
addyosmani/agent-skills printed Found 24 skills. Run this first, always
— it is the cheapest way to find out that the repo you were about to install wholesale contains
twenty-three things you do not want.
Install one skill, unattended
npx skills add vercel-labs/agent-skills -g -y -s vercel-composition-patterns -a claude-code -g is global (user-level), -y skips the prompts, -s names
the skill, -a names the agents. Without -s you get an interactive
picker; --all is shorthand for "every skill, every agent, no prompts" and is almost
never what you want. Two things the run prints that are worth noticing. First, a
security risk assessment panel — three columns, Gen / Socket / Snyk, with a
verdict per skill and a link to the registry page. Second, the closing line:
Review skills before use; they run with full agent permissions. The tool is telling
you the truth; see the security section below.
Where the files actually land
This has moved, and both layouts are in the wild. On skills 1.5.22 a global install
writes a real directory to ~/.claude/skills/<name>/. Older
installs on the same machine (from March 2026) are instead symlinks pointing
into ~/.agents/skills/<name>/, and I watched a skills update
re-materialise a project skill into that symlinked layout mid-test. So:
ls -la ~/.claude/skills/ will show you a mix of real folders and symlinks, and
neither is wrong.
What is constant is the bookkeeping. Global state lives in
~/.agents/.skill-lock.json ("version": 3) regardless of layout, one
entry per skill:
"vercel-composition-patterns": {
"source": "vercel-labs/agent-skills",
"sourceType": "github",
"sourceUrl": "https://github.com/vercel-labs/agent-skills.git",
"skillPath": "skills/composition-patterns/SKILL.md",
"skillFolderHash": "bf90d0a4b83ea054653350f9c67f6de235d3a368",
"installedAt": "2026-08-06T10:04:29.765Z",
"updatedAt": "2026-08-06T10:04:29.765Z"
}
Two details worth internalising. The ~/.agents/ directory is agent-agnostic on
purpose — one skill, one record, many agents reading it. And the installed folder name comes from
the name in the skill's frontmatter, not from its path in the repo: the entry above
lives at skills/composition-patterns/ upstream but installs as
vercel-composition-patterns.
Project-scope installs work the same way, minus the -g, writing to ./.claude/skills/ and a skills-lock.json at the project root that you can commit.
Search the registry from a script
The registry exposes a plain JSON search endpoint, no key required:
curl -s "https://skills.sh/api/search?q=changelog"
It returns { query, searchType, skills[], count, duration_ms }, where each
skill carries id, skillId, name, installs and
source. The id is exactly the owner/repo/skill triple you
need to install it. Handy when you want to grep the ecosystem rather than browse it.
The pinning trap
Here is the section nobody has written, and it is the reason "pin your skills to a commit" is advice that quietly does not apply to most of the ecosystem.
You can append a 40-character commit SHA to the source with #:
npx skills add "vercel-labs/agent-skills#7c180d9044c9ae2b442b567aad4e42a28dd5ed62" -y -s vercel-optimize -a claude-code
That worked. The lock file recorded "ref": "7c180d90…" alongside a
computedHash, and a subsequent skills update preserved both — the pin
held. Now the identical syntax against a different repo:
npx skills add "addyosmani/agent-skills#f03b4a84b08b76608bbab3133e56e49e361f230b" -y --all ■ Failed to clone repository
fatal: Remote branch f03b4a84b08b76608bbab3133e56e49e361f230b not found in upstream origin Same CLI, same syntax, same day, both repos public and both indexed on skills.sh. So what is the difference? It is not the repo's contents and it is not the registry — it is which code path the installer takes.
Exactly which case works
The CLI keeps a hardcoded allowlist of sources it fetches through the GitHub
blob API instead of cloning. In skills 1.5.22 that list is three owners —
vercel, vercel-labs, heygen-com — plus one specifically
allowlisted repo, zapier/connectors. You can see which path you got from the spinner
text: Fetching skills… is the blob path, Cloning repository… is not.
Everything not on that list is fetched with the equivalent of:
git clone --depth 1 --branch <ref> <url>
And git clone --branch accepts a branch name or a tag name — never a commit
SHA. That is the whole mechanism. The blob path passes your ref to an API that
resolves any commit-ish; the clone path passes it to a flag that cannot.
You can prove it is the code path and not the repo by forcing an allowlisted repo off the fast
path. The --full-depth flag disables the blob route, and the pin that succeeded
thirty seconds earlier now fails with the same error:
npx skills add "vercel-labs/agent-skills#7c180d9044c9ae2b442b567aad4e42a28dd5ed62" --full-depth -y -s vercel-optimize -a claude-code
fatal: Remote branch 7c180d9044c9ae2b442b567aad4e42a28dd5ed62 not found in upstream origin What to do instead: pin to a tag
A tag is a ref that --branch accepts, so tag-pinning works on every repo
that publishes releases — including the one where the SHA failed:
npx skills add "addyosmani/agent-skills#0.6.6" -y -s code-review-and-quality -a claude-code That installed, and the lock recorded the pin the same way a SHA would have:
{
"version": 1,
"skills": {
"code-review-and-quality": {
"source": "addyosmani/agent-skills",
"ref": "0.6.6",
"sourceType": "github",
"skillPath": "skills/code-review-and-quality/SKILL.md",
"computedHash": "ae7a873053c84dd5a76f70c05a21efc4095017e95b8f5db778eb826809859cac"
}
}
}
So the practical rule is a short one. Prefer a release tag. Reach for a commit
SHA only against vercel, vercel-labs, heygen-com or
zapier/connectors, and expect that allowlist to change without notice. If a repo has
neither tags nor an allowlist entry, you are tracking a moving branch whether you like it or not
— and the computedHash in the lock file is then your only signal that the contents
changed under you.
On the plugin side the pinning story is inverted and much simpler: every marketplace entry
already carries a resolved ref and sha in the catalogue JSON, so a
plugin install is pinned by the marketplace rather than by you.
Project or global — and why
Same decision you make for CLAUDE.md, and the same answer: project scope for anything that encodes how this repo works, global scope for anything that encodes how you work.
| Scope | Path | Install | Use it for |
|---|---|---|---|
| Project | ./.claude/skills/<name>/ | npx skills add … -s <skill> | Deploy steps, this repo's review checklist, its migration conventions. Commit it and the whole team gets it. |
| Global | ~/.claude/skills/<name>/ | add -g | Your commit-message style, your preferred test runner, language expertise you want everywhere. |
| Plugin | ~/.claude/plugins/cache/… | claude plugin install | Bundles you want as a unit — skills plus the hooks and MCP servers that make them work. |
The tiebreaker: a project skill is reviewable in a pull request. If your team argues about how
something should be done, that argument belongs in a committed
.claude/skills/ folder where it can be diffed — not in each person's home directory.
Write your own — the minimal SKILL.md
A skill is a directory with a SKILL.md in it. The frontmatter contract is two fields
and the installer will tell you so if you get it wrong: Skills require a SKILL.md with name
and description. Scaffold one with npx skills init my-release-notes, or just
write it:
---
name: release-notes
description: Draft release notes from merged PRs. Use when the user asks for
a changelog, release notes, or a summary of what shipped since the last tag.
---
# Release notes
## When to use
Only when a release is being prepared — not for ordinary commit messages.
## Instructions
1. Find the previous tag with `git describe --tags --abbrev=0`.
2. List merged PRs since it, grouped by conventional-commit prefix.
3. Write user-facing outcomes, not commit subjects. Skip chores.
Save that as .claude/skills/release-notes/SKILL.md and it is installed. There is no
build step and no registration.
The description is the whole game. Only the name and
description are loaded into every session — the body is read only after the model
decides to use the skill. So the description is not documentation for humans, it is the
routing rule: it is the only thing the model sees when deciding whether this skill is
relevant. "Helps with releases" will never fire. Look at how the shipped ones are written — they
all follow the same shape, a sentence of what it does followed by an explicit trigger clause:
description: Create a git commit with a clear, value-communication message.
Use when the user asks to commit/save staged or unstaged changes with a
repo-appropriate, value-communicating message. Name the trigger words a user would actually type. Say when not to use it if the skill sits next to a similar one. A skill with a vague description is a skill you wrote for nobody.
How to check what you already have
Two ecosystems, so two inventories. There is no single command, and this is the part that surprises people.
npx skills list -g --json # global plain-git skills
npx skills list --json # project skills (this is the default scope!)
claude plugin list # installed plugins
claude plugin details <name> # what a plugin actually contains Watch the default scope. Plain skills list --json lists
project skills, so in a repo with none it prints [] — which reads exactly
like "nothing is installed" and is not. You want -g.
The -g --json output is the closest thing to an honest audit, because it enumerates
everything sitting in ~/.claude/skills/ including skills the CLI did not install. On
my machine it returned 16 entries: 5 with a populated source (installed by the CLI,
traceable to a repo) and 11 with "source": null — hand-written or copied in, with no
provenance at all. Each entry also lists the agents it is registered for.
What that command cannot see is plugin-bundled skills. Those live under
~/.claude/plugins/cache/ and never touch ~/.claude/skills/. A
32-skill plugin was active on the same machine and appeared in none of the 16 rows. If you want
the true picture you have to read both lists and mentally union them.
Uninstall cleanly
For a plain-git skill, mirror the install flags:
npx skills remove -g -s vercel-composition-patterns -a claude-code -y
I verified this leaves nothing behind: the folder disappeared from
~/.claude/skills/ and the entry disappeared from
~/.agents/.skill-lock.json, which then diffed byte-identical against the backup I
took before starting. That is a genuinely clean uninstall, which is not something you can assume.
For a plugin, and then for the marketplace if you no longer want its catalogue:
claude plugin uninstall code-simplifier@claude-plugins-official
claude plugin marketplace remove anthropic-agent-skills
Remember the declared-name rule: marketplace remove takes the registered name, not
the owner/repo you typed when adding it. And if you hand-wrote a skill, uninstalling
is rm -rf on its directory — there is no registry to update.
The honest security note
A skill is instructions that steer your agent inside your repository with your
credentials. That is much closer to installing a shell alias somebody else wrote than to
downloading a wallpaper. The skills CLI ends every single install with the line
Review skills before use; they run with full agent permissions, and it is not
boilerplate.
It is also not just markdown. Installing one skill from a well-known repo laid down
156 files — the SKILL.md, plus a lib/ and
scripts/ tree of several dozen executable .mjs files the skill invokes
while it runs. "It's only a prompt" is not a description of what you installed.
Four habits that cost nothing:
- Run
-lfirst, then read the SKILL.md. Not skim — read. It is the thing that will be steering the agent that has write access to your repo. - Prefer a pinned tag to a moving branch, per the section above. An unpinned
install means the next
skills updatecan change your agent's behaviour with no diff you ever looked at. - Be suspicious of reach that exceeds the job. A changelog skill that wants to run network commands, or a formatting skill shipping shell scripts, is worth a second look. The registry's Gen / Socket / Snyk risk columns are a starting point, not a clearance.
- Prefer project scope for anything team-facing, because a committed skill gets reviewed and a global one never does.
None of this is a reason to avoid skills — they are the highest-leverage configuration in the agent. It is a reason to install them the way you install dependencies rather than the way you install browser extensions. The same instinct applies to what you pre-approve and to which MCP servers you connect.
Frequently asked questions
Where do Claude Code skills go?
Three places. Hand-written or npx skills-installed: .claude/skills/<name>/SKILL.md in a project, or ~/.claude/skills/<name>/SKILL.md globally (older installs symlink there from ~/.agents/skills/). Plugin-bundled: ~/.claude/plugins/cache/<marketplace>/<plugin>/<version>/skills/, which never appears in ~/.claude/skills.
claude plugin install or npx skills add — which do I want?
npx skills add for a single skill from any public repo, and when you use more than one agent. claude plugin install for a curated bundle that ships skills together with the hooks, subagents or MCP servers that make them work. The catalogue held 278 official plugins in August 2026.
Why does "skills list" say nothing is installed?
Because list defaults to project scope and prints [] in a repo with no project skills. Use npx skills list -g --json for your global ones — and remember it still cannot see plugin-bundled skills.
Can I pin a skill to a commit SHA?
Only for repos on the CLI's fast-path allowlist — vercel, vercel-labs, heygen-com and zapier/connectors as of 1.5.22. Everything else is fetched with git clone --branch, which rejects a SHA. Pin to a release tag instead; that works everywhere.
Do skills cost me context tokens?
Yes. Every installed skill's name and description sit in every session so the model can route to it. claude plugin details <name> prints the number — one 32-skill bundle measured ~3,060 always-on tokens per session.
Where Backgrind fits
The awkward part of all this is the one no command solves: two ecosystems, two directories, and
no single view of what is actually loaded. Backgrind's skills browser reads both
— the plain-git skills in ~/.claude/skills and the ones bundled inside installed
plugins — in one list, with the source repo next to each so you can tell what came from where and
what has no provenance at all. Backgrind is a desktop overlay that PTY-wraps the
claude CLI you already have: your login, your config, your skills, in an
always-on-top window that pings you when the agent needs a decision. The install steps above are
the same either way; the difference is being able to see the result.
Sources
Every command on this page was run on macOS on August 2, 2026, against Claude Code
2.1.221 and skills 1.5.22, and the results quoted are the
real output. Plugin subcommands and flags: claude plugin --help and
claude plugin marketplace --help. The plugin catalogue, install counts and resolved
refs: claude plugin list --available --json. Token projections:
claude plugin details. The skills CLI surface:
npx skills --help and vercel-labs/skills. Registry search:
skills.sh and its
/api/search endpoint. The fast-path allowlist and the
git clone --depth 1 --branch fallback that causes the pinning failure were read
directly out of the published skills@1.5.22 bundle and then confirmed by experiment
against vercel-labs/agent-skills and
addyosmani/agent-skills. Skill authoring format:
Claude Code — agent skills.