Package managers transformed software development. package.json for Node.js, requirements.txt for Python — one manifest file, one install command, reproducible environments everywhere. Microsoft APM brings this model to AI agents.
As AI coding assistants become core development tools, managing their configurations — skills, prompts, instructions, MCP servers — grows complex. APM solves this by treating agent context as versioned, executable infrastructure: declare dependencies once, reproduce them everywhere.
I recently experimented with APM on a project at work, where we will be deploying it across teams, and later implement in our build pipeline. The CLI integration with agents works exactly as documented — reliable, predictable, well-behaved. But IntelliJ IDEA revealed a different story. The AI Assistant plugin or Junie plugin for example were not using the commands and/or instructions as I expected. This resulted in unexpected behaviour when invoked through the IDE. Also the Junie reviewer we are using in the CICD pipeline required some custom configuration to bridge these gaps. But that friction is where the real learning happens: understanding the pitfalls, discovering best practices through trial and error, seeing how agent primitives actually behave in production rather than in theory. I'm still early in this journey. There's significantly more to explore, and I'm looking forward to it.
What Is Microsoft APM?
Agent Package Manager (APM) is Microsoft's open-source dependency manager for AI agents — npm for agent context. One apm.yml manifest declares skills, prompts, instructions, agents, hooks, plugins, and MCP servers. One command reproduces the exact setup across every client on every machine.
Running apm install resolves dependencies transitively, creates apm.lock.yaml with full commit SHAs and integrity hashes, scans for security issues, and configures GitHub Copilot, Claude Code, Cursor, OpenCode, Codex, Gemini CLI, and Windsurf automatically.
The Problem APM Solves
Without APM, agent configuration is tribal knowledge. Developers configure AI assistants manually, skills are installed ad-hoc with no version tracking, and reproducing agent behaviour across machines is fragile. Security scanning for malicious prompts? Manual at best.
APM transforms this. Clone a repository, run apm install, and every developer gets byte-for-byte identical agent configuration — versioned, security-scanned, cross-platform. The same setup works in GitHub Copilot, Claude Code, Cursor, and every other supported harness.
How APM Works
The apm.yml Manifest
Everything starts with apm.yml — a declarative manifest that describes what your agent needs. It declares the six APM primitives: instructions, skills, prompts, agents, MCP servers, and hooks. Here's a simple example:
name: my-dev-agent
version: 1.0.0
dependencies:
"@skills/java": "^2.1.0"
"@mcp/filesystem": "^1.0.0"
skills:
- source: github
repo: company/internal-skills
path: skills/code-review.md
mcp:
filesystem:
command: npx
args: ["-y", "@modelcontextprotocol/server-filesystem", "/workspace"]
This file declares Java skills from a package registry, an MCP server for filesystem access, and a custom code review skill from an internal repository. APM handles the rest.
Dependency Resolution
When you run apm install, APM:
- Resolves all dependencies transitively — Skills can depend on other skills
- Downloads packages — From configured registries or Git repositories
- Scans content for security issues — Hidden Unicode, suspicious patterns
- Creates
apm.lock.yaml— With full 40-character commit SHAs - Configures detected AI clients — Copilot, Claude, Cursor, etc.
- Prompts for permission — Before installing MCP servers
Key Features
Cross-Platform Support
One manifest, every platform. APM compiles primitives into harness-specific formats — .github/instructions/ for Copilot, .cursor/rules/ for Cursor, and so on. Your apm.yml works across GitHub Copilot, Claude Code, Cursor, OpenCode, Codex, Gemini CLI, and Windsurf without modification.
Security Scanning
Every apm install automatically scans packages for:
- Hidden Unicode — Characters that appear harmless but could change agent behaviour
- Integrity hashes — Lockfile verification to detect tampering
- MCP server gating — Transitive MCP servers require explicit trust prompts
- Critical findings — Packages with severe security issues are blocked automatically
Dependency Source Locking with apm-policy.yml
Enterprise security teams control exactly which sources, scopes, and primitives the organisation permits. Stored at <org>/.github/apm-policy.yml, this governance file enforces policy at install time with tighten-only inheritance: enterprise → organisation → repository.
version: 1
# Lock to internal GitLab only
allowed_sources:
- type: git
host: gitlab.company.com
org: company/*
require_auth: true
- type: registry
url: https://registry.company.com
require_signing: true
# Block public sources
blocked_sources:
- type: git
host: github.com
reason: "Use internal mirror only"
# Security requirements
security:
require_lockfile: true
require_integrity_hashes: true
block_unsigned_packages: true
scan_for_unicode: true
Enforcement: Every apm install validates dependency sources against the policy, including transitive MCP servers. Dependencies from non-allowed sources are blocked immediately. Policy violations are logged to audit trails.
For organisations with on-premise GitLab or GitHub Enterprise, this provides complete supply chain control: agents can only install content from internally reviewed repositories.
APM Primitives
APM handles six core primitives, each stored in .apm/ subdirectories and compiled into harness-specific formats for your AI clients:
Instructions
Always-on rules attached to file globs that enforce coding standards, architectural patterns, or team conventions. Stored in .apm/instructions/, they're compiled into formats like .github/instructions/ or .cursor/rules/ depending on your harness.
Use cases: CQRS patterns, multi-tenancy standards, code style enforcement, naming conventions.
Skills
Multi-file capabilities where SKILL.md serves as the entry point. Skills are model-invoked guides that agents select at runtime based on the description field in their frontmatter. Located in .apm/skills/<name>/.
Each skill must stay under 500 lines and 5,000 tokens. For extensive context, use references/ subdirectories that the skill body can load explicitly.
Example: A code-review skill activates when an agent sees 'the user asks for code review or PR feedback'.
Prompts
Reusable templates with .prompt.md extensions, stored in .apm/prompts/. Prompts are invoked through scripts or CLI commands, not automatically activated.
Use cases: /document, /refactor, /write-tests — predefined workflows developers trigger on-demand.
Agents
Named agent definitions in .apm/agents/ with .agent.md files. Each agent specifies model selection, system prompt, and tool whitelist for a particular expertise domain.
Examples: @api-architect, @security-expert, @performance-specialist — invoked explicitly via @agent-name.
MCP Servers
Tool providers declared in apm.yml under mcp:. APM installs them automatically into every detected AI client, managing lifecycle, configuration, and authentication. Transitive MCP servers require explicit trust prompts for security.
Capabilities: Filesystem operations, database queries, API integrations (GitHub, Jira, Slack), search and indexing.
Hooks
Lifecycle event handlers stored in .apm/hooks/ that execute during pre-install, post-install, compile, or run operations.
Use cases: Environment validation, custom configuration, integration with existing toolchains.
Whether managing a single developer's AI assistant or standardising agent capabilities across an enterprise, APM makes AI agent configuration as reproducible and maintainable as your application dependencies.