Seven ADRs described code that no longer exists or behaviour the gates do
not have. Where the wrong text came from main it carries a dated
correction; where this branch introduced it, it is fixed in place, because
main never published it and there is no record to preserve.
Fixed in place, branch-introduced:
- ADR-0021's 2026-09-14 correction asserted apm audit --ci "was never a
drift gate at all". It is one: it replays the install and diffs. The
claim contradicted this branch's own AGENTS.md and gates.md.
- ADR-0015 said unconditionally that no pre-push hook needs the network.
The guarantee holds only once apm install has populated apm_modules/.
- ADR-0014's 2026-09-16 correction said restoring .pre-commit-hooks.yaml
would ship a hook that fails for every consumer, because their checkout
has no lib-boundary-resolver.sh. pre-commit clones the whole hook repo
and skill-size-check.sh resolves the library from BASH_SOURCE, so the
hook would work.
- ADR-0019's "twelve hooks pass under unshare -rn" matched neither HEAD
(8) nor main (14), and stated the offline guarantee unconditionally.
Corrected, inherited from main:
- ADR-0022 and ADR-0013 named skill-frontmatter's pre-commit hook as the
enforcer of mandatory metadata.version. That hook was deleted on this
branch; the check lives in skill-size-check.sh.
- ADR-0022 enumerated the tip rule's carve-outs as a closed list and
described a single merge-base. The gate also exempts a tree-identical
skill and intersects every base from merge-base --all, and emits a third
failure form. 8cfd54f said the documented behaviour did not change; it
did. The gate is correct and is unchanged -- the record was not.
- ADR-0020's Decision still routed description overflow to README.md, its
ADR-0025 amendment pointed the mirrored constants at validate.sh, which
holds none, and its Enforcement table still named the two deleted
validate.sh paths.
- ADR-0015's Status claimed every plugin's plugin.json is pack output;
none exist.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NwD8Egs5r4ndqeFLmhusX2
16 KiB
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.
Correction (2026-09-20): the present tense above has expired for plugin.json. ADR-0024 made
apm the only supported install path and deleted per-plugin plugin.json with the native install
support that needed it. No plugin carries one at HEAD — git ls-files | grep -c 'plugin\.json'
returns 0 — so .claude-plugin/marketplace.json is the only apm pack-compiled output left. Read
the Status line as the state at execution, 2026-08-12.
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.jsonand per-providerplugin.jsonfiles become compiled output viaapm compile/apm pack, generated fromapm.yml+.apm/per plugin, extensible to otherapm 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 toplugins/<name>/.apm/skills/andplugins/<name>/.apm/agents/*.agent.md. - New operational tooling —
apm-install(skill),apm-workflow(skill),apm-orchestrate(agent) — lands inkyberforge, 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).forgeis 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-authorare not adapted — they are superseded and deleted. Unlikeskill-author/agent-author, nothing in these two skills carries forward as authoring routing:apm compile/apm packwill generate.claude-plugin/marketplace.jsonand per-providerplugin.jsondirectly fromapm.yml+.apm/, soapm-install/apm-workflow/apm-orchestrate(issue #88, already landed on this branch) fully replace what these two skills did.plugin-author/marketplace-authorwere deleted in issue #90's execution.- Translating the existing plugins into
apm.yml+.apm/and running the real conversion was executed under issue #90 (https://git.dev.rkdr.net/Defame1297/holocron/issues/90), which tracks that work through to merge. 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. Superseded 2026-08-17: CONTEXT.md was cut back to one-line definitions, and the compiled-output model is now described indocs/spec/architecture.md. The same trim deleted the "lint plugin" entry cited under Considered options below; that pointer now readsdocs/spec/architecture.md's plugin scope table, which carries the repo-agnostic-versus-marketplace-specific argument.
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 docs/spec/architecture.md's plugin scope table) — 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 validateas a required terminal check) have been added intoapm-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.Correction (2026-09-19): "ADR-0006's version-parity/patch-bump rule" misattributes the patch-bump half. ADR-0006 states a version-parity rule and nothing about patch bumps — the string
patchdoes not appear in it (git show origin/main:docs/adr/0006-plugin-version-parity.md). Only the parity half was ADR-0006's, and only that half was dropped. A patch-bump rule does exist and is live:plugins/kyberforge/.apm/skills/apm-workflow/references/configure.md— bump a package's ownapm.ymlversion:whenever anything reaching its compiled output changes. ADR-0024 §4 repeated this misattribution and is corrected there too. - 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 —apmdoesn'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 insideapm-workflow's reference docs (references/marketplace.mdfor the root catalog version rule,references/configure.mdfor the per-package version-bump-on-content-edit rule), applied manually by whoever editsapm.yml.
Consequences
- ADR-0001 is superseded (issue #90).
- ADR-0006 (plugin-version-parity) is moot (issue #90):
plugin.json/marketplace.jsonare now compiled output of a singleapm.yml, so there's no second hand-authored file left to keep in parity, andplugin-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.mdextension 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 aplugins/<name>/agents/...path) updated for the.apm/nesting as part of issue #90's execution. kyberforgegained 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.mdcompiles verbatim to both Claude and Copilot, so those files carry only the fields in theapm-agent-allowlistsection ofplugins/kyberforge/.apm/skills/agent-audit/references/field-inventory.md(nowfactory-audit/references/agent-field-inventory.md, see ADR-0025) (as amended 2026-08-14:name/description/model/source_keys/disallowedTools) — existing dual-file<name>.md+<name>.agent.mdpairs could not be raw-moved, only re-authored. - Two follow-up issues tracked the remaining work: #89 (
skill-author/agent-authorrouting adaptation — closed, merged in #93) and #90 (the actual repo conversion, which also deletedplugin-author/marketplace-author— tracked through to merge; treat #90's own state as the authority on whether it has landed, not this line). displayNameis gone from all six compiledplugin.jsonfiles — accepted, not overlooked.apm.ymlhas no key that compiles to it:synthesize_plugin_json_from_apm_yml(apm_cli/deps/plugin_parser.py) emits onlyname,version,description,author,license,homepage,repositoryandkeywords, and nothing inplugin_manifest.pyaddsdisplayNameafterwards. So everyplugins/<name>/.claude-plugin/plugin.jsonnow carriesauthor/description/homepage/keywords/license/name/repository/version(plusmcpServersforbin) and nodisplayName. The field is optional —plugins/kyberforge/docs/research/docs/claude-code-plugins/api-reference.md:14listsdisplayNameasRequired: No, "Human-readable name shown in plugin manager" — which is whyclaude plugin validate --strictstill passes on all six. The visible cost is that the plugin manager falls back to the barenameas each plugin's label. Accepted as the price ofapm.ymlbeing the single authoring source: re-injectingdisplayNamepost-compile would mean a secondreinject_*workaround of the kind ADR-0017's amendment reserves for fields apm strips on a factually wrong premise, and apm's premise here is simply that the key does not exist in its schema.owner.emailwas dropped by mistake and has been restored (2026-08-14). An earlier revision of this ADR listedowner.emailalongsidedisplayNameas a fieldapm.yml"has no key that compiles to." That was wrong.apm_cli/marketplace/yml_schema.py:186defines_AUTHOR_OBJECT_KEYS = frozenset({"name", "email", "url"}), and anemail:under rootapm.yml'smarketplace.ownerblock was empirically confirmed to compile straight through into.claude-plugin/marketplace.json'sowner. The key is declared in rootapm.ymlagain and the compiledownerblock is{name, email, url}. OnlydisplayNameis a genuine schema gap; this one was a documentation error that removed working configuration.mattpocock-skillsis pinned to an exact version, and the pin is advanced by hand. Pre-conversion the entry was{"repo": "mattpocock/skills", "source": "github"}— an unpinned reference that tracked the upstream default branch, so consumers got whatever was on it at install time. The conversion first replaced that withversion: "^1.2.0", which was still not a pin: a caret range has nothing to freeze it, because there is no lockfile formarketplace.packages[].apm packre-resolved the range against upstream on every run, so an upstreamv1.2.4would immediately invalidate the committedref/shaand failapm-pack-check-cleanwith exit 4 — blocking every push in the repo, triggered by a third party at an unrelated moment, with no local change to explain it. Rootapm.ymltherefore declares an exactversion: "1.2.3", whichapm packfreezes into.claude-plugin/marketplace.jsonasref: v1.2.3+ an explicitsha. Two consequences, both intended: the committed ref/sha is genuinely reproducible and cannot move under the repo, and picking up a new upstream release is a deliberate act — a human edits theversion:string in rootapm.ymland re-runsapm pack. apm has no version-bump automation (established under "Versioning" in issue #90's plan), so an ageing pin is the accepted cost of a push gate that only fires on this repo's own changes. Note the pin does not make the entry offline-resolvable: an exact version still requires agit ls-remote, which is why two pre-push hooks needed the network (seeAGENTS.md). Superseded 2026-09-13: themattpocock-skillsentry has been removed from rootapm.ymlentirely, along with thecodexmarketplace output profile. No pre-push hook needs the network any longer — onceapm installhas populatedapm_modules/. The guarantee is a property of a populated install, not of the hook set: on a fresh cloneapm-audit-ci'sdeployed-files-presentfails outright, and itsdriftandconfig-consistencyinstall-replays have no cache to replay from and clone from the holocron remote (README.md:89;docs/spec/gates.md, "Pushing without a network").- 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 reportedSkills (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 byscripts/sync-plugin-content.sh) — see that ADR for the root cause and the fix. Superseded 2026-09-14: ADR-0024 deleted that mirror and its generator along with nativeclaude plugin installsupport. The discoverability gap this paragraph describes is therefore no longer bridged — it is no longer a gap this repo has, because apm is now the only supported install path and apm reads.apm/directly.