Plugins & Marketplaces

This content was generated with the assistance of AI and should be verified against the official documentation of each tool and framework before being relied on in production.

This section’s bibliography lists the reference material consulted while preparing these pages.

This page is written against the Claude Code CLI 2.1.283, VS Code 1.139 with the GitHub Copilot Chat extension, and the GitHub Copilot CLI 1.0.88, all re-verified as current as of 2026-09-28; re-check the linked docs before relying on an exact field name, since both products change these surfaces often. Every ai-catalog example is excerpted from the repository at the pinned commit 58fb709 (main).

A plugin is a directory of skills, agents, hooks, MCP servers and other components that Claude Code installs and loads as one unit, instead of a team copying loose skill folders into every project. A marketplace is a git repository or directory that lists plugins and where to fetch each one, so installing and updating a whole set of customizations is one command rather than a manual file copy. Both concepts also now exist, under the same names, on GitHub Copilot — covered at the end of this page.

What a plugin can bundle

A plugin’s component types are the same surfaces the rest of this sub-section covers individually, packaged together:

Component Covered in depth on

Skills

Skills

Agents (subagents)

Subagents & Custom Agents

Hooks

Hooks

MCP servers

Configuring MCP Servers

Commands (flat .md command files; skills are preferred for new plugins)

Prompt Files & Slash Commands

Once a plugin is enabled, every skill, agent and command it defines that Claude can invoke on its own has its name and description loaded into context on every turn, in every session where the plugin is enabled — exactly like a project-level skill — so a plugin with many always-on components has a real, ongoing context cost even in sessions that never use it. Verified against Claude Code — Plugins overview.

The plugin manifest: .claude-plugin/plugin.json

A plugin’s manifest is optional — without one, Claude Code loads whatever it finds in the standard directory layout below, and the plugin’s name comes from its marketplace entry. Write a manifest when the plugin needs metadata, a component outside its default location, userConfig, or an inline component definition. The manifest lives at .claude-plugin/plugin.json under the plugin root; every other plugin file (skills/, commands/, hooks/, and so on) sits at the plugin root itself, not inside .claude-plugin/.

The table below covers every top-level plugin.json field currently documented, verified against the Claude Code plugin manifest reference:

Field Type What it does

$schema

string

A JSON Schema URL for editor autocomplete; Claude Code ignores it at load time.

name

string

Required. The plugin’s kebab-case identifier. Every component it defines is namespaced under it, so a skill check-license in plugin ai-catalog-gates runs as /ai-catalog-gates:check-license.

displayName

string

A human-readable name shown in the UI in place of name.

version

string

A version string (not checked against semver). Setting it pins users to that version until it changes; see "Installing, versioning and updates" below.

description

string

A short explanation of what the plugin provides.

author

object

name (required), plus optional email and url.

homepage

string

A documentation URL. Must parse as a URL or the plugin fails to load.

repository

string

The source repository URL. Not validated.

license

string

An SPDX identifier, e.g. Apache-2.0 or MIT.

keywords

array of strings

Discovery tags.

metadata

object

A free-form object for the plugin author’s own data; Claude Code doesn’t read it.

defaultEnabled

boolean

Whether the plugin starts enabled when a user hasn’t set it explicitly in enabledPlugins (see "Team distribution via settings" below). Defaults to true.

dependencies

array

Other plugins that must be enabled for this one to work; each entry is a bare name, "name@marketplace", or an object with name/marketplace/version.

skills

path or array of paths

Extra directories to scan for skills (each a <name>/SKILL.md folder, or "." for the plugin root itself). Adds to the default skills/ scan rather than replacing it.

commands

path, array of paths, or object map

Flat .md command files or directories of them, or a map of command name to {source or content, description, argumentHint, model, allowedTools}. Replaces the default commands/ scan.

agents

path or array of paths

Agent .md files (directories aren’t accepted). Replaces the default agents/ scan.

hooks

path, object, or array of either

A .json hook-config file path, or an inline object in the same shape as hooks in settings.json (see Hooks). Merges with hooks/hooks.json when that file also exists.

mcpServers

path, object, or array of either

A .json MCP-config file path, an .mcpb/.dxt bundle path or URL, or an inline map of server name to config (see Configuring MCP Servers). Merges with .mcp.json at the plugin root: that file loads first, then each declared shape in order, and a server name declared later replaces an earlier one.

lspServers

path, object, or array of either

A .json LSP-config file path or an inline map keyed by server name. Merges with .lsp.json.

outputStyles

path or array of paths

Output style files or directories (see Output Styles, Status Line & More). Replaces the default output-styles/ scan.

settings

object

Settings applied while the plugin is enabled; only agent and subagentStatusLine currently take effect.

userConfig

object

Values Claude Code prompts the user for when the plugin is enabled (type, title, description, plus optional required, default, options, sensitive), so users don’t have to hand-edit settings.json. Saved values are referenced as ${user_config.KEY} in MCP and LSP server config, exec-form hook args, and skill and agent content (where only non-sensitive values are substituted); sensitive values go to the platform’s secure credential store instead of settings.json.

channels

array of objects

Message channels the plugin provides, each bound to one of its MCP servers.

A workflows field and an experimental container (themes, monitors, evals) also exist for narrower cases; see the reference above for their exact shapes. Every component path must start with ./, must resolve inside the plugin root, and must exist — claude plugin validate ./my-plugin checks both before you ship.

Directory layout

Each component type has a default location under the plugin root, used whenever the manifest doesn’t point somewhere else:

Component Default location Notes

Manifest

.claude-plugin/plugin.json

Optional.

Skills

skills/

One <name>/SKILL.md per skill. A plugin with SKILL.md at its root and no skills/ directory loads as a single skill.

Commands

commands/

Flat Markdown command files; prefer skills/ for new plugins.

Agents

agents/

Agent Markdown files.

Hooks

hooks/hooks.json

Hook configuration, in the same shape as settings.json’s `hooks key.

MCP servers

.mcp.json

MCP server definitions, in the same shape as a project .mcp.json (see Configuring MCP Servers).

Output styles

output-styles/

Output style Markdown files.

Executables

bin/

Files here are put on the Bash tool’s PATH while the plugin is enabled.

A plugin using the default locations for every component type
my-plugin/
├── .claude-plugin/
│   └── plugin.json      # manifest: name, version, description, ...
├── skills/
│   └── review/
│       └── SKILL.md      # runs as /my-plugin:review
├── agents/
│   └── reviewer.md       # a subagent Claude can delegate to
├── hooks/
│   └── hooks.json        # hooks that run on lifecycle events
└── .mcp.json              # adds an MCP server, giving Claude tools

Verified against the plugin manifest reference's standard layout table and the plugins overview's component diagram.

A concrete example: packaging a subset of ai-catalog

ai-catalog has no .claude-plugin/plugin.json and no marketplace.json on main at the pinned commit; today its 102 iru- skills are distributed by copying .claude/skills/ folders directly into a consuming repository, and Plugins / Packaging and distributing skills, agents, and CLAUDE.md describe plugin packaging only in prose. The plugin.json and marketplace.json below are a *new, illustrative example, written for this page, that would package three of its real, pinned components — the iru-check-license and iru-check-security skills plus the iru-gate-runner agent — as an installable plugin. Nothing here ships in ai-catalog today.

Directory layout for the illustrative ai-catalog-gates plugin
ai-catalog-gates/
├── .claude-plugin/
│   └── plugin.json
├── skills/
│   ├── iru-check-license/
│   │   └── SKILL.md
│   └── iru-check-security/
│       └── SKILL.md
└── agents/
    └── iru-gate-runner.md
ai-catalog-gates/.claude-plugin/plugin.json
{
  "name": "ai-catalog-gates",
  "displayName": "ai-catalog Quality Gates",
  "version": "0.1.0",
  "description": "License-header and secret-scanning skills, plus the gate-runner subagent that dispatches to them, from the ai-catalog issue-to-release pipeline.",
  "author": {
    "name": "Alberto Irurueta",
    "url": "https://github.com/albertoirurueta"
  },
  "homepage": "https://github.com/albertoirurueta/ai-catalog",
  "repository": "https://github.com/albertoirurueta/ai-catalog",
  "license": "Apache-2.0",
  "keywords": ["quality-gate", "license-header", "secret-scanning", "ai-catalog"]
}

skills/iru-check-license/SKILL.md and skills/iru-check-security/SKILL.md here would be verbatim copies of the pinned files at iru-check-license/SKILL.md and iru-check-security/SKILL.md — both already model: haiku, mechanical-work skills, as Skills covers for iru-check-license. agents/iru-gate-runner.md would be a copy of the pinned iru-gate-runner.md, whose own frontmatter (tools: Skill, Bash, Read) is unchanged by being packaged this way — a plugin doesn’t alter a component’s own frontmatter, only where Claude Code finds it and how it’s namespaced. Since no manifest field here points elsewhere, both directories are picked up by the default skills/ and agents/ scans described under "Directory layout" above, so the skills and agents keys in plugin.json above are omitted, not just unset.

A team would list this plugin from its own marketplace:

ai-catalog-gates-marketplace/.claude-plugin/marketplace.json
{
  "name": "ai-catalog-gates-marketplace",
  "description": "An illustrative marketplace listing a packaged subset of the ai-catalog quality-gate pipeline.",
  "owner": {
    "name": "Alberto Irurueta",
    "url": "https://github.com/albertoirurueta"
  },
  "plugins": [
    {
      "name": "ai-catalog-gates",
      "source": "./plugins/ai-catalog-gates",
      "description": "License-header and secret-scanning skills, plus the gate-runner subagent, from ai-catalog."
    }
  ]
}

marketplace.json’s required top-level fields are `name, owner and plugins; each plugins entry requires name and source (here a path relative to the marketplace root, since the plugin sits inside the marketplace directory itself), and may also set any plugin.json field, such as description above, which overrides the plugin’s own value in listings. Verified against Claude Code — Create a marketplace and the marketplace reference. Run claude plugin validate ./ai-catalog-gates-marketplace before publishing either file — it catches a missing name, an empty owner.name, a relative source path containing .., and errors inside each relative-source plugin’s own plugin.json.

Installing, versioning and updates

In Claude Code
# register the marketplace (a GitHub repo, git URL, or local path)
/plugin marketplace add albertoirurueta/ai-catalog-gates-marketplace

# install a plugin from it -- <plugin-name>@<marketplace-name>
/plugin install ai-catalog-gates@ai-catalog-gates-marketplace

# from a shell, without starting a session
claude plugin marketplace add albertoirurueta/ai-catalog-gates-marketplace
claude plugin install ai-catalog-gates@ai-catalog-gates-marketplace --scope project

Installing picks a scope: user (every project on this machine), project (everyone working in the repository, via the committed .claude/settings.json — each collaborator still runs the install command themselves once), or local (this repository, this machine only). A plugin with a pinned version field stays on that version until it’s changed; an unpinned plugin from a marketplace with auto-update on refreshes its on-disk copy after each session start, and a running session keeps the version it already loaded until /reload-plugins. Anthropic’s official marketplace and marketplaces added from a claude.ai account auto-update by default; every other marketplace, including a private team one, defaults to auto-update off — update a plugin explicitly with /plugin → Installed → the plugin → Update now, or claude plugin update ai-catalog-gates@ai-catalog-gates-marketplace from a shell, or turn auto-update on for the marketplace from /plugin → Marketplaces. Verified against Claude Code — Install and manage plugins.

Team distribution via settings

Committing a plugin’s enabledPlugins entry to a project’s .claude/settings.json turns it on for everyone who opens the repository, and extraKnownMarketplaces registers the marketplace itself so nobody has to run /plugin marketplace add by hand first. Both keys are verified against the settings reference's #enabledplugins and #extraknownmarketplaces entries and work in any settings file (managed, user, project or local), with the usual precedence between them:

.claude/settings.json
{
  "extraKnownMarketplaces": {
    "ai-catalog-gates-marketplace": {
      "source": {
        "source": "github",
        "repo": "albertoirurueta/ai-catalog-gates-marketplace"
      }
    }
  },
  "enabledPlugins": {
    "ai-catalog-gates@ai-catalog-gates-marketplace": true
  }
}

extraKnownMarketplaces maps a marketplace name to an object with a source (github, git, url, file, directory, or an inline settings source) and an optional autoUpdate boolean. enabledPlugins maps plugin-name@marketplace-name to a boolean; a plugin with no entry anywhere falls back to its own defaultEnabled value. Committing the entry doesn’t download the plugin for collaborators — each still installs it once — and a plugin an organization’s managed settings force-enables or blocks this way can’t be re-enabled, disabled or repointed from a lower-precedence settings file. Claude Code honors extraKnownMarketplaces from a repository’s .claude/settings.json only after the user accepts the workspace trust dialog for that folder. This is the same distribution shape Permissions & Settings covers for allow/deny rules generally.

GitHub Copilot’s equivalent

GitHub Copilot has its own plugin and marketplace system, verified against GitHub Copilot — About plugins. A Copilot plugin bundles the same kind of components — custom agents (*.agent.md), skills (SKILL.md under skills/<name>/), hooks (hooks.json) and MCP/LSP server configurations — into one installable unit, for Copilot CLI, the Copilot cloud agent, and the GitHub Copilot app. Its manifest is also plugin.json at the plugin root; Copilot documents two manifest shapes:

  • Agent Plugins 1.0 — an open, cross-vendor schema ($schema: https://agent-plugins.org/schemas/1.0.0/plugin.schema.json) with name, version, description, author, homepage, repository, license, keywords and an extensions object for client-specific data. Skills (skills/) and MCP servers (mcp.json) sit at fixed locations; Copilot-specific agents, hooks, commands and LSP servers go under a com.github.copilot/ directory that other clients ignore.

  • Legacy Copilot plugins — no $schema, with configurable component paths and .mcp.json, .github/mcp.json or the mcpServers manifest field for MCP configuration. A legacy manifest can also live at .claude-plugin/plugin.json, among other locations.

A Copilot plugin marketplace is likewise defined by a marketplace.json with name, owner, metadata (description, version) and a plugins array of {name, description, version, source} entries — close enough to Claude Code’s shape that GitHub’s own docs allow saving it under a .claude-plugin/ directory as an alternative to .github/plugin/. Two marketplaces, copilot-plugins and awesome-copilot, are registered by default.

In GitHub Copilot (CLI)
# register a marketplace (owner/repo on GitHub, a git URL, or a local path)
copilot plugin marketplace add albertoirurueta/ai-catalog-gates-marketplace

# install a plugin from it -- <plugin-name>@<marketplace-name>
copilot plugin install ai-catalog-gates@ai-catalog-gates-marketplace

# list what's installed
copilot plugin list

For team and organization-wide distribution, Copilot’s own configuration reference, the Copilot CLI plugin reference, names enabledPlugins and extraKnownMarketplaces as its managed-policy keys too — the same names Claude Code uses, consistent with both following the shared Agent Plugins 1.0 direction — declared in ~/.copilot/settings.json (personal), a repository’s .github/copilot/settings.json (project, read by both the CLI and the cloud agent), or an organization’s MDM-managed configuration; a plugin or marketplace a managed policy pins this way can’t be re-enabled, disabled or repointed locally, exactly as with Claude Code above. That reference page does not give the full JSON shape of these two keys the way Claude Code’s settings reference does for its own, so this page states only what’s confirmed — the key names and their managed-policy behavior — rather than assuming an identical schema.

VS Code’s own extension surface (installed .vsix packages from the Visual Studio Marketplace) is a separate, older distribution mechanism for the editor as a whole, not a way to package Copilot’s own skills/agents/hooks/MCP bundle the way a plugin does; it isn’t covered further here.