Scope: what I ran, and what I did not
Everything on this page was run on one Windows 11 machine on 2026-10-19, inside a scratch directory that was not a git repository. Nothing is reconstructed from memory. Three things are explicitly not first-hand:
-
The
/skillsmenu inside a live session. A headless session on this machine dies before it starts: see failure 12. - The “skill is installed but a new session does not see it” symptom. Same reason. The reload behaviour below comes from the official docs, not from my terminal.
- Two Windows-only failures reported in GitHub issues, marked as such near the end. I did not reproduce them here.
And the first install did fail, so the rest of this page is not a happy
path with a footnote. My git http.proxy pointed at
127.0.0.1:7890, where nothing was listening. Failure 1 is
that exact run. Once git pointed at the live listener, the same command
went through.
Three ways in. Pick one.
The installer (npx skills add, npm package skills,
repo vercel-labs/skills) is the only one that also feeds other
agents. The other two exist because it needs git and npm to work, and half
the support threads in this space are people whose git cannot reach GitHub.
| Way in | Command | Lands in | What I saw |
|---|---|---|---|
| Cross-agent installer | npx skills add owner/repo | project .claude/skills/name/ | exit 0, 9.4 s, 15 skills |
| By hand | copy SKILL.md into place | project or user ~/.claude/skills/ | paths verified on disk |
| Plugin marketplace | claude plugin install name@market | ~/.claude/plugins/cache/... | exit 0, 13.6 s + 1.5 s |
Method 1: npx skills add (9.4 s, 15 skills)
The package is skills, version 1.7.2 on 2026-10-19, and it
ships two bin names, skills and add-skill. It
knows 80 agent names — I counted them out of its own error message in
failure 7 — including claude-code, cursor,
codex, windsurf and gemini-cli.
- Check the proxy before you check the installer.
git config --global --get http.proxy. If it prints a local port, confirm something is listening on it. This one step prevents failure 1, the single most common reason an install appears blocked. - Preview the repo.
npx -y skills add obra/superpowers --listprints each skill name and description and stops. On my machine: exit 0, 22.8 s, and a closing hint to install a subset with--skill. It is slower than the install itself, because it still clones the repo. - Install with every prompt answered.
npx -y skills add obra/superpowers -y --agent claude-code. Without-yand--agentit refuses outside a terminal: failure 4. - Read the directory, not the summary. The run ends with
Done!and a line reminding you that skills execute with the agent's full permissions. It also writesskills-lock.json, which records each skill'sskillPathand the sha256 of itsSKILL.md.
o Source: https://github.com/obra/superpowers.git
o Repository cloned
o Found 15 skills
• Installing all 15 skills
o Installed 15 skills ---------------------------------+
brainstorming (copied)
-> .\.claude\skills\brainstorming
... fourteen more, same shape
— Done! Review skills before use; they run with full agent permissions. Per-skill receipt lines trimmed; everything else is verbatim. Four runs on this machine took 8.6 s, 9.4 s, 9.6 s and 10.0 s; a separate run on the same machine the same day took 12.4 s. The 15 skills weigh 426.1 KB.
It does not need a git repo to install into a project: my directory had a
package.json and no .git, and
skills list still reports scope: project. Add
-g for user-level, --agent '*' for every detected
agent, --copy to physically copy files instead of linking them.
What fifteen skills actually look like on disk
Fifteen real directories, not symlinks, 426.1 KB total. Individual
SKILL.md files run from 2.9 KB to 32.6 KB. Some bundle
scripts: brainstorming ships scripts/server.cjs,
start-server.sh and an HTML template. That is the part the
one-line summary hides — Done! Review skills before use is
the CLI telling you it just put executable code on your disk.
Method 2: put the folder in the right place
Your agent does not install skills through a registry; it reads directories. These are the paths from the official docs, and I confirmed the first two on disk.
| Level | Path | Loads for |
|---|---|---|
| Project | project/.claude/skills/name/SKILL.md | sessions started in that repo |
| User | ~/.claude/skills/name/SKILL.md | every project on this machine |
| Subdirectory | subdir/.claude/skills/name/SKILL.md | sessions started inside that subdirectory |
| Plugin | plugin/skills/name/SKILL.md | invoked as /plugin-name:skill-name |
| Enterprise | .claude/skills/name/SKILL.md in the managed settings directory | every machine the org deploys to |
On this machine, ~/.claude/skills/ holds about fifteen
directories such as cloudflare, wrangler and
web-perf, each a folder with one SKILL.md.
There is also a separate ~/.agents/skills/: that is the
installer's own convention directory, not the one Claude Code reads by
default. Copying into the wrong one is a silent no-op.
Same-name precedence, per the docs: enterprise beats user, user beats
project. Two names are reserved and will not load: synced
(case-insensitive) and anything under the anthropic-skills
namespace. On Windows the “name contains <” rule is
unreachable, because < is not a legal filename character.
The advantage of manual install: no lock file, no settings entry, deleting the directory is the uninstall. The cost: you own the version.
Method 3: the plugin marketplace
Documented as two slash commands inside a session,
/plugin marketplace add anthropics/claude-plugins-official
then /plugin install skill-creator@claude-plugins-official.
The same two steps exist as CLI verbs, which is what I ran:
claude plugin marketplace add anthropics/claude-plugins-official --scope project
claude plugin install skill-creator@claude-plugins-official --scope project -y [ok] Successfully added marketplace: claude-plugins-official (declared in project settings)
[ok] Successfully installed plugin: skill-creator@claude-plugins-official (scope: project)
Installed plugins:
> skill-creator@claude-plugins-official
Version: ea10b213686c
Scope: project
Status: [ok] enabled
Marketplace add took 13.6 s, the plugin install 1.5 s. The CLI prints those
three lines with a square-root glyph; the substitution note at the head of
the failure list covers why they read [ok] here.
The files do not land in your project. The project
.claude/settings.json gets two entries,
enabledPlugins and extraKnownMarketplaces, and
the skill itself lives at
~/.claude/plugins/cache/claude-plugins-official/skill-creator/ea10b213686c/skills/skill-creator/SKILL.md.
So “the plugin is installed and my project has no skill files” is correct
behaviour, not a bug. Plugin skills also keep their namespaced name, which
is why they never fight a project skill for the short name.
Verify the skill is actually installed
Four checks, cheapest first. The first three are things I ran; the fourth is documented, not reproduced.
- The installer's own ledger.
npx -y skills list --json. Fields:name,path,scope,agents,source. This proves the installer believes it installed something. It does not prove the file is readable. - The disk.
.claude/skills/name/SKILL.mdexists, is a real directory, and is not a broken link. This is where a “listed but not loadable” install surfaces. - Claude Code's own validator.
claude plugin validate .claude/skillsprintedValidation passedwith exit 0 for my fifteen skills. Read failure 11 before you trust it. - Inside a session.
/skillslists what loaded, grouped by source. No restart is normally needed: the docs say the skills directories are watched and changes apply live. If the top-level skills directory did not exist when the session started, run/reload-skillsonce. Plugin skills need/reload-plugins.
Avoid skills list -g as a smoke test. On this machine it took
77.8 s (exit 0) with roughly a hundred global skill
directories present. Issue #1389 reports 20–25 s on a similarly crowded
Windows box, so the order of magnitude is not mine alone.
Twelve failures, in the order you hit them
One substitution, stated up front
The CLI paints some lines with a check mark, a square-root sign or a
cross glyph, and this site's style rules reject all three. Where you see
[ok] or a bare x in the blocks below, the real
output had one of those glyphs. Every other character — words, paths,
punctuation, exit codes, timings — is copied as printed.
1. Clone dies with “via 127.0.0.1”
Symptom. Cloning spins, then fails in about five seconds (exit 1, 5.0 s on the first run):
x Failed to clone repository
| Failed to clone https://github.com/obra/superpowers.git: Cloning into 'C:\Users\...\Temp\skills-0cSW6M'...
| fatal: unable to access 'https://github.com/obra/superpowers.git/':
| Failed to connect to github.com port 443 via 127.0.0.1 after 2055 ms: Could not connect to server
— Installation failed Root cause. git config --global http.proxy
pointed at http://127.0.0.1:7890. Nothing was listening on
7890 — the proxy client on this machine listens on 7897. The phrase
via 127.0.0.1 is the tell: the request never left the box, so
no amount of retrying or VPN switching will help.
Fix. git config --global --unset http.proxy,
or point it at the port that is actually open. Verify with
git ls-remote https://github.com/obra/superpowers.git before
rerunning the installer. If you only want this for one command, inject it
for the child process instead of editing the global config.
2. Direct connection: “Recv failure: Connection was reset”
Symptom. A different error with the same shape. With no
proxy in the way the clone ends in
Recv failure: Connection was reset after roughly 23 seconds
(measured on the same machine in a separate run, 23.2 s; the line
x Failed to clone repository and the closing
Installation failed are identical).
Root cause. The TCP connection to GitHub is being reset in transit. This is a network-path problem, not an installer defect and not a bad repo name.
Fix. Use a proxy that actually works, or a mirror. Do not reinstall in a loop and do not start dissecting the npm package: the command never reached the repository. The distinction matters, because failure 1 is a config you can fix in one line and this one is the network you happen to be on.
3. The installer can exit 0 and install nothing
Symptom. This is the one worth remembering. Make
.claude a regular file instead of a directory — one stray
redirect is enough — and the installer fails every single skill, then
reports success anyway. Exit code: 0, after 9.2 s.
x Failed to install 15
| x brainstorming -> Claude Code: ENOTDIR: not a directory, mkdir '...\err-path2\.claude'
| x diagnosing-superpowers -> Claude Code: ENOTDIR: not a directory, mkdir '...\.claude'
... thirteen more, identical
— Done! Review skills before use; they run with full agent permissions. Root cause. Per-skill failures are collected into a
summary, but the process still ends on the success path. No
skills-lock.json was written, and the directory contained
nothing but my placeholder file. The summary line
Failed to install 15 is the only trace.
Fix. Never gate CI on this exit code. Assert the artefact:
skills list --json plus a check that
.claude/skills/name/SKILL.md exists. If you see ENOTDIR,
confirm .claude is a directory.
4. Outside a terminal it refuses to install
Symptom. In a script, a CI job, or any wrapper without a TTY, the clone succeeds and then it gives up (exit 1, 8.6 s):
■ Select skills to install
| Cancelled
— Installation cancelled
Interactive prompt required but stdin is not a TTY. Nothing was installed.
Use --agent <name> (or --agent '*') and -y to run non-interactively. Root cause. The default flow asks which agent and which skills. With no TTY it cannot draw the picker, and it chooses to install nothing rather than guess.
Fix. Pass -y --agent claude-code, plus
--skill a b or --all. This is the only form that
belongs in a Dockerfile or a CI step.
5. A wrong repo name reports “Authentication failed”
Symptom. Typo the repo and you do not get a 404 (exit 1, 11.7 s):
Authentication failed for https://github.com/obra/superpowers-does-not-exist.git.
- For private repos, ensure you have access
- Retry with SSH: npx skills add git@github.com:obra/superpowers-does-not-exist.git
- Check access with: gh auth status -h github.com or ssh -T git@github.com Root cause. Over HTTPS, “private repo” and “repo does not exist” are the same 401. The CLI folds both into one message and then offers credential advice.
Fix. Open the repo URL in a browser first. Do not spend
time on SSH keys for a name you misspelled. Both halves matter:
owner/repo, not just the repo.
6. A bare name is treated as a git path
Symptom. skills add superpowers (exit 1,
2.7 s):
o Source: superpowers
x Failed to clone superpowers: fatal: repository 'superpowers' does not exist Root cause. That argument accepts a package id or a URL; a single word is handed straight to git. Interactively it would have offered you a picker, but non-interactively there is no fallback.
Fix. Write owner/repo or paste the GitHub
URL. To search by keyword use npx skills find some-keyword.
7. Wrong agent name: it knows 80, not yours
Symptom. --agent foo-agent fails after the
clone (exit 1, 8.6 s) and prints the whole valid list. It is exactly 80
names:
x Invalid agents: foo-agent
• Valid agents: aider-desk, amp, antigravity, ..., claude-code, openclaw, cline,
..., codex, ..., cursor, ..., gemini-cli, github-copilot, ..., trae,
..., windsurf, zed, ... (80 total) Root cause. A whitelist, matched literally. The display
name “Claude Code” is not accepted; the id claude-code is.
Fix. Use claude-code, or
--agent '*' to hit every agent it detects. Re-check with
skills ls -a claude-code.
8. Wrong skill name gives you a list, not a diagnosis
Symptom. --skill no-such-skill exits 1 after
8.3 s and prints Available skills: followed by the list. It
does not say which name was wrong or which one you probably meant.
Root cause. Name filtering runs after discovery, and the failure path is a generic “unknown selection”.
Fix. Run --list first and copy the name
exactly. Skill names are directory names, so case and hyphens matter.
9. skills update finishes the work, then crashes on exit
Symptom. The update succeeds and the process still exits non-zero (10.3 s):
Checking for skill updates...
Updating for: Claude Code
Checking 15 skill(s)...
[ok] All project skills are up to date
Assertion failed: !(handle->flags & UV_HANDLE_CLOSING), file src\win\async.c, line 76 Root cause. Issue #2461: the CLI fires a telemetry request
before exiting, then calls process.exit() before the socket
teardown finishes. On Windows that trips a libuv assertion. Exit code
-1073740791 (0xC0000409). The issue reports
async.c: line 94 on Node 24.19.0; this machine runs Node
24.15.0 and reports line 76. Same mechanism, different line number.
The command worked — only the exit status is corrupted.
Fix. Read the output, not the status. In a pipeline, keep
skills update out of the gate, or pin a version without the
bug. Note that skills add and skills list exited
0 cleanly in every run I did; only update reproduced this.
10. Wrong marketplace or plugin name in the plugin path
Symptom. Two different mistakes, two different amounts of help (both exit 1):
Failed to install plugin "skill-creator@no-such-marketplace":
Plugin "skill-creator" not found in marketplace "no-such-marketplace".
Your local copy may be out of date - try `claude plugin marketplace update no-such-marketplace`.
Failed to install plugin "no-such-plugin@claude-plugins-official":
Plugin "no-such-plugin" not found in marketplace "claude-plugins-official" Root cause. “Marketplace missing” and “plugin missing inside a marketplace” collapse into one message, and the suggested fix only applies to the second.
Fix. claude plugin marketplace list first —
mine started as No marketplaces configured. Add the
marketplace, then check the plugin name. Only run
marketplace update when the marketplace exists and its
catalogue is stale.
11. validate passes on a broken SKILL.md
Symptom. I wrote a deliberately broken frontmatter
(description: [unclosed) and
claude plugin validate .claude/skills still printed
Validation passed with exit 0. With the whole frontmatter
block removed it printed one warning and still exited 0:
frontmatter: No frontmatter block found. Add YAML frontmatter between ---
delimiters at the top of the file to set description and other metadata. Root cause. Per the docs, when the YAML between the
delimiters fails to parse the skill body still loads with empty metadata.
/name keeps working, but Claude has no
description to match on, so automatic invocation silently
never fires. The validator checks structure, not meaning.
Fix. Start a session with claude --debug to
see the parse error. Write description in the words a user
would actually type, front-load the keywords (each entry's combined text
is capped at 1536 characters), and add
disable-model-invocation: true if you want manual-only.
12. A headless session dies before it can list anything
Symptom. claude -p "reply with one word: ok"
exits 1 in 3.0 s with a model error, not a skill error:
[claude-code:unrecognized_model] {"model":"deepseek-v4-pro[1m]","query_source":"sdk"}
There's an issue with the selected model. It may not exist or you may not have
access to it. Run --model to pick a different model. Root cause. This machine's Claude Code is configured with a model id the CLI cannot resolve in headless mode. It is an environment problem, unrelated to skills.
Fix. Point the session at a valid model. This is also the
honest reason the /skills menu is described from docs on this
page rather than screenshotted from my terminal.
Failures from issues I could not reproduce
Marked as second-hand on purpose. Both are Windows-specific and both deserve a line here, but neither happened to me.
No git on the machine. from issue npx skills add fails with
Failed to clone ...: Error: spawn git ENOENT. Per issue #1010,
only three owners (vercel, vercel-labs,
heygen-com) take a git-free download path; every other repo
needs git installed. Fix: install Git for Windows, or use one of those
owners.
Node installed under a path with spaces. from issue Issues #1457 and #941 report
skills update printing Failed to update ... for
every skill when Node lives in C:\Program Files\nodejs,
because the update path spawns a child process through a shell without
quoting the executable. My Node is at
E:\Program Files\nodejs — also a space — and 1.7.2 did not
reproduce it: I hit failure 9 instead. Treat it as version-dependent.
When not to use the installer
- npm works but git does not. The installer ends in
git clone. Download the repo as a zip and copy one folder into.claude/skills/; you skip failures 1, 2, 5 and 6 entirely and leave no lock file behind. - You want one skill out of a big repo. Fifteen skills means fifteen descriptions in context on every turn. Per the docs, when the listing exceeds its budget the descriptions get truncated starting with the skills you call least — and at install time it has no idea which those are.
- You are gating CI. Failure 3 exits 0 on total failure; failure 9 exits non-zero on success. Assert artefacts, not status codes.
- You only need the files to exist. Then the manual path
is strictly less stateful: no lock file, no settings entry, and
rm -rfis a complete uninstall.
The short version
Run the installer with -y --agent claude-code after checking
that git's proxy points at a live port. Expect 8.6 to 12.4 seconds for
fifteen skills. Then verify with
skills list --json, the presence of
.claude/skills/name/SKILL.md, and
claude plugin validate .claude/skills — remembering that the
validator passes broken YAML, and that the installer's exit code is not
evidence either way.
The scratch directory still holds the fifteen installed skills, plus three
folders I created on purpose to test the blind spots
(broken-yaml, no-frontmatter,
synced). The Chinese edition of this page carries the same
numbers: install guide (Chinese).