← All posts

Guide

How to install Claude Code skills — both ecosystems, end to end

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.

Marketplace plugin claude plugin install Plain-git skill npx skills add plugin cache ~/.claude/plugins/cache/… skills directory ~/.claude/skills/<name>/ Claude Code reads both
Two installers, two directories, one agent. No single command lists both — which is why "what do I have installed?" is harder than it should be.

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.

ScopePathInstallUse 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 -gYour commit-message style, your preferred test runner, language expertise you want everywhere.
Plugin~/.claude/plugins/cache/…claude plugin installBundles 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:

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.