Skip to content

Your First Package

In about ten minutes you will scaffold an APM package, add a skill that auto-activates inside Copilot or Claude, add a custom agent that pairs with it, install both into a project, and ship the result as a plugin. No prompts, no cat <<EOF, no compile step you do not need.

If you want the conceptual map first, read Anatomy of an APM Package. Otherwise, start here.

  • APM installed — see Installation.
  • A GitHub account and an empty repo for publishing (step 5).
  • A runtime where you can try the result: GitHub Copilot, Claude Code, Kiro, or Cursor.
Terminal window
apm init -y team-skills
cd team-skills

apm init creates exactly one file — the manifest. The .apm/ source tree is yours to author.

team-skills/
+-- apm.yml

Open apm.yml and give it a real description. The rest of the manifest is already correct:

apm.yml

name: team-skills
version: 1.0.0
description: Skills and agents for our team's review workflow
author: your-handle
dependencies:
apm: []
mcp: []
includes: auto
scripts: {}

includes: auto records explicit consent to deploy or pack local content. Omitting the field preserves legacy implicit consent and produces an audit advisory. Use an explicit list of paths when you need an exhaustive publication boundary. Source layout is independent: .apm/ is authoritative when present; otherwise supported plugin-native root directories remain pack sources.

A skill is a chunk of expertise that the runtime activates automatically based on its description. No slash command, no manual selection: the agent sees the description, decides the skill is relevant, and pulls it in. That auto-activation is what separates skills from prompts.

Create one for drafting pull-request descriptions:

.apm/skills/pr-description/SKILL.md

---
name: pr-description
description: >-
Activate when the user asks for a pull-request description, a summary of
uncommitted changes, or release notes. Use when preparing to open a PR or
when the user says "draft a PR description for me".
---
# PR Description Skill
Produce a PR description with these sections, in order:
## Summary
One sentence. What changes and why. No file lists, no implementation detail.
## Motivation
Two to four sentences. The problem this solves or the capability it adds.
Link to the issue or design doc if one exists.
## Changes
Bullet list grouped by area (e.g. "API", "Tests", "Docs"). One bullet per
logical change, not per file.
## Risk and rollback
Note any breaking changes, migrations required, or feature flags.
Mention how to revert if something breaks.
## Testing
How you verified the change. Commands run, environments tested.

The frontmatter description is a contract with the runtime: write it as “activate when …”. The body is the operating manual the agent reads when the skill fires.

Want to inspect a real one? The skill that governs this CLI’s own architecture decisions lives at .apm/skills/python-architecture/SKILL.md in this repo. Same shape, different concern.

See the Skills guide for the full schema.

A custom agent (.agent.md) is a named expert your runtime can invoke directly. While skills auto-activate based on context, agents are summoned on demand — typically with @agent-name.

Pair the skill with a reviewer agent that critiques the diff before the PR goes out:

.apm/agents/team-reviewer.agent.md

---
name: team-reviewer
description: Senior reviewer that critiques diffs against team standards before PR submission.
---
# Team Reviewer
You are a senior engineer reviewing a teammate's diff before it becomes
a pull request. Your job is to catch the things that waste reviewer
time downstream.
## What to check, in order
1. **Correctness.** Does the code do what its commit message claims?
Spot logic errors, off-by-ones, unhandled error paths.
2. **Tests.** Are the changed code paths covered? Are new public APIs
exercised by at least one test? Flag missing coverage explicitly.
3. **Naming and clarity.** Are names accurate? Would a new contributor
understand this in six months?
4. **Surface area.** Does this change export anything new? If yes, is
that intentional and documented?
## Output format
Group findings by severity: **Blocking**, **Should fix**, **Nit**.
For each finding, cite the file and line. End with a one-line verdict:
"Ready to ship", "Address blockers then ship", or "Needs another pass".
Do not rewrite the code yourself. Point and explain.

A real example: this repo’s documentation agent lives at .apm/agents/doc-writer.agent.md.

See the Agent Workflows guide for more.

Run install with an explicit target. APM treats your repo as the package and deploys its .apm/ content into the Copilot runtime directories:

Terminal window
apm install --target copilot

Output:

[+] <project root> (local)
|-- 1 agents integrated -> .github/agents/
|-- 1 skill(s) integrated -> .agents/skills/
[i] Added apm_modules/ to .gitignore

Note the split: agents are runtime-specific and land under .github/agents/ (Copilot’s directory). Skills land under .agents/skills/ — the cross-client universal location that Copilot, Cursor, OpenCode, Codex, Gemini, and Windsurf all read. Claude Code and Kiro are the exceptions: they read .claude/skills/ and .kiro/skills/, respectively.

Your tree now has source on the left and runtime-ready output on the right:

team-skills/
+-- .apm/ # source you edit
| +-- skills/
| | +-- pr-description/SKILL.md
| +-- agents/
| +-- team-reviewer.agent.md
+-- .agents/ # generated -- cross-client skills
| +-- skills/
| +-- pr-description/SKILL.md
+-- .github/ # generated -- runtime-specific
| +-- agents/
| +-- team-reviewer.agent.md
+-- apm.yml
+-- apm.lock.yaml

apm install resolves which harness directories to populate using a strict priority chain: --target flag > apm.yml targets: > auto-detect from filesystem signals (.claude/, CLAUDE.md, .cursor/, .github/copilot-instructions.md, .codex/, .gemini/, GEMINI.md, .opencode/, .windsurf/, .kiro/). The example layout above shows .github/ because .github/copilot-instructions.md exists in the project; if you also have .claude/, .cursor/, .opencode/, .gemini/, or .kiro/, those directories get populated too. With no signal at all, apm install exits with code 2 and a teaching message instead of silently picking a target — declare an intent explicitly via --target copilot (or another harness), or by adding targets: [copilot] to apm.yml. Run apm targets to inspect what APM detects in the current directory. To target explicitly, see the Compilation guide.

What about apm compile? Compile is a different concern: it generates merged AGENTS.md / CLAUDE.md / GEMINI.md files for tools that read a top-level context document for instructions. Targets listed under post-install instruction compilation print a hint after apm install when dependency instructions need apm compile. Gemini and Claude also receive commands, skills, hooks, and MCP via apm install. Claude instructions deploy directly to .claude/rules/, while Copilot and Cursor read their native instruction directories — none of those instruction paths needs a compile step. If your project commits those generated files, set targets: in apm.yml to keep the committed set consistent across machines. See Pin committed output with targets:.

Now open Copilot or Claude in this project. Ask “draft a PR description for my last commit”. The pr-description skill activates on its own. To get the review pass, type @team-reviewer review my staged changes.

Push to GitHub:

Terminal window
git init
git add apm.yml .apm/
git commit -m "Initial team-skills package"
git remote add origin https://github.com/your-handle/team-skills.git
git push -u origin main

In any other project’s apm.yml:

dependencies:
apm:
- your-handle/team-skills

Then apm install — consumers get the same skill and agent in their runtime dirs, with version pinning recorded in apm.lock.yaml.

For a real published package to read, see microsoft/apm-sample-package (install with apm install microsoft/apm-sample-package#v1.0.0).

The same package can ship as a standalone plugin — no APM required for consumers. This lets you target plugin-aware hosts (Copilot CLI plugins, the broader plugin ecosystem) with the primitives you already authored.

Terminal window
apm pack

Output (plugin format is the default):

build/team-skills-1.0.0/
+-- plugin.json # synthesized, schema-conformant per https://json.schemastore.org/claude-code-plugin.json
+-- apm.lock.yaml # enriched copy with bundle_files manifest (used by `apm install <bundle>` for integrity)
+-- agents/
| +-- team-reviewer.agent.md
+-- skills/
+-- pr-description/SKILL.md

No apm.yml, no apm_modules/, no .apm/. Just primitives in plugin-native layout. Convention dirs (agents/, skills/, commands/, instructions/) are auto-discovered by Claude Code, so the synthesized plugin.json does not list them.

If you know up front that you want to ship a plugin, you can scaffold with apm plugin init team-skills, which adds plugin.json next to apm.yml from day one. See Repo shapes to pick a layout before you commit. APM still gives you dependency management, the lockfile, and audit while you author; pack produces the plugin bundle when you ship.

For the full reference, see the Pack & Distribute guide and the Plugin authoring guide.

APM recognizes three layouts. Pick the one that matches what you are shipping:

  • One skill — put SKILL.md at the repo root, with optional agents/, assets/, or scripts/ directories alongside it. Add apm.yml if you need dependency management (this is a HYBRID package). APM installs the whole directory as a single skill bundle.

  • Multiple primitives — use the .apm/ directory with skills/, agents/, instructions/ subdirectories (the layout used in this guide). APM hoists each primitive into the consumer’s runtime dirs individually.

  • Claude plugin — if you already have a plugin.json, APM can consume it directly without restructuring.

For the full comparison and metadata precedence rules, see Package Types.

Morty Proxy This is a proxified and sanitized view of the page, visit original site.