Short answers to what readers ask most about this topic.
01What is a Claude Code plugin marketplace?
A marketplace is a catalog that distributes Claude Code plugins. It is a single file, .claude-plugin/marketplace.json, at the root of a repository, listing a name, an owner and an array of plugins with their sources. Users add the marketplace once, then install individual plugins from it by name.
02Why are my users not getting my plugin update?
Almost always the version field. If you set version on a plugin entry, the plugin is pinned to that string and users receive an update only when the string changes, so pushing a fix without bumping it leaves everyone on their cached copy. If you omit version on a git source, the version comes from the resolved commit and every push is an update.
03Which plugin source type should I use?
A relative path is the simplest when plugins live in the same repository as the marketplace. Use a github or url source when a plugin has its own repository and release cycle, git-subdir for a directory inside a monorepo, and npm if you already publish there. Archive and command sources exist for build systems rather than for people.
04How do I rename a plugin without breaking existing installs?
Add a renames object to marketplace.json mapping the old name to the new one, and Claude Code follows the rename chain automatically for users who installed the old name. Mapping an old name to null marks the plugin as removed. This requires Claude Code v2.1.193 or later.
05How do I distribute a marketplace to my whole team?
Add extraKnownMarketplaces to the project's .claude/settings.json so the marketplace arrives with the repository once the folder is trusted, and list the plugins under enabledPlugins. Organisations can also restrict which marketplaces are permitted at all with the strictKnownMarketplaces managed setting.
A Claude Code plugin marketplace is one file, .claude-plugin/marketplace.json, at the root of a repository. It needs a name, an owner and a list of plugins, each with a source. The single decision that causes the most support work is the version field: set it and bump it on every release, or your users quietly keep running a cached copy.
I published an internal marketplace, pushed a fix to a plugin, told the team to update, and watched three people report the old behaviour anyway. Nothing was broken. I had simply left version out of one entry and set it in another, and the two behave in opposite ways — which is the kind of detail you find out from your colleagues rather than from a stack trace.
This post is the authoring side of plugins: the manifest and every field that matters, the seven source types and when each is the right answer, how versioning actually decides who gets your update, renames and strict mode, validating before you publish, getting the marketplace onto a team's machines without asking anyone to type a command, and locking down which marketplaces an organisation permits at all.
The manifest is small, and three fields are required
Only name, owner and plugins are required, and each plugin entry needs only name and source. Everything else — displayName, description, version, author, license, keywords, category — exists so the entry reads well in the Discover tab and so you can control updates. Here is a realistic file rather than a minimal one:
Two details are easy to miss. Relative paths resolve from the marketplace root, not from the .claude-plugin directory that holds the file. And a set of marketplace names is reserved for Anthropic — claude-plugins-official, anthropic-plugins, agent-skills and a dozen more — along with names that impersonate them, so pick something that is obviously yours.
Seven source types, and the one you probably want
The source field decides where the plugin is fetched from, and the choice has more consequences than it looks. A relative path keeps everything in one repository and is the simplest thing that works. A github or url source lets a plugin live in its own repository with its own release cycle. The rest exist for specific situations.
Choosing a source type:
Source
When it is the right answer
Relative path
Plugins live in the same repository as the marketplace. Must start with a dot-slash, unless you set metadata.pluginRoot and use a bare directory name
github or url
The plugin has its own repository. Optional ref pins a branch or tag; optional sha pins an exact 40-character commit
git-subdir
The plugin is a directory inside a large monorepo. Sparse clone, so you do not pull the whole thing
npm
You already publish to a registry. Takes package, an optional version range, and a custom registry URL
archive or command
A zip over HTTPS with an optional sha256 for integrity, or a local command that prints a plugin directory. Both are for build systems, not for people
Two constraints bite in practice. A marketplace distributed as a bare marketplace.json URL cannot resolve relative paths at all, so a file that works from a git clone breaks when you host it as a plain file — use another source type. And archives must be HTTPS end to end, including every redirect, with a 256 MiB ceiling.
Version is the update switch, and it works both ways
This is the field worth understanding properly, because both of its failure modes look like something else. What version does depends on whether you set it and on what kind of source you used:
Set version, and the plugin is pinned to that string. Users get an update only when the string changes — so pushing a fix without bumping it leaves everyone on the cached copy.
Omit version on a git source, and the version is derived from the resolved commit. Every commit you push becomes an update for everyone, including the ones you meant as work in progress.
Command sources always include a hash of the command output, and archive sources use the sha256 when you set one, so an explicit version does not pin either of them.
Two release channels cost nothing to run: publish the same plugin twice, in a stable marketplace pinned to a stable branch and a latest marketplace pinned to latest. People who want the new thing add the second marketplace; everyone else never notices you shipped. That is far less work than trying to encode risk tolerance in a version range.
Renames and strict mode, so you can change your mind
Renaming a plugin normally strands everyone who installed the old name. The renames object fixes that: map the old name to the new one and Claude Code follows the chain automatically, or map it to null to mark a plugin removed. It needs v2.1.193 or later, and it costs one line, so add it the first time you rename anything rather than promising yourself you will remember.
Strict mode decides who owns the component list. Left at its default of true, the plugin's own plugin.json is the authority and your marketplace entry can add extra components on top. Set it to false and the marketplace entry becomes the entire definition, which conflicts if plugin.json also declares components. Use false only when you are the operator deliberately controlling what a third-party plugin exposes.
Validate before you publish
There is a real validator, and it catches the errors that are otherwise invisible until a user reports them: syntax, duplicate plugin names, source paths that traverse out of the repository, invalid local plugin.json files, and version mismatches between the entry and the plugin. Unrecognised fields come back as warnings rather than errors, and a near-miss field name gets a suggestion — pass strict when you want warnings to fail the run.
# Add a marketplace — GitHub shorthand, a git URL, or a path
claude plugin marketplace add acme-corp/claude-plugins
claude plugin marketplace add acme-corp/claude-plugins@v2.0
claude plugin marketplace add https://gitlab.com/team/plugins.git
claude plugin marketplace add ./my-marketplace --scope project
claude plugin marketplace list [--json]
claude plugin marketplace update [name]
claude plugin marketplace remove <name> [--scope <scope>]
# Validate BEFORE you publish. This is the whole quality gate.
claude plugin validate .
claude plugin validate ./my-plugin --strict # warnings become errors
# What a user actually runs
/plugin install code-formatter@acme-tools
/plugin install code-formatter@acme-tools --scope project
Rolling it out without asking anyone to type a command
The path that scales is settings rather than instructions. Put extraKnownMarketplaces in the project's settings file and the marketplace arrives with the repository once the folder is trusted; add enabledPlugins and the plugins arrive with it. Note one v2.1.195 change worth planning around: adding a marketplace this way no longer installs plugins that come from an external source, so a member sees the install command instead of a working plugin.
// .claude/settings.json — the marketplace arrives with the repo
{
"extraKnownMarketplaces": {
"acme-tools": {
"source": { "source": "github", "repo": "acme-corp/claude-plugins" },
"autoUpdate": true // managed settings only
}
},
"enabledPlugins": { "code-formatter@acme-tools": true }
}
// Managed settings — an allowlist of what may be added at all.
{
"strictKnownMarketplaces": [
{ "source": "github", "repo": "acme-corp/*" },
{ "source": "hostPattern", "hostPattern": "^github\\.example\\.com$" }
]
}
// undefined = no restriction. [] = total lockdown, official
// marketplace included.
Deciding what an organisation may add at all
For a managed environment, strictKnownMarketplaces is an allowlist of the marketplaces users are permitted to add. Leave it undefined and there is no restriction; set it to an empty array and you have total lockdown, official marketplace included. Entries match on a GitHub repository, including an owner wildcard, on an exact URL, or on a regular expression against the host or filesystem path.
Two smaller levers are worth knowing. A marketplace entry can carry a relevance object, and when an administrator allowlists the marketplace through the pluginSuggestionMarketplaces managed setting, matching plugins are pinned at the top of the Discover tab as suggested for this directory. And defaultEnabled set to false lets you ship a plugin that installs without switching itself on, which is the polite default for anything that costs money or calls an external service.
Start with one repository, relative-path sources and an explicit version on every entry, because that combination has the fewest surprises. Run the validator in whatever checks the repository already has, so a broken manifest never reaches a colleague. And write the renames entry the first time you rename a plugin, not the second time, when someone tells you their install disappeared.