diff --git a/apm.yml b/apm.yml index 54a32a7..c8c3f5a 100644 --- a/apm.yml +++ b/apm.yml @@ -75,31 +75,25 @@ marketplace: packages: - name: kyberforge - description: Skills and agents for creating, maintaining, and managing a Claude Code / Copilot CLI plugin marketplace. source: ./plugins/kyberforge category: Developer Tools - name: bin - description: Skills for everyday AI-assisted development work that is not tied to a single tool, forge or language, and has not yet been split into a focused plugin. source: ./plugins/bin category: Utilities - name: git - description: Skills and agents for working with a local Git clone over the git wire protocol, and for authoring and running the pre-commit hooks that guard it. source: ./plugins/git category: Version Control - name: gitea - description: Skills and agents for working with a Gitea forge through its HTTP API — the forge's own objects, as distinct from the local git clone. source: ./plugins/gitea category: Version Control - name: core - description: Skills for authoring and auditing a repo's AGENTS.md and the provider adapter files that defer to it. source: ./plugins/core category: Productivity - name: lint - description: Skills and agents for configuring and running linters. source: ./plugins/lint category: Developer Tools diff --git a/docs/adr/0021-plugin-descriptions-state-a-domain-boundary.md b/docs/adr/0021-plugin-descriptions-state-a-domain-boundary.md index 3fd00ad..55519fd 100644 --- a/docs/adr/0021-plugin-descriptions-state-a-domain-boundary.md +++ b/docs/adr/0021-plugin-descriptions-state-a-domain-boundary.md @@ -18,6 +18,9 @@ file, `.claude-plugin/marketplace.json`. Read the "four generated files" in Cont generated files" in Consequences as historical counts, true when written. The blast radius shrank; the staleness hazard that motivated this ADR did not. +**Amended 2026-09-16:** the root `marketplace.packages[]` copy of each description was removed; the +package `apm.yml` is now the single source. See the amendment before Consequences. + ## Context A plugin's published description is one string authored twice — in `plugins//apm.yml` and in @@ -203,6 +206,32 @@ sit inside ADR-0020's tiers; the tier would have been silent through all three f string, not a link — and the README's own plugin list carries the same enumeration with the same staleness, so this relocates the defect rather than fixing it. +## Amendment (2026-09-16): the root copy is removed — the package `apm.yml` is the single source + +The Decision's rule that "the two copies … stay identical" is retired by removing the second copy. +The six `description:` lines under root `apm.yml`'s `marketplace.packages[]` are deleted, the same way +`2def060` deleted the six `version:` lines beside them. `plugins//apm.yml`'s `description:` is +now the only place a package's published description is authored. + +The rule's own justification — "the root entry is what reaches the compiled marketplace" — was true +only while the root entry set the field. apm's Claude marketplace mapper resolves a local-path entry's +`description` curator-first: the entry's value wins when present, and when it is absent the value is +read from the package's own `apm.yml` (`apm_cli/marketplace/output_mappers.py`, the `is_local` branch +calling `_apply_field_with_precedence` with `source_label="package apm.yml"`). The root copy was +therefore an override, not a mirror. Nothing enforced the identity rule, and on drift apm silently +published the root value. Removing the copy removes the drift rather than leaving it unchecked. + +All six root copies were byte-identical to their package's `apm.yml` when they were removed. After +the removal, `apm pack` regenerated `.claude-plugin/marketplace.json` with every `description` unchanged, +and `apm pack --check-versions --check-clean --dry-run` passes. The consequence for the "unbounded +obligation" in Context is that a description edit is now one edit, not two. The package version bump +and the catalog patch bump it earns are unchanged +(`plugins/kyberforge/.apm/skills/apm-workflow/references/configure.md`). + +This applies to local-path (`source: ./…`) entries only. A remote entry has no local package +`apm.yml` to fall back to. Its `description:`, when set, is still the published text, and when it +is absent apm uses whatever its best-effort remote metadata fetch returns. + ## Consequences **Three descriptions are rewritten and the compiled output regenerated.** Eight generated files diff --git a/plugins/kyberforge/.apm/skills/apm-workflow/references/configure.md b/plugins/kyberforge/.apm/skills/apm-workflow/references/configure.md index e4d45d2..c8fd5a8 100644 --- a/plugins/kyberforge/.apm/skills/apm-workflow/references/configure.md +++ b/plugins/kyberforge/.apm/skills/apm-workflow/references/configure.md @@ -53,13 +53,19 @@ output changes.** Two triggers, not one: 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`. +Under a `per_package` strategy this `version:` is the single source for a local-path +(`source: ./…`) catalog entry: when that `marketplace.packages[]` entry omits `version:`, +`apm pack` reads it from the package's `apm.yml`. Do not restate it there. On a local entry a +`version:` 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. +`description:` behaves the same way: a local entry that omits it publishes the package `apm.yml`'s +`description`, and one that sets it silently overrides it. A remote entry is different. There, +`version:` is the semver range that selects which git tag to resolve, and a remote entry must carry +`version:` or `ref:`. Its `description:`, when set, is the published text. + +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 diff --git a/plugins/kyberforge/.apm/skills/apm-workflow/references/marketplace.md b/plugins/kyberforge/.apm/skills/apm-workflow/references/marketplace.md index b305868..a14443a 100644 --- a/plugins/kyberforge/.apm/skills/apm-workflow/references/marketplace.md +++ b/plugins/kyberforge/.apm/skills/apm-workflow/references/marketplace.md @@ -68,10 +68,13 @@ marketplace: Without this block, the default versioning strategy ties every listed package to the marketplace/root version. -With it, each entry's version comes from its package's own `apm.yml`. An entry may also set -`version:`, but that is an override: it silently wins in the compiled `marketplace.json`, and -`apm pack --check-versions` does not flag the mismatch. Omit it unless an override is intended — -see `references/configure.md`. +With it, each local-path (`source: ./…`) entry's version comes from its package's own +`apm.yml`, and so does its `description`. A local entry may also set `version:` or `description:`, +but either one is an override: it silently wins in the compiled `marketplace.json`, and +`apm pack --check-versions` does not flag a version mismatch. Omit both unless an override is +intended — see `references/configure.md`. A remote entry is different: its `version:` is the semver +range that selects the git tag to resolve (matched through the entry's `tag_pattern`, else +`build.tagPattern`), not an override, and the entry must set `version:` or `ref:`. ## Bumping the catalog's own version (repo policy) @@ -86,9 +89,10 @@ earned it: - **Patch** when the set of packages is unchanged but what the catalog publishes moved: a `marketplace:`-block field (the catalog description, owner, `build:`/`outputs:` config, or an existing entry's description or category), or any listed package's own `apm.yml` `version:`. The - most frequent trigger by far is the package bump. The root entry carries no `version:`, but the - compiled `marketplace.json` publishes each package's version, so a package bump alone changes the - catalog and alone earns the patch — made in the same commit (see `references/configure.md`). + most frequent trigger by far is the package bump. When entries omit `version:` (the recommended + local form), the compiled `marketplace.json` still publishes each package's version, so a package + bump alone changes the catalog and alone earns the patch — made in the same commit (see + `references/configure.md`). Keep the root `apm.yml`'s top-level `version:` in step with `marketplace.version`. They are separate keys — the top-level one is not inherited into the compiled `marketplace.json`, but `apm audit`