Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
291 changes: 227 additions & 64 deletions docs/src/content/docs/getting-started/first-package.md
Original file line number Diff line number Diff line change
@@ -1,117 +1,280 @@
---
title: "Your First Package"
description: "Create, publish, and install your first APM package in minutes."
description: "Build a real APM package with a skill and an agent, install it, and ship it as a plugin."
sidebar:
order: 3
---

This tutorial walks you through creating an APM package from scratch, publishing it, and installing it in another project.
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](../../introduction/anatomy-of-an-apm-package/).
Otherwise, start here.

## Prerequisites

- APM installed ([Installation guide](/apm/getting-started/installation/))
- A GitHub account and a repository to publish to
- APM installed -- see [Installation](/apm/getting-started/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 the Package
## 1. Scaffold

```bash
apm init my-coding-standards
cd my-coding-standards
apm init -y team-skills
cd team-skills
```

This creates:
`apm init` creates exactly one file -- the manifest. The `.apm/` source tree
is yours to author.

```
my-coding-standards/
└── apm.yml # Package manifest
team-skills/
+-- apm.yml
```

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

**`apm.yml`**

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

> **Note:** By default, `apm init` creates only `apm.yml`. The directory structure below is what you build manually in the following steps. See [Anatomy of an APM Package](../../introduction/anatomy-of-an-apm-package/) for what `.apm/` is and why files live there.
## 2. Add a skill

## 2. Add an Instruction
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 a coding standard that applies to all Python files:
Create one for drafting pull-request descriptions:

```bash
cat > .apm/instructions/python.instructions.md << 'EOF'
**`.apm/skills/pr-description/SKILL.md`**

```markdown
---
applyTo: "**/*.py"
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".
---
# Python Standards
- Use type hints for all function parameters and return values
- Follow PEP 8 style guidelines
- Write docstrings for all public functions
- Prefer `pathlib.Path` over `os.path`
EOF
# 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.
```

## 3. Add a Prompt
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.

Create a reusable slash command:
> Want to inspect a real one? The skill that governs this CLI's own
> architecture decisions lives at
> [`.apm/skills/python-architecture/SKILL.md`](https://github.com/microsoft/apm/blob/main/.apm/skills/python-architecture/SKILL.md)
> in this repo. Same shape, different concern.

```bash
cat > .apm/prompts/security-audit.prompt.md << 'EOF'
See the [Skills guide](/apm/guides/skills/) for the full schema.

## 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`**

```markdown
---
description: Run a security audit on the current file
name: team-reviewer
description: Senior reviewer that critiques diffs against team standards before PR submission.
---
Review this code for common security issues:
1. Input validation and sanitization
2. Authentication and authorization checks
3. Sensitive data exposure
4. SQL injection and XSS vulnerabilities
Provide specific line numbers and suggested fixes.
EOF
# 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.
```

## 4. Update the Manifest
> A real example: this repo's documentation agent lives at
> [`.apm/agents/doc-writer.agent.md`](https://github.com/microsoft/apm/blob/main/.apm/agents/doc-writer.agent.md).

Edit `apm.yml` to describe your package:
See the [Agent Workflows guide](/apm/guides/agent-workflows/) for more.

```yaml
name: my-coding-standards
version: 1.0.0
description: Team coding standards and security prompts
## 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:

```bash
apm install
```

## 5. Publish
Output:

```
[+] <project root> (local)
|-- 1 agent integrated -> .github/agents/
|-- 1 skill(s) integrated -> .github/skills/
[i] Added apm_modules/ to .gitignore
```
Comment on lines +170 to +175
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

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

The documented apm install output snippet does not match the current CLI output formatting. download_complete() emits " [+] <project root> (local)" (indented) and the integration logger currently prints "{n} agents integrated" (plural label), so "1 agent integrated" will not appear. Suggest updating this block to either match the exact strings produced by the CLI or wording it as illustrative output (so readers are not looking for exact lines).

Copilot uses AI. Check for mistakes.

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
+-- .github/ # generated by apm install
| +-- skills/
| | +-- pr-description/SKILL.md
| +-- agents/
| +-- team-reviewer.agent.md
+-- apm.yml
+-- apm.lock.yaml
```

Push to a git repository:
`apm install` auto-detects which runtimes you have. The example above shows
`.github/` because Copilot is the default fallback. If `.claude/`, `.cursor/`,
or `.opencode/` exists in the project, they get populated too. To target
explicitly, see the [Compilation guide](/apm/guides/compilation/).

> **What about `apm compile`?** Compile is a different concern: it
> generates merged `AGENTS.md` / `CLAUDE.md` files for tools that read a
> single top-level context document (Codex, Gemini, plain `agents`-protocol
> hosts). 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

Push to GitHub:

```bash
git init
git add .
git commit -m "Initial APM package"
git remote add origin https://github.com/you/my-coding-standards.git
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
Comment on lines 214 to 219
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

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

After running apm install in step 4, the repo now contains .github/ (deployed primitives) and apm.lock.yaml (deployment + pin record), but step 5 tells users to commit only apm.yml and .apm/. This conflicts with other docs that recommend committing deployed runtime dirs and the lockfile for reproducibility and for hosted runtimes that read from the repo without running apm install first. Suggest either adding .github/ + apm.lock.yaml to the commit command or explicitly calling out why this tutorial is intentionally source-only and what readers should do in real repos.

Copilot uses AI. Check for mistakes.
```

## 6. Install in Another Project
In any other project's `apm.yml`:

In any project:

```bash
apm install you/my-coding-standards
```yaml
dependencies:
apm:
- your-handle/team-skills
```

APM automatically:
- Downloads the package to `apm_modules/`
- Copies instructions to `.github/instructions/`
- Copies prompts to `.github/prompts/`
- Updates `apm.yml` with the dependency
Then `apm install` -- consumers get the same skill and agent in their
runtime dirs, with version pinning recorded in `apm.lock.yaml`.

## 7. Optional: Compile for Other Tools
For a real published package to read, see
[`microsoft/apm-sample-package`](https://github.com/microsoft/apm-sample-package)
(install with `apm install microsoft/apm-sample-package#v1.0.0`).

If you use tools beyond GitHub Copilot, Claude, Cursor, and OpenCode (which read deployed primitives natively), generate compiled instruction files:
## 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.

```bash
apm compile
apm pack --format plugin
```

Output:

```
build/team-skills-1.0.0/
+-- plugin.json # synthesized from apm.yml
+-- agents/
| +-- team-reviewer.agent.md
+-- skills/
+-- pr-description/SKILL.md
```

No `apm.yml`, no `apm_modules/`, no `.apm/`. Just primitives in
plugin-native layout.

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.

This produces `AGENTS.md` (for Codex, Gemini) and `CLAUDE.md` for tools that need a single instructions file. Copilot, Claude, and Cursor users can skip this step — OpenCode users need `apm compile` only if their packages include instructions (OpenCode reads `AGENTS.md` for those).
For the full reference, see the [Pack & Distribute guide](/apm/guides/pack-distribute/)
and the [Plugin authoring guide](/apm/guides/plugins/).

## Next Steps
## Next steps

- Add [skills](/apm/guides/skills/) to your package
- Set up [dependencies](/apm/guides/dependencies/) on other packages
- Distribute as a standalone plugin — see [Plugin authoring](../../guides/plugins/#plugin-authoring) and [Pack & Distribute](../../guides/pack-distribute/)
- Explore the [CLI reference](/apm/reference/cli-commands/) for more commands
- [Anatomy of an APM Package](/apm/introduction/anatomy-of-an-apm-package/)
-- the full mental model: `.apm/` vs `apm_modules/` vs `.github/`.
- [Skills guide](/apm/guides/skills/) -- bundled resources, sub-skills,
activation tuning.
- [Agent Workflows guide](/apm/guides/agent-workflows/) -- chaining agents,
GitHub Agentic Workflows integration.
- [Dependencies guide](/apm/guides/dependencies/) -- depend on other APM
packages, file-level imports, version pinning.
- [`apm audit`](/apm/reference/cli-commands/) -- scan dependencies for
policy violations before they ship.
33 changes: 21 additions & 12 deletions docs/src/content/docs/introduction/anatomy-of-an-apm-package.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,33 +41,42 @@ APM separates two concerns that those folders conflate:
### A concrete example: this repo

The `microsoft/apm` repository (the one shipping the CLI you are reading docs
for) dogfoods this layout. It contains both source and compiled output side by
side:
for) dogfoods this layout. It contains both source and compiled output side
by side:

```
microsoft/apm/
+-- apm.yml
+-- .apm/
| +-- skills/
| | +-- writing-skills/
| | +-- python-architecture/
| | +-- SKILL.md
| +-- instructions/
| +-- agents/
| | +-- doc-writer.agent.md
| +-- instructions/
+-- .github/
| +-- skills/
| | +-- writing-skills/
| | +-- SKILL.md (compiled from .apm/, byte-identical)
| +-- instructions/
| | +-- python-architecture/
| | +-- SKILL.md (deployed from .apm/ by apm install)
| +-- agents/
| | +-- doc-writer.agent.md
| +-- instructions/
+-- src/
+-- tests/
```

The file under `.apm/skills/writing-skills/SKILL.md` is the source. The file
under `.github/skills/writing-skills/SKILL.md` is the compiled artifact that
the in-repo Copilot agent actually loads while we work on the CLI. Same
content today, but only one of them is authoritative -- and only one of them
gets shipped when this repo is consumed as an APM package.
The source files under `.apm/` are authoritative. You can inspect them on
GitHub:
[`.apm/skills/python-architecture/SKILL.md`](https://github.com/microsoft/apm/blob/main/.apm/skills/python-architecture/SKILL.md)
and
[`.apm/agents/doc-writer.agent.md`](https://github.com/microsoft/apm/blob/main/.apm/agents/doc-writer.agent.md).
Their counterparts under `.github/` are the deployed copies the in-repo
Copilot agent actually loads while we work on the CLI.

For simple primitives the deployed file is byte-identical to the source.
The deploy step can also augment files for runtime-specific concerns (e.g.
adding diagnostic guidance for a particular target), so treat `.github/`
as build output: never edit it by hand, always re-deploy from `.apm/`.
Comment on lines +77 to +79
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

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

The statement that deploy "can also augment files" with an example of "adding diagnostic guidance" looks speculative; the concrete behavior in the CLI is mainly format/target-specific transformations (e.g., instructions to Claude/Cursor rule formats, prompts to commands) and otherwise byte-for-byte copies for agents/skills. Suggest replacing the example with a behavior that is definitely implemented, or removing the parenthetical example to avoid implying a feature that may not exist.

Suggested change
The deploy step can also augment files for runtime-specific concerns (e.g.
adding diagnostic guidance for a particular target), so treat `.github/`
as build output: never edit it by hand, always re-deploy from `.apm/`.
For some targets, APM generates runtime-specific formats from the source, so
treat `.github/` as build output: never edit it by hand, always re-deploy
from `.apm/`.

Copilot uses AI. Check for mistakes.

## Why not just put primitives in `.github/` directly?

Expand Down
Loading