docs: correct the apm-only change after a five-agent review

A five-agent review of 718c79a and d2480b8 found no skill, agent or hook
regressions (39 skills before and after) and confirmed both hook removals
are genuinely moot -- verified against the tree, not taken on the commit's
word. It did find one functional regression (fixed separately) and this
documentation drift.

Counting errors, all from a git pathspec `*` crossing `/`:
  - 17 .bats files shipped to consumers is really 10; 17 counted tracked
    paths merely containing /tests/, one of them a template asset
  - "roughly 88s off every push" is ~92.4s; 88 omitted validate-plugins
  - "roughly 70% of each plugin remains live" holds only for kyberforge;
    the real spread is 44.3% (bin) to 70.6%, now a table
  - the pre-push enforcement row was half-corrected: 33 entries stood
    unstruck (now 27) and 14 -> 11 switched counting basis mid-sentence
  - the root .claude-plugin/plugin.json was described as "kept"; it has
    never been tracked

gates.md said "Ten hooks" above a nine-row table (11 was decremented for
one removal, not two), and "both need the claude CLI" for one remaining
validator. Its pretty-format-json exclude rationale claimed six
alternations expanding to sixteen files in a passage headed "Mind which
number you are quoting" -- four alternations, two live files; the two
dead ones are dropped from the pattern. check-useless-excludes could not
catch this: it only flags an exclude matching nothing at all.

ADR-0024 cited ADR-0006 for a patch-bump rule it does not contain and
which ADR-0015 explicitly retired; stated apm's marketplace probe order
backwards (.claude-plugin/ is the last candidate, not the first, so the
earlier .github/plugin/ deletion only demoted resolution); undercounted
apm's skill-deploying targets as seven when there are fifteen; and never
recorded that validate-plugins was removed. The symlink hedge is resolved:
apm_cli/security/gate.py's ignore_non_content() drops symlinks silently on
deploy while apm_modules/ materialization dereferences them, so content
survives that far and vanishes at install. Accepted with no replacement
guard, per decision -- kyberforge/docs/hooks.md previously asserted a
guard that had been deleted with its script.

Four plugin READMEs still advertised `claude plugin install`; ADRs 0001,
0006, 0013, 0014, 0015 and 0019 described deleted machinery in the present
tense, 0019 most consequentially as the live justification for the
SessionStart hook's .apm/ path. CONTEXT.md's "apm package" entry forbade
"plugin" while using it in its own body, and "Output profile" lost the
antecedent for "one catalogue serves both".

run-tests.sh gains the .claude/skills/ exclusion run-bats.sh already had.
Latent today -- no test-*.sh lives under any .apm/skills/*/tests/ -- but
apm now deploys those directories, so one would be discovered twice.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YR2CjVumUbEGWcMikcoXBD
This commit is contained in:
2026-09-14 18:09:03 +00:00
parent d2480b8191
commit 061bb3d5b4
18 changed files with 290 additions and 238 deletions

View File

@@ -4,42 +4,36 @@ Skills and agents for creating, maintaining, and managing a Claude Code / Copilo
## Install
**Claude Code:**
apm is the only supported install path (ADR-0024). Declare this package in the consuming project's `apm.yml`:
```bash
claude plugin marketplace add <owner>/<repo>
claude plugin install kyberforge@<marketplace-name>
```yaml
dependencies:
apm:
- git: git@git.dev.rkdr.net:Defame1297/holocron.git
path: plugins/kyberforge
```
**GitHub Copilot CLI:**
Then:
```bash
copilot plugin marketplace add <owner>/<repo>
copilot plugin install kyberforge
apm install
```
**Local (development):**
The entry above is unpinned and tracks the remote's default branch — add `ref: <tag>` to pin a release. Registering the catalogue instead (`apm marketplace add git@git.dev.rkdr.net:Defame1297/holocron.git --name holocron`) gets you the `kyberforge@holocron` short name, but writes to `~/.apm/marketplaces.json` at user scope; the git+path object needs nothing beyond the manifest.
```bash
# Claude Code
claude --plugin-dir ./plugins/kyberforge
# GitHub Copilot CLI
copilot plugin install ./plugins/kyberforge
```
**Native plugin installs do not work.** This package ships no per-plugin manifest and no flat content directories, so a host that installs it natively gets zero skills, agents and hooks — and Claude Code raises no error while doing it (ADR-0024).
## Contents
Authoring source lives in `.apm/`. The `skills/`, `agents/`, and `hooks/hooks.json` paths below are the generated mirror that plugin hosts actually scan — produced by `scripts/sync-plugin-content.sh`, never hand-edited (ADR-0017).
Authoring source lives in `.apm/`; it is the only content source and the only thing `apm install` deploys (ADR-0024).
| Component | Path | Description |
|---|---|---|
| Skills | `.apm/skills/` → `skills/` | Slash commands available after install |
| Agents | `.apm/agents/*.agent.md` → `agents/` | Role-based agents; one vendor-neutral `.agent.md` per agent, copied verbatim to both targets (ADR-0016) |
| Hooks | `.apm/hooks/` → `hooks/hooks.json` | Event-triggered automation — read by Claude Code only, see below |
| MCP servers | `.mcp.json` | Model Context Protocol server definitions (hand-authored at the plugin root) |
| Skills | `.apm/skills/` | Slash commands available after install |
| Agents | `.apm/agents/*.agent.md` | Role-based agents; one vendor-neutral `.agent.md` per agent (ADR-0016) |
| Hooks | `.apm/hooks/` | Event-triggered automation — Claude Code only, see below |
**Hooks are Claude Code-only in practice.** Claude Code convention-scans `hooks/hooks.json` at the plugin root, so that file is live. Copilot CLI has no default hooks path — `agents` and `skills` default to `agents/` and `skills/`, but `hooks` defaults to nothing (`docs/research/docs/github-copilot-plugins/configuration.md:47`), so Copilot reads hooks only via an explicit `"hooks": "hooks.json"` pointer in `plugin.json` (`docs/research/docs/github-copilot-plugins/examples.md:49`). apm's manifest compiler strips pointer fields from every manifest it generates, so neither `.claude-plugin/plugin.json` nor `.github/plugin/plugin.json` carries one, and re-injecting it is the option ADR-0017 explicitly rejected. Copilot therefore loads no hooks from this plugin — and did not load them from the old root-level `hooks.json` either. The Copilot half of this row is aspirational, not current behaviour.
**Hooks are Claude Code-only.** apm merges `.apm/hooks/*.json` into the consuming project's `.claude/settings.json` at install. Copilot CLI has no default hooks path — `agents` and `skills` default to `agents/` and `skills/`, but `hooks` defaults to nothing (`docs/research/docs/github-copilot-plugins/configuration.md:47`), so Copilot reads hooks only via an explicit pointer in a plugin manifest — and since ADR-0024 there is no per-plugin manifest to carry one. Copilot therefore loads no hooks from this plugin. Details, including why a pointer was the wrong fix even when a manifest existed, are in `docs/hooks.md`.
## Skills