Execute the plugin→APM conversion #90
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
The actual conversion work — use
apm-install/apm-workflow/apm-orchestrate(built in #88) plusagent-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.jsonbecome compiled output ofapm compile/apm pack. Once parity is verified, deleteplugin-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
Directory naming: keep
plugins/<name>/. No rename topackages/<name>/. Confirmed indocs/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, andsource: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 referencesplugins/<name>/..., for zero functional gain.Versioning:
apm.yml'smarketplace.versioning: { strategy: per_package }, with each plugin's real independent version declared inmarketplace.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.apm.yml's ownversion(the marketplace catalog's identity version, currently0.3.1) keepsmarketplace-author's old convention: minor bump on package add/remove, patch bump for marketplace-block-only field edits.apm.ymlversionis bumped manually by whoever edits that plugin's.apm/content. Confirmed via the CLI reference/configuration/examples/troubleshooting research docs:apmhas no native version-bump automation (noapm version bump, nothing changelog- or conventional-commits-driven) — so no new script gets built for this. Instead, document both rules as guidance insideapm-workflow's existing reference files (doc-only addition, not new tooling):references/marketplace.md— state the minor/patch root-version rule, tied to theadd-packageoperation / marketplace-block edits.references/configure.md— state thatedit-configchanging a package's own.apm/content should bump that package's ownapm.ymlversion.mattpocock-skills(remote GitHub-sourced entry, not a plugin this repo owns) needs noapm.yml/.apm/scaffolding. It becomes a plainmarketplace.packages[]entry in rootapm.ymlwithsource: mattpocock/skills(the plain-repo shorthandpackages[].sourceaccepts — confirmed inconfiguration.md), replacing the currentsource: {repo, source: "github"}JSON shape.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-packagecalls land in the same rootapm.ymlfile — a shared-state hazard, not a dependency-ordering one).Parity verification gate (must all pass clean before deleting
plugin-author/marketplace-author):.claude-plugin/marketplace.jsonand each provider'splugin.jsonagainst the currently-committed versions — same plugin/skill/agent inventory and version numbers; formatting/field-order differences fromapm's serializer are expected and fine.claude plugin validate --strictpasses on every compiled plugin.apm audit --cipasses clean (plainapm auditis not CI-equivalent — seeapm-workflowSKILL.md Gotchas).Preconditions
apm --versionsucceeds before dispatching anything..apm/agents/*.agent.mdcompiles verbatim to both Claude and Copilot, so it must droptools:and all Claude-only fields (isolation,maxTurns,effort,memory,permissionMode). Do notgit mvthe existing dual<name>.md+<name>.agent.mdpair into.apm/agents/. Re-author each throughagent-authorin 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— invokingkyberforge:apm-orchestrate(andagent-author/skill-authorfor content migration). Each subagent's brief:.claude-plugin/plugin.json+ rootplugin.jsonfor real metadata (name,description,version,license,keywords,author).apm plugin init <name> --yesfrom insideplugins/<name>/(viaapm-orchestrate'sconfigure: init-package) — scaffoldsapm.yml+.apm/in place.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: autounless there's a reason to scope narrower.skills/<name>/→.apm/skills/<name>/): straight copy, content-identical across targets — plaingit mvis fine.agent-authorin plugin scope per the Preconditions note above — not a raw move.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 underincludes: auto. Confirm.mcp.jsonpassthrough empirically — no MCP-primitive compile mapping was found in the research corpus, so check whetherapm compileneeds an explicitdependencies.mcpentry instead.apm compilefor this package alone; fix errors before reporting done.apm.ymlwritten, content migrated, any surprises (feed forward — other plugins in the same batch may hit the same issue).Phase B — root marketplace registration (strictly sequential)
Then add
mattpocock-skillsdirectly as anapm.ymledit (notadd-package— it's a remote source, not a local path):source: mattpocock/skills. Apply the versioning decision (per-package strategy, each entry'sversion:set to that plugin's real current version) as part of this phase.Phase C — compile, pack, verify parity
git diffthe newly-compiled.claude-plugin/marketplace.jsonand eachplugin.jsonagainst 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 whatapm compile/apm packemits for Copilot's marketplace-equivalent output and whether.github/plugin/marketplace.jsonstill needs separate mirroring — not documented in the research corpus.Phase D — cleanup (only after Phase C passes clean)
plugins/kyberforge/skills/plugin-author/andplugins/kyberforge/skills/marketplace-author/..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.yamlneeds the same update or should stay layout-agnostic for external consumers.scripts/check-scope-walkup-sync.sh's hardcoded references to kyberforge's own script paths (they move under.apm/skills/).plugins/[^/]+/skills/orplugins/[^/]+/agents/assumption and fix each hit.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..apm/agents/path (project/user scope unaffected; plugin scope already redefined by ADR-0016).git:git-commits(Conventional Commits); do not push without explicit confirmation.Definition of done
apm.yml+.apm/;.claude-plugin/marketplace.jsonand everyplugin.jsonare compiled artifacts, not hand-edited.plugin-author/marketplace-authordeleted.CONTEXT.mdand ADR-0001/0006/0010/0015 reflect the post-conversion state.Depends on #88 (done). Benefits from #89 (done, merged in #93).
Research:
plugins/kyberforge/docs/research/docs/microsoft-apm/.Scope correction (per ADR-0015): per the ADR-0015 correction recorded on branch
feat/88-marketplace-apm-conversion(commit92e7ff2, "docs(kyberforge): narrow issue #89 scope, migrate CC platform facts to apm-workflow"), this issue's execution now also includes deletingplugin-author/marketplace-authoronceapm compile/apm packoutput 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:agents/-directory stray-file validator gotcha,claude plugin validateas a required terminal check) — already carried intoapm-workflow's reference docs as of this correction, so no further action needed on those specifically.apm.yml's single-manifest model and were deliberately dropped — not carried forward.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 toapm.yml'smarketplace.packages[].versionfield. Where/how to re-apply it is #90's decision, not resolved by ADR-0015.Executed on branch
feat/90-execute-apm-conversion, commitfd08b79(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 installedclaudebinary directly (stringson the CLI executable) for any literal reference to.apm/orapm.yml— found zero. Its plugin-loading convention is a flatskills//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 marketplacesource:fields still point at the plugin root (./plugins/bin, etc.) — not at anapm pack-generated bundle.apm pack's only flat-skills/-mirroring output isbuild/<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 --strictpassing clean on all 6 (that check validates manifest shape, not skill discoverability — confirmed viastrings/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-skillsis now pinned, where it was previously unpinned.apm packrefuses to build against a mutable branch ref (main) — pinned toversion: "^1.2.0", which resolved tov1.2.3(SHA835450e) at pack time..github/plugin/marketplace.json(the Copilot marketplace mirror) was not touched by this conversion and is now stale. Confirmed viaapm_cli's ownoutput_profiles.pysource: onlyclaudeandcodexmarketplace 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).curl -sSL https://aka.ms/apm-unix | sh) failed mid-download in this environment (GitHub release asset download died). Usedpipx install apm-cliinstead — now documented as a fallback inapm-install's own SKILL.md.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
.github/plugin/marketplace.json's fate.Not closing the issue myself pending those.
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) — fixedSynced 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 mirroringmarketplace-authorused to do by hand — just done once manually rather than by a skill). It'll go stale again on the nextapm packunless re-synced by hand or someone builds tooling for it — no native Copilot marketplace output exists inapmto automate this away.A second, related apm gap found while pushing
The pre-push hook's
validate-marketplace --strictcheck caught something real: the compiled.claude-plugin/marketplace.jsonwas missing its top-leveldescription/versionfields 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 writesdescription/versioninto the compiled output when they're set as an explicit override inside themarketplace:block ofapm.yml— the top-levelapm.ymldescription:/version:fields are computed into an internal fallback value but then silently dropped by the output mapper, never reaching the compiled JSON.namedoesn't have this problem (always written unconditionally); onlydescriptionandversiondo.Fixed by adding explicit
marketplace.description:/marketplace.version:overrides to rootapm.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 --stricton 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.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 reportSkills (0) Agents (0) Hooks (0) MCP servers (0). Root cause: skill/agent content moved toplugins/<name>/.apm/{skills,agents}/on this branch, which Claude Code's installer does not scan (it only scans flatskills//agents//hooks/at the plugin root — confirmed by inspecting the installed plugin cache layout, which still uses the flat convention). The oldskills/agents/hooks/mcpServerspointer fields were also deleted from everyplugin.jsonrather than repointed. Runningapm pack— the documented fix — doesn't resolve it either: it bundles content intobuild/<name>-<version>/, a directory nothing inmarketplace.json'ssource: ./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):
apm pack's output (or a bridge) to what the marketplace source / Claude's installer actually reads.scripts/check-manifests.shsilently no-ops. It validates theskills/hooks/mcpServers/agentsfields inplugin.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.plugin.json/marketplace.jsonare compiled output ofapm pack, not hand-edited — but nothing in CI enforces that. Worth anapm pack --check-clean-equivalent gate.plugins/<name>/plugin.jsonis a stale third manifest.apm packonly writes.claude-plugin/plugin.jsonand.github/plugin/plugin.json— the root-levelplugins/<name>/plugin.jsonis never written by it at all, yetcheck-manifests.shstill 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,modelis 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-authordeleted, compiled-output parity holds (only cosmetic diffs),.github/plugin/marketplace.jsonmirror is byte-identical, and CONTEXT.md/ADR-0001/0006/0010/0015 are substantively updated.Follow-up cleanup pushed:
7910b8b(docs(kyberforge): fix path drift and content gaps from apm conversion), on top of5e23250, branchfeat/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):
.apm/nesting, verified against actual on-disk paths and the live.pre-commit-hooks.yaml.skills/and anagents/path regex updated; ADR-0014 never had anagents/-path regex (its one "agents" mention is a Vale glob-section identifier, not a filesystem path).plugin-author/marketplace-author(both are deleted now)..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 intoapm-workflowduring the conversion, despite ADR-0015 claiming it was. Recovered it from git history (anthropic-*,claude-*,agent-skills,official-claude-plugins) and inlined it directly.agent-author/references/deployment-modes.mdcontradicted its own stated.apm/agents/convention two lines above.AGENTS.md's hand-edit was also retroactively audited viacore: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.
Progress update —
feat/90-execute-apm-conversionjust pushed with 8 commits since the last push:Core fix — plugin content bridge
38f1ba4bridges.apm/content to Claude Code's flat plugin discovery: Claude Code and Copilot convention-scanagents/,skills/,commands/, etc. at the plugin root and have zero awareness of apm's.apm/nesting (confirmed empirically — a liveclaude --plugin-dirtest showedSkills(0) Agents(0)before the fix).scripts/sync-plugin-content.shnow mirrors.apm/{agents,skills,commands,instructions,extensions,hooks}into the flat convention dirs viaapm pack --format plugin, reusing apm's own.apm/→plugin mapping instead of custom drift logic. Applied across all 6 plugins; stale root-levelplugin.jsonduplicates removed;scripts/check-manifests.shrewritten for the new contract. Documented in ADR-0017.CI/audit gates (apm-native)
6e77c11adds 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).5f42f57enables codex marketplace output.b0936adfixesplugin.jsongoing stale after name/version/description edits by forcing regeneration on every real (non---check) sync.Performance (pre-push gate: 2m40s → 1m12s, ~2.2x)
c3a56d8scopes theskill-frontmatterpre-commit hook to.apm/only (it was redundantly re-validating the compiled mirror copy too) and parallelizessync-plugin-content.sh's per-pluginapm packcalls (3.14s → 1.28s in--checkmode).a8beff7parallelizes both test runners (tests/run-bats.sh,tests/run-tests.sh) using bounded background jobs — no new dependencies (bats' native--jobsneeds GNU parallel, which isn't installed, so this uses bash's own job control instead). Verified fixture isolation first (all tests use their ownmktempdirs, 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 fullpre-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.