Marketplaces
Marketplaces are curated indexes of plugins hosted in a Git repository (typically GitHub or GitLab). Each marketplace contains a marketplace.json file that maps plugin names to source locations. APM resolves these entries to Git URLs, so plugins installed from marketplaces get the same version locking, security scanning, and governance as any other APM dependency.
How marketplaces work
Section titled “How marketplaces work”A marketplace is a repository with a marketplace.json at its root (GitHub or GitLab). The file lists plugins with their source type and location:
{ "name": "Acme Plugins", "plugins": [ { "name": "code-review", "description": "Automated code review agent", "source": { "type": "github", "repo": "acme/code-review-plugin" } }, { "name": "style-guide", "source": { "type": "url", "url": "https://github.com/acme/style-guide.git" } }, { "name": "eslint-rules", "source": { "type": "git-subdir", "repo": "acme/monorepo", "subdir": "plugins/eslint-rules" } }, { "name": "local-tools", "source": "./tools/local-plugin" } ]}Both Copilot CLI and Claude Code marketplace.json formats are supported. Copilot CLI uses "repository" and "ref" fields; Claude Code uses "source" (string or object). APM normalizes entries from either format into its canonical dependency representation.
Supported source types
Section titled “Supported source types”| Type | Description | Example |
|---|---|---|
github | GitHub owner/repo shorthand | acme/code-review-plugin |
url | Full HTTPS or SSH Git URL | https://github.com/acme/style-guide.git |
git-subdir | Subdirectory within a Git repository (repo + subdir) | acme/monorepo + plugins/eslint-rules |
String source | Subdirectory within the marketplace repository itself | ./tools/local-plugin |
npm sources are not supported. Copilot CLI format uses "repository" and optional "ref" fields instead of "source".
Source key aliases
Section titled “Source key aliases”The install resolver accepts both legacy (Copilot CLI) and current (Claude Code) key names in marketplace.json source objects:
| Current key | Legacy alias | Notes |
|---|---|---|
source (discriminator) | type | Values: github, git-subdir, url |
repo | repository | Must be owner/repo format |
sha | commit | Resolved commit SHA |
repo (git-subdir) | url | Must be owner/repo, not a full URL |
Marketplace authors should use the current keys (emitted by apm pack). Legacy aliases are accepted for backward compatibility with older manifests.
Plugin root directory
Section titled “Plugin root directory”Marketplaces can declare a metadata.pluginRoot field to specify the base directory for bare-name sources:
{ "metadata": { "pluginRoot": "./plugins" }, "plugins": [ { "name": "my-tool", "source": "my-tool" } ]}With pluginRoot set to ./plugins, the source "my-tool" resolves to owner/repo/plugins/my-tool. Sources that already contain a path separator (e.g. ./custom/path) are not affected by pluginRoot.
Versioned plugins
Section titled “Versioned plugins”Plugins can declare a version field and a source.ref that points to a specific Git tag or commit:
{ "name": "code-review", "description": "Automated code review agent", "version": "2.1.0", "source": { "type": "github", "repo": "acme/code-review-plugin", "ref": "v2.1.0" }}The version field is informational (displayed by apm view and apm outdated). The source.ref determines which Git ref APM checks out during install.
Register a marketplace
Section titled “Register a marketplace”apm marketplace add acme/plugin-marketplaceThis registers the marketplace and fetches its marketplace.json. By default APM tracks the main branch.
Default alias resolution
Section titled “Default alias resolution”When --name is not provided, APM resolves the local alias in this order:
namefield declared in the marketplace’smarketplace.json(if present and valid)- Repository name (fallback)
This ensures parity with Claude Code install instructions — if a marketplace’s marketplace.json declares "name": "addy-agent-skills", APM registers it under that alias and shows a hint:
[*] Registering marketplace 'addy-agent-skills'...[+] Marketplace 'addy-agent-skills' registered (1 plugins)[i] Install plugins with: apm install <plugin>@addy-agent-skillsUse --name to override the alias explicitly.
Options:
--name/-n— Override the local alias (defaults to themarketplace.jsonnamefield, then repo name)--branch/-b— Branch to track (default:main)--host— Git host FQDN for non-github.com hosts (default:github.comorGITHUB_HOSTenv var)
# Register with a custom name on a specific branchapm marketplace add acme/plugin-marketplace --name acme-plugins --branch release
# Register from a GitHub Enterprise host (two equivalent forms)apm marketplace add acme/plugin-marketplace --host ghes.corp.example.comapm marketplace add ghes.corp.example.com/acme/plugin-marketplaceGitLab-hosted marketplaces
Section titled “GitLab-hosted marketplaces”gitlab.com is recognized as GitLab automatically. For self-managed GitLab, set GITLAB_HOST to that instance’s FQDN, or list several hosts in APM_GITLAB_HOSTS (comma-separated). See Authentication for host configuration and tokens.
APM fetches marketplace.json via the GitLab REST v4 raw-file API when the host classifies as GitLab (not the GitHub Contents API). Candidate paths are unchanged: repository root, .github/plugin/marketplace.json, and .claude-plugin/marketplace.json.
# GitLab.com (FQDN in the argument or via --host)apm marketplace add mygroup/plugin-marketplace --host gitlab.comapm marketplace add gitlab.com/mygroup/plugin-marketplace
# Self-managed GitLab (set GITLAB_HOST or APM_GITLAB_HOSTS so APM classifies the instance as GitLab, then use FQDN in the path or --host)apm marketplace add git.company.com/mygroup/plugin-marketplaceapm marketplace add mygroup/plugin-marketplace --host git.company.comList registered marketplaces
Section titled “List registered marketplaces”apm marketplace listShows all registered marketplaces with their source repository and branch.
Browse plugins
Section titled “Browse plugins”View all plugins available in a specific marketplace:
apm marketplace browse acme-pluginsSearch a marketplace
Section titled “Search a marketplace”Search plugins by name or description in a specific marketplace using QUERY@MARKETPLACE:
apm search "code review@skills"Options:
--limit— Maximum results to return (default: 20)
apm search "linting@awesome-copilot" --limit 5The @MARKETPLACE scope is required — this avoids name collisions when different
marketplaces contain plugins with the same name. To see everything in a marketplace,
use apm marketplace browse <name> instead.
Install from a marketplace
Section titled “Install from a marketplace”Use the NAME@MARKETPLACE syntax to install a plugin from a specific marketplace:
# Install using the source ref from the marketplace entryapm install code-review@acme-plugins
# Install with a specific git ref overrideapm install code-review@acme-plugins#v2.0.0
# Install from a specific branchapm install code-review@acme-plugins#mainThe # separator carries a raw git ref that overrides the source.ref from the marketplace entry. Without #, APM uses the ref defined in the marketplace manifest.
APM resolves the plugin name against the marketplace index, fetches the underlying Git repository using the resolved ref, and installs it as a standard APM dependency. The resolved source appears in apm.yml and apm.lock.yaml just like any direct dependency.
On GitLab-class hosts (gitlab.com and self-managed instances when APM classifies the host as GitLab), monorepo layouts—plugins whose marketplace.json sources point at a subdirectory inside the marketplace repository—work with this syntax; you do not need a manual git: + path: dependency entry for apm install. When you declare Git dependencies yourself in apm.yml, nested paths may still need the object form with explicit git: and path:—see the Dependencies guide.
For full apm install options, see CLI Commands.
View plugin details
Section titled “View plugin details”Show metadata for a marketplace plugin:
apm view code-review@acme-pluginsDisplays the plugin’s name, version, description, source, and tags.
Provenance tracking
Section titled “Provenance tracking”Marketplace-resolved plugins are tracked in apm.lock.yaml with full provenance:
apm_modules: acme/code-review-plugin: resolved: https://github.com/acme/code-review-plugin#main commit: abc123def456789 discovered_via: acme-plugins marketplace_plugin_name: code-reviewThe discovered_via field records which marketplace was used for discovery. marketplace_plugin_name stores the original plugin name from the index. The resolved URL and commit pin the exact version, so builds remain reproducible regardless of marketplace availability.
Cache behavior
Section titled “Cache behavior”APM caches marketplace indexes locally with a 1-hour TTL. Within that window, commands like search and browse use the cached index. After expiry, APM fetches a fresh copy from the network. If the network request fails, APM falls back to the expired cache (stale-if-error) so commands still work offline.
Force a cache refresh:
# Refresh a specific marketplaceapm marketplace update acme-plugins
# Refresh all registered marketplacesapm marketplace updateRegistry proxy support
Section titled “Registry proxy support”When PROXY_REGISTRY_URL is set, marketplace commands (add, browse, search, update) fetch marketplace.json through the registry proxy (Artifactory Archive Entry Download) first. Only if the proxy does not return the file does APM fall back to the host API: GitHub Contents API for GitHub/GHES, or GitLab REST v4 raw file endpoints for GitLab-classified hosts. When PROXY_REGISTRY_ONLY=1 is also set, that direct host API fallback is blocked entirely, enabling fully air-gapped marketplace discovery for both GitHub- and GitLab-backed indexes.
export PROXY_REGISTRY_URL="https://art.corp.example.com/artifactory/github"export PROXY_REGISTRY_ONLY=1 # optional: block direct GitHub/GitLab API access
apm marketplace add anthropics/skills # fetches via Artifactoryapm marketplace browse skills # fetches via ArtifactoryThis builds on the same proxy infrastructure used by apm install. See Registry Proxy & Air-gapped for full configuration, the bypass-prevention contract, and the air-gapped CI playbook.
Manage marketplaces
Section titled “Manage marketplaces”Remove a registered marketplace:
apm marketplace remove acme-plugins
# Skip confirmation promptapm marketplace remove acme-plugins --yesRemoving a marketplace does not uninstall plugins previously installed from it. Those plugins remain pinned in apm.lock.yaml to their resolved Git sources.
Validate a marketplace
Section titled “Validate a marketplace”Check a marketplace manifest for schema errors and duplicate entries:
apm marketplace validate acme-plugins
# Verbose outputapm marketplace validate acme-plugins --verboseCatches: missing required fields and duplicate plugin names (case-insensitive).
For full option details, see CLI Commands.
Security
Section titled “Security”Version immutability
Section titled “Version immutability”APM caches version-to-ref mappings in ~/.apm/cache/marketplace/version-pins.json. On subsequent installs, APM compares the marketplace ref against the cached pin. If a version’s ref has changed, APM warns:
WARNING: Version 2.0.0 of code-review@acme-plugins ref changed: was 'v2.0.0', now 'deadbeef'. This may indicate a ref swap attack.This detects marketplace maintainers (or compromised accounts) silently pointing an existing version at different code.
Shadow detection
Section titled “Shadow detection”When installing a marketplace plugin, APM checks all other registered marketplaces for plugins with the same name. A match produces a warning:
WARNING: Plugin 'code-review' also found in marketplace 'other-plugins'. Verify you are installing from the intended source.Shadow detection runs automatically during install — no configuration required.
Best practices
Section titled “Best practices”- Use commit SHAs as refs — tags and branches can be moved; commit SHAs cannot.
- Keep plugin names unique across marketplaces — avoids shadow warnings and reduces confusion.
- Review immutability warnings — a changed ref for an existing version is a strong signal of tampering.
Authoring: monorepo workflows
Section titled “Authoring: monorepo workflows”When building a marketplace that tracks packages from a monorepo (multiple packages inside one Git repository), use --subdir to point each entry at its subdirectory:
apm marketplace package add acme/monorepo --subdir plugins/eslint-rules --name eslint-rulesapm marketplace package add acme/monorepo --subdir plugins/formatter --name formatterRef auto-resolution
Section titled “Ref auto-resolution”Mutable git refs (HEAD, branch names) are automatically resolved to concrete 40-character SHAs before being stored in apm.yml. This ensures supply-chain safety — the entry always pins to an immutable commit.
Default behaviour (no --ref): When neither --version nor --ref is provided, the current HEAD SHA is pinned automatically:
# Resolves HEAD to its current SHA and stores itapm marketplace package add acme/code-reviewExplicit HEAD: Passing --ref HEAD warns that HEAD is mutable, then resolves:
apm marketplace package add acme/code-review --ref HEAD# [!] 'HEAD' is a mutable ref. Resolving to current SHA for safety.# [i] Resolved HEAD to abc123def456Branch names: Branch names that match refs/heads/* on the remote are also resolved:
apm marketplace package add acme/code-review --ref main# [!] 'main' is a branch (mutable ref). Resolving to current SHA for safety.# [i] Resolved main to abc123def456Updating pinned SHAs: Use package set with --ref HEAD to re-pin to the latest commit:
apm marketplace package set code-review --ref HEADTags and concrete SHAs are stored as-is without resolution.
Creating your own marketplace
Section titled “Creating your own marketplace”If you want to create and maintain your own marketplace registry, see the Marketplace Authoring Guide.