Claude Code's (and Copilot's) native plugin installer has zero awareness of .apm/ nesting -- it convention-scans only flat skills/, agents/, commands/, hooks.json at each plugin's root. Confirmed via strings on the installed claude binary and live installs of git@holocron/gitea@holocron/kyberforge@ holocron, all reporting Skills(0) Agents(0) Hooks(0) post ADR-0015's apm conversion. Root cause (apm_cli/core/plugin_manifest.py): apm's plugin.json compiler deliberately strips skills/agents/commands keys, assuming the host already auto-discovers those convention directories -- it has no model of .apm/ being host-visible at all. Separately, apm's own bundle exporter (apm_cli/bundle/plugin_exporter.py, behind `apm pack --format plugin`) implements the correct .apm/ -> flat mapping, but only ever targeted build/<name>-<version>/, a path nothing in marketplace.json's source: points at. scripts/sync-plugin-content.sh wraps that bundle exporter and copies its agents/, skills/, commands/, instructions/, extensions/, and merged hooks.json back into each plugin's own root as a second tracked compiled-output category -- same governance status as .claude-plugin/plugin.json: generated from .apm/, never hand-edited. tests/ subdirectories are excluded from the mirror (dev fixtures, not host-visible runtime content; several hardcode a relative repo-root walk-up sized for the .apm/-nested depth, which breaks when duplicated one level shallower). Applied for real across all 6 plugins and verified two ways: `claude plugin validate --strict` passes on every real plugin directory, and a live `claude --plugin-dir <path> -p "list skills/agents"` behavioral test confirms content is now actually discovered. Also, from the same issue #90 review round: - scripts/check-manifests.sh pointed at each plugin's root-level plugin.json (checking skills/hooks/mcpServers/agents pointer fields) -- that file was a stale near-duplicate of .claude-plugin/plugin.json nothing else read or wrote, now deleted across all 6 plugins. check-manifests.sh is rewritten to validate .claude-plugin/plugin.json instead, and drops the pointer-field checks entirely (nothing to check -- those fields are correctly absent by design). Content-presence drift is now check-plugin-content-sync's job, a new pre-push hook wired in .pre-commit-config.yaml. docs/adr/0017 records the root cause and decision in full, including two rejected alternatives (patching plugin.json's path fields directly -- apm's compiler strips them on every run; pointing marketplace.json at apm pack's build/ output -- a version-suffixed non-source directory nothing can install from without an extra build step). ADR-0015 and CONTEXT.md are updated to point at it. Refs: #90
133 lines
9.4 KiB
Markdown
133 lines
9.4 KiB
Markdown
# Microsoft APM replaces the hand-authored plugin/marketplace model as this repo's authoring source of truth
|
|
|
|
**Status: executed (2026-08-12, issue #90).** All six plugins now carry `apm.yml` + `.apm/` as
|
|
their authoring source; `.claude-plugin/marketplace.json` and every plugin's `plugin.json` are
|
|
`apm pack`-compiled output. **Supersedes ADR-0001** ("Skills are distributed via plugins... each
|
|
plugin contains its own `skills/` directory") — in effect.
|
|
|
|
This repo replaces its hand-maintained Claude Code plugin/marketplace authoring model
|
|
(`.claude-plugin/marketplace.json` + per-plugin `plugin.json`) with Microsoft APM (`apm.yml` +
|
|
`.apm/`) as the authoring source of truth — an outright replacement of the authoring layer, not an
|
|
additive overlay. This ADR records the decision from a `grill-with-docs` session on issue #88.
|
|
|
|
## Context
|
|
|
|
Every plugin under `plugins/<name>/` currently ships two hand-maintained manifests
|
|
(`.claude-plugin/plugin.json` for Claude Code, root `plugin.json` for Copilot CLI) plus a
|
|
hand-maintained root `.claude-plugin/marketplace.json` listing all plugins. Adding a provider means
|
|
hand-authoring a third manifest shape; keeping the two existing ones in parity is itself a tracked
|
|
concern (ADR-0006).
|
|
|
|
Research on Microsoft APM (`plugins/kyberforge/docs/research/docs/microsoft-apm/`) found that its
|
|
documented "monorepo-hybrid" repo shape maps directly onto this repo's existing `plugins/<name>/`
|
|
layout: each plugin becomes its own `apm.yml` + `.apm/{skills,agents,hooks,prompts,instructions}/`
|
|
package, listed from a root `apm.yml`'s `marketplace:` block. `apm compile`/`apm pack` generate
|
|
per-target output — including a `.claude-plugin/marketplace.json` — from that vendor-neutral
|
|
`.apm/` tree, so provider manifests become compiled artifacts instead of hand-authored files, and
|
|
new providers (Copilot, Gemini, Codex — all supported by `apm runtime setup`) no longer require a
|
|
new hand-maintained manifest format.
|
|
|
|
## Decision
|
|
|
|
- **The `plugins/<name>/` monorepo-hybrid directory layout survives.** `.claude-plugin/marketplace.json`
|
|
and per-provider `plugin.json` files become **compiled output** via `apm compile`/`apm pack`,
|
|
generated from `apm.yml` + `.apm/` per plugin, extensible to other `apm runtime`-supported
|
|
providers without hand-maintaining a separate manifest per provider.
|
|
- **This supersedes ADR-0001** ("Skills are distributed via plugins... each plugin
|
|
contains its own `skills/` directory"). Executed in issue #90: skills and agents physically moved
|
|
to `plugins/<name>/.apm/skills/` and `plugins/<name>/.apm/agents/*.agent.md`.
|
|
- New operational tooling — `apm-install` (skill), `apm-workflow` (skill), `apm-orchestrate`
|
|
(agent) — lands in `kyberforge`, tracked in issue #88
|
|
(https://git.dev.rkdr.net/Defame1297/holocron/issues/88).
|
|
- Adapting `skill-author`/`agent-author`'s routing to author `.apm/`-native content (retargeting to
|
|
`.apm/skills/`, `.apm/agents/` paths — the content these two skills author is still meaningful
|
|
post-conversion) is deferred to issue #89
|
|
(https://git.dev.rkdr.net/Defame1297/holocron/issues/89). `forge` is out of scope for #89 — it
|
|
stays untouched by this whole conversion effort and keeps routing to whatever the live author
|
|
skills are at the time.
|
|
- **`plugin-author`/`marketplace-author` are not adapted — they are superseded and deleted.**
|
|
Unlike `skill-author`/`agent-author`, nothing in these two skills carries forward as authoring
|
|
routing: `apm compile`/`apm pack` will generate `.claude-plugin/marketplace.json` and
|
|
per-provider `plugin.json` directly from `apm.yml` + `.apm/`, so `apm-install`/`apm-workflow`/
|
|
`apm-orchestrate` (issue #88, already landed on this branch) fully replace what these two skills
|
|
did. `plugin-author`/`marketplace-author` were deleted in issue #90's execution.
|
|
- Translating the existing plugins into `apm.yml` + `.apm/` and running the real conversion was
|
|
executed in issue #90 (https://git.dev.rkdr.net/Defame1297/holocron/issues/90, closed).
|
|
- `CONTEXT.md`'s "Plugin"/"Plugin marketplace" glossary entries were rewritten in issue #90 to
|
|
describe the compiled-output model directly, rather than carrying a forward-pointer to this ADR.
|
|
|
|
## Considered options
|
|
|
|
**Additive/compile-layer only, no `apm.yml` (rejected).** Keep `plugin.json`/`marketplace.json`
|
|
hand-authored and bolt APM on top as an optional extra. Rejected: doesn't achieve the multi-provider
|
|
compile-reuse goal APM's package model provides, and leaves the existing dual-manifest hand
|
|
maintenance in place unchanged.
|
|
|
|
**New standalone `plugins/apm/` plugin (rejected).** `plugins/lint/` was split out of `kyberforge`
|
|
specifically because Vale tooling is generic and repo-agnostic, not holocron-marketplace-specific
|
|
(see `CONTEXT.md`'s "lint plugin" entry) — the same argument applies to a generic `apm` CLI
|
|
wrapper. The shipped `apm-install`/`apm-workflow` skills are, in fact, generic, repo-agnostic APM
|
|
CLI documentation with no holocron-specific content, so a standalone `plugins/apm/` would have
|
|
been a defensible split on artifact content alone. Rejected anyway, in favor of `kyberforge`,
|
|
because holocron is currently the only repo that needs this tooling — standing up a separate
|
|
plugin for a single consumer isn't worth it yet. Accepted as an explicit tradeoff (same pattern
|
|
as ADR-0011's `gitea-workflow` naming tradeoff) — worth revisiting if this tooling is ever reused
|
|
outside holocron's own conversion.
|
|
|
|
## Content migration out of `plugin-author`/`marketplace-author`
|
|
|
|
A content audit of `plugin-author`/`marketplace-author` (same `grill-with-docs` session as this
|
|
correction) sorted what they document into three buckets:
|
|
|
|
- **Claude Code platform constraints — carried forward.** Facts that stay true regardless of
|
|
authoring model (reserved plugin-name prefixes; the `agents/`-directory stray-`.md`-file
|
|
validator gotcha, ADR-0010; `claude plugin validate` as a required terminal check) have been
|
|
added into `apm-workflow`'s reference docs, since compiled output still has to satisfy these
|
|
constraints post-conversion.
|
|
- **Dual-manifest artifacts — obsolete, not carried forward.** Conventions that existed only
|
|
because of hand-authored dual manifests (ADR-0006's version-parity/patch-bump rule, the
|
|
CC-vs-Copilot field-placement split, dual-file mirroring) are obsolete under `apm.yml`'s
|
|
single-manifest model and were deliberately dropped.
|
|
- **Holocron policy choice — resolved in #90.** `marketplace-author`'s catalog-version convention
|
|
(minor bump for package add/remove, patch bump for field-only updates) isn't an APM mechanic —
|
|
`apm` doesn't enforce it, and has no native version-bump automation at all — so rather than
|
|
building a new script, the convention is now documented as guidance inside `apm-workflow`'s
|
|
reference docs (`references/marketplace.md` for the root catalog version rule,
|
|
`references/configure.md` for the per-package version-bump-on-content-edit rule), applied
|
|
manually by whoever edits `apm.yml`.
|
|
|
|
## Consequences
|
|
|
|
- ADR-0001 is superseded (issue #90).
|
|
- ADR-0006 (plugin-version-parity) is moot (issue #90): `plugin.json`/`marketplace.json` are now
|
|
compiled output of a single `apm.yml`, so there's no second hand-authored file left to keep in
|
|
parity, and `plugin-author` — the skill that enforced ADR-0006 — was deleted rather than adapted
|
|
(see "Content migration" above).
|
|
- ADR-0010 (agent sources relocated outside agents dir) was updated (issue #90) for agents now
|
|
living at `plugins/<name>/.apm/agents/*.agent.md` — the directory path changed; the pre-existing
|
|
`.agent.md` extension convention (ADR-0005/ADR-0010) and project/user scope are unaffected, per
|
|
ADR-0016.
|
|
- ADR-0014 (Vale prefilter ships from the plugin) had its hardcoded `plugins/<name>/skills/...`
|
|
paths (the Vale prefilter is skill-scoped only; ADR-0014 never referenced a
|
|
`plugins/<name>/agents/...` path) updated for the `.apm/` nesting as part of issue #90's
|
|
execution.
|
|
- `kyberforge` gained three new artifacts (issue #88) before any conversion of existing content
|
|
happened, then lost two (`plugin-author`/`marketplace-author`, deleted once issue #90 verified
|
|
parity) — net version bump 1.3.1 → 1.4.0. The root marketplace catalog bumped 0.3.1 → 0.3.2 to
|
|
match.
|
|
- ADR-0016 (a narrower decision discovered while designing issue #89) turned out to gate how
|
|
issue #90 had to re-author plugin-scope agents: `.apm/agents/*.agent.md` compiles verbatim to
|
|
both Claude and Copilot, so those files carry only `name`/`description`/`model`/`source_keys` —
|
|
existing dual-file `<name>.md`+`<name>.agent.md` pairs could not be raw-moved, only re-authored.
|
|
- Two follow-up issues tracked the remaining work, both done: #89 (`skill-author`/`agent-author`
|
|
routing adaptation, merged in #93) and #90 (the actual repo conversion, which also deleted
|
|
`plugin-author`/`marketplace-author`).
|
|
- **Caveat on "Status: executed" above:** issue #90's own execution comment flagged, before merge,
|
|
that Claude Code's ability to actually load content out of `.apm/` was unverified — that caveat
|
|
turned out to be a real defect, not a formality: the native installer has zero awareness of
|
|
`.apm/` and reported `Skills (0) Agents (0) Hooks (0)` on every plugin installed from this
|
|
marketplace. The manifest-compilation deliverable this ADR describes was genuinely complete;
|
|
runtime discoverability was not. Fixed in ADR-0017 (a second, compiled flat-directory content
|
|
mirror at each plugin root, generated by `scripts/sync-plugin-content.sh`) — see that ADR for
|
|
the root cause and the fix.
|