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.
Prerequisites
Section titled “Prerequisites”- 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, or Cursor.
1. Scaffold
Section titled “1. Scaffold”apm init -y team-skillscd team-skillsapm init creates exactly one file — the manifest. The .apm/ source tree
is yours to author.
team-skills/+-- apm.ymlOpen apm.yml and give it a real description. The rest of the manifest is
already correct:
apm.yml
name: team-skillsversion: 1.0.0description: Skills and agents for our team's review workflowauthor: your-handledependencies: apm: [] mcp: []includes: autoscripts: {}includes: auto is the field that makes step 4 work: with no remote
dependencies declared, apm install walks your local .apm/ tree
and deploys what it finds. Set includes: [] (or omit the field) and
local content stops deploying. Override with an explicit list of
paths to gate exactly what ships.
2. Add a skill
Section titled “2. Add a skill”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-descriptiondescription: >- 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 perlogical 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.mdin this repo. Same shape, different concern.
See the Skills guide for the full schema.
3. Add a custom agent
Section titled “3. Add a custom agent”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-reviewerdescription: 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 becomesa pull request. Your job is to catch the things that waste reviewertime 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.
4. Deploy and use
Section titled “4. Deploy and use”Run install with no arguments. APM treats your repo as the package and
deploys its .apm/ content into the runtime directories your tools read:
apm installOutput:
[+] <project root> (local)|-- 1 agents integrated -> .github/agents/|-- 1 skill(s) integrated -> .agents/skills/[i] Added apm_modules/ to .gitignoreNote 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, and Gemini all read. Claude Code
is the exception: it reads .claude/skills/.
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.yamlapm 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/). The example layout
above shows .github/ because .github/copilot-instructions.md exists in the
project; if you also have .claude/, .cursor/, .opencode/, or .gemini/, 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 mergedAGENTS.md/CLAUDE.md/GEMINI.mdfiles for tools that read a top-level context document for instructions (Codex, Gemini, plainagents-protocol hosts). Gemini also receives commands, skills, hooks, and MCP viaapm install. Copilot, Claude Code, and Cursor read the per-skill directories directly — no compile step needed.
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.
5. Publish as a package
Section titled “5. Publish as a package”Push to GitHub:
git initgit add apm.yml .apm/git commit -m "Initial team-skills package"git remote add origin https://github.com/your-handle/team-skills.gitgit push -u origin mainIn any other project’s apm.yml:
dependencies: apm: - your-handle/team-skillsThen 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).
6. Ship as a plugin (optional)
Section titled “6. Ship as a plugin (optional)”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.
apm packOutput (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.mdNo 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 init --plugin team-skills, which adds plugin.json next to apm.yml
from day one. 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.
Choosing a package layout
Section titled “Choosing a package layout”APM recognizes three layouts. Pick the one that matches what you are shipping:
-
One skill — put
SKILL.mdat the repo root, with optionalagents/,assets/, orscripts/directories alongside it. Addapm.ymlif 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 withskills/,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.
Next steps
Section titled “Next steps”- Anatomy of an APM Package
— the full mental model:
.apm/vsapm_modules/vs.github/. - Skills guide — bundled resources, sub-skills, activation tuning.
- Agent Workflows guide — chaining agents, GitHub Agentic Workflows integration.
- Dependencies guide — depend on other APM packages, file-level imports, version pinning.
apm audit— scan dependencies for policy violations before they ship.