feat(kyberforge): add apm-install/apm-workflow/apm-orchestrate, ADR-0015 #91
@@ -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`).
|
||||
@@ -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.
|
||||
@@ -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`).
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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`.
|
||||
@@ -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`
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
Reference in New Issue
Block a user