# Plugins and marketplaces in Copilot CLI

Package the ticket-service skill, hooks and reviewer agent as a plugin, publish it in a Git marketplace, and install, update and scope it in Copilot CLI.

Source: https://ai-sw-factory.mellicci.dev/fundamentals/plugins/copilot-cli

Copilot CLI supports two plugin formats. This page uses the legacy Copilot format, which keeps every component folder at the plugin root; Agent Plugins 1.0 makes skills and MCP servers portable across compatible clients and puts Copilot-specific parts (agents, hooks) under `com.github.copilot/`. Both are compared under Specifics.

## At a glance

| | Copilot CLI |
|---|---|
| Term | Plugins, distributed through marketplaces |
| Configured in | `plugin.json` (plugin), `marketplace.json` (marketplace), `enabledPlugins` and `extraKnownMarketplaces` in settings |
| Loads / runs | Install copies the plugin into `~/.copilot/installed-plugins/`; the CLI reads that cache in later sessions |
| Scope & precedence | User-wide, or one repository via `.github/copilot/settings.json`. Your own agent or skill with the same ID beats the plugin's |

## Build the scenario

Plugin `ticket-service-kit` 1.0.0 bundles the `add-migration` skill, the `format.sh`, `guard.sh` and `log.sh` hooks, and the `reviewer` agent. It doesn't ship the `github` MCP server, because Copilot CLI has a built-in GitHub server.

```text
ticket-service-kit/
├── plugin.json
├── hooks.json
├── agents/
│   └── reviewer.agent.md
├── skills/
│   └── add-migration/
│       └── SKILL.md
└── scripts/
    ├── format.sh
    ├── guard.sh
    └── log.sh
```

```json
{
  "name": "ticket-service-kit",
  "description": "ticket-service skill, hooks and reviewer agent",
  "version": "1.0.0",
  "author": { "name": "Acme Platform" },
  "license": "MIT",
  "keywords": ["ticket-service", "migrations"]
}
```

The skill, hooks and agent files keep the content from the [skills](https://ai-sw-factory.mellicci.dev/fundamentals/skills/copilot-cli), [hooks](https://ai-sw-factory.mellicci.dev/fundamentals/hooks/copilot-cli) and [subagents](https://ai-sw-factory.mellicci.dev/fundamentals/subagents/copilot-cli) pages. The marketplace is the Git repository `acme/agent-marketplace`, with the plugin under `plugins/`.

```json
{
  "name": "agent-marketplace",
  "owner": { "name": "Acme Platform" },
  "metadata": { "description": "Acme coding-agent plugins", "version": "1.0.0" },
  "plugins": [
    {
      "name": "ticket-service-kit",
      "description": "ticket-service skill, hooks and reviewer agent",
      "version": "1.0.0",
      "source": "./plugins/ticket-service-kit"
    }
  ]
}
```

Save it as `.github/plugin/marketplace.json` in `acme/agent-marketplace`.

| Step | Command (terminal, or `/plugin ...` in a session) | Effect |
|---|---|---|
| Test locally | `copilot plugin install ./ticket-service-kit` | Caches the plugin; reinstall to pick up edits |
| Add marketplace | `copilot plugin marketplace add acme/agent-marketplace` | Registers it as `agent-marketplace` |
| Install | `copilot plugin install ticket-service-kit@agent-marketplace` | Installs the bundle |
| Update | `copilot plugin update ticket-service-kit` (`--all` for every plugin) | Pulls the new version |
| Uninstall | `copilot plugin uninstall ticket-service-kit` | Removes it |

To recommend the plugin to the team, commit `.github/copilot/settings.json`. The documentation says `enabledPlugins` auto-installs plugins, and the plugin is active only in that repository.

```json
{
  "extraKnownMarketplaces": {
    "agent-marketplace": { "source": { "source": "github", "repo": "acme/agent-marketplace" } }
  },
  "enabledPlugins": { "ticket-service-kit@agent-marketplace": true }
}
```

## Specifics

### Plugin layout and manifest

| Item | Legacy format (used above) | Agent Plugins 1.0 |
|---|---|---|
| Opt-in | No `$schema` | `$schema` set to the `agent-plugins.org` 1.0.0 (or 1.1.0) `plugin.schema.json` URL |
| Manifest location | `.plugin/plugin.json`, `plugin.json`, `.github/plugin/plugin.json` or `.claude-plugin/plugin.json` (checked in that order) | `plugin.json` at the plugin root |
| Required fields | `name` (kebab-case, max 64) | `$schema`, `name` |
| Other fields | `description`, `version`, `author`, `homepage`, `repository`, `license`, `keywords`, `category`, `tags`, plus component paths | `version`, `description`, `author`, `homepage`, `repository`, `license`, `keywords`, `extensions`; nothing else |
| Component paths | Configurable (`agents`, `skills`, `hooks`, `mcpServers`, ...) | Fixed; unknown fields are ignored |

The documentation says to choose Agent Plugins 1.0 for portable skills and MCP servers, and the legacy format for custom component paths or an existing Copilot-specific plugin. A rejected 1.x version loads nothing; it does not fall back to legacy.

### What a plugin can contain

| Component | Legacy location | Agent Plugins 1.0 location |
|---|---|---|
| Skills | `skills/NAME/SKILL.md` | `skills/NAME/SKILL.md` (portable) |
| MCP servers | `.mcp.json`, `.github/mcp.json` or `mcpServers` | `mcp.json` (portable) |
| Custom agents | `agents/NAME.agent.md` | `com.github.copilot/agents/` |
| Hooks | `hooks.json` or `hooks/hooks.json` | `com.github.copilot/hooks/hooks.json` |
| Also | `commands`, `lsp.json` | `com.github.copilot/` `commands/`, `rules/`, `lsp.json` |

Hook scripts are plain files in the plugin. The documentation doesn't specify how a plugin's hook command resolves the path to its own scripts; the hook `cwd` is documented as relative to the repository root. `${PLUGIN_ROOT}` is documented for MCP `args`, `env` and `cwd`, and for a plugin agent's `mcp-servers`.

### Marketplaces

| Source of a marketplace | `marketplace add` argument |
|---|---|
| GitHub repository | `OWNER/REPO`, or `OWNER/REPO#ref` |
| Other Git host | `https://host/OWNER/REPO.git` |
| Local directory | `/path/to/marketplace` |

The CLI looks for `marketplace.json`, `.plugin/`, `.github/plugin/` then `.claude-plugin/`. Required fields are `name`, `owner` and `plugins`; each plugin entry needs `name` and `source`. A `source` is a relative path, or an object with `github` or `url` type, optional `ref`, and a 40-character `sha` to pin an exact commit. `copilot-plugins` and `awesome-copilot` are registered by default and can't be removed. `copilot plugin marketplace list|browse|update|remove` manage the rest.

### Install, update and scope

| Topic | Behavior |
|---|---|
| Install specs | `plugin@marketplace`, `OWNER/REPO`, `OWNER/REPO:PATH`, Git URL, local path |
| Location | `~/.copilot/installed-plugins/MARKETPLACE/PLUGIN-NAME` (direct installs under `_direct/`) |
| Update | Manual with `copilot plugin update`. Built-in marketplaces auto-update at session start; your own marketplace opts in with `autoUpdate: true` in user or managed settings (a repository setting is ignored) |
| Toggle | `copilot plugin enable` / `disable` keeps the files |
| Scope | User install is global. A repository `enabledPlugins` entry activates the plugin in that repository only |
| Same ID locally | Agents and skills: first found wins, and a project or personal agent or skill silently beats the plugin's. MCP servers: the plugin beats your `mcp-config.json`, and `--additional-mcp-config` beats the plugin |
| Dev mount | `--plugin-dir DIRECTORY` loads a plugin for one session |

Claude-format plugins and marketplaces are accepted: the CLI also reads `.claude-plugin/plugin.json` and `.claude-plugin/marketplace.json`, and the cross-tool subset of `.claude/settings.json` (including `enabledPlugins`).

### Trust and management

| Topic | Behavior |
|---|---|
| Trust | A plugin runs hooks and MCP servers you didn't write. The documentation doesn't describe an install-time review or sandbox, so review it first |
| Pinning | Use `version` in the marketplace entry and a `sha` in `source` for reproducible installs |
| Enterprise | Administrators can set `enabledPlugins`, `extraKnownMarketplaces` and `strictKnownMarketplaces` in `managed-settings.json`; managed entries can't be toggled locally and show a `Managed` badge in `/plugin` |
| Dashboard | `/plugin` lists plugins and flags available updates |

## Gotchas

- Installing caches the plugin. After editing a local plugin, run `copilot plugin install ./ticket-service-kit` again (a directory-source marketplace loads live, needing only a restart).
- A project or personal `reviewer` agent or `add-migration` skill silently shadows the plugin's. Nothing warns you.
- Uninstall takes the plugin name from `plugin.json`, not a path. Removing a marketplace with installed plugins fails unless you add `--force`, which uninstalls them.
- Marketplaces are added by `OWNER/REPO` but removed by their own `name`, which comes from `marketplace.json`.
- `enabledPlugins` in a repository names the marketplace as `plugin@marketplace`; the repository-level `autoUpdate` is ignored, so updates there stay manual.
