fix(kyberforge): bridge apm content to Claude Code's flat plugin discovery

Claude Code's (and Copilot's) native plugin installer has zero awareness of
.apm/ nesting -- it convention-scans only flat skills/, agents/, commands/,
hooks.json at each plugin's root. Confirmed via strings on the installed
claude binary and live installs of git@holocron/gitea@holocron/kyberforge@
holocron, all reporting Skills(0) Agents(0) Hooks(0) post ADR-0015's apm
conversion. Root cause (apm_cli/core/plugin_manifest.py): apm's plugin.json
compiler deliberately strips skills/agents/commands keys, assuming the host
already auto-discovers those convention directories -- it has no model of
.apm/ being host-visible at all. Separately, apm's own bundle exporter
(apm_cli/bundle/plugin_exporter.py, behind `apm pack --format plugin`)
implements the correct .apm/ -> flat mapping, but only ever targeted
build/<name>-<version>/, a path nothing in marketplace.json's source: points
at.

scripts/sync-plugin-content.sh wraps that bundle exporter and copies its
agents/, skills/, commands/, instructions/, extensions/, and merged
hooks.json back into each plugin's own root as a second tracked
compiled-output category -- same governance status as
.claude-plugin/plugin.json: generated from .apm/, never hand-edited. tests/
subdirectories are excluded from the mirror (dev fixtures, not host-visible
runtime content; several hardcode a relative repo-root walk-up sized for the
.apm/-nested depth, which breaks when duplicated one level shallower).
Applied for real across all 6 plugins and verified two ways: `claude plugin
validate --strict` passes on every real plugin directory, and a live
`claude --plugin-dir <path> -p "list skills/agents"` behavioral test
confirms content is now actually discovered.

Also, from the same issue #90 review round:
- scripts/check-manifests.sh pointed at each plugin's root-level plugin.json
  (checking skills/hooks/mcpServers/agents pointer fields) -- that file was a
  stale near-duplicate of .claude-plugin/plugin.json nothing else read or
  wrote, now deleted across all 6 plugins. check-manifests.sh is rewritten to
  validate .claude-plugin/plugin.json instead, and drops the pointer-field
  checks entirely (nothing to check -- those fields are correctly absent by
  design). Content-presence drift is now check-plugin-content-sync's job, a
  new pre-push hook wired in .pre-commit-config.yaml.

docs/adr/0017 records the root cause and decision in full, including two
rejected alternatives (patching plugin.json's path fields directly -- apm's
compiler strips them on every run; pointing marketplace.json at apm pack's
build/ output -- a version-suffixed non-source directory nothing can install
from without an extra build step). ADR-0015 and CONTEXT.md are updated to
point at it.

Refs: #90
This commit is contained in:
2026-08-13 16:59:03 +00:00
parent 7910b8b12c
commit 38f1ba4e03
217 changed files with 14455 additions and 175 deletions

View File

@@ -0,0 +1,118 @@
---
source_keys:
- agents-md-official
- context7-websites-agents-md
- context7-agentsmd-agents-md
---
# What good AGENTS.md content looks like
AGENTS.md has no required schema — there's no field to fill in, only sections that either
earn their place or don't. Agents treat this file as a set of live directives, not
documentation: they will actually run the commands it lists and fix failures before
finishing a task. That means a wrong or stale line is worse than a missing one. Verify
every command against something real in the repo before writing it down.
## Section-by-section guidance
**Setup / build commands** — the install and dev-server commands, exactly as they appear
in `package.json` scripts, a `Makefile`, or a `Cargo.toml`/`pyproject.toml` equivalent. One
line per command, each with a one-clause note on what it does if the name alone isn't
obvious. Skip this section if there's genuinely nothing beyond "clone and run" — don't pad
it with a restated `git clone`.
**Code style** — only conventions that aren't already enforced by a linter/formatter config
the agent will pick up on its own (a `.eslintrc`, `rustfmt.toml`, etc. speaks for itself).
Write down the conventions that live only in people's heads: naming patterns, module
boundaries, patterns to avoid, anything a linter can't catch. If the repo has no
undocumented conventions beyond what tooling enforces, skip this section.
**Testing instructions** — the exact command(s) to run the suite, where to find
per-package or per-workflow test configuration (e.g. `.github/workflows/`), and any
non-obvious requirement (a service that must be running, an env var that must be set).
State plainly that the agent should run tests before considering a change done and fix
failures — don't leave this implicit.
**Security considerations** — only repo-specific hazards: a data-handling boundary, a
credential pattern to never hardcode, a destructive command that needs a confirmation
step. Do not restate general security advice ("don't commit secrets") that any agent
already assumes — that's padding, not a directive.
**Commit / PR conventions** — the title/format convention if one exists (e.g. a
Conventional Commits type prefix, a ticket-number requirement), and any check that must
pass before a PR is opened (lint, test, type-check). Point at the real command, not
"make sure it passes."
**Dev environment tips** — the handful of things that save real time and are easy to miss:
how to jump to a specific package in a monorepo without `ls`-ing around, how to register a
new package so the toolchain sees it, where to look up a canonical name/id. This section
is for genuine friction points observed in this repo, not generic advice.
## What separates useful content from padding
A useful section names a real file, command, or path that exists in this repo right now.
A padded section could be pasted into any repo unchanged and still "make sense" — that's
the tell. If a sentence would read the same in a different codebase, it doesn't belong.
Prefer four accurate lines over twelve generic ones.
## Worked example (minimal project)
```markdown
# AGENTS.md
## Setup commands
- Install deps: `pnpm install`
- Start dev server: `pnpm dev`
- Run tests: `pnpm test`
## Code style
- TypeScript strict mode
- Single quotes, no semicolons
- Use functional patterns where possible
## Dev environment tips
- Use `pnpm dlx turbo run where <project_name>` to jump to a package instead of scanning with `ls`.
- Run `pnpm install --filter <project_name>` to add the package to your workspace so Vite, ESLint, and TypeScript can see it.
- Check the `name` field inside each package's `package.json` to confirm the right name.
## Testing instructions
- Find the CI plan in the `.github/workflows` folder.
- Run `pnpm turbo run test --filter <project_name>` to run every check defined for that package.
- From the package root you can just call `pnpm test`. The commit should pass all tests before you merge.
- Fix any test or type errors until the whole suite is green.
- Add or update tests for the code you change, even if nobody asked.
## PR instructions
- Title format: [<project_name>] <Title>
- Always run `pnpm lint` and `pnpm test` before committing.
```
Every line above names a real command or path — that's the standard to hold this repo's
version to, not the specific tooling shown (a Python/Cargo/Go repo's AGENTS.md should look
nothing like this one in its specifics, only in how concrete each line is).
## Monorepo / nested placement
```
my-monorepo/
├── AGENTS.md # Root-level: applies to the whole repo
├── packages/
│ ├── api/
│ │ └── AGENTS.md # API-specific instructions; overrides root for this package
│ ├── web/
│ │ └── AGENTS.md # Web app-specific instructions
│ └── shared/
│ └── AGENTS.md # Shared library instructions
```
Precedence rule: the file nearest the edited path wins. Nested files are **not** merged
with the root file — an agent editing inside `packages/api/` reads only
`packages/api/AGENTS.md`, never the root file in addition. Consequences:
- A nested file must stand alone. Don't write "also see the root file" — write what the
agent needs, full stop.
- Don't duplicate root content in a nested file "just in case." If a nested file repeats
root-level setup instructions verbatim, that's a sign it shouldn't exist as a separate
file at all — the subtree isn't actually different enough to warrant one.
- Only create a nested file when the subtree has a genuinely different stack, build tool,
or convention than the root (see `SKILL.md` Step 2 for the placement decision itself).

View File

@@ -0,0 +1,25 @@
# Sources
## agents-md-official
- **URL:** https://agents.md/
- **Description:** Official agents.md website — format spec, common-sections checklist, precedence rules (nearest-file-wins, no merge across files), monorepo nesting patterns
- **Research doc:** plugins/core/docs/research/docs/agentsmd/sources.md
- **Contributing files:** SKILL.md, references/content-guide.md
- **Status:** `extracted`
## context7-websites-agents-md
- **URL:** context7:/websites/agents_md
- **Description:** Context7 index of the official agents.md website — overview, governance, cross-tool compatibility, configuration examples
- **Research doc:** plugins/core/docs/research/docs/agentsmd/sources.md
- **Contributing files:** SKILL.md, references/content-guide.md
- **Status:** `extracted`
## context7-agentsmd-agents-md
- **URL:** context7:/agentsmd/agents.md
- **Description:** Context7 index of the agentsmd/agents.md repository — format spec, nested monorepo patterns, file structure examples
- **Research doc:** plugins/core/docs/research/docs/agentsmd/sources.md
- **Contributing files:** SKILL.md, references/content-guide.md
- **Status:** `extracted`