docs(kyberforge): add Microsoft APM research reference set

Capture Microsoft's Agent Package Manager (APM) — overview, install,
config, CLI reference, registries/marketplace, monorepo shapes,
testing/validation, troubleshooting, and examples — as structured
reference docs under plugins/kyberforge/docs/research/docs/microsoft-apm/.

Lays the groundwork for issue #88 (build agents/skills to execute a
marketplace-to-APM conversion of this repo).
This commit is contained in:
2026-08-10 17:06:07 +00:00
parent 8f523da270
commit 1d07d1a76b
10 changed files with 631 additions and 0 deletions

View File

@@ -0,0 +1,99 @@
---
topic: cli-reference
source_keys:
- context7-microsoft-apm
---
## Install
```bash
apm install [PACKAGE_REF...] [OPTIONS]
```
With no arguments, resolves and installs everything declared in `apm.yml` against `apm.lock.yaml`. Explicit `PACKAGE_REF` arguments (e.g. `acme/internal-tools#^1.0.0`) install and add that dependency. `apm install --update` re-resolves and accepts new upstream content even when it doesn't match the recorded lockfile hash (see troubleshooting). `apm install --target agent-skills` generates a vendor-neutral output directory for IDE-agnostic tool support instead of a harness-specific one.
## Compile
```bash
apm compile
```
Generates per-target output (Claude, Copilot, etc.) from the vendor-neutral `.apm/` primitive source tree, per the `compilation:` block in `apm.yml`.
## Pack
```bash
apm pack --dry-run # resolve and print; do not write
apm pack --offline # cached refs only
apm pack --include-prerelease # allow pre-release tags
apm pack -v # per-entry resolution detail
apm pack --marketplace=claude --json # JSON output for CI pipelines
```
Bundles a producer package into a distributable artifact.
## Publish
```bash
apm publish --package acme/my-skill --dry-run -v
apm publish --package acme/my-skill
```
Publishes a producer package (root containing `apm.yml`, `.apm/`, and optionally a `registries:` block) to a registry. Always dry-run with `-v` first to see resolution detail before publishing for real.
## Runtime management
```bash
apm runtime setup copilot # install with APM defaults
apm runtime setup codex --version 0.20.0 # pinned version
apm runtime setup llm --vanilla # skip APM-managed config
apm runtime list # what's installed
apm runtime status # which runtime `apm run` will pick
apm runtime remove gemini -y # uninstall without prompting
```
## Run
```bash
apm run <script> [--param key=value]
```
Executes a named script defined under `scripts:` in `apm.yml`, with `--param` substituting values into the script's parameters (used, for example, when the script wraps a Gemini CLI invocation).
## Audit (validation)
```bash
apm audit # local: scan deployed files for hidden Unicode
apm audit --ci # CI gate: lockfile consistency + drift replay + policy
apm audit --file <path> # standalone: scan an arbitrary file
```
See `testing-and-validation.md` for CI wiring and exit-code behavior.
## Marketplace
```bash
apm marketplace init # add the marketplace: block to apm.yml
apm marketplace check # validate every listed package ref resolves
apm marketplace package add <path> --name <n> # register a local package into the marketplace
apm marketplace add <source> [--name <n>] # register a marketplace as a consumer (see marketplace-and-registries.md for source forms)
```
## Plugin scaffolding
```bash
apm plugin init <name> --yes
```
Scaffolds a new package's `apm.yml` + `.apm/` skeleton in the current directory.
## Config
```bash
apm config set <key> <value>
apm config get <key>
apm config unset <key>
apm experimental enable registries # required before registry.* config takes effect
```
Used for workstation-level settings such as private registry URLs/tokens (see `marketplace-and-registries.md`).

View File

@@ -0,0 +1,118 @@
---
topic: configuration
source_keys:
- context7-microsoft-apm
---
## The `apm.yml` manifest
Every APM package — producer or consumer — is rooted in an `apm.yml` file. The only required fields are `name` and `version` (SemVer):
```yaml
name: my-pkg
version: 1.0.0
```
## Full schema
```yaml
name: my-pkg
version: 1.0.0
description: Code review skills for Python services
author: Jane Doe # plain string, or {name, email?, url?} object
license: MIT
homepage: https://example.com/my-pkg
repository: https://github.com/org/my-pkg
keywords: [ai, review, python]
# Constrains what .apm/ may contain: instructions, skill, hybrid, or prompts
type: skill
# Pins which harnesses this package compiles to. Prefer the plural `targets:`
# list form; the legacy singular `target:` CSV form is still accepted.
targets:
- copilot
- claude
# "auto" publishes the authoritative local source layout, or list explicit
# repo paths to define the complete publication set.
includes: auto
dependencies:
apm:
- microsoft/apm-sample-package#v1.0.0 # pinned to a tag
- github/awesome-copilot/skills/review-and-refactor # single primitive
mcp:
- microsoft/azure-devops-mcp # MCP server dependency
lsp:
- name: pyright
command: pyright-langserver
args: ["--stdio"]
extensionToLanguage:
".py": python
# Same shape as dependencies, but excluded from the shipped artifact —
# for dev-only tooling and tests.
devDependencies:
apm:
- my-org/internal-test-skills
# Named commands runnable via `apm run <name>`
scripts:
start: "copilot -p 'README.prompt.md'"
review: "copilot -p 'code-review.prompt.md'"
compilation:
target: all
strategy: distributed
exclude:
- "apm_modules/**"
placement:
min_instructions_per_file: 1
policy:
fetch_failure_default: warn
registries:
public-apm:
url: https://registry.example.com/api/public-apm
default: public-apm
marketplace:
owner:
name: contoso
url: https://github.com/contoso
packages:
- name: code-review
source: contoso/code-review
version: "^1.0.0"
tags: [review, quality]
```
## Dependency reference forms
`dependencies.apm` entries accept several forms: a pinned tag (`owner/repo#tag`), a plain repo (uses default branch), a single primitive path within a repo, a raw git URL, a `git:`/`path:`/`ref:` object for finer control, or a local relative path (`./packages/my-shared-skills`).
## MCP server secrets
Secrets for MCP server config (headers, env vars) should use `${VAR}` indirection rather than literal values, so they're resolved by APM or the host harness at install/runtime and never committed to the manifest:
```yaml
mcp:
- name: linear
registry: false
transport: http
url: https://mcp.linear.app/sse
headers:
Authorization: "Bearer ${LINEAR_TOKEN}"
- name: my-internal
registry: false
transport: stdio
command: my-server
env:
API_TOKEN: "${MY_API_TOKEN}"
```
## Registries
Registries are optional — any git repo is a valid package source by default — but a project can declare named registries and pick a `default:` for shorthand dependency resolution, useful for teams centralizing internal packages.

View File

@@ -0,0 +1,80 @@
---
topic: examples
source_keys:
- context7-microsoft-apm
---
## Producer quickstart
A minimal consumer flow: install a package by owner/name, then compile it to the active harness's format.
```bash
apm install your-org/your-project
apm compile
```
## Authoring an agent primitive
Agents are markdown files with YAML frontmatter defining metadata, model constraints, and tool permissions, followed by a prose system-instructions body:
```markdown
---
name: security-review
description: Reviews diffs for OWASP top-10 issues and missing input validation.
model: gpt-5
tools:
Read: true
Grep: true
---
You are a security reviewer. Your job is to inspect the working diff
for...
```
## On-disk package layout
```text
.apm/
skills/
my-skill/
SKILL.md
scripts/
references/
assets/
prompts/
review.prompt.md
instructions/
style.instructions.md
agents/
cli-logging-expert.agent.md
hooks/
pre-commit.json
```
## Publish → install round trip
```bash
# Producer: package root with apm.yml, .apm/, and (optionally) a registries: block
apm publish --package acme/my-skill --dry-run -v
apm publish --package acme/my-skill
# Consumer: another repo
apm install acme/internal-tools#^1.0.0
```
## Cross-tool / IDE-agnostic install
```bash
apm install --target agent-skills
```
Generates a vendor-neutral skills directory usable across IDEs rather than a single harness-specific output.
## Running a script with parameters (Gemini CLI example)
```bash
# Run a script from apm.yml, substituting a parameter
apm run start --param service_name=api-gateway
```
Once a runtime like Gemini CLI is installed via `apm runtime setup gemini`, it can also be invoked directly for interactive mode (`gemini`), sandboxed/isolated execution (`gemini -s`), or with an explicit model (`gemini -m gemini-2.5-pro-preview`).

View File

@@ -0,0 +1,39 @@
---
topic: installation
source_keys:
- context7-microsoft-apm
---
## Quick install (recommended)
A one-line install script auto-detects the platform, downloads the latest binary, and configures the system `PATH`:
```bash
curl -sSL https://aka.ms/apm-unix | sh
```
On Windows, the installer adds both the current directory and the bin directory to `PATH`, so it works from native shells, Git Bash, and process APIs alike.
## Customizing the install
- **Pin a specific version**: append `@vX.Y.Z` to the piped script arguments, e.g. `curl -sSL https://aka.ms/apm-unix | sh -s -- @v1.2.3`.
- **Custom install directory**: set `APM_INSTALL_DIR` before running the script, e.g. `APM_INSTALL_DIR=$HOME/.local/bin sh`.
- **Air-gapped / GitHub Enterprise mirror**: set `GITHUB_URL` and `VERSION` env vars against a local `install.sh`, e.g. `GITHUB_URL=https://github.corp.com VERSION=v1.2.3 sh install.sh`.
## Alternative install methods
- **pip**: `pip install apm-cli` — requires Python 3.10 or higher.
- **Manual binary**: download the platform-specific archive from the GitHub releases page, extract it, move the binary to a permanent directory, and add that directory to `PATH`.
## Installing agent runtimes
APM itself doesn't execute agents, but it can install and manage the runtimes that do, via `apm runtime setup <name>`:
```bash
apm runtime setup copilot # recommended default
apm runtime setup codex
apm runtime setup gemini
apm runtime setup llm
```
Installing GitHub Copilot CLI through APM pulls it from the public npm registry and requires Node.js v22+ and npm v10+; no authentication is needed for the install step itself. Use `apm runtime list` to see which runtimes are currently installed and which one `apm run` will pick by default.

View File

@@ -0,0 +1,76 @@
---
topic: marketplace-and-registries
source_keys:
- context7-microsoft-apm
---
## Building a marketplace from a producer repo
Standard sequence to turn a repo into an APM marketplace (a curated set of packages other consumers can point at):
```bash
apm marketplace init # 1. add the marketplace: block to apm.yml
$EDITOR apm.yml # 2. describe each package
apm marketplace check # 3. validate refs resolve
apm pack # 4. build marketplace artifacts
git add apm.yml .claude-plugin/marketplace.json
git commit -m "Release v1.0.0" && git tag v1.0.0 && git push --tags
```
Note the build step emits a `.claude-plugin/marketplace.json` artifact alongside `apm.yml` — APM's `apm pack` generates the Claude Code-native marketplace manifest as one of its per-target compile outputs, so an APM-based marketplace can still be consumed by Claude Code's existing marketplace mechanism without a separate hand-maintained file.
## Registering a marketplace as a consumer
`apm marketplace add` accepts many source shapes — this is the distribution/consumption side:
```bash
# GitHub shorthand
apm marketplace add my-org/awesome-agents
# GitLab via host shorthand
apm marketplace add gitlab.com/my-org/awesome-agents --host gitlab.com
# Azure DevOps Services / Server, Gitea, Bitbucket Server — any self-hosted git, pinned with #ref
apm marketplace add https://gitea.example.com/org/repo.git#v1.0.0 --name custom
# Hosted marketplace.json URL
apm marketplace add https://catalog.example.com/marketplace.json --name catalog
# SSH
apm marketplace add git@gitea.example.com:org/repo.git --name custom
# Local filesystem (bare repo, working directory, or marketplace.json file directly) — no server needed
apm marketplace add /srv/marketplaces/agent-forge.git --name agent-forge
apm marketplace add ./vendor/marketplace.json --name vendor
apm marketplace add file:///srv/marketplaces/agent-forge.git --name agent-forge
```
The local-filesystem and `file://` forms mean a fully local, offline marketplace — pointing `apm marketplace add` at a path or bare repo on disk — needs no hosted registry or network access at all. This is the direct fit for an internal/homelab setup that wants package discovery without standing up infrastructure.
## Private / self-hosted registries (experimental)
Distinct from `marketplace add` (which points at a *catalog* of packages), registries are a REST endpoint for hosting the packages themselves (e.g., Artifactory, JFrog, or any endpoint implementing the standard Registry HTTP API). This is opt-in and currently experimental:
```bash
apm experimental enable registries
# Project-level: apm.yml has a registries: block and registry-routed deps
apm install
# Workstation-level config only (no registries: block committed to apm.yml)
apm config set registry.corp-main.url https://artifactory.corp.example.com/apm
apm config set registry.corp-main.token eyJ...
apm config set registry.corp-main.default true
apm install
# CI: pass the token via env var, never commit it
APM_REGISTRY_TOKEN_CORP_MAIN=eyJ... apm install --frozen
```
`apm config get`/`apm config unset` manage individual keys the same way. Public registries need no authentication; private ones need a token configured per the above.
## Which mechanism to use
- **Local packages, no distribution needed yet**: local-path dependencies in `apm.yml` (`./packages/my-shared-skills`) — no marketplace or registry involved at all.
- **Internal catalog, still git-based, no server**: `apm marketplace add` against a local path, bare repo, or `file://` URI, or a plain git host (Gitea, GitHub, etc.) — this is the natural fit if this repo's own git remote should double as the marketplace source.
- **Package-level hosting at scale / access control**: registries (Artifactory-style REST endpoint) — more infrastructure, only worth it once package count or access-control needs outgrow git-based discovery.

View File

@@ -0,0 +1,71 @@
---
topic: monorepo-and-repo-shapes
source_keys:
- context7-microsoft-apm
---
## Repo shapes
APM documents named patterns for how a repo can host multiple packages. Two are directly relevant to converting an existing multi-plugin repo:
### Monorepo
Multiple independent plugins under one repo, each with its own manifest and `.apm/` tree, plus a root `apm.yml` that lists them as local-path packages:
```text
my-monorepo/
apm.yml # marketplace + local-path packages
packages/
plugin-a/
apm.yml # plugin-a's manifest
.apm/
agents/
expert.agent.md
instructions/
style.instructions.md
skills/
my-skill/
SKILL.md
plugin-b/
apm.yml
.apm/
prompts/
review.prompt.md
hooks/
pre-tool.json
```
### Monorepo-hybrid
The variant for a repo that both ships its own plugins *and* curates/re-lists others: multiple plugins live under a packages directory, each with its own manifest for independent compilation and testing, while a single root marketplace lists them all as local-path entries. This is the closest documented match to this repo's current `plugins/<name>/` layout (each plugin already self-contained with its own skills/agents/hooks).
## Scaffolding a monorepo
```bash
apm plugin init plugin-a --yes # run from inside packages/plugin-a
apm plugin init plugin-b --yes # run from inside packages/plugin-b
cd ../..
apm marketplace init --owner acme-org --name acme-monorepo
apm marketplace package add ./packages/plugin-a --name plugin-a
apm marketplace package add ./packages/plugin-b --name plugin-b
```
`apm plugin init` scaffolds a single package's `apm.yml` + `.apm/` skeleton; `apm marketplace package add` registers an already-existing local package path into the root marketplace listing without re-scaffolding it — this is the command to point at each of this repo's existing `plugins/*` directories once each has its own `apm.yml`.
## Per-package versioning
Plugins in a monorepo don't have to share a version with the root or each other:
```yaml
marketplace:
versioning: { strategy: per_package }
packages:
- { name: plugin-a, source: ./packages/plugin-a, version: 2.0.0 }
- { name: plugin-b, source: ./packages/plugin-b, version: 0.1.0 }
```
Without this, the default versioning strategy ties all listed packages to the marketplace/root version — worth checking explicitly, since this repo's plugins (git, gitea, kyberforge, lint, core, bin) currently version independently (see the patch-bump-per-plugin pattern already in this repo's commit history).
## What's still a manual translation, not an APM feature
Nothing in the docs describes an automated converter from an existing `.claude-plugin/marketplace.json` + `plugin.json` pair into `apm.yml`. The shapes are compatible (`apm pack` emits `.claude-plugin/marketplace.json` as a compile target), but populating each plugin's `apm.yml` metadata, `type:`, `targets:`, and `dependencies:` from the current manifests is manual per-package work, not a single migration command.

View File

@@ -0,0 +1,37 @@
---
topic: overview
source_keys:
- context7-microsoft-apm
---
## What APM is
APM (Agent Package Manager) applies a standard package-management model — declare, lock, install, audit — to AI agent configuration. It manages the skills, prompts, instructions, agents, and tools an AI coding assistant needs, so that configuration is version-controlled, peer-reviewed, and reproducible across developer machines and CI pipelines, the same way a dependency manager keeps application code reproducible.
## Scope: install and integrity plane only
APM is deliberately narrow. It governs what reaches disk and enforces policy conformance on that install — nothing more. It is explicitly **not**:
- A runtime for executing agents
- An LLM gateway or model-call proxy
- A fine-tuning tool
- A marketplace requiring a specific distribution platform
It also does not manage agent permissions or version model weights. Any git repository can serve as a valid APM package — there's no mandated central registry, though named registries are supported for teams that want one.
## Producer / consumer model
- A **producer** package is a directory containing an `apm.yml` manifest, primitives under `.apm/`, and a `README.md`.
- A **consumer** project declares dependencies on producer packages in its own `apm.yml` and installs them with `apm install`.
- `apm compile` generates per-target output (e.g., Claude-specific or Copilot-specific files) from the vendor-neutral `.apm/` source tree.
- `apm pack` bundles a producer package into a distributable artifact.
## Package anatomy
APM packages organize content into subdirectories under `.apm/` by primitive type:
- `skills/` — multi-file capabilities (each with its own `SKILL.md`, plus optional `scripts/`, `references/`, `assets/`)
- `prompts/` — reusable prompt templates (`*.prompt.md`)
- `instructions/` — always-on rules (`*.instructions.md`)
- `agents/` — model and tool configuration for a named agent (`*.agent.md`)
- `hooks/` — host-harness lifecycle event bindings
This mirrors how the vendor-neutral primitives compile down to provider-specific formats (Claude, Copilot, etc.) via `apm compile`.

View File

@@ -0,0 +1,8 @@
# Sources
## context7-microsoft-apm
- **URL:** context7:/microsoft/apm
- **Description:** Microsoft APM (Agent Package Manager) — open-source dependency manager for AI agent configuration (skills, prompts, instructions, agents, hooks, MCP/LSP deps), applying a declare/lock/install/audit workflow.
- **Contributing files:** overview.md, installation.md, configuration.md, cli-reference.md, examples.md, troubleshooting.md, testing-and-validation.md, marketplace-and-registries.md, monorepo-and-repo-shapes.md
- **Status:** `extracted`

View File

@@ -0,0 +1,51 @@
---
topic: testing-and-validation
source_keys:
- context7-microsoft-apm
---
## `apm audit`
APM's built-in validation/integrity tool, usable both locally and as a CI gate:
```bash
apm audit # local: scan deployed files for hidden Unicode
apm audit --ci # CI gate: lockfile consistency + drift replay
apm audit --file <path> # standalone: scan an arbitrary file
```
`apm audit --ci` runs baseline lockfile checks, install-replay drift detection (does a clean `apm install` reproduce what's on disk), and org policy checks. It returns exit code `0` on success and `1` on any violation, so it composes as a normal CI gate step. It's meant to sit alongside — not replace — existing lint/test/security-scan CI steps: it specifically covers AI agent configuration integrity, hidden-content scanning, lockfile verification, and policy enforcement, not general code correctness.
## Policy checks
`apm audit --ci` auto-discovers an org policy from the git remote if `--policy`/`--policy-source` isn't given explicitly; `--no-policy` skips policy discovery for a single invocation. This lets an org centrally define required checks (e.g., which primitive types are allowed, required metadata fields) without every package repo repeating the config.
## Marketplace ref validation
Separately from `apm audit`, `apm marketplace check` validates that every package reference declared in a marketplace's `apm.yml` actually resolves (correct path/ref, manifest present) before you build or publish — this is the step that catches a typo'd local path or a stale pinned tag before it ships.
## CI integration example (GitHub Actions)
```yaml
jobs:
apm-audit:
runs-on: ubuntu-latest
permissions:
contents: read
security-events: write
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with: { python-version: "3.12" }
- run: pip install apm-cli==X.Y.Z # pin to the version you standardize on
- run: apm install
- run: apm audit --ci -f sarif --output apm-audit.sarif
- uses: github/codeql-action/upload-sarif@v3
with: { sarif_file: apm-audit.sarif }
```
`-f sarif --output <file>` emits SARIF, which GitHub Code Scanning can ingest directly for inline annotations on PRs — useful if this repo's CI already surfaces findings that way.
## Frozen installs
`apm install --frozen` (seen in the private-registry install flow) fails instead of silently re-resolving if the lockfile is out of date — the CI equivalent of `npm ci` vs `npm install`. Worth using in any CI job that shouldn't be allowed to drift the lockfile.

View File

@@ -0,0 +1,52 @@
---
topic: troubleshooting
source_keys:
- context7-microsoft-apm
---
## Manifest / lockfile ref mismatch
Happens when the version or ref declared in `apm.yml` no longer matches what's recorded in the stale `apm.lock.yaml`:
```text
<owner>/<repo>: manifest ref 'v2' != lockfile ref 'v1'
N ref mismatch(es) -- run 'apm install' to update lockfile
```
Fix: run `apm install` to reconcile the lockfile with the manifest.
## Missing lockfile
Occurs when a command that needs a resolved dependency graph runs before the first install:
```text
lockfile not found at apm.lock.yaml; run 'apm install' to generate it
```
## Lockfile version mismatch
The installed `apm` binary is older than the lockfile format it's being asked to read:
```text
[x] apm.lock.yaml uses lockfile_version "2", this binary supports "1"
[>] Upgrade APM: see https://...
```
Fix: upgrade the APM binary to a version that supports the newer lockfile schema.
## Content hash mismatch (possible supply-chain issue)
Raised when downloaded dependency bytes don't match the hash recorded in the lockfile:
```text
[x] Content hash mismatch for <owner>/<repo>: expected <sha>, got <sha>.
The downloaded content differs from the lockfile record. This may
indicate a supply-chain attack. Use 'apm install --update' to accept
new content and update the lockfile.
```
This is a fail-closed integrity check — treat an unexpected occurrence as a security signal, not just a stale-cache annoyance. Only use `apm install --update` once you've confirmed the new upstream content is legitimate (e.g., a real re-tag), since it deliberately overwrites the recorded hash.
## Dependency version conflicts
Direct and transitive dependency constraints are resolved by intersecting version ranges. Example: a manifest directly depends on `acme/foo#^1.2.0`, and a transitive dependency (`acme/bar`) pulls in `acme/foo#^1.5.0`. The effective constraint is the intersection, `[>=1.5.0, <2.0.0)`, and APM picks the highest tag in that range. If the two constraints don't overlap at all (e.g. `^1.2.0` vs. `^2.0.0`), resolution fails closed rather than silently picking one side — install errors out instead of guessing.