installs.me
< cd ~/blog

·5 min read#plugins#troubleshooting

Why Your Claude Code Plugin Won't Install (and How to Fix It)

Nine times out of ten, a Claude Code plugin that "won't install" is failing for one of five boring, diagnosable reasons. None of them are your skill's fault. They're all in the delivery layer: the marketplace JSON, the source URL, or a cache somewhere between your server and the CLI. Here's the symptom-to-fix table I wish existed when I was debugging installs.me.

First, know what "install" actually does

Two commands, two distinct network operations:

/plugin marketplace add https://installs.me/lautaro
/plugin install lautaro@lautaro-installs

The first fetches a marketplace.json (Claude Code will also probe .claude-plugin/marketplace.json under the URL you give it) and registers the marketplace locally under the name declared inside that file, not the URL. The second resolves the plugin's source from that registered marketplace and pulls the actual plugin content.

Every failure mode lives in one of those two steps. Figure out which step is failing and you've cut the search space in half.

Symptom: "plugin not found" right after you shipped a fix

You updated your marketplace.json, the new version is live (you checked with curl), but /plugin install still can't see the new plugin or still pulls the old version.

Claude Code caches the marketplace manifest at add time. It does not re-fetch on every install. The fix is one command:

/plugin marketplace update lautaro-installs

Note the argument: the marketplace name from the JSON, not the URL you added it with. This is the single most common "it works in curl but not in Claude Code" report I've seen, and the fix takes two seconds once you know the cache exists.

If update itself seems to no-op, remove and re-add:

/plugin marketplace remove lautaro-installs
/plugin marketplace add https://installs.me/lautaro

Symptom: marketplace adds fine, install fails silently or 404s

Open your marketplace.json and look at the source field of the failing plugin. If it's a relative path like "./plugins/lautaro" and your marketplace is served over HTTP, that's the bug.

Relative sources work when the marketplace is a local directory or a git repo, because there's a filesystem or a clone to resolve them against. Over a plain URL there is no "rest of the repo" to walk. Claude Code can't turn ./plugins/lautaro into a series of HTTP GETs for files it doesn't know exist. The failure is quiet, which makes it nasty.

The fix: plugins distributed via an HTTP marketplace need a git-backed source. The shape that works:

{
  "name": "lautaro",
  "source": {
    "source": "git",
    "url": "https://github.com/you/persona-plugins",
    "path": "plugins/lautaro"
  }
}

That's the git-subdir pattern: point at a repo Claude Code can actually clone, then scope to the subdirectory holding the plugin (.claude-plugin/plugin.json, skills/, commands/, and so on). The clone gives the CLI a real filesystem, and relative resolution works again. This is exactly how installs.me serves personas: the marketplace JSON is dynamic per creator, but every plugin source resolves to a git repo.

Symptom: your server shows the new JSON, the CLI gets the old one

You've run /plugin marketplace update, you've even removed and re-added, and Claude Code still receives a stale manifest. Now the cache isn't in the CLI. It's in front of your server.

If you host on Vercel, Cloudflare, or anything with a CDN, check your response headers:

curl -sI https://installs.me/lautaro | grep -i cache

A cache-control: s-maxage=3600 (or a framework default doing the same thing) means the edge serves the old manifest for up to an hour regardless of what your origin says now. Serverless framework route handlers often get cached by default without you ever writing a cache header.

Fix on the server, not the client:

Cache-Control: no-store

or at minimum a short s-maxage with stale-while-revalidate if you want edge caching for traffic reasons. A marketplace manifest is tiny; there's no good reason to cache it aggressively. Debug tip: curl twice and diff the age and x-vercel-cache (or cf-cache-status) headers. HIT on a manifest you just deployed is your smoking gun.

Symptom: "it installed" but nothing shows up

The install succeeded, /plugin lists it, but the skills don't trigger. Two usual causes.

First, scope confusion. Marketplaces and plugins can be registered at user scope or project scope. If a teammate added the marketplace inside one repo's project settings, it exists there and nowhere else. Opening Claude Code in a different directory shows nothing, and everyone concludes the install "didn't work." Check where it landed: user-scope registrations live under ~/.claude, project-scope under the repo's .claude directory. Run /plugin in the directory where you expect it to work, not just anywhere.

Second, the skill itself never loads because its frontmatter is broken. A skill is a SKILL.md with YAML frontmatter that must carry name and description. The description is not documentation, it's the trigger: Claude reads it to decide when to load the skill on demand. A missing description, malformed YAML (unquoted colon in the description is the classic), or a name that doesn't match the directory means the skill sits there installed and inert. If /plugin shows the plugin but the behavior never fires, open the SKILL.md and validate the frontmatter before blaming the install pipeline.

Symptom: marketplace add fails outright

If /plugin marketplace add itself errors, work through these in order:

  1. The URL doesn't return JSON. Some frameworks return an HTML 404 page with status 200. curl -s <url> | head -c 200 and confirm you see {.
  2. The manifest is invalid. curl -s <url> | jq . locally. A trailing comma kills the whole marketplace.
  3. Name collision. You already have a marketplace registered under the same name. Remove the old one first.
  4. Auth in the way. If the manifest URL sits behind a login redirect, the CLI gets a 302 to an HTML page, not your JSON.

The five-minute triage, in order

Verified against Claude Code CLI 2.1.x, this is the sequence: curl the marketplace URL and jq it (rules out server and syntax), check cache headers (rules out CDN staleness), run /plugin marketplace update <name> (rules out CLI cache), inspect the failing plugin's source for a relative path over HTTP (the silent killer), then check scope and SKILL.md frontmatter (rules out "installed but dead"). Ninety percent of broken installs die at step three or four.

The delivery layer is unglamorous, but it's the difference between "clone my repo and copy files around" and a persona anyone can install in ten seconds.

Install a person

installs.me turns your files, calendar and calls into a Claude Code plugin that thinks like you. Anyone installs it with two commands:

/plugin marketplace add https://installs.me/lautaro
/plugin install lautaro@lautaro-installs