Execute the plugin→APM conversion #90

Closed
opened 2026-08-10 17:41:14 +00:00 by Claude · 6 comments
Collaborator

The actual conversion work — use apm-install/apm-workflow/apm-orchestrate (built in #88) plus agent-author/skill-author (retargeted to .apm/-native authoring in #89/#93) to convert this repo's hand-maintained .claude-plugin/plugin.json + .claude-plugin/marketplace.json (mirrored to .github/plugin/marketplace.json) into Microsoft APM (apm.yml + .apm/) as the authoring source of truth, per ADR-0015. plugin.json/marketplace.json become compiled output of apm compile/apm pack. Once parity is verified, delete plugin-author/marketplace-author.

Status: grilled and ready to execute (2026-08-12, grilled against ADR-0015, ADR-0016, and the Microsoft APM research corpus). This body replaces the original open-ended description — every question flagged below and in the prior comment is now resolved.

Resolved decisions

  1. Directory naming: keep plugins/<name>/. No rename to packages/<name>/. Confirmed in docs/research/docs/microsoft-apm/monorepo-and-repo-shapes.md: packages/ in APM's own docs is an illustrative example directory name only — apm plugin init, apm marketplace package add ./path, and source: accept any path. A rename would touch ADR-0014's hardcoded Vale regexes, .pre-commit-config.yaml, scripts/check-scope-walkup-sync.sh, and every skill/agent body that references plugins/<name>/..., for zero functional gain.

  2. Versioning:

    • Root apm.yml's marketplace.versioning: { strategy: per_package }, with each plugin's real independent version declared in marketplace.packages[].version. The default (root-tied) strategy would silently collapse all six plugins onto one shared version — a real regression, since this repo's plugins already version independently today.
    • Root apm.yml's own version (the marketplace catalog's identity version, currently 0.3.1) keeps marketplace-author's old convention: minor bump on package add/remove, patch bump for marketplace-block-only field edits.
    • Each plugin's own apm.yml version is bumped manually by whoever edits that plugin's .apm/ content. Confirmed via the CLI reference/configuration/examples/troubleshooting research docs: apm has no native version-bump automation (no apm version bump, nothing changelog- or conventional-commits-driven) — so no new script gets built for this. Instead, document both rules as guidance inside apm-workflow's existing reference files (doc-only addition, not new tooling):
      • references/marketplace.md — state the minor/patch root-version rule, tied to the add-package operation / marketplace-block edits.
      • references/configure.md — state that edit-config changing a package's own .apm/ content should bump that package's own apm.yml version.
  3. mattpocock-skills (remote GitHub-sourced entry, not a plugin this repo owns) needs no apm.yml/.apm/ scaffolding. It becomes a plain marketplace.packages[] entry in root apm.yml with source: mattpocock/skills (the plain-repo shorthand packages[].source accepts — confirmed in configuration.md), replacing the current source: {repo, source: "github"} JSON shape.

  4. Sequencing — four phases, detailed below. Parallel scaffold of all six plugins (including kyberforge — no reason to special-case it, since converting the repo's own source doesn't touch the already-cached installed copy of the tooling doing the work), then strictly sequential root-marketplace registration (six add-package calls land in the same root apm.yml file — a shared-state hazard, not a dependency-ordering one).

  5. Parity verification gate (must all pass clean before deleting plugin-author/marketplace-author):

    • Semantic diff of compiled .claude-plugin/marketplace.json and each provider's plugin.json against the currently-committed versions — same plugin/skill/agent inventory and version numbers; formatting/field-order differences from apm's serializer are expected and fine.
    • claude plugin validate --strict passes on every compiled plugin.
    • apm audit --ci passes clean (plain apm audit is not CI-equivalent — see apm-workflow SKILL.md Gotchas).

Preconditions

  • Confirm apm --version succeeds before dispatching anything.
  • ADR-0016 applies: plugin-scope .apm/agents/*.agent.md compiles verbatim to both Claude and Copilot, so it must drop tools: and all Claude-only fields (isolation, maxTurns, effort, memory, permissionMode). Do not git mv the existing dual <name>.md + <name>.agent.md pair into .apm/agents/. Re-author each through agent-author in plugin scope so the stripping happens correctly; preserve the original prose body, only the frontmatter shape changes.

Phase A — per-plugin conversion (parallel, one subagent per plugin)

Dispatch six subagents in parallel — one each for bin, core, git, gitea, kyberforge, lint — invoking kyberforge:apm-orchestrate (and agent-author/skill-author for content migration). Each subagent's brief:

  1. Read the plugin's current .claude-plugin/plugin.json + root plugin.json for real metadata (name, description, version, license, keywords, author).
  2. apm plugin init <name> --yes from inside plugins/<name>/ (via apm-orchestrate's configure: init-package) — scaffolds apm.yml + .apm/ in place.
  3. Fill in apm.yml: carry forward the plugin's current version (don't reset it — these version independently today), description, author, license, keywords, type: (set before any content lands, per what the plugin actually contains), targets: [claude, copilot] at minimum, includes: auto unless there's a reason to scope narrower.
  4. Migrate content:
    • Skills (skills/<name>/ → .apm/skills/<name>/): straight copy, content-identical across targets — plain git mv is fine.
    • Agents: re-author via agent-author in plugin scope per the Preconditions note above — not a raw move.
    • Hooks (hooks/ + hooks.json → .apm/hooks/*.json): move as-is once confirmed genuinely Claude-native hook JSON (nested or naked shape, both accepted).
    • bin/, docs/, README.md, sources.md, .mcp.json: not APM primitives, stay at the package root under includes: auto. Confirm .mcp.json passthrough empirically — no MCP-primitive compile mapping was found in the research corpus, so check whether apm compile needs an explicit dependencies.mcp entry instead.
  5. apm compile for this package alone; fix errors before reporting done.
  6. Report: apm.yml written, content migrated, any surprises (feed forward — other plugins in the same batch may hit the same issue).

Phase B — root marketplace registration (strictly sequential)

apm marketplace init --owner Defame1297 --name holocron   # once
apm marketplace package add ./plugins/bin --name bin
apm marketplace package add ./plugins/core --name core
apm marketplace package add ./plugins/git --name git
apm marketplace package add ./plugins/gitea --name gitea
apm marketplace package add ./plugins/kyberforge --name kyberforge
apm marketplace package add ./plugins/lint --name lint

Then add mattpocock-skills directly as an apm.yml edit (not add-package — it's a remote source, not a local path): source: mattpocock/skills. Apply the versioning decision (per-package strategy, each entry's version: set to that plugin's real current version) as part of this phase.

Phase C — compile, pack, verify parity

apm marketplace check
apm compile
apm pack --dry-run -v
apm pack
claude plugin validate --strict plugins/<name>/   # each of the six
apm audit --ci

git diff the newly-compiled .claude-plugin/marketplace.json and each plugin.json against what's currently committed. All three parity checks (semantic diff, claude plugin validate --strict, apm audit --ci) must pass clean before Phase D. Also confirm empirically what apm compile/apm pack emits for Copilot's marketplace-equivalent output and whether .github/plugin/marketplace.json still needs separate mirroring — not documented in the research corpus.

Phase D — cleanup (only after Phase C passes clean)

  • Delete plugins/kyberforge/skills/plugin-author/ and plugins/kyberforge/skills/marketplace-author/.
  • Update .pre-commit-config.yaml's hardcoded path regexes for the new .apm/ nesting: ^plugins/[^/]+/skills/[^/]+/SKILL\.md$ and ^plugins/[^/]+/agents/[^/]+\.md$ both need the .apm/ segment added; the agents pattern also needs the extension updated to .agent.md (plugin-scope agents are now single-file .agent.md, not .md, per ADR-0016). Check whether the shipped root .pre-commit-hooks.yaml needs the same update or should stay layout-agnostic for external consumers.
  • Update scripts/check-scope-walkup-sync.sh's hardcoded references to kyberforge's own script paths (they move under .apm/skills/).
  • Grep the repo for any other hardcoded plugins/[^/]+/skills/ or plugins/[^/]+/agents/ assumption and fix each hit.
  • Rewrite CONTEXT.md's "Plugin"/"Plugin marketplace" glossary entries for the compiled-output model; drop the ADR-0015 forward-pointer now that the conversion has executed.
  • Mark ADR-0001 formally superseded.
  • Mark ADR-0006 (plugin-version-parity) moot.
  • Update ADR-0010 for the new .apm/agents/ path (project/user scope unaffected; plugin scope already redefined by ADR-0016).
  • Commit via git:git-commits (Conventional Commits); do not push without explicit confirmation.

Definition of done

  • All six plugins compile cleanly from apm.yml + .apm/; .claude-plugin/marketplace.json and every plugin.json are compiled artifacts, not hand-edited.
  • plugin-author/marketplace-author deleted.
  • All three parity checks pass.
  • CONTEXT.md and ADR-0001/0006/0010/0015 reflect the post-conversion state.
  • Issue closed with a note that ADR-0015's "pending issue #90" language is now stale.

Depends on #88 (done). Benefits from #89 (done, merged in #93).

Research: plugins/kyberforge/docs/research/docs/microsoft-apm/.

The actual conversion work — use `apm-install`/`apm-workflow`/`apm-orchestrate` (built in #88) plus `agent-author`/`skill-author` (retargeted to `.apm/`-native authoring in #89/#93) to convert this repo's hand-maintained `.claude-plugin/plugin.json` + `.claude-plugin/marketplace.json` (mirrored to `.github/plugin/marketplace.json`) into Microsoft APM (`apm.yml` + `.apm/`) as the authoring source of truth, per ADR-0015. `plugin.json`/`marketplace.json` become **compiled output** of `apm compile`/`apm pack`. Once parity is verified, delete `plugin-author`/`marketplace-author`. **Status: grilled and ready to execute (2026-08-12, grilled against ADR-0015, ADR-0016, and the Microsoft APM research corpus).** This body replaces the original open-ended description — every question flagged below and in the prior comment is now resolved. ## Resolved decisions 1. **Directory naming: keep `plugins/<name>/`.** No rename to `packages/<name>/`. Confirmed in `docs/research/docs/microsoft-apm/monorepo-and-repo-shapes.md`: `packages/` in APM's own docs is an illustrative example directory name only — `apm plugin init`, `apm marketplace package add ./path`, and `source:` accept any path. A rename would touch ADR-0014's hardcoded Vale regexes, `.pre-commit-config.yaml`, `scripts/check-scope-walkup-sync.sh`, and every skill/agent body that references `plugins/<name>/...`, for zero functional gain. 2. **Versioning:** - Root `apm.yml`'s `marketplace.versioning: { strategy: per_package }`, with each plugin's real independent version declared in `marketplace.packages[].version`. The default (root-tied) strategy would silently collapse all six plugins onto one shared version — a real regression, since this repo's plugins already version independently today. - Root `apm.yml`'s own `version` (the marketplace catalog's identity version, currently `0.3.1`) keeps `marketplace-author`'s old convention: **minor** bump on package add/remove, **patch** bump for marketplace-block-only field edits. - Each plugin's own `apm.yml` `version` is bumped manually by whoever edits that plugin's `.apm/` content. Confirmed via the CLI reference/configuration/examples/troubleshooting research docs: `apm` has **no** native version-bump automation (no `apm version bump`, nothing changelog- or conventional-commits-driven) — so no new script gets built for this. Instead, **document both rules as guidance inside `apm-workflow`'s existing reference files** (doc-only addition, not new tooling): - `references/marketplace.md` — state the minor/patch root-version rule, tied to the `add-package` operation / marketplace-block edits. - `references/configure.md` — state that `edit-config` changing a package's own `.apm/` content should bump that package's own `apm.yml` version. 3. **`mattpocock-skills`** (remote GitHub-sourced entry, not a plugin this repo owns) needs no `apm.yml`/`.apm/` scaffolding. It becomes a plain `marketplace.packages[]` entry in root `apm.yml` with `source: mattpocock/skills` (the plain-repo shorthand `packages[].source` accepts — confirmed in `configuration.md`), replacing the current `source: {repo, source: "github"}` JSON shape. 4. **Sequencing** — four phases, detailed below. Parallel scaffold of all six plugins (including kyberforge — no reason to special-case it, since converting the repo's own source doesn't touch the already-cached installed copy of the tooling doing the work), then strictly sequential root-marketplace registration (six `add-package` calls land in the *same* root `apm.yml` file — a shared-state hazard, not a dependency-ordering one). 5. **Parity verification gate** (must all pass clean before deleting `plugin-author`/`marketplace-author`): - Semantic diff of compiled `.claude-plugin/marketplace.json` and each provider's `plugin.json` against the currently-committed versions — same plugin/skill/agent inventory and version numbers; formatting/field-order differences from `apm`'s serializer are expected and fine. - `claude plugin validate --strict` passes on every compiled plugin. - `apm audit --ci` passes clean (plain `apm audit` is not CI-equivalent — see `apm-workflow` SKILL.md Gotchas). ## Preconditions - Confirm `apm --version` succeeds before dispatching anything. - **ADR-0016 applies**: plugin-scope `.apm/agents/*.agent.md` compiles verbatim to both Claude and Copilot, so it must drop `tools:` and all Claude-only fields (`isolation`, `maxTurns`, `effort`, `memory`, `permissionMode`). **Do not `git mv` the existing dual `<name>.md` + `<name>.agent.md` pair into `.apm/agents/`.** Re-author each through `agent-author` in plugin scope so the stripping happens correctly; preserve the original prose body, only the frontmatter shape changes. ## Phase A — per-plugin conversion (parallel, one subagent per plugin) Dispatch six subagents in parallel — one each for `bin`, `core`, `git`, `gitea`, `kyberforge`, `lint` — invoking `kyberforge:apm-orchestrate` (and `agent-author`/`skill-author` for content migration). Each subagent's brief: 1. Read the plugin's current `.claude-plugin/plugin.json` + root `plugin.json` for real metadata (`name`, `description`, `version`, `license`, `keywords`, `author`). 2. `apm plugin init <name> --yes` from inside `plugins/<name>/` (via `apm-orchestrate`'s `configure: init-package`) — scaffolds `apm.yml` + `.apm/` in place. 3. Fill in `apm.yml`: carry forward the plugin's *current* version (don't reset it — these version independently today), `description`, `author`, `license`, `keywords`, `type:` (set before any content lands, per what the plugin actually contains), `targets: [claude, copilot]` at minimum, `includes: auto` unless there's a reason to scope narrower. 4. Migrate content: - **Skills** (`skills/<name>/` → `.apm/skills/<name>/`): straight copy, content-identical across targets — plain `git mv` is fine. - **Agents**: re-author via `agent-author` in plugin scope per the Preconditions note above — not a raw move. - **Hooks** (`hooks/` + `hooks.json` → `.apm/hooks/*.json`): move as-is once confirmed genuinely Claude-native hook JSON (nested or naked shape, both accepted). - **`bin/`, `docs/`, `README.md`, `sources.md`, `.mcp.json`**: not APM primitives, stay at the package root under `includes: auto`. Confirm `.mcp.json` passthrough empirically — no MCP-primitive compile mapping was found in the research corpus, so check whether `apm compile` needs an explicit `dependencies.mcp` entry instead. 5. `apm compile` for this package alone; fix errors before reporting done. 6. Report: `apm.yml` written, content migrated, any surprises (feed forward — other plugins in the same batch may hit the same issue). ## Phase B — root marketplace registration (strictly sequential) ``` apm marketplace init --owner Defame1297 --name holocron # once apm marketplace package add ./plugins/bin --name bin apm marketplace package add ./plugins/core --name core apm marketplace package add ./plugins/git --name git apm marketplace package add ./plugins/gitea --name gitea apm marketplace package add ./plugins/kyberforge --name kyberforge apm marketplace package add ./plugins/lint --name lint ``` Then add `mattpocock-skills` directly as an `apm.yml` edit (not `add-package` — it's a remote source, not a local path): `source: mattpocock/skills`. Apply the versioning decision (per-package strategy, each entry's `version:` set to that plugin's real current version) as part of this phase. ## Phase C — compile, pack, verify parity ``` apm marketplace check apm compile apm pack --dry-run -v apm pack claude plugin validate --strict plugins/<name>/ # each of the six apm audit --ci ``` `git diff` the newly-compiled `.claude-plugin/marketplace.json` and each `plugin.json` against what's currently committed. All three parity checks (semantic diff, `claude plugin validate --strict`, `apm audit --ci`) must pass clean before Phase D. Also confirm empirically what `apm compile`/`apm pack` emits for Copilot's marketplace-equivalent output and whether `.github/plugin/marketplace.json` still needs separate mirroring — not documented in the research corpus. ## Phase D — cleanup (only after Phase C passes clean) - Delete `plugins/kyberforge/skills/plugin-author/` and `plugins/kyberforge/skills/marketplace-author/`. - Update `.pre-commit-config.yaml`'s hardcoded path regexes for the new `.apm/` nesting: `^plugins/[^/]+/skills/[^/]+/SKILL\.md$` and `^plugins/[^/]+/agents/[^/]+\.md$` both need the `.apm/` segment added; the agents pattern also needs the extension updated to `.agent.md` (plugin-scope agents are now single-file `.agent.md`, not `.md`, per ADR-0016). Check whether the shipped root `.pre-commit-hooks.yaml` needs the same update or should stay layout-agnostic for external consumers. - Update `scripts/check-scope-walkup-sync.sh`'s hardcoded references to kyberforge's own script paths (they move under `.apm/skills/`). - Grep the repo for any other hardcoded `plugins/[^/]+/skills/` or `plugins/[^/]+/agents/` assumption and fix each hit. - Rewrite `CONTEXT.md`'s "Plugin"/"Plugin marketplace" glossary entries for the compiled-output model; drop the ADR-0015 forward-pointer now that the conversion has executed. - Mark ADR-0001 formally superseded. - Mark ADR-0006 (plugin-version-parity) moot. - Update ADR-0010 for the new `.apm/agents/` path (project/user scope unaffected; plugin scope already redefined by ADR-0016). - Commit via `git:git-commits` (Conventional Commits); do not push without explicit confirmation. ## Definition of done - All six plugins compile cleanly from `apm.yml` + `.apm/`; `.claude-plugin/marketplace.json` and every `plugin.json` are compiled artifacts, not hand-edited. - `plugin-author`/`marketplace-author` deleted. - All three parity checks pass. - `CONTEXT.md` and ADR-0001/0006/0010/0015 reflect the post-conversion state. - Issue closed with a note that ADR-0015's "pending issue #90" language is now stale. Depends on #88 (done). Benefits from #89 (done, merged in #93). Research: `plugins/kyberforge/docs/research/docs/microsoft-apm/`.
Claude added this to the Kyberforge basics milestone 2026-08-10 17:41:14 +00:00
Claude added the Kind/Feature label 2026-08-10 17:41:14 +00:00
Author
Collaborator

Scope correction (per ADR-0015): per the ADR-0015 correction recorded on branch feat/88-marketplace-apm-conversion (commit 92e7ff2, "docs(kyberforge): narrow issue #89 scope, migrate CC platform facts to apm-workflow"), this issue's execution now also includes deleting plugin-author/marketplace-author once apm compile/apm pack output is verified to have parity with what's hand-maintained today.

The "Verify the compiled output has parity ... before considering any provider manifest hand-authoring retired" bullet above now means, specifically: retiring = deleting those two skills.

Before deleting them, see ADR-0015's "Content migration out of plugin-author/marketplace-author" section for the full audit of what needs to be preserved elsewhere first:

  • Claude Code platform constraints (reserved plugin-name prefixes, the ADR-0010 agents/-directory stray-file validator gotcha, claude plugin validate as a required terminal check) — already carried into apm-workflow's reference docs as of this correction, so no further action needed on those specifically.
  • Dual-manifest-only conventions (ADR-0006 version-parity/patch-bump rule, CC-vs-Copilot field-placement split) are obsolete under apm.yml's single-manifest model and were deliberately dropped — not carried forward.
  • Still unresolved, and this issue's to decide: marketplace-author's catalog version-bump convention (minor bump for package add/remove, patch bump for field-only updates) isn't an APM mechanic, but is still a meaningful holocron policy worth re-applying to apm.yml's marketplace.packages[].version field. Where/how to re-apply it is #90's decision, not resolved by ADR-0015.
**Scope correction (per ADR-0015):** per the ADR-0015 correction recorded on branch `feat/88-marketplace-apm-conversion` (commit `92e7ff2`, "docs(kyberforge): narrow issue #89 scope, migrate CC platform facts to apm-workflow"), this issue's execution now also includes **deleting `plugin-author`/`marketplace-author`** once `apm compile`/`apm pack` output is verified to have parity with what's hand-maintained today. The "Verify the compiled output has parity ... before considering any provider manifest hand-authoring retired" bullet above now means, specifically: retiring = deleting those two skills. Before deleting them, see ADR-0015's "Content migration out of `plugin-author`/`marketplace-author`" section for the full audit of what needs to be preserved elsewhere first: - Claude Code platform constraints (reserved plugin-name prefixes, the ADR-0010 `agents/`-directory stray-file validator gotcha, `claude plugin validate` as a required terminal check) — already carried into `apm-workflow`'s reference docs as of this correction, so no further action needed on those specifically. - Dual-manifest-only conventions (ADR-0006 version-parity/patch-bump rule, CC-vs-Copilot field-placement split) are obsolete under `apm.yml`'s single-manifest model and were deliberately dropped — not carried forward. - **Still unresolved, and this issue's to decide:** `marketplace-author`'s catalog version-bump convention (minor bump for package add/remove, patch bump for field-only updates) isn't an APM mechanic, but is still a meaningful holocron policy worth re-applying to `apm.yml`'s `marketplace.packages[].version` field. Where/how to re-apply it is #90's decision, not resolved by ADR-0015.
Author
Collaborator

Executed on branch feat/90-execute-apm-conversion, commit fd08b79 (not pushed yet, no PR opened). Full rationale is in the commit message — this comment covers what isn't there.

⚠️ Open question before this can be considered actually done

Claude Code's native plugin loader appears to have no awareness of .apm/ at all. Checked the installed claude binary directly (strings on the CLI executable) for any literal reference to .apm/ or apm.yml — found zero. Its plugin-loading convention is a flat skills//agents//commands//hooks/ directory scan at the plugin root (confirmed indirectly too: the stale installed plugin cache at ~/.claude/plugins/cache/holocron/kyberforge/1.3.1/ mirrors the old flat layout verbatim, meaning that's what Claude Code's installer actually copied).

Root apm.yml's marketplace source: fields still point at the plugin root (./plugins/bin, etc.) — not at an apm pack-generated bundle. apm pack's only flat-skills/-mirroring output is build/<name>-<version>/, a distribution artifact nothing currently points the marketplace at.

Net effect: it's currently unverified whether Claude Code can actually discover any skill/agent content in these plugins when it (re)installs them from this marketplace, despite claude plugin validate --strict passing clean on all 6 (that check validates manifest shape, not skill discoverability — confirmed via strings/behavioral testing, not by reading validator source). I started a live behavioral test (claude -p ... --plugin-dir) to settle this empirically but was told to defer it mid-session, so it's unresolved, not disproven. This needs to be checked (or a way to bridge .apm/ → flat convention dirs needs to be added) before treating this conversion as functionally complete, not just manifest-complete.

Other things worth knowing

  • mattpocock-skills is now pinned, where it was previously unpinned. apm pack refuses to build against a mutable branch ref (main) — pinned to version: "^1.2.0", which resolved to v1.2.3 (SHA 835450e) at pack time.
  • .github/plugin/marketplace.json (the Copilot marketplace mirror) was not touched by this conversion and is now stale. Confirmed via apm_cli's own output_profiles.py source: only claude and codex marketplace output profiles exist — there is no native Copilot marketplace output. This file has no automated regeneration path going forward; needs a decision (hand-mirror it, drop it, or something else).
  • apm CLI install: the documented quick-install (curl -sSL https://aka.ms/apm-unix | sh) failed mid-download in this environment (GitHub release asset download died). Used pipx install apm-cli instead — now documented as a fallback in apm-install's own SKILL.md.
  • Both parity gates that matter for an eventual PR are green locally: apm audit --ci, apm marketplace check, claude plugin validate --strict (×6), check-manifests.sh, and the full test suite (165/165 bats, 13/13 shell scripts).

Before closing

  1. Resolve the runtime-loading question above — it's the one thing that could mean this isn't actually done despite every check passing.
  2. Decide on .github/plugin/marketplace.json's fate.
  3. Push the branch and open a PR (nothing pushed yet — needs your explicit go-ahead).

Not closing the issue myself pending those.

Executed on branch `feat/90-execute-apm-conversion`, commit `fd08b79` (not pushed yet, no PR opened). Full rationale is in the commit message — this comment covers what isn't there. ## ⚠️ Open question before this can be considered actually done Claude Code's native plugin loader appears to have **no awareness of `.apm/` at all**. Checked the installed `claude` binary directly (`strings` on the CLI executable) for any literal reference to `.apm/` or `apm.yml` — found zero. Its plugin-loading convention is a flat `skills/`/`agents/`/`commands/`/`hooks/` directory scan at the plugin root (confirmed indirectly too: the stale installed plugin cache at `~/.claude/plugins/cache/holocron/kyberforge/1.3.1/` mirrors the old flat layout verbatim, meaning that's what Claude Code's installer actually copied). Root `apm.yml`'s marketplace `source:` fields still point at the plugin root (`./plugins/bin`, etc.) — not at an `apm pack`-generated bundle. `apm pack`'s only flat-`skills/`-mirroring output is `build/<name>-<version>/`, a distribution artifact nothing currently points the marketplace at. Net effect: it's currently unverified whether Claude Code can actually discover any skill/agent content in these plugins when it (re)installs them from this marketplace, despite `claude plugin validate --strict` passing clean on all 6 (that check validates manifest shape, not skill discoverability — confirmed via `strings`/behavioral testing, not by reading validator source). I started a live behavioral test (`claude -p ... --plugin-dir`) to settle this empirically but was told to defer it mid-session, so it's unresolved, not disproven. This needs to be checked (or a way to bridge `.apm/` → flat convention dirs needs to be added) before treating this conversion as functionally complete, not just manifest-complete. ## Other things worth knowing - **`mattpocock-skills` is now pinned**, where it was previously unpinned. `apm pack` refuses to build against a mutable branch ref (`main`) — pinned to `version: "^1.2.0"`, which resolved to `v1.2.3` (SHA `835450e`) at pack time. - **`.github/plugin/marketplace.json` (the Copilot marketplace mirror) was not touched** by this conversion and is now stale. Confirmed via `apm_cli`'s own `output_profiles.py` source: only `claude` and `codex` marketplace output profiles exist — there is no native Copilot marketplace output. This file has no automated regeneration path going forward; needs a decision (hand-mirror it, drop it, or something else). - **apm CLI install**: the documented quick-install (`curl -sSL https://aka.ms/apm-unix | sh`) failed mid-download in this environment (GitHub release asset download died). Used `pipx install apm-cli` instead — now documented as a fallback in `apm-install`'s own SKILL.md. - Both parity gates that matter for an eventual PR are green locally: `apm audit --ci`, `apm marketplace check`, `claude plugin validate --strict` (×6), `check-manifests.sh`, and the full test suite (165/165 bats, 13/13 shell scripts). ## Before closing 1. Resolve the runtime-loading question above — it's the one thing that could mean this isn't actually done despite every check passing. 2. Decide on `.github/plugin/marketplace.json`'s fate. 3. Push the branch and open a PR (nothing pushed yet — needs your explicit go-ahead). Not closing the issue myself pending those.
Author
Collaborator

Update: pushed. Branch is now on the remote at commit 5e23250 — PR not opened yet: https://git.dev.rkdr.net/Defame1297/holocron/pulls/new/feat/90-execute-apm-conversion

.github/plugin/marketplace.json (item 2) — fixed

Synced it back to mirror the compiled .claude-plugin/marketplace.json, restoring the byte-identical parity the two files had before this conversion (confirmed they were identical pre-conversion, so this is the same mirroring marketplace-author used to do by hand — just done once manually rather than by a skill). It'll go stale again on the next apm pack unless re-synced by hand or someone builds tooling for it — no native Copilot marketplace output exists in apm to automate this away.

The pre-push hook's validate-marketplace --strict check caught something real: the compiled .claude-plugin/marketplace.json was missing its top-level description/version fields entirely (this is the exact gap I'd flagged as "not just formatting" during Phase C, now confirmed as an actual failure, not just a cosmetic concern).

Root cause, confirmed via apm_cli's own source (marketplace/output_mappers.py): the Claude marketplace mapper only writes description/version into the compiled output when they're set as an explicit override inside the marketplace: block of apm.yml — the top-level apm.yml description:/version: fields are computed into an internal fallback value but then silently dropped by the output mapper, never reaching the compiled JSON. name doesn't have this problem (always written unconditionally); only description and version do.

Fixed by adding explicit marketplace.description:/marketplace.version: overrides to root apm.yml (duplicating the top-level values — a real apm rough edge, not a holocron-specific choice). All local gates green again after the fix: claude plugin validate --strict on the marketplace manifest, apm marketplace check, apm audit --ci, and the full pre-push hook suite (which is what actually caught this — the earlier local checks I'd run didn't include this specific validator).

Still outstanding

The runtime skill/agent-discovery question from the previous comment is still open — deferred, not resolved. Everything else (parity gates, .github/plugin/marketplace.json, the description/version gap) is now fixed and pushed.

Update: pushed. Branch is now on the remote at commit `5e23250` — PR not opened yet: https://git.dev.rkdr.net/Defame1297/holocron/pulls/new/feat/90-execute-apm-conversion ## `.github/plugin/marketplace.json` (item 2) — fixed Synced it back to mirror the compiled `.claude-plugin/marketplace.json`, restoring the byte-identical parity the two files had before this conversion (confirmed they were identical pre-conversion, so this is the same mirroring `marketplace-author` used to do by hand — just done once manually rather than by a skill). It'll go stale again on the next `apm pack` unless re-synced by hand or someone builds tooling for it — no native Copilot marketplace output exists in `apm` to automate this away. ## A second, related apm gap found while pushing The pre-push hook's `validate-marketplace --strict` check caught something real: the compiled `.claude-plugin/marketplace.json` was missing its top-level `description`/`version` fields entirely (this is the exact gap I'd flagged as "not just formatting" during Phase C, now confirmed as an actual failure, not just a cosmetic concern). Root cause, confirmed via `apm_cli`'s own source (`marketplace/output_mappers.py`): the Claude marketplace mapper only writes `description`/`version` into the compiled output when they're set as an **explicit override inside the `marketplace:` block** of `apm.yml` — the top-level `apm.yml` `description:`/`version:` fields are computed into an internal fallback value but then silently dropped by the output mapper, never reaching the compiled JSON. `name` doesn't have this problem (always written unconditionally); only `description` and `version` do. Fixed by adding explicit `marketplace.description:`/`marketplace.version:` overrides to root `apm.yml` (duplicating the top-level values — a real apm rough edge, not a holocron-specific choice). All local gates green again after the fix: `claude plugin validate --strict` on the marketplace manifest, `apm marketplace check`, `apm audit --ci`, and the full pre-push hook suite (which is what actually caught this — the earlier local checks I'd run didn't include this specific validator). ## Still outstanding The runtime skill/agent-discovery question from the previous comment is still open — deferred, not resolved. Everything else (parity gates, `.github/plugin/marketplace.json`, the description/version gap) is now fixed and pushed.
Claude reopened this issue 2026-08-13 07:38:33 +00:00
Author
Collaborator

Reopening: the Definition of Done isn't actually met, despite every automated gate (apm audit --ci, claude plugin validate --strict ×6, apm marketplace check) passing clean.

Confirmed via empirical test (claude plugin install git@holocron, gitea@holocron, kyberforge@holocron): all three report Skills (0) Agents (0) Hooks (0) MCP servers (0). Root cause: skill/agent content moved to plugins/<name>/.apm/{skills,agents}/ on this branch, which Claude Code's installer does not scan (it only scans flat skills//agents//hooks/ at the plugin root — confirmed by inspecting the installed plugin cache layout, which still uses the flat convention). The old skills/agents/hooks/mcpServers pointer fields were also deleted from every plugin.json rather than repointed. Running apm pack — the documented fix — doesn't resolve it either: it bundles content into build/<name>-<version>/, a directory nothing in marketplace.json's source: ./plugins/<name> points at. This is exactly the "runtime-loading question" flagged as unresolved/deferred in the prior comment on this issue — not disproven, confirmed as a real bug.

Deferring the following to the next session, batched with the git-hooks/CI work (they share the same root cause and packaging-fix path):

  1. Plugin discoverability (above) — needs a real fix connecting apm pack's output (or a bridge) to what the marketplace source / Claude's installer actually reads.
  2. scripts/check-manifests.sh silently no-ops. It validates the skills/hooks/mcpServers/agents fields in plugin.json, but since those fields were deleted (not repointed) on this branch, an absent field reads as "nothing to check" and the script passes clean. The pre-push gate this repo relies on can no longer catch a plugin shipping zero content — it should have caught finding #1 and didn't.
  3. No CI drift gate for compiled manifests. ADRs/CONTEXT.md now assert plugin.json/marketplace.json are compiled output of apm pack, not hand-edited — but nothing in CI enforces that. Worth an apm pack --check-clean-equivalent gate.
  4. Root plugins/<name>/plugin.json is a stale third manifest. apm pack only writes .claude-plugin/plugin.json and .github/plugin/plugin.json — the root-level plugins/<name>/plugin.json is never written by it at all, yet check-manifests.sh still reads fields from it. Decide whether to delete it or wire it into the packing output.

Minor, not blocking: the branch's commit message claims plugin-scope agents "now carry only name/description/model/source_keys" — in practice all 4 converted agents omit model:. Per ADR-0016's own template, model is optional (omitting it means inherit the runtime default), so this isn't a bug, just an inaccurate commit message. No action needed.

Everything else from the original Definition of Done checklist verified clean: all 6 plugins have apm.yml+.apm/, plugin-author/marketplace-author deleted, compiled-output parity holds (only cosmetic diffs), .github/plugin/marketplace.json mirror is byte-identical, and CONTEXT.md/ADR-0001/0006/0010/0015 are substantively updated.

Reopening: the Definition of Done isn't actually met, despite every automated gate (`apm audit --ci`, `claude plugin validate --strict` ×6, `apm marketplace check`) passing clean. **Confirmed via empirical test** (`claude plugin install git@holocron`, `gitea@holocron`, `kyberforge@holocron`): all three report `Skills (0) Agents (0) Hooks (0) MCP servers (0)`. Root cause: skill/agent content moved to `plugins/<name>/.apm/{skills,agents}/` on this branch, which Claude Code's installer does not scan (it only scans flat `skills/`/`agents/`/`hooks/` at the plugin root — confirmed by inspecting the installed plugin cache layout, which still uses the flat convention). The old `skills`/`agents`/`hooks`/`mcpServers` pointer fields were also deleted from every `plugin.json` rather than repointed. Running `apm pack` — the documented fix — doesn't resolve it either: it bundles content into `build/<name>-<version>/`, a directory nothing in `marketplace.json`'s `source: ./plugins/<name>` points at. This is exactly the "runtime-loading question" flagged as unresolved/deferred in the prior comment on this issue — not disproven, confirmed as a real bug. **Deferring the following to the next session, batched with the git-hooks/CI work (they share the same root cause and packaging-fix path):** 1. **Plugin discoverability** (above) — needs a real fix connecting `apm pack`'s output (or a bridge) to what the marketplace source / Claude's installer actually reads. 2. **`scripts/check-manifests.sh` silently no-ops.** It validates the `skills`/`hooks`/`mcpServers`/`agents` fields in `plugin.json`, but since those fields were deleted (not repointed) on this branch, an absent field reads as "nothing to check" and the script passes clean. The pre-push gate this repo relies on can no longer catch a plugin shipping zero content — it should have caught finding #1 and didn't. 3. **No CI drift gate for compiled manifests.** ADRs/CONTEXT.md now assert `plugin.json`/`marketplace.json` are compiled output of `apm pack`, not hand-edited — but nothing in CI enforces that. Worth an `apm pack --check-clean`-equivalent gate. 4. **Root `plugins/<name>/plugin.json` is a stale third manifest.** `apm pack` only writes `.claude-plugin/plugin.json` and `.github/plugin/plugin.json` — the root-level `plugins/<name>/plugin.json` is never written by it at all, yet `check-manifests.sh` still reads fields from it. Decide whether to delete it or wire it into the packing output. **Minor, not blocking:** the branch's commit message claims plugin-scope agents "now carry only name/description/model/source_keys" — in practice all 4 converted agents omit `model:`. Per ADR-0016's own template, `model` is optional (omitting it means inherit the runtime default), so this isn't a bug, just an inaccurate commit message. No action needed. Everything else from the original Definition of Done checklist verified clean: all 6 plugins have `apm.yml`+`.apm/`, `plugin-author`/`marketplace-author` deleted, compiled-output parity holds (only cosmetic diffs), `.github/plugin/marketplace.json` mirror is byte-identical, and CONTEXT.md/ADR-0001/0006/0010/0015 are substantively updated.
Author
Collaborator

Follow-up cleanup pushed: 7910b8b (docs(kyberforge): fix path drift and content gaps from apm conversion), on top of 5e23250, branch feat/90-execute-apm-conversion. All local gates (full test suite, manifest checks, Vale sync, scope walk-up, marketplace validation) passed clean on push.

Fixed the remaining review findings that were in-scope for this session (everything except the deferred items in the previous comment — those still need the discoverability fix first):

  • ADR-0014 — updated 6 stale flat-path references to .apm/ nesting, verified against actual on-disk paths and the live .pre-commit-hooks.yaml.
  • ADR-0015 — corrected an inaccurate claim that ADR-0014 had both a skills/ and an agents/ path regex updated; ADR-0014 never had an agents/-path regex (its one "agents" mention is a Vale glob-section identifier, not a filesystem path).
  • CONTEXT.md — fixed the Skill glossary entry, the Vale-prefilter section, and the stale "pending issue #90 (not yet changed)" forward-pointer for plugin-author/marketplace-author (both are deleted now).
  • LESSONS.md and two skill test READMEs — fixed stale paths missing the .apm/ segment.
  • apm-workflow/references/marketplace.md — found a real content gap, not just a stale link: the Claude Code reserved-plugin-name-prefix list was never actually carried into apm-workflow during the conversion, despite ADR-0015 claiming it was. Recovered it from git history (anthropic-*, claude-*, agent-skills, official-claude-plugins) and inlined it directly.
  • Bonus: an example in agent-author/references/deployment-modes.md contradicted its own stated .apm/agents/ convention two lines above.

AGENTS.md's hand-edit was also retroactively audited via core:agentsmd-audit — passed clean, no fix needed.

No PR opened yet — link is up (https://git.dev.rkdr.net/Defame1297/holocron/pulls/new/feat/90-execute-apm-conversion) whenever that's wanted. Still open pending the discoverability fix and the rest of the deferred git-hooks/CI batch from the previous comment.

Follow-up cleanup pushed: `7910b8b` (`docs(kyberforge): fix path drift and content gaps from apm conversion`), on top of `5e23250`, branch `feat/90-execute-apm-conversion`. All local gates (full test suite, manifest checks, Vale sync, scope walk-up, marketplace validation) passed clean on push. Fixed the remaining review findings that were in-scope for this session (everything **except** the deferred items in the previous comment — those still need the discoverability fix first): - **ADR-0014** — updated 6 stale flat-path references to `.apm/` nesting, verified against actual on-disk paths and the live `.pre-commit-hooks.yaml`. - **ADR-0015** — corrected an inaccurate claim that ADR-0014 had both a `skills/` and an `agents/` path regex updated; ADR-0014 never had an `agents/`-path regex (its one "agents" mention is a Vale glob-section identifier, not a filesystem path). - **CONTEXT.md** — fixed the Skill glossary entry, the Vale-prefilter section, and the stale "pending issue #90 (not yet changed)" forward-pointer for `plugin-author`/`marketplace-author` (both are deleted now). - **LESSONS.md** and two skill test READMEs — fixed stale paths missing the `.apm/` segment. - **`apm-workflow/references/marketplace.md`** — found a real content gap, not just a stale link: the Claude Code reserved-plugin-name-prefix list was never actually carried into `apm-workflow` during the conversion, despite ADR-0015 claiming it was. Recovered it from git history (`anthropic-*`, `claude-*`, `agent-skills`, `official-claude-plugins`) and inlined it directly. - Bonus: an example in `agent-author/references/deployment-modes.md` contradicted its own stated `.apm/agents/` convention two lines above. `AGENTS.md`'s hand-edit was also retroactively audited via `core:agentsmd-audit` — passed clean, no fix needed. No PR opened yet — link is up (https://git.dev.rkdr.net/Defame1297/holocron/pulls/new/feat/90-execute-apm-conversion) whenever that's wanted. Still open pending the discoverability fix and the rest of the deferred git-hooks/CI batch from the previous comment.
Author
Collaborator

Progress update — feat/90-execute-apm-conversion just pushed with 8 commits since the last push:

Core fix — plugin content bridge

  • 38f1ba4 bridges .apm/ content to Claude Code's flat plugin discovery: Claude Code and Copilot convention-scan agents/, skills/, commands/, etc. at the plugin root and have zero awareness of apm's .apm/ nesting (confirmed empirically — a live claude --plugin-dir test showed Skills(0) Agents(0) before the fix). scripts/sync-plugin-content.sh now mirrors .apm/{agents,skills,commands,instructions,extensions,hooks} into the flat convention dirs via apm pack --format plugin, reusing apm's own .apm/→plugin mapping instead of custom drift logic. Applied across all 6 plugins; stale root-level plugin.json duplicates removed; scripts/check-manifests.sh rewritten for the new contract. Documented in ADR-0017.

CI/audit gates (apm-native)

  • 6e77c11 adds pre-push gates using apm's own tooling rather than custom checks: apm marketplace check (remote ref reachability), apm audit --ci (lockfile/policy/hidden-content integrity), apm pack --check-versions --check-clean --dry-run (closes this issue's deferred "check-clean-equivalent gate" item).
  • 5f42f57 enables codex marketplace output.
  • b0936ad fixes plugin.json going stale after name/version/description edits by forcing regeneration on every real (non---check) sync.

Performance (pre-push gate: 2m40s → 1m12s, ~2.2x)

  • c3a56d8 scopes the skill-frontmatter pre-commit hook to .apm/ only (it was redundantly re-validating the compiled mirror copy too) and parallelizes sync-plugin-content.sh's per-plugin apm pack calls (3.14s → 1.28s in --check mode).
  • a8beff7 parallelizes both test runners (tests/run-bats.sh, tests/run-tests.sh) using bounded background jobs — no new dependencies (bats' native --jobs needs GNU parallel, which isn't installed, so this uses bash's own job control instead). Verified fixture isolation first (all tests use their own mktemp dirs, nothing touches the live repo tree), and verified correctness on both pass and fail paths.

All work verified via bash tests/run-tests.sh (green) and a full pre-commit run --all-files --hook-stage pre-push (all 13 hooks passing, confirmed again on this push). Branch not yet opened as a PR — let me know if you'd like that next.

Progress update — `feat/90-execute-apm-conversion` just pushed with 8 commits since the last push: **Core fix — plugin content bridge** - `38f1ba4` bridges `.apm/` content to Claude Code's flat plugin discovery: Claude Code and Copilot convention-scan `agents/`, `skills/`, `commands/`, etc. at the plugin root and have zero awareness of apm's `.apm/` nesting (confirmed empirically — a live `claude --plugin-dir` test showed `Skills(0) Agents(0)` before the fix). `scripts/sync-plugin-content.sh` now mirrors `.apm/{agents,skills,commands,instructions,extensions,hooks}` into the flat convention dirs via `apm pack --format plugin`, reusing apm's own `.apm/`→plugin mapping instead of custom drift logic. Applied across all 6 plugins; stale root-level `plugin.json` duplicates removed; `scripts/check-manifests.sh` rewritten for the new contract. Documented in ADR-0017. **CI/audit gates (apm-native)** - `6e77c11` adds pre-push gates using apm's own tooling rather than custom checks: `apm marketplace check` (remote ref reachability), `apm audit --ci` (lockfile/policy/hidden-content integrity), `apm pack --check-versions --check-clean --dry-run` (closes this issue's deferred "check-clean-equivalent gate" item). - `5f42f57` enables codex marketplace output. - `b0936ad` fixes `plugin.json` going stale after name/version/description edits by forcing regeneration on every real (non-`--check`) sync. **Performance (pre-push gate: 2m40s → 1m12s, ~2.2x)** - `c3a56d8` scopes the `skill-frontmatter` pre-commit hook to `.apm/` only (it was redundantly re-validating the compiled mirror copy too) and parallelizes `sync-plugin-content.sh`'s per-plugin `apm pack` calls (3.14s → 1.28s in `--check` mode). - `a8beff7` parallelizes both test runners (`tests/run-bats.sh`, `tests/run-tests.sh`) using bounded background jobs — no new dependencies (bats' native `--jobs` needs GNU parallel, which isn't installed, so this uses bash's own job control instead). Verified fixture isolation first (all tests use their own `mktemp` dirs, nothing touches the live repo tree), and verified correctness on both pass and fail paths. All work verified via `bash tests/run-tests.sh` (green) and a full `pre-commit run --all-files --hook-stage pre-push` (all 13 hooks passing, confirmed again on this push). Branch not yet opened as a PR — let me know if you'd like that next.
Sign in to join this conversation.