The root apm.yml packages[] entries no longer carry version:, and a version there is a silent override that --check-versions does not catch. configure.md and marketplace.md now name the package's own apm.yml as the single source and drop version: from the examples. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
6.4 KiB
topic, source_keys
| topic | source_keys | |
|---|---|---|
| configure |
|
Scaffolding a new package
apm plugin init --yes --target claude,copilot
Run from inside the target package directory, with no positional name argument (see Gotchas). Creates apm.yml + plugin.json in the current directory — it does NOT scaffold a .apm/ skeleton. Primitive subdirectories (.apm/skills/, .apm/agents/, .apm/hooks/) must be created manually as content is migrated into them. Run this once per package (e.g. once per plugins/<name>/ directory in a monorepo-hybrid layout), not once for the whole repo.
apm.yml — required fields
Only name and version (SemVer) are required:
name: my-pkg
version: 1.0.0
apm.yml — top-level keys
name,version— required (see above)description,author,license,homepage,repository,keywords— standard package metadatatype—instructions | skill | hybrid | prompts; selects how the package is processed at install/compile time. It is a routing selector, not a constraint on what.apm/may contain (see Gotchas)targets— which harnesses this package compiles to (plural list form preferred; legacy singulartarget: copilot,claudeCSV form still accepted)includes—autopublishes the authoritative local layout as-is; it is not scoped down to what's relevant, so anything narrower needs an explicit repo-path list. Note:autoalso does not sweep generic root-level passthrough files (README.md, docs/, sources.md, config files) into theapm packdistribution bundle — seereferences/compile.mddependencies/devDependencies—apm/mcp/lspentries;devDependenciesshare the same shape but are excluded from the shipped artifactscripts— named commands runnable viaapm run <name>compilation— target/strategy/exclude/placement controls forapm compile/apm packpolicy— e.g.fetch_failure_defaultregistries— named registry endpoints for shorthand dependency resolutionmarketplace— owner + packages list; seereferences/marketplace.mdfor the full marketplace workflow
Bumping a package's own version (repo policy)
apm ships no version-bump command, so version: in a package's own apm.yml is a hand edit.
Policy: bump a package's own apm.yml version: whenever anything that reaches its compiled
output changes. Two triggers, not one:
- Its
.apm/content — a new or removed skill/agent/hook, or a substantive edit to an existing one. - Its own
apm.ymlmanifest metadata —description,keywords,author,license,homepage,repository. These are compiled verbatim into.claude-plugin/plugin.jsonand.github/plugin/plugin.json, so editing them republishes the package's public description under an unchanged version number, which is the same defect as shipping changed content silently. Purely local edits that reach no compiled output — aREADME.md, adocs/page — do not require a bump on their own.
The version belongs to the package, not to the repo: editing plugins/foo/.apm/ never bumps
plugins/bar/apm.yml.
Under a per_package strategy this version: is the single source: when a catalog's
marketplace.packages[] entry omits version:, apm pack reads it from the package's apm.yml.
Do not restate it there. A version: on the entry is an override, not a copy — it silently wins in
the compiled marketplace.json, and apm pack --check-versions still reports [matches] when it
disagrees with the package's own number, so drift between the two is never caught. Set one only
when an override is the intent. A skipped bump is not caught either: nothing infers intent from a
content diff. The catalog's own version follows a separate rule — see references/marketplace.md.
Dependency reference forms
dependencies.apm entries accept: a pinned tag (owner/repo#tag), a plain repo (uses default branch), a single primitive path within a repo, a raw git URL, a git:/path:/ref: object for finer control, or a local relative path (./packages/my-shared-skills).
MCP server secrets
${VAR} indirection is required for MCP server secrets (headers, env vars) in apm.yml, never literal values — see SKILL.md Gotchas.
Registries (config-level, not apm.yml)
Any git repo is a valid package source by default — no registry required. To declare named registries for shorthand dependency resolution:
apm experimental enable registries # required first — see Gotchas
apm config set registry.corp-main.url https://artifactory.corp.example.com/apm
apm config set registry.corp-main.token eyJ...
apm config set registry.corp-main.default true
apm config get/apm config unset manage individual keys the same way.
Gotchas
apm.yml'stype:field validates nothing about.apm/. It selects processing:instructionscompiles to AGENTS.md only,skillinstalls a native skill only,promptsemits commands only,hybriddoes both (seeapm_cli/models/validation.py,PackageContentType). apm checks only that the value parses to one of those four strings; no check anywhere compares it against the primitives actually on disk, and no mismatch diagnostic exists. A package declaringtype: instructionswhile shipping.apm/skills/therefore raises no error — the mismatch resolves silently, either by omitting that primitive from the install/compile output or, in apm 0.28.0 whereget_effective_type()routes off the on-disk layout and never reads the declared field, by ignoring the declared value outright. Both directions are silent:apm installandapm compilecan exit 0 having shipped none of the primitives you expected. Settype:to cover every primitive the package ships, and confirm the deployed output rather than the exit code.apm experimental enable registriesmust run before anyregistry.*config takes effect. Declaring aregistries:block or runningapm config set registry.*without it silently does nothing — no error, no warning.apm plugin init <name>run with a positional name argument, from inside a directory already named<name>, creates a wrongly-nested<name>/<name>/subdirectory — it treats the positional arg as "create a new project directory named X," not "confirm the current directory is X." Fix: omit the positional argument entirely when already cd'd into the target package directory — runapm plugin init --yes --target claude,copilotinstead.