Publish to a marketplace
A marketplace in APM is a curated index of packages that one repo
publishes and many repos install from. You author it as a
marketplace: block in apm.yml, build it into
.claude-plugin/marketplace.json with apm pack, and let consumers
register your repo with apm marketplace add. This page walks the
producer side: schema, build, and the optional apm marketplace publish flow that opens PRs against pinned consumer repos.
For the consumer side — adding a marketplace, browsing it, installing packages from it — see Marketplaces.
End to end
Section titled “End to end”apm marketplace init # 1. add the block to apm.yml$EDITOR apm.yml # 2. describe each packageapm marketplace check # 3. validate refs resolveapm pack # 4. compile marketplace.jsongit add apm.yml .claude-plugin/marketplace.jsongit commit -m "Release v1.0.0" && git push # 5. shipA consumer in another repo then runs:
apm marketplace add acme-org/my-marketplaceapm install example-package@my-marketplaceThat is the loop. Everything below is detail.
What lives where
Section titled “What lives where”APM uses a single source-of-truth model:
apm.yml— hand-edited. Themarketplace:block declares your registry: owner, packages, version ranges..claude-plugin/marketplace.json— generated byapm pack. Byte-compatible with Anthropic’s marketplace.json so Claude Code, Copilot CLI, and APM all read the same artefact.
Both files are committed. The legacy standalone marketplace.yml is
deprecated; if you still have one, run apm marketplace migrate.
Author the registry
Section titled “Author the registry”Scaffold the block:
apm marketplace init --owner acme-orgThis appends a richly commented marketplace: block to apm.yml
(creating apm.yml if absent). The minimal shape:
name: my-project # inherited into marketplace top levelversion: 1.0.0description: Curated plugins for the acme-org engineering team
marketplace: owner: name: acme-org url: https://github.com/acme-org
build: tagPattern: "v{version}" # default; per-package overridable
packages: - name: example-package description: Human-readable description consumers see source: acme-org/example-package version: "^1.0.0"
- name: pinned-package source: acme-org/pinned-package ref: 3f2a9b1c # explicit SHA/tag/branch
- name: local-tool source: ./packages/local-tool # ships from this same repo version: 0.1.0The key in apm.yml is packages:. It becomes plugins: in the
compiled marketplace.json — that rename is the only structural
transform apm pack performs. Strict schema: unknown keys raise an
error, never silently ignored.
For the full field reference (every key on every entry, including
subdir, tag_pattern, include_prerelease, metadata,
pluginRoot, and Anthropic pass-through fields like tags, author,
license), see Marketplace authoring.
apm packapm pack resolves every remote packages: entry against
git ls-remote, leaves local-path entries untouched, and writes
.claude-plugin/marketplace.json atomically. Useful flags:
apm pack --dry-run # resolve and print; do not writeapm pack --offline # cached refs onlyapm pack --include-prerelease # allow pre-release tagsapm pack -v # per-entry resolution detailExit codes: 0 build succeeded, 1 build error (network, missing
ref, no tag matches range), 2 schema error in the marketplace:
block.
The same apm pack run also produces a bundle to ./build/<name>/
when apm.yml declares dependencies:. Marketplace projects with no
dependencies: block produce only marketplace.json. See
Pack a bundle for the bundle side.
Validate before you ship
Section titled “Validate before you ship”apm marketplace check # every package's ref/range resolvesapm marketplace doctor # local environment diagnosticsapm marketplace outdated # packages with newer matching tagscheck is the gate to run in CI: a missing tag or unresolvable range
exits non-zero before you push the release commit.
Publish updates to pinned consumers
Section titled “Publish updates to pinned consumers”apm marketplace publish is the optional fan-out: it opens PRs
against a list of consumer repos that pin the previous marketplace
version, bumping each one to the version you just released.
targets: - repo: acme-org/service-a branch: main - repo: acme-org/service-b branch: develop path_in_repo: apm.yml # defaultapm marketplace publish --dry-run # previewapm marketplace publish --yes # push branches and open PRsapm marketplace publish --no-pr # push branches, skip gh PR creationIt clones each target, edits its apm.yml to point at the new
marketplace ref, pushes a feature branch, and opens a PR via gh.
State is journaled to .apm/publish-state.json. Failures in one
target do not abort the others; the exit code is non-zero if any
target failed.
This flow assumes gh is authenticated and the runner has push
access to every target — it is targeted at internal/org marketplaces
where you control both sides. Public marketplaces should rely on
consumers running apm install --update on their own cadence.
Pitfalls
Section titled “Pitfalls”packages:notplugins:in theapm.ymlsource. Theplugins:name only appears in the compiled JSON.- Both
apm.yml(marketplace:block) andmarketplace.ymlpresent is a hard error. Pick one; prefer the block and runapm marketplace migrateto consolidate. *.jsonin.gitignorewill silently skip the generated file.apm marketplace initwarns on this; if you hit it, add an unignore:!.claude-plugin/marketplace.json.- Local-path entries skip git resolution. They emit the path
verbatim; consumers see the same path. Use
metadata.pluginRootif your plugins live under a common subdirectory. - No
versions[]array. Each compiled package carries one resolved ref — the highest tag matching the range at build time. Re-runapm packand re-tag to publish a new version.
Governance
Section titled “Governance”Org policy can restrict which marketplaces a consumer is allowed to register and which packages it can install from them. That gate runs on the consumer side at install time. See Governance overview for the producer-side implications (signing, allow-listed sources).
Where next
Section titled “Where next”- Pack a bundle — the other thing
apm packproduces. - Preview and validate — dry-runs and schema checks before you tag.
- Install packages — the consumer flow your marketplace feeds into.