Create and distribute a plugin marketplace

Tags

official-docs claude-code-cli

Content

Documentation Index

Fetch the complete documentation index at: https://code.claude.com/docs/llms.txt Use this file to discover all available pages before exploring further.

Create and distribute a plugin marketplace

Build and host plugin marketplaces to distribute Claude Code extensions across teams and communities.

A plugin marketplace is a catalog that lets you distribute plugins to others. Marketplaces provide centralized discovery, version tracking, automatic updates, and support for multiple source types (git repositories, local paths, and more). This guide shows you how to create your own marketplace to share plugins with your team or community.

Looking to install plugins from an existing marketplace? See Discover and install prebuilt plugins.

Overview

Creating and distributing a marketplace involves:

  1. Creating plugins: build one or more plugins with skills, agents, hooks, MCP servers, or LSP servers. This guide assumes you already have plugins to distribute; see Create plugins for details on how to create them.
  2. Creating a marketplace file: define a marketplace.json that lists your plugins and where to find them (see Create the marketplace file).
  3. Host the marketplace: push to GitHub, GitLab, or another git host (see Host and distribute marketplaces).
  4. Share with users: users add your marketplace with /plugin marketplace add and install individual plugins (see Discover and install plugins).

Once your marketplace is live, you can update it by pushing changes to your repository. Users refresh their local copy with /plugin marketplace update.

Walkthrough: create a local marketplace

This example creates a marketplace with one plugin: a /quality-review skill for code reviews. You'll create the directory structure, add a skill, create the plugin manifest and marketplace catalog, then install and test it.

bash theme={null} mkdir -p my-marketplace/.claude-plugin mkdir -p my-marketplace/plugins/quality-review-plugin/.claude-plugin mkdir -p my-marketplace/plugins/quality-review-plugin/skills/quality-review

Create a SKILL.md file that defines what the /quality-review skill does.

```markdown my-marketplace/plugins/quality-review-plugin/skills/quality-review/SKILL.md theme={null}
---
description: Review code for bugs, security, and performance
disable-model-invocation: true
---

Review the code I've selected or the recent changes for:
- Potential bugs or edge cases
- Security concerns
- Performance issues
- Readability improvements

Be concise and actionable.
```

Create a plugin.json file that describes the plugin. The manifest goes in the .claude-plugin/ directory.

```json my-marketplace/plugins/quality-review-plugin/.claude-plugin/plugin.json theme={null}
{
  "name": "quality-review-plugin",
  "description": "Adds a /quality-review skill for quick code reviews",
  "version": "1.0.0"
}
```

Create the marketplace catalog that lists your plugin.

```json my-marketplace/.claude-plugin/marketplace.json theme={null}
{
  "name": "my-plugins",
  "owner": {
    "name": "Your Name"
  },
  "plugins": [
    {
      "name": "quality-review-plugin",
      "source": "./plugins/quality-review-plugin",
      "description": "Adds a /quality-review skill for quick code reviews"
    }
  ]
}
```

Add the marketplace and install the plugin.

```shell theme={null}
/plugin marketplace add ./my-marketplace
/plugin install quality-review-plugin@my-plugins
```

Select some code in your editor and run your new skill.

```shell theme={null}
/quality-review
```

To learn more about what plugins can do, including hooks, agents, MCP servers, and LSP servers, see Plugins.

How plugins are installed: When users install a plugin, Claude Code copies the plugin directory to a cache location. This means plugins can't reference files outside their directory using paths like ../shared-utils, because those files won't be copied.

If you need to share files across plugins, use symlinks. See Plugin caching and file resolution for details.

Create the marketplace file

Create .claude-plugin/marketplace.json in your repository root. This file defines your marketplace's name, owner information, and a list of plugins with their sources.

Each plugin entry needs at minimum a name and source (where to fetch it from). See the full schema below for all available fields.

```json theme={null} { "name": "company-tools", "owner": { "name": "DevTools Team", "email": "devtools@example.com" }, "plugins": [ { "name": "code-formatter", "source": "./plugins/formatter", "description": "Automatic code formatting on save", "version": "2.1.0", "author": { "name": "DevTools Team" } }, { "name": "deployment-tools", "source": { "source": "github", "repo": "company/deploy-plugin" }, "description": "Deployment automation tools" } ] }


## Marketplace schema

### Required fields

| Field     | Type   | Description                                                                                                                                                            | Example        |
| :-------- | :----- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------- |
| `name`    | string | Marketplace identifier (kebab-case, no spaces). This is public-facing: users see it when installing plugins (for example, `/plugin install my-tool@your-marketplace`). | `"acme-tools"` |
| `owner`   | object | Marketplace maintainer information ([see fields below](#owner-fields))                                                                                                 |                |
| `plugins` | array  | List of available plugins                                                                                                                                              | See below      |

<Note>
  **Reserved names**: The following marketplace names are reserved for official Anthropic use and cannot be used by third-party marketplaces: `claude-code-marketplace`, `claude-code-plugins`, `claude-plugins-official`, `anthropic-marketplace`, `anthropic-plugins`, `agent-skills`, `knowledge-work-plugins`, `life-sciences`. Names that impersonate official marketplaces (like `official-claude-plugins` or `anthropic-tools-v2`) are also blocked.
</Note>

### Owner fields

| Field   | Type   | Required | Description                      |
| :------ | :----- | :------- | :------------------------------- |
| `name`  | string | Yes      | Name of the maintainer or team   |
| `email` | string | No       | Contact email for the maintainer |

### Optional metadata

| Field                  | Type   | Description                                                                                                                                                               |
| :--------------------- | :----- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `metadata.description` | string | Brief marketplace description                                                                                                                                             |
| `metadata.version`     | string | Marketplace version                                                                                                                                                       |
| `metadata.pluginRoot`  | string | Base directory prepended to relative plugin source paths (for example, `"./plugins"` lets you write `"source": "formatter"` instead of `"source": "./plugins/formatter"`) |

## Plugin entries

Each plugin entry in the `plugins` array describes a plugin and where to find it. You can include any field from the [plugin manifest schema](https://code.claude.com/en/plugins-reference#plugin-manifest-schema) (like `description`, `version`, `author`, `commands`, `hooks`, etc.), plus these marketplace-specific fields: `source`, `category`, `tags`, and `strict`.

### Required fields

| Field    | Type           | Description                                                                                                                                            |
| :------- | :------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name`   | string         | Plugin identifier (kebab-case, no spaces). This is public-facing: users see it when installing (for example, `/plugin install my-plugin@marketplace`). |
| `source` | string\|object | Where to fetch the plugin from (see [Plugin sources](#plugin-sources) below)                                                                           |

### Optional plugin fields

**Standard metadata fields:**

| Field         | Type    | Description                                                                                                                       |
| :------------ | :------ | :-------------------------------------------------------------------------------------------------------------------------------- |
| `description` | string  | Brief plugin description                                                                                                          |
| `version`     | string  | Plugin version                                                                                                                    |
| `author`      | object  | Plugin author information (`name` required, `email` optional)                                                                     |
| `homepage`    | string  | Plugin homepage or documentation URL                                                                                              |
| `repository`  | string  | Source code repository URL                                                                                                        |
| `license`     | string  | SPDX license identifier (for example, MIT, Apache-2.0)                                                                            |
| `keywords`    | array   | Tags for plugin discovery and categorization                                                                                      |
| `category`    | string  | Plugin category for organization                                                                                                  |
| `tags`        | array   | Tags for searchability                                                                                                            |
| `strict`      | boolean | Controls whether `plugin.json` is the authority for component definitions (default: true). See [Strict mode](#strict-mode) below. |

**Component configuration fields:**

| Field        | Type           | Description                                                    |
| :----------- | :------------- | :------------------------------------------------------------- |
| `skills`     | string\|array  | Custom paths to skill directories containing `<name>/SKILL.md` |
| `commands`   | string\|array  | Custom paths to flat `.md` skill files or directories          |
| `agents`     | string\|array  | Custom paths to agent files                                    |
| `hooks`      | string\|object | Custom hooks configuration or path to hooks file               |
| `mcpServers` | string\|object | MCP server configurations or path to MCP config                |
| `lspServers` | string\|object | LSP server configurations or path to LSP config                |

## Plugin sources

Plugin sources tell Claude Code where to fetch each individual plugin listed in your marketplace. These are set in the `source` field of each plugin entry in `marketplace.json`.

Once a plugin is cloned or copied into the local machine, it is copied into the local versioned plugin cache at `~/.claude/plugins/cache`.

| Source        | Type                            | Fields                             | Notes                                                                                                                                             |
| ------------- | ------------------------------- | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| Relative path | `string` (e.g. `"./my-plugin"`) | none                               | Local directory within the marketplace repo. Must start with `./`. Resolved relative to the marketplace root, not the `.claude-plugin/` directory |
| `github`      | object                          | `repo`, `ref?`, `sha?`             |                                                                                                                                                   |
| `url`         | object                          | `url`, `ref?`, `sha?`              | Git URL source                                                                                                                                    |
| `git-subdir`  | object                          | `url`, `path`, `ref?`, `sha?`      | Subdirectory within a git repo. Clones sparsely to minimize bandwidth for monorepos                                                               |
| `npm`         | object                          | `package`, `version?`, `registry?` | Installed via `npm install`                                                                                                                       |

<Note>
  **Marketplace sources vs plugin sources**: These are different concepts that control different things.

  * **Marketplace source** — where to fetch the `marketplace.json` catalog itself. Set when users run `/plugin marketplace add` or in `extraKnownMarketplaces` settings. Supports `ref` (branch/tag) but not `sha`.
  * **Plugin source** — where to fetch an individual plugin listed in the marketplace. Set in the `source` field of each plugin entry inside `marketplace.json`. Supports both `ref` (branch/tag) and `sha` (exact commit).

  For example, a marketplace hosted at `acme-corp/plugin-catalog` (marketplace source) can list a plugin fetched from `acme-corp/code-formatter` (plugin source). The marketplace source and plugin source point to different repositories and are pinned independently.
</Note>

### Relative paths

For plugins in the same repository, use a path starting with `./`:

```json theme={null}
{
  "name": "my-plugin",
  "source": "./plugins/my-plugin"
}

Paths resolve relative to the marketplace root, which is the directory containing .claude-plugin/. In the example above, ./plugins/my-plugin points to <repo>/plugins/my-plugin, even though marketplace.json lives at <repo>/.claude-plugin/marketplace.json. Do not use ../ to reference paths outside the marketplace root.

Relative paths only work when users add your marketplace via Git (GitHub, GitLab, or git URL). If users add your marketplace via a direct URL to the marketplace.json file, relative paths will not resolve correctly. For URL-based distribution, use GitHub, npm, or git URL sources instead. See Troubleshooting for details.

GitHub repositories

```json theme={null} { "name": "github-plugin", "source": { "source": "github", "repo": "owner/plugin-repo" } }


You can pin to a specific branch, tag, or commit:

```json theme={null}
{
  "name": "github-plugin",
  "source": {
    "source": "github",
    "repo": "owner/plugin-repo",
    "ref": "v2.0.0",
    "sha": "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0"
  }
}
Field Type Description
repo string Required. GitHub repository in owner/repo format
ref string Optional. Git branch or tag (defaults to repository default branch)
sha string Optional. Full 40-character git commit SHA to pin to an exact version

Git repositories

```json theme={null} { "name": "git-plugin", "source": { "source": "url", "url": "https://gitlab.com/team/plugin.git" } }


You can pin to a specific branch, tag, or commit:

```json theme={null}
{
  "name": "git-plugin",
  "source": {
    "source": "url",
    "url": "https://gitlab.com/team/plugin.git",
    "ref": "main",
    "sha": "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0"
  }
}
Field Type Description
url string Required. Full git repository URL (https:// or git@). The .git suffix is optional, so Azure DevOps and AWS CodeCommit URLs without the suffix work
ref string Optional. Git branch or tag (defaults to repository default branch)
sha string Optional. Full 40-character git commit SHA to pin to an exact version

Git subdirectories

Use git-subdir to point to a plugin that lives inside a subdirectory of a git repository. Claude Code uses a sparse, partial clone to fetch only the subdirectory, minimizing bandwidth for large monorepos.

```json theme={null} { "name": "my-plugin", "source": { "source": "git-subdir", "url": "https://github.com/acme-corp/monorepo.git", "path": "tools/claude-plugin" } }


You can pin to a specific branch, tag, or commit:

```json theme={null}
{
  "name": "my-plugin",
  "source": {
    "source": "git-subdir",
    "url": "https://github.com/acme-corp/monorepo.git",
    "path": "tools/claude-plugin",
    "ref": "v2.0.0",
    "sha": "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0"
  }
}

The url field also accepts a GitHub shorthand (owner/repo) or SSH URLs (git@github.com:owner/repo.git).

Field Type Description
url string Required. Git repository URL, GitHub owner/repo shorthand, or SSH URL
path string Required. Subdirectory path within the repo containing the plugin (for example, "tools/claude-plugin")
ref string Optional. Git branch or tag (defaults to repository default branch)
sha string Optional. Full 40-character git commit SHA to pin to an exact version

npm packages

Plugins distributed as npm packages are installed using npm install. This works with any package on the public npm registry or a private registry your team hosts.

```json theme={null} { "name": "my-npm-plugin", "source": { "source": "npm", "package": "@acme/claude-plugin" } }


To pin to a specific version, add the `version` field:

```json theme={null}
{
  "name": "my-npm-plugin",
  "source": {
    "source": "npm",
    "package": "@acme/claude-plugin",
    "version": "2.1.0"
  }
}

To install from a private or internal registry, add the registry field:

```json theme={null} { "name": "my-npm-plugin", "source": { "source": "npm", "package": "@acme/claude-plugin", "version": "^2.0.0", "registry": "https://npm.example.com" } }


| Field      | Type   | Description                                                                                  |
| :--------- | :----- | :------------------------------------------------------------------------------------------- |
| `package`  | string | Required. Package name or scoped package (for example, `@org/plugin`)                        |
| `version`  | string | Optional. Version or version range (for example, `2.1.0`, `^2.0.0`, `~1.5.0`)                |
| `registry` | string | Optional. Custom npm registry URL. Defaults to the system npm registry (typically npmjs.org) |

### Advanced plugin entries

This example shows a plugin entry using many of the optional fields, including custom paths for commands, agents, hooks, and MCP servers:

```json theme={null}
{
  "name": "enterprise-tools",
  "source": {
    "source": "github",
    "repo": "company/enterprise-plugin"
  },
  "description": "Enterprise workflow automation tools",
  "version": "2.1.0",
  "author": {
    "name": "Enterprise Team",
    "email": "enterprise@example.com"
  },
  "homepage": "https://docs.example.com/plugins/enterprise-tools",
  "repository": "https://github.com/company/enterprise-plugin",
  "license": "MIT",
  "keywords": ["enterprise", "workflow", "automation"],
  "category": "productivity",
  "commands": [
    "./commands/core/",
    "./commands/enterprise/",
    "./commands/experimental/preview.md"
  ],
  "agents": ["./agents/security-reviewer.md", "./agents/compliance-checker.md"],
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "${CLAUDE_PLUGIN_ROOT}/scripts/validate.sh"
          }
        ]
      }
    ]
  },
  "mcpServers": {
    "enterprise-db": {
      "command": "${CLAUDE_PLUGIN_ROOT}/servers/db-server",
      "args": ["--config", "${CLAUDE_PLUGIN_ROOT}/config.json"]
    }
  },
  "strict": false
}

Key things to notice:

Strict mode

The strict field controls whether plugin.json is the authority for component definitions (skills, agents, hooks, MCP servers, output styles).

Value Behavior
true (default) plugin.json is the authority. The marketplace entry can supplement it with additional components, and both sources are merged.
false The marketplace entry is the entire definition. If the plugin also has a plugin.json that declares components, that's a conflict and the plugin fails to load.

When to use each mode:

Host and distribute marketplaces

GitHub provides the easiest distribution method:

  1. Create a repository: Set up a new repository for your marketplace
  2. Add marketplace file: Create .claude-plugin/marketplace.json with your plugin definitions
  3. Share with teams: Users add your marketplace with /plugin marketplace add owner/repo

Benefits: Built-in version control, issue tracking, and team collaboration features.

Host on other git services

Any git hosting service works, such as GitLab, Bitbucket, and self-hosted servers. Users add with the full repository URL:

```shell theme={null} /plugin marketplace add https://gitlab.com/company/plugins.git


### Private repositories

Claude Code supports installing plugins from private repositories. For manual installation and updates, Claude Code uses your existing git credential helpers, so HTTPS access via `gh auth login`, macOS Keychain, or `git-credential-store` works the same as in your terminal. SSH access works as long as the host is already in your `known_hosts` file and the key is loaded in `ssh-agent`, since Claude Code suppresses interactive SSH prompts for the host fingerprint and key passphrase.

Background auto-updates run at startup without credential helpers, since interactive prompts would block Claude Code from starting. To enable auto-updates for private marketplaces, set the appropriate authentication token in your environment:

| Provider  | Environment variables        | Notes                                     |
| :-------- | :--------------------------- | :---------------------------------------- |
| GitHub    | `GITHUB_TOKEN` or `GH_TOKEN` | Personal access token or GitHub App token |
| GitLab    | `GITLAB_TOKEN` or `GL_TOKEN` | Personal access token or project token    |
| Bitbucket | `BITBUCKET_TOKEN`            | App password or repository access token   |

Set the token in your shell configuration (for example, `.bashrc`, `.zshrc`) or pass it when running Claude Code:

```bash theme={null}
export GITHUB_TOKEN=ghp_xxxxxxxxxxxxxxxxxxxx

For CI/CD environments, configure the token as a secret environment variable. GitHub Actions automatically provides GITHUB_TOKEN for repositories in the same organization.

Test locally before distribution

Test your marketplace locally before sharing:

```shell theme={null} /plugin marketplace add ./my-local-marketplace /plugin install test-plugin@my-local-marketplace


For the full range of add commands (GitHub, Git URLs, local paths, remote URLs), see [Add marketplaces](https://code.claude.com/en/discover-plugins#add-marketplaces).

### Require marketplaces for your team

You can configure your repository so team members are automatically prompted to install your marketplace when they trust the project folder. Add your marketplace to `.claude/settings.json`:

```json theme={null}
{
  "extraKnownMarketplaces": {
    "company-tools": {
      "source": {
        "source": "github",
        "repo": "your-org/claude-plugins"
      }
    }
  }
}

You can also specify which plugins should be enabled by default:

```json theme={null} { "enabledPlugins": { "code-formatter@company-tools": true, "deployment-tools@company-tools": true } }


For full configuration options, see [Plugin settings](https://code.claude.com/en/settings#plugin-settings).

<Note>
  If you use a local `directory` or `file` source with a relative path, the path resolves against your repository's main checkout. When you run Claude Code from a git worktree, the path still points at the main checkout, so all worktrees share the same marketplace location. Marketplace state is stored once per user in `~/.claude/plugins/known_marketplaces.json`, not per project.
</Note>

### Pre-populate plugins for containers

For container images and CI environments, you can pre-populate a plugins directory at build time so Claude Code starts with marketplaces and plugins already available, without cloning anything at runtime. Set the `CLAUDE_CODE_PLUGIN_SEED_DIR` environment variable to point at this directory.

To layer multiple seed directories, separate paths with `:` on Unix or `;` on Windows. Claude Code searches each directory in order, and the first seed that contains a given marketplace or plugin cache wins.

The seed directory mirrors the structure of `~/.claude/plugins`:

$CLAUDE_CODE_PLUGIN_SEED_DIR/ known_marketplaces.json marketplaces//... cache////...


To build a seed directory, run Claude Code once during image build, install the plugins you need, then copy the resulting `~/.claude/plugins` directory into your image and point `CLAUDE_CODE_PLUGIN_SEED_DIR` at it.

To skip the copy step, set `CLAUDE_CODE_PLUGIN_CACHE_DIR` to your target seed path during the build so plugins install directly there:

```bash theme={null}
CLAUDE_CODE_PLUGIN_CACHE_DIR=/opt/claude-seed claude plugin marketplace add your-org/plugins
CLAUDE_CODE_PLUGIN_CACHE_DIR=/opt/claude-seed claude plugin install my-tool@your-plugins

Then set CLAUDE_CODE_PLUGIN_SEED_DIR=/opt/claude-seed in your container's runtime environment so Claude Code reads from the seed on startup.

At startup, Claude Code registers marketplaces found in the seed's known_marketplaces.json into the primary configuration, and uses plugin caches found under cache/ in place without re-cloning. This works in both interactive mode and non-interactive mode with the -p flag.

Behavior details:

Managed marketplace restrictions

For organizations requiring strict control over plugin sources, administrators can restrict which plugin marketplaces users are allowed to add using the strictKnownMarketplaces setting in managed settings.

When strictKnownMarketplaces is configured in managed settings, the restriction behavior depends on the value:

Value Behavior
Undefined (default) No restrictions. Users can add any marketplace
Empty array [] Complete lockdown. Users cannot add any new marketplaces
List of sources Users can only add marketplaces that match the allowlist exactly

Common configurations

Disable all marketplace additions:

```json theme={null} { "strictKnownMarketplaces": [] }


Allow specific marketplaces only:

```json theme={null}
{
  "strictKnownMarketplaces": [
    {
      "source": "github",
      "repo": "acme-corp/approved-plugins"
    },
    {
      "source": "github",
      "repo": "acme-corp/security-tools",
      "ref": "v2.0"
    },
    {
      "source": "url",
      "url": "https://plugins.example.com/marketplace.json"
    }
  ]
}

Allow all marketplaces from an internal git server using regex pattern matching on the host. This is the recommended approach for GitHub Enterprise Server or self-hosted GitLab instances:

```json theme={null} { "strictKnownMarketplaces": [ { "source": "hostPattern", "hostPattern": "^github\.example\.com$" } ] }


Allow filesystem-based marketplaces from a specific directory using regex pattern matching on the path:

```json theme={null}
{
  "strictKnownMarketplaces": [
    {
      "source": "pathPattern",
      "pathPattern": "^/opt/approved/"
    }
  ]
}

Use ".*" as the pathPattern to allow any filesystem path while still controlling network sources with hostPattern.

strictKnownMarketplaces restricts what users can add, but does not register marketplaces on its own. To make allowed marketplaces available automatically without users running /plugin marketplace add, pair it with extraKnownMarketplaces in the same managed-settings.json. See Using both together.

How restrictions work

Restrictions are validated early in the plugin installation process, before any network requests or filesystem operations occur. This prevents unauthorized marketplace access attempts.

The allowlist uses exact matching for most source types. For a marketplace to be allowed, all specified fields must match exactly:

Because strictKnownMarketplaces is set in managed settings, individual users and project configurations cannot override these restrictions.

For complete configuration details including all supported source types and comparison with extraKnownMarketplaces, see the strictKnownMarketplaces reference.

Version resolution and release channels

Plugin versions determine cache paths and update detection. You can specify the version in the plugin manifest (plugin.json) or in the marketplace entry (marketplace.json).

When possible, avoid setting the version in both places. The plugin manifest always wins silently, which can cause the marketplace version to be ignored. For relative-path plugins, set the version in the marketplace entry. For all other plugin sources, set it in the plugin manifest.

Set up release channels

To support "stable" and "latest" release channels for your plugins, you can set up two marketplaces that point to different refs or SHAs of the same repo. You can then assign the two marketplaces to different user groups through managed settings.

The plugin's plugin.json must declare a different version at each pinned ref or commit. If two refs or commits have the same manifest version, Claude Code treats them as identical and skips the update.

Example

```json theme={null} { "name": "stable-tools", "plugins": [ { "name": "code-formatter", "source": { "source": "github", "repo": "acme-corp/code-formatter", "ref": "stable" } } ] }


```json theme={null}
{
  "name": "latest-tools",
  "plugins": [
    {
      "name": "code-formatter",
      "source": {
        "source": "github",
        "repo": "acme-corp/code-formatter",
        "ref": "latest"
      }
    }
  ]
}
Assign channels to user groups

Assign each marketplace to the appropriate user group through managed settings. For example, the stable group receives:

```json theme={null} { "extraKnownMarketplaces": { "stable-tools": { "source": { "source": "github", "repo": "acme-corp/stable-tools" } } } }


The early-access group receives `latest-tools` instead:

```json theme={null}
{
  "extraKnownMarketplaces": {
    "latest-tools": {
      "source": {
        "source": "github",
        "repo": "acme-corp/latest-tools"
      }
    }
  }
}

Validation and testing

Test your marketplace before sharing.

Validate your marketplace JSON syntax:

```bash theme={null} claude plugin validate .


Or from within Claude Code:

```shell theme={null}
/plugin validate .

Add the marketplace for testing:

```shell theme={null} /plugin marketplace add ./path/to/marketplace


Install a test plugin to verify everything works:

```shell theme={null}
/plugin install test-plugin@marketplace-name

For complete plugin testing workflows, see Test your plugins locally. For technical troubleshooting, see Plugins reference.

Manage marketplaces from the CLI

Claude Code provides non-interactive claude plugin marketplace subcommands for scripting and automation. These are equivalent to the /plugin marketplace commands available inside an interactive session.

Plugin marketplace add

Add a marketplace from a GitHub repository, git URL, remote URL, or local path.

```bash theme={null} claude plugin marketplace add [options]


**Arguments:**

* `<source>`: GitHub `owner/repo` shorthand, git URL, remote URL to a `marketplace.json` file, or local directory path. To pin to a branch or tag, append `@ref` to the GitHub shorthand or `#ref` to a git URL

**Options:**

| Option                | Description                                                                                                                                         | Default |
| :-------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------- | :------ |
| `--scope <scope>`     | Where to declare the marketplace: `user`, `project`, or `local`. See [Plugin installation scopes](https://code.claude.com/en/plugins-reference#plugin-installation-scopes) | `user`  |
| `--sparse <paths...>` | Limit checkout to specific directories via git sparse-checkout. Useful for monorepos                                                                |         |

Add a marketplace from GitHub using `owner/repo` shorthand:

```bash theme={null}
claude plugin marketplace add acme-corp/claude-plugins

Pin to a specific branch or tag with @ref:

```bash theme={null} claude plugin marketplace add acme-corp/claude-plugins@v2.0


Add from a git URL on a non-GitHub host:

```bash theme={null}
claude plugin marketplace add https://gitlab.example.com/team/plugins.git

Add from a remote URL that serves the marketplace.json file directly:

```bash theme={null} claude plugin marketplace add https://example.com/marketplace.json


Add from a local directory for testing:

```bash theme={null}
claude plugin marketplace add ./my-marketplace

Declare the marketplace at project scope so it is shared with your team via .claude/settings.json:

```bash theme={null} claude plugin marketplace add acme-corp/claude-plugins --scope project


For a monorepo, limit the checkout to the directories that contain plugin content:

```bash theme={null}
claude plugin marketplace add acme-corp/monorepo --sparse .claude-plugin plugins

Plugin marketplace list

List all configured marketplaces.

```bash theme={null} claude plugin marketplace list [options]


**Options:**

| Option   | Description    |
| :------- | :------------- |
| `--json` | Output as JSON |

### Plugin marketplace remove

Remove a configured marketplace. The alias `rm` is also accepted.

```bash theme={null}
claude plugin marketplace remove <name>

Arguments:

Removing a marketplace also uninstalls any plugins you installed from it. To refresh a marketplace without losing installed plugins, use claude plugin marketplace update instead.

Plugin marketplace update

Refresh marketplaces from their sources to retrieve new plugins and version changes.

```bash theme={null} claude plugin marketplace update [name]


**Arguments:**

* `[name]`: marketplace name to update, as shown by `claude plugin marketplace list`. Updates all marketplaces if omitted

Both `remove` and `update` fail when run against a seed-managed marketplace, which is read-only. When updating all marketplaces, seed-managed entries are skipped and other marketplaces still update. To change seed-provided plugins, ask your administrator to update the seed image. See [Pre-populate plugins for containers](#pre-populate-plugins-for-containers).

## Troubleshooting

### Marketplace not loading

**Symptoms**: Can't add marketplace or see plugins from it

**Solutions**:

* Verify the marketplace URL is accessible
* Check that `.claude-plugin/marketplace.json` exists at the specified path
* Ensure JSON syntax is valid and frontmatter is well-formed using `claude plugin validate` or `/plugin validate`
* For private repositories, confirm you have access permissions

### Marketplace validation errors

Run `claude plugin validate .` or `/plugin validate .` from your marketplace directory to check for issues. The validator checks `plugin.json`, skill/agent/command frontmatter, and `hooks/hooks.json` for syntax and schema errors. Common errors:

| Error                                             | Cause                                           | Solution                                                                                       |
| :------------------------------------------------ | :---------------------------------------------- | :--------------------------------------------------------------------------------------------- |
| `File not found: .claude-plugin/marketplace.json` | Missing manifest                                | Create `.claude-plugin/marketplace.json` with required fields                                  |
| `Invalid JSON syntax: Unexpected token...`        | JSON syntax error in marketplace.json           | Check for missing commas, extra commas, or unquoted strings                                    |
| `Duplicate plugin name "x" found in marketplace`  | Two plugins share the same name                 | Give each plugin a unique `name` value                                                         |
| `plugins[0].source: Path contains ".."`           | Source path contains `..`                       | Use paths relative to the marketplace root without `..`. See [Relative paths](#relative-paths) |
| `YAML frontmatter failed to parse: ...`           | Invalid YAML in a skill, agent, or command file | Fix the YAML syntax in the frontmatter block. At runtime this file loads with no metadata.     |
| `Invalid JSON syntax: ...` (hooks.json)           | Malformed `hooks/hooks.json`                    | Fix JSON syntax. A malformed `hooks/hooks.json` prevents the entire plugin from loading.       |

**Warnings** (non-blocking):

* `Marketplace has no plugins defined`: add at least one plugin to the `plugins` array
* `No marketplace description provided`: add `metadata.description` to help users understand your marketplace
* `Plugin name "x" is not kebab-case`: the plugin name contains uppercase letters, spaces, or special characters. Rename to lowercase letters, digits, and hyphens only (for example, `my-plugin`). Claude Code accepts other forms, but the Claude.ai marketplace sync rejects them.

### Plugin installation failures

**Symptoms**: Marketplace appears but plugin installation fails

**Solutions**:

* Verify plugin source URLs are accessible
* Check that plugin directories contain required files
* For GitHub sources, ensure repositories are public or you have access
* Test plugin sources manually by cloning/downloading

### Private repository authentication fails

**Symptoms**: Authentication errors when installing plugins from private repositories

**Solutions**:

For manual installation and updates:

* Verify you're authenticated with your git provider (for example, run `gh auth status` for GitHub)
* Check that your credential helper is configured correctly: `git config --global credential.helper`
* Try cloning the repository manually to verify your credentials work

For background auto-updates:

* Set the appropriate token in your environment: `echo $GITHUB_TOKEN`
* Check that the token has the required permissions (read access to the repository)
* For GitHub, ensure the token has the `repo` scope for private repositories
* For GitLab, ensure the token has at least `read_repository` scope
* Verify the token hasn't expired

### Marketplace updates fail in offline environments

**Symptoms**: Marketplace `git pull` fails and Claude Code wipes the existing cache, causing plugins to become unavailable.

**Cause**: By default, when a `git pull` fails, Claude Code removes the stale clone and attempts to re-clone. In offline or airgapped environments, re-cloning fails the same way, leaving the marketplace directory empty.

**Solution**: Set `CLAUDE_CODE_PLUGIN_KEEP_MARKETPLACE_ON_FAILURE=1` to keep the existing cache when the pull fails instead of wiping it:

```bash theme={null}
export CLAUDE_CODE_PLUGIN_KEEP_MARKETPLACE_ON_FAILURE=1

With this variable set, Claude Code retains the stale marketplace clone on git pull failure and continues using the last-known-good state. For fully offline deployments where the repository will never be reachable, use CLAUDE_CODE_PLUGIN_SEED_DIR to pre-populate the plugins directory at build time instead.

Git operations time out

Symptoms: Plugin installation or marketplace updates fail with a timeout error like "Git clone timed out after 120s" or "Git pull timed out after 120s".

Cause: Claude Code uses a 120-second timeout for all git operations, including cloning plugin repositories and pulling marketplace updates. Large repositories or slow network connections may exceed this limit.

Solution: Increase the timeout using the CLAUDE_CODE_PLUGIN_GIT_TIMEOUT_MS environment variable. The value is in milliseconds:

bash theme={null} export CLAUDE_CODE_PLUGIN_GIT_TIMEOUT_MS=300000 # 5 minutes

Plugins with relative paths fail in URL-based marketplaces

Symptoms: Added a marketplace via URL (such as https://example.com/marketplace.json), but plugins with relative path sources like "./plugins/my-plugin" fail to install with "path not found" errors.

Cause: URL-based marketplaces only download the marketplace.json file itself. They do not download plugin files from the server. Relative paths in the marketplace entry reference files on the remote server that were not downloaded.

Solutions:

Files not found after installation

Symptoms: Plugin installs but references to files fail, especially files outside the plugin directory

Cause: Plugins are copied to a cache directory rather than used in-place. Paths that reference files outside the plugin's directory (such as ../shared-utils) won't work because those files aren't copied.

Solutions: See Plugin caching and file resolution for workarounds including symlinks and directory restructuring.

For additional debugging tools and common issues, see Debugging and development tools.

See also