Skip to content

Add APM manifest as alternate install path (additive to plugin)#37

Open
AlexDeMichieli wants to merge 5 commits into
mainfrom
feat/apm-manifest
Open

Add APM manifest as alternate install path (additive to plugin)#37
AlexDeMichieli wants to merge 5 commits into
mainfrom
feat/apm-manifest

Conversation

@AlexDeMichieli

@AlexDeMichieli AlexDeMichieli commented Jul 19, 2026

Copy link
Copy Markdown
Collaborator

What is APM?

APM (Agent Package Manager) is an open-source dependency manager for AI agent primitives — skills, prompts, instructions, hooks, agents, MCP servers. Think npm install but for agent configuration. One apm.yml describes everything an agent needs; apm install reproduces it deterministically on any machine, with content hashes pinned in apm.lock.yaml.

How it complements the plugin

Plugin install and APM install are additive, not competing — they operate at different layers:

  • Plugin = the runtime bundle Copilot loads (agents/skills/hooks). Distributed via the Copilot marketplace and enabled centrally through the enterprise console + .github-private/.github/copilot/settings.json. Frictionless, GitHub-native, zero developer action.
  • APM = the install/governance layer around those primitives. Files land in the consumer repo, pinned by hash, content-scanned, auditable in every PR.

The 4-layer defense-in-depth model

APM + hooks (from #33) together give you distinct checks at four moments in the agent lifecycle:

Moment Layer Check Blocks
Author-time APM producer Schema validation Malformed packages
Install-time APM CLI Content-integrity scan + policy Hidden Unicode, prompt-injection payloads, disallowed sources, unpinned refs
PR-time apm audit --ci Drift / hash-mismatch check Tampering with materialized primitives, hand-edits, sneaky diff
Runtime Copilot hooks (#33) preToolUse / postToolUse policy Bad tool calls at execution (destructive writes, secret exfil, MCP alt-paths)

Plugin marketplace install gives you layer 4 only (once #33 lands). APM adds layers 1–3. That's the "regulated customers" pitch: defense in depth across the whole lifecycle, not just runtime.

Runtime hooks (PR #33) remain the enforcement point — APM never gates tool calls at execution. It stops bad code from reaching the agent; hooks stop the agent from doing bad things with the code it has.

When APM adds value

  • Regulated customer (bank, gov, healthcare) — needs SBOM, lockfile provenance, tamper detection. apm lock export --format cyclonedx gives auditors a standard inventory of every prompt/skill an agent can see.
  • Air-gapped / restricted network — the migration plugin files land in the consumer repo at install time, so no marketplace fetch is needed at runtime.
  • Customer wants to customize skills — they fork, publish their own APM package, and their own apm-policy.yml restricts what other teams in their org can install on top of it.
  • Multi-vendor AI stack — same apm.yml also configures Claude, Cursor, Codex, and others. Nothing else on the market does this today.
  • Reproducibilitymain moves; a pinned tag + content hash doesn't. Consumers don't get silently upgraded when we push to main.

Additional capabilities worth noting

  • apm outdated — surfaces which pinned deps have newer versions available. Explicit updates, not automatic drift.
  • Selective skill installapm install .../plugin --skill jenkins-migration --skill actionlint cherry-picks; reduces attack surface.
  • Enterprise policy (apm-policy.yml) — org-level rules (require_pinned_version, allowed_sources, require_explicit_includes) with tighten-only inheritance from enterprise → org → repo. Wired into apm audit --ci, so PRs that violate policy fail before merge.
  • MCP-server trust prompts — transitive MCP servers require explicit consent; prevents "install skill X, get a hidden MCP server that reads your GitHub token" supply-chain attacks.
  • Deployment ledger — records who deployed what and when, separate from the lockfile. Audit trail for change-control.

How to test

The APM CLI is client-side, so testing is a one-liner in any scratch repo. Verified end-to-end against feat/apm-manifest at commit 33d7d80:

# Install the APM CLI once
curl -sSL https://aka.ms/apm-unix | sh

# In a fresh test repo
mkdir /tmp/apm-migrator-test && cd /tmp/apm-migrator-test
git init
cat > apm.yml <<'YAML'
name: apm-migrator-test
version: 0.0.1
targets: [copilot]
dependencies:
  apm:
    - github/actions-migrations-via-copilot/plugin#feat/apm-manifest
YAML

apm install     # 9 agents + 11 skills materialized, apm.lock.yaml written
apm audit --ci  # 10/10 integrity checks pass on a fresh install

Note the /plugin suffix on the dependency spec — that's a virtual path pointing at the subdirectory where plugin.json lives. APM recognizes this as a Plugin collection package type (APM docs) and dissects plugin.json to install the agents and skills. Zero producer refactor required.

Once merged and a tag (e.g. v1.3.0) is cut, the dependency line becomes github/actions-migrations-via-copilot/plugin#v1.3.0.

Enforcement demos (verified locally)

Drift detection catches tampering. Modified a materialized skill file, apm audit --ci failed with:

content-integrity: 1 file(s) with hash drift
  hash-drift: .agents/skills/jenkins-migration/SKILL.md
  expected=fedf7085c7b9..., actual=6fe2322e9af7...
[x] 2 of 9 check(s) failed

Wire this into a .github/workflows/apm-audit.yml and tampered PRs never merge.

SBOM export works out of the box:

apm lock export --format cyclonedx  # or spdx

Produces an industry-standard bill of materials with the resolved commit SHA baked into the purl. Zero effort for procurement/compliance.

Scope

  • apm.yml (new, minimal) — declares actions-migrator@1.2.0, targets: copilot. APM ignores this at install time (uses plugin/plugin.json via virtual path) but kept for future marketplace: block authoring.
  • README.md — new Option C — Install via APM subsection alongside existing Options A/B, documents the /plugin virtual-path syntax.
  • .gitignore — append APM-generated paths (apm_modules/, build/, .agents/).

No behavior change to the plugin runtime. Additive only. Zero file overlap with #33.

Deferred to follow-ups

  • Commit apm.lock.yaml (needs apm install from a maintainer)
  • .github/workflows/apm-audit.yml for apm audit --ci on every PR
  • docs/enterprise/apm-policy-example.yml
  • After feat: deterministic enforcement hooks for migration quality #33 merges, evaluate whether hooks should also ship as an APM primitive (they already work via plugin channel)

Refs

- Add apm.yml declaring actions-migrator v1.2.0 as an APM package
  (targets: copilot). Schema mirrors github/expert-services-agent-skill
  PR #3.
- Add README 'Option C — Install via APM' section with a
  'Why APM complements the plugin' comparison table explaining that
  plugin and APM install solve different problems and are additive
  (control plane vs lockfile provenance / content scan / SBOM).
- Ignore APM-generated output (apm_modules/, build/, .agents/); the
  committed source of truth remains plugin/ and agents/.

apm.lock.yaml is intentionally omitted from this PR — it should be
generated by running 'apm install' in a follow-up commit once a
maintainer has the APM CLI available.

No behavior change to the plugin runtime. Additive only.
Copilot AI review requested due to automatic review settings July 19, 2026 13:43
@AlexDeMichieli
AlexDeMichieli marked this pull request as draft July 19, 2026 13:44

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds an experimental APM installation path alongside existing Copilot plugin options.

Changes:

  • Adds an APM package manifest.
  • Documents APM installation and governance benefits.
  • Ignores APM-generated output.
Show a summary per file
File Description
apm.yml Defines APM package metadata and target.
README.md Documents APM installation and comparison.
.gitignore Excludes generated APM artifacts.

Review details

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 2/3 changed files
  • Comments generated: 4
  • Review effort level: Medium

Comment thread apm.yml
- reusable-workflows
targets:
- copilot
includes: auto
Comment thread README.md Outdated
```yaml
dependencies:
apm:
- github/actions-migrations-via-copilot#v1.2.0
Comment thread README.md Outdated
| --- | --- | --- |
| Control plane | GitHub Copilot admin UI + `.github-private` settings | `apm-policy.yml` in a policy repo (tighten-only inheritance) |
| Version resolution | Whatever `main` (or the marketplace pointer) resolves to at runtime | Semver tag pinned in `apm.yml`, hash pinned in `apm.lock.yaml` |
| Content integrity | — | Hidden-Unicode / prompt-injection scan on every install |
Comment thread README.md Outdated
| Tampering detection | — | `apm audit --ci` diffs on-disk primitives against lockfile hashes |
| Audit trail | Enterprise audit log | Lockfile diff on every PR; `apm lock export --format cyclonedx\|spdx` (SBOM) |
| Air-gapped / restricted network | Depends on marketplace reachability | Files land in the consumer repo — no runtime fetch |
| Non-Copilot harnesses (Claude, Cursor, Codex, ...) | — | Same manifest deploys to every supported harness |
Rationale lives in the PR description; README stays focused on
install instructions.
APM's default includes: auto looks for primitives at .apm/ or root
conventional paths (agents/, skills/). Our primitives live under
plugin/agents/ and plugin/skills/ — an explicit includes list points
APM there without moving files or introducing duplication.

Per microsoft/apm docs (apm pack reference), an explicit includes
list is exhaustive and overrides implicit discovery. Confirmed with
@danielmeppiel that plugin-native paths are supported.
Copilot AI review requested due to automatic review settings July 20, 2026 20:19

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review details

Comments suppressed due to low confidence (1)

README.md:116

  • This pinned example resolves the existing v1.2.0 tag, whose commit predates and does not contain the new apm.yml. As a result, consumers copying this command cannot use the manifest or its includes declaration, so the documented APM install path is not reproducible from that release. Point this at the first release tag that actually contains the manifest (the repository already also has v1.3.0, which likewise predates it), or clearly use a temporary ref until that release is cut.
    - github/actions-migrations-via-copilot#v1.2.0
  • Files reviewed: 2/3 changed files
  • Comments generated: 0 new
  • Review effort level: Medium

APM's install-time validator requires the target path to be a valid
package shape (.apm/, top-level skills/, curated aggregator, plugin.json,
or SKILL.md). Our root has apm.yml only, so pointing consumers at the
whole repo fails validation.

Pointing at /plugin (the subdirectory containing plugin.json) resolves
as APM's 'Plugin collection' package type — APM dissects plugin.json
and maps the declared agents/ and skills/ directories into the
consumer's runtime paths. No producer refactor needed.

Verified end-to-end: apm install materialized 9 agents + 11 skills,
wrote apm.lock.yaml with resolved commit + per-file hashes.
Copilot AI review requested due to automatic review settings July 21, 2026 01:16

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review details

Comments suppressed due to low confidence (1)

apm.yml:25

  • This manifest is not installable as the repository-root package described in the PR test. APM only classifies an apm.yml package when it has a .apm/ source tree or non-empty dependencies; this repo has neither, and the actual plugin.json is under plugin/. As a result, github/actions-migrations-via-copilot#<ref> is classified as invalid, while the documented /plugin install bypasses this new manifest entirely. Move/expose the plugin primitives in an APM-recognized root layout (or otherwise make the root package resolve to plugin/) and verify the root-reference test.
includes: auto
  • Files reviewed: 2/3 changed files
  • Comments generated: 1
  • Review effort level: Medium

Comment thread README.md

```bash
curl -sSL https://aka.ms/apm-unix | sh # macOS / Linux
# irm https://aka.ms/apm-windows | iex # Windows
@AlexDeMichieli
AlexDeMichieli marked this pull request as ready for review July 21, 2026 01:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants