feat(kyberforge): execute plugin-to-apm marketplace conversion

Why:
ADR-0015 established that Microsoft APM (apm.yml + .apm/) should replace
this repo's hand-authored plugin.json/marketplace.json model, with those
files becoming compiled output of `apm pack` instead of files edited by
hand via the (now-retired) plugin-author/marketplace-author skills.
Issue #90 was the deferred execution of that decision, gated on #88
(apm tooling) and #89 (apm-native agent-author/skill-author routing).

Implementation notes:
- All six plugins (bin, core, git, gitea, kyberforge, lint) now carry
  apm.yml + .apm/{skills,agents,hooks} as their authoring source. Skills
  moved with a plain git mv (content-identical across targets). Agents
  were re-authored, not moved: per ADR-0016, .apm/agents/*.agent.md
  compiles verbatim to both Claude and Copilot, so plugin-scope agents
  now carry only name/description/model/source_keys -- no tools: field,
  no Claude-only knobs (isolation, maxTurns, effort, memory,
  permissionMode).
- Root apm.yml registers all 7 marketplace packages (6 local plus
  mattpocock-skills as a remote entry) under versioning: per_package,
  matching this repo's existing independent-plugin-versioning practice.
- .claude-plugin/marketplace.json and every plugin's plugin.json are now
  apm-pack-compiled output, verified against the prior hand-maintained
  content: same names/descriptions/versions/licenses/authors, only
  cosmetic serialization differences (JSON key order, owner email vs.
  url, Unicode escaping).
- plugin-author and marketplace-author are retired now that apm-based
  authoring fully replaces their job; kyberforge bumped 1.3.1 -> 1.4.0
  for that removal, and the root marketplace catalog bumped
  0.3.1 -> 0.3.2 to match, per the version-bump convention now
  documented in apm-workflow's reference docs instead of a dedicated
  script (apm has no native version-bump automation).
- Fixed hardcoded pre-.apm/ path assumptions across
  .pre-commit-config.yaml, .pre-commit-hooks.yaml,
  scripts/check-scope-walkup-sync.sh, scripts/sync-vale-styles.sh,
  scripts/check-vale-style-sync.sh, six plugins' root plugin.json
  (stale skills/hooks/agents pointer fields that check-manifests.sh
  validates), and several tests/*.bats and tests/*.sh fixtures --
  including a bats REPO_ROOT relative-path depth bug (10 files, one
  extra .apm/ directory level to walk up) and a vale probe-path
  isolation regression introduced mid-fix.
- Corrected empirically-wrong assumptions surfaced this session in
  apm-workflow/apm-install's own reference docs: `apm marketplace
  package add` does not accept local paths (only owner/repo remote
  shorthand -- local packages are registered by editing apm.yml's
  marketplace.packages[] directly); `apm compile` is a consumer-side
  AGENTS.md/CLAUDE.md generator, not the plugin.json producer, and
  hard-fails on skill/agent-only packages without --clean; `apm plugin
  init <name>` nests a stray subdirectory when run with a positional
  name arg from inside a same-named directory; no native Copilot
  marketplace output profile exists; .mcp.json is merged into the
  compiled plugin.json content-aware and target-scoped, with no
  dependencies.mcp entry needed for simple passthrough; pipx is the
  correct pip fallback on externally-managed Python environments.
- Renamed agent-author's copilot.agent.md template asset to
  copilot.agent.md.template so apm compile's recursive *.agent.md glob
  stops misparsing the placeholder template as a real agent primitive.

Impact:
plugin.json and marketplace.json are compiled artifacts from here on --
editing them by hand is no longer the workflow; edit apm.yml/.apm/ and
run apm pack. CONTEXT.md's Plugin/Plugin marketplace glossary entries
reflect this. ADR-0001 is marked superseded, ADR-0006 moot, and
ADR-0010 updated for the new .apm/agents/ path (project/user scope
unaffected, per ADR-0016). Full local verification: claude plugin
validate --strict on all 6 plugins, apm audit --ci, apm marketplace
check, check-manifests.sh, and the full test suite (165/165 bats,
13/13 shell scripts) all pass clean.

Fixes: #90
Refs: #88, #89
ADR: 0015
ADR: 0016

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ub96PyaSRD9BHPktotj1pC
This commit is contained in:
2026-08-12 18:09:37 +00:00
parent 50d5c30a3c
commit 5e232503c4
289 changed files with 741 additions and 1974 deletions

View File

@@ -0,0 +1,24 @@
# pc-author
Create, add, remove, update, and configure `.pre-commit-config.yaml`.
## What it does
Manages the pre-commit configuration file in any git repo. When invoked, it scans the repo for languages, proposes appropriate hooks with rationale, and writes or modifies `.pre-commit-config.yaml`. It validates every write with `pre-commit validate-config` and flags stale revision pins. It does not run hooks or install them into `.git/hooks/` — use `pc-run` for that.
## Usage
```
/pc-author
```
Invoke with no arguments. The skill determines from context whether to create a new config or modify an existing one.
## Files
| File | Purpose |
|------|---------|
| `SKILL.md` | Skill instructions for agents |
| `references/hooks-by-language.md` | Hook recommendations by detected language/extension |
| `references/README.md` | Index of files in references/ |
| `references/sources.md` | Provenance — research sources that informed this skill |

View File

@@ -0,0 +1,91 @@
---
name: pc-author
description: >
Use when the user wants to create, add hooks to, remove hooks from, update,
or configure .pre-commit-config.yaml. Triggers on: "set up pre-commit",
"add a hook", "remove this hook", "configure pre-commit", "create a pre-commit
config", "disable trailing whitespace hook", "add shellcheck", "update my
pre-commit config", even if the user does not name pre-commit explicitly.
Do not use for running hooks, installing git hooks, or bumping revision pins
— use pc-run for those.
allowed-tools: Bash Read Write Edit
metadata:
category: devtools
source_keys:
- context7-pre-commit-com
- pre-commit-com
- context7-pre-commit-hooks
- pre-commit-hooks-github
---
## Gotchas
- `rev` must be an immutable tag or commit SHA — never a branch name. `pre-commit autoupdate` breaks silently on branches.
- Fixers (`trailing-whitespace`, `end-of-file-fixer`, `pretty-format-json`) modify files but do NOT auto-stage them. The commit is blocked; the user must re-stage and recommit. Warn when adding fixers.
- `pre-commit validate-config` catches YAML structure errors but does NOT check whether hook `id`s exist in the target repo's manifest, and does NOT download or run hooks. It is fast; run it after every write.
- When removing a hook leaves its repo block with zero hooks, delete the entire repo block — an empty `hooks: []` causes `validate-config` to fail.
- `language: system` and `language: script` are deprecated names. Use `language: unsupported` and `language: unsupported_script` for new local hooks.
## Route
Check before acting:
- `.pre-commit-config.yaml` does not exist → **Create from scratch**
- File exists → **Modify existing**
## Create from scratch
1. Run a shallow extension scan:
```bash
git ls-files | grep -oE '\.[a-z]+$' | sort | uniq -c | sort -rn
```
2. Read `references/hooks-by-language.md` to map detected extensions to recommended hooks. For a minimal starting point instead of a full recommendation set, `pre-commit sample-config > .pre-commit-config.yaml` prints a small starter config to build on.
3. State the proposed config in full before writing. Wait for user confirmation.
4. Write `.pre-commit-config.yaml`.
5. Run `pre-commit validate-config`. If non-zero: show the error, fix it, re-validate. Never leave a broken config.
## Modify existing
Read `.pre-commit-config.yaml` first. Note any stale `rev` values (see **Rev staleness** below) but do not change them.
### Adding a hook
1. Run a shallow extension scan to detect languages in the repo:
```bash
git ls-files | grep -oE '\.[a-z]+$' | sort | uniq -c | sort -rn
```
2. Read `references/hooks-by-language.md` for the correct repo URL, rev, and recommended args for any hook before writing.
3. Check for duplicates — if the same hook ID or equivalent tool already exists in the config, say so and stop.
4. To sanity-check a hook against the repo's actual files before committing to it in config, smoke-test it with `pre-commit try-repo <repo-url> <hook-id> --verbose` (or a local path for hooks under development). This runs the hook without writing anything.
5. If the hook's source repo already exists in the config, add the hook under that repo block. Otherwise append a new repo block.
6. State the proposed addition. Wait for confirmation.
7. Write. Run `pre-commit validate-config`. If non-zero: show error, fix, re-validate.
### Removing a hook
1. Identify the hook entry and its repo block.
2. State what will be removed: hook ID, and whether the parent repo block will also be deleted (if it would have zero hooks remaining). Wait for confirmation.
3. Remove the hook entry. If the repo block now has zero hooks remaining, remove the entire repo block.
4. Write. Run `pre-commit validate-config`. If non-zero: revert the edit, show the error, and stop — do not leave a broken config (removal edits are not safely auto-fixable, unlike a bad new hook block, which can usually be corrected in place).
### Configuring top-level keys
Only when the user explicitly asks. Valid keys: `fail_fast`, `default_stages`, `default_language_version`, `minimum_pre_commit_version`, `exclude`, `files`, `default_install_hook_types`.
State the proposed change and wait for confirmation before writing.
## Rev staleness
When reading the config, for each repo listed in `references/hooks-by-language.md`, compare its `rev` in the user's config against the rev in that file. Flag any mismatch as potentially outdated and tell the user to run `pc-run` to autoupdate. Repos not in the reference cannot be checked — skip them silently. Do not modify `rev` values yourself.
The reference table's pins can themselves go stale between updates — treat a mismatch as a prompt to check, not a certainty. `pre-commit autoupdate` (via `pc-run`) is the authoritative source for what the current rev actually is.
## Scope boundary
This skill manages `.pre-commit-config.yaml` only. It does not:
- Author `.pre-commit-hooks.yaml` (publishing hooks for external consumers)
- Run `pre-commit install`
- Execute hooks or run the test suite
- Bump `rev` values
For those operations, use `pc-run`.

View File

@@ -0,0 +1,14 @@
---
source_keys:
- context7-pre-commit-com
- pre-commit-com
- context7-pre-commit-hooks
- pre-commit-hooks-github
---
# references/
| File | Purpose |
|---|---|
| `hooks-by-language.md` | Hook recommendations by language/context — repo, rev, and rationale for adding hooks |
| `sources.md` | Provenance: research sources that informed this skill |

View File

@@ -0,0 +1,120 @@
---
source_keys:
- context7-pre-commit-com
- pre-commit-com
- context7-pre-commit-hooks
- pre-commit-hooks-github
---
# Hook Recommendations by Language / Context
Use this table when creating a config from scratch or recommending hooks to add.
Always check the existing config for duplicates before proposing.
## Universal (recommend for every repo)
| Hook ID | Repo | Rev | Rationale |
|---------|------|-----|-----------|
| `end-of-file-fixer` | `https://github.com/pre-commit/pre-commit-hooks` | `v6.0.0` | Ensures files end with a newline — prevents spurious diffs |
| `trailing-whitespace` | `https://github.com/pre-commit/pre-commit-hooks` | `v6.0.0` | Strips trailing whitespace — prevents invisible diff noise |
| `check-merge-conflict` | `https://github.com/pre-commit/pre-commit-hooks` | `v6.0.0` | Catches unresolved merge markers before commit |
| `detect-private-key` | `https://github.com/pre-commit/pre-commit-hooks` | `v6.0.0` | Blocks PEM private key material |
| `check-added-large-files` | `https://github.com/pre-commit/pre-commit-hooks` | `v6.0.0` | Blocks accidentally committing large binary files |
| `check-case-conflict` | `https://github.com/pre-commit/pre-commit-hooks` | `v6.0.0` | Catches filenames that would collide on case-insensitive filesystems |
| `mixed-line-ending` | `https://github.com/pre-commit/pre-commit-hooks` | `v6.0.0` | Normalizes line endings |
| `no-commit-to-branch` | `https://github.com/pre-commit/pre-commit-hooks` | `v6.0.0` | Blocks direct commits to protected branches — defaults to blocking `main`+`master` with no args; add `args: [--branch, <name>]` only to protect additional branch names |
## Shell (`.sh`)
| Hook ID | Repo | Rev | Rationale |
|---------|------|-----|-----------|
| `shellcheck` | `https://github.com/jumanjihouse/pre-commit-hooks` | `3.0.0` | **Unverified — not in research corpus, verify upstream before use.** Static analysis for shell scripts; catches common errors |
Recommended args: `args: [--severity=warning]`
## Python (`.py`)
| Hook ID | Repo | Rev | Rationale |
|---------|------|-----|-----------|
| `check-ast` | `https://github.com/pre-commit/pre-commit-hooks` | `v6.0.0` | Validates Python files parse as valid AST |
| `check-builtin-literals` | `https://github.com/pre-commit/pre-commit-hooks` | `v6.0.0` | Enforces literal syntax for `dict()`, `list()` |
For formatting: check if `black`, `ruff`, or `isort` is already configured in `pyproject.toml` before recommending them.
## JSON (`.json`)
| Hook ID | Repo | Rev | Rationale |
|---------|------|-----|-----------|
| `check-json` | `https://github.com/pre-commit/pre-commit-hooks` | `v6.0.0` | Validates JSON parses correctly |
| `pretty-format-json` | `https://github.com/pre-commit/pre-commit-hooks` | `v6.0.0` | Auto-formats JSON (fixer — warns user to re-stage after commit) |
## YAML (`.yaml`, `.yml`)
| Hook ID | Repo | Rev | Rationale |
|---------|------|-----|-----------|
| `check-yaml` | `https://github.com/pre-commit/pre-commit-hooks` | `v6.0.0` | Validates YAML parses correctly |
For Kubernetes/Helm YAML with custom tags, add `args: ['--unsafe']` and `exclude: ^helm/templates/`.
## TOML (`.toml`)
| Hook ID | Repo | Rev | Rationale |
|---------|------|-----|-----------|
| `check-toml` | `https://github.com/pre-commit/pre-commit-hooks` | `v6.0.0` | Validates TOML parses correctly |
## Secrets / security
| Hook ID | Repo | Rev | Rationale |
|---------|------|-----|-----------|
| `gitleaks` | `https://github.com/gitleaks/gitleaks` | `v8.30.1` | **Unverified — not in research corpus, verify upstream before use.** Scans for secrets and high-entropy strings |
## Commit message
| Hook ID | Repo | Rev | Stage | Rationale |
|---------|------|-----|-------|-----------|
| `conventional-pre-commit` | `https://github.com/compilerla/conventional-pre-commit` | `v2.4.0` | `commit-msg` | Enforces Conventional Commits format |
When adding commit-msg hooks, also add `default_install_hook_types: [pre-commit, commit-msg]` to the top-level config if not already present.
## Meta-validation (add last, after all other repos)
```yaml
- repo: meta
hooks:
- id: check-hooks-apply # catches hooks that match no files
- id: check-useless-excludes # catches exclude patterns that match no files
```
## Local hooks (repo: local)
Use for repo-specific scripts that don't belong in an external hook repo.
```yaml
- repo: local
hooks:
- id: run-tests
name: Run test suite
entry: bash tests/run-tests.sh
language: unsupported_script
pass_filenames: false
always_run: true
stages: [pre-push]
```
Language choices for local hooks:
- `unsupported` — system PATH tool (pre-commit does not manage env)
- `unsupported_script` — script at a repo-relative path
- `fail` — always-fail guard; `entry` text becomes the error message
- `python` — isolated venv; use `additional_dependencies` for pip packages
- `node` — isolated node env; `additional_dependencies` are npm packages
- `ruby` — isolated gem env; `additional_dependencies` are gems
- `golang` — builds from source; `additional_dependencies` are Go module paths
- `rust` — Cargo build
- `docker` — Docker image built from `entry`; use when no other language fits
- `docker_image` — pulls a pre-built Docker image by `entry`
- `conda` — Conda environment; conda-native hooks
- `coursier` — Coursier (Scala/JVM) environment; JVM hooks
## Rev pin freshness
The revs above were last verified current at time of writing (matched against the plugin's own research corpus in `docs/research/docs/pre-commit/`; rows marked "Unverified" have no such backing and must be checked against upstream before use). Since `pc-author`'s "Rev staleness" check treats this table as ground truth, a pin that goes stale here produces false-positive staleness warnings for users who already have a newer, correct rev. Re-verify these pins periodically (e.g. against each repo's latest release tag). When in doubt, treat `pre-commit autoupdate`'s own output as the authoritative staleness signal, not a mismatch against this table.

View File

@@ -0,0 +1,33 @@
# Sources
## context7-pre-commit-com
- **URL:** context7:/pre-commit/pre-commit.com
- **Description:** Official pre-commit.com documentation — installation, configuration schema, CLI reference, hook authoring, advanced features, troubleshooting
- **Contributing files:** SKILL.md, references/hooks-by-language.md
- **Research doc:** plugins/git/docs/research/docs/pre-commit/{overview,configuration,cli-reference,hook-authoring}.md
- **Status:** `extracted`
## pre-commit-com
- **URL:** https://pre-commit.com/
- **Description:** Pre-commit framework homepage — full docs covering install, config, CLI, hook authoring, stages, local hooks, meta hooks, hazmat helpers, CI integration
- **Contributing files:** SKILL.md, references/hooks-by-language.md
- **Research doc:** plugins/git/docs/research/docs/pre-commit/{overview,configuration,cli-reference,hook-authoring}.md
- **Status:** `extracted`
## context7-pre-commit-hooks
- **URL:** context7:/pre-commit/pre-commit-hooks
- **Description:** Official pre-commit-hooks collection — all available hook IDs with options and examples
- **Contributing files:** references/hooks-by-language.md
- **Research doc:** plugins/git/docs/research/docs/pre-commit/hooks-reference.md § pre-commit-hooks (official collection)
- **Status:** `extracted`
## pre-commit-hooks-github
- **URL:** https://raw.githubusercontent.com/pre-commit/pre-commit-hooks/main/README.md
- **Description:** Official pre-commit-hooks README — complete hook listing with all args, categories, deprecated hooks, and latest version (v6.0.0)
- **Contributing files:** references/hooks-by-language.md
- **Research doc:** plugins/git/docs/research/docs/pre-commit/hooks-reference.md § pre-commit-hooks (official collection), § Deprecated hooks
- **Status:** `extracted`