After this chapter you can name the seven primitive types APM manages — instruction, prompt, skill, agent, plugin, MCP server, and hook — tell the three that look alike apart by who triggers them, explain that APM is built on the open AGENTS.md, SKILL.md, and MCP standards rather than replacing them, and describe how one source primitive compiles into each harness's native files. Naming the primitives is what makes a context declaration portable and a security decision governable in the chapters ahead.
Objective
Concept/Theory
You can't package what you can't name
In Chapter 1 the team's agent context was an undifferentiated pile — “an AI setup,” “some rules,” “that prompt.” You can't declare a pile in a manifest, pin it in a lockfile, or gate it in a policy. Before any of that, each item needs a type. That is the whole job of this chapter: hand you the nouns. Chapter 2 showed that names and namespaces are what tame ambiguity in package managers; here we give agent context its names.
APM's word for a typed unit is a primitive — “the atomic unit APM
ships.” The supported kinds are instructions, skills, prompts, agents, hooks, commands, plugins,
and MCP servers
(glossary) —
though “command” is a prompt as some harnesses project it rather than a separate
thing to author, and the experimental canvas type is out of scope here, which leaves
seven authorable types. A
primitive is not the same as a package: a package is the unit of distribution — a
directory with an apm.yml that can bundle many primitives — while a primitive is
one typed unit inside it. And not every file is a primitive: only files under the recognised primitive
layout are discovered, validated, and deployed; everything else is just repo content
(glossary).
The primitive vocabulary
APM manages seven primitive types you'll meet daily. The point of the vocabulary is that they are not interchangeable: each has a different trigger, cost, and blast radius. Read the middle column carefully — who (or what) invokes it is the axis that keeps the types straight.
| Primitive | What it is | Who invokes it | Problem it solves |
|---|---|---|---|
| Instruction | Repository-scoped guardrails and coding standards, scoped by file glob | Nobody — ambient, read on every turn (always-on) | Persistent rules you never have to re-state |
| Prompt | A parameterized, runnable workflow — “a callable program for an LLM” | You — explicitly, by name (you run it) | A repeatable multi-step task or checklist on demand |
| Skill | Model-invocable know-how — a SKILL.md folder plus bundled resources |
The model — when a task matches its description (it reaches for it) | Specialized capability loaded only when relevant |
| Agent | A persona with its own scope, tools, and system prompt | The user or orchestrator selects it as the acting persona | A bounded specialist instead of one generalist |
| Plugin | A bundle of the primitives above, packaged for one-shot install | Installed as one unit, then unpacked into its primitives | Shipping a set of primitives together |
| MCP server | An external tool or data connection over Model Context Protocol | The agent at runtime, when it calls that tool | Governed access to outside tools and data |
| Hook | A lifecycle handler that runs before or after agent tool calls | The harness runtime, automatically at that event | Deterministic automation around tool calls |
Two more pairs are worth keeping straight. An agent is who is acting — a persona with its own tools and boundaries; a skill is how to do a task — a procedure the acting agent can pull in, and one agent can use many skills. And a plugin is not a new capability at all: it is a packaging format that ships several primitives together and is normalized back into those same typed primitives at install time (primitives and targets).
Built on standards, not instead of them
APM does not invent its file formats. It is “built on standards: AGENTS.md · Agent Skills / SKILL.md · MCP” (microsoft/apm README). Each standard is an independent, open format APM adopts for one slice of the vocabulary:
- AGENTS.md — “a simple, open format for guiding coding agents… a dedicated, predictable place to provide context and instructions” that works across many agents (agents.md). APM's instructions compile into AGENTS.md-style files.
-
Agent Skills / SKILL.md — “a lightweight, open format for extending AI
agent capabilities… a skill is a folder containing a
SKILL.mdfile” loaded by progressive disclosure (agentskills.io). APM's skill primitive is this format. - MCP (Model Context Protocol) — “an open-source standard for connecting AI applications to external systems” (modelcontextprotocol.io). APM declares MCP servers against this protocol.
Standing on shared standards is what makes APM a manager rather than another silo. The
standards define the file and protocol formats; APM adds the dependency layer on top
— resolution, pinning, a lockfile, policy, and multi-harness compilation. So APM-produced context
is readable by tools that never installed APM, and APM can consume primitives authored by people who
never used it. Concretely, apm compile emits distributed AGENTS.md context files from your
instructions — the open standard is the output, not a proprietary blob
(What is APM?).
In APM
One source, many harnesses
A harness is the agent runtime that executes primitives — harnesses include
GitHub Copilot, Claude Code, Cursor, Codex, Gemini, OpenCode, Windsurf, and Kiro, with Antigravity as
an additional explicit-only target — and “each harness has
its own primitive directory layout and file format”
(glossary). A
primitive, by contrast, is harness-agnostic. APM's central move is to sit between the two: you author
one set of primitives under .apm/, and APM writes them into each harness's native
location. It “does not invent a runtime format. It writes the files each tool already
understands and stays out of the way at agent runtime”
(What is APM?).
Because each harness has its own format, APM either writes a primitive natively (the harness
reads it directly) or compiles it (APM transforms it into a shape the harness understands).
The clearest proof is to install one source package into two harnesses and look at what lands
on disk. The public microsoft/apm-sample-package ships four of the seven primitive types,
so four rows follow — a real install, same source, zero edits, once with
--target copilot and once with --target claude:
Source primitive (.apm/…) |
Copilot (.github/…) — native |
Claude Code (.claude/…) — compiled |
|---|---|---|
instruction instructions/*.instructions.md |
.github/instructions/*.instructions.md |
.claude/rules/*.md — renamed to a rule |
prompt prompts/*.prompt.md |
.github/prompts/*.prompt.md |
.claude/commands/*.md — a /command (mode key dropped) |
agent agents/*.agent.md |
.github/agents/*.agent.md |
.claude/agents/*.md |
skill skills/<name>/SKILL.md |
.agents/skills/<name>/SKILL.md |
.claude/skills/<name>/SKILL.md |
Read across any row and portability stops being a slogan. The same source instruction becomes a
Copilot .github/instructions/ file but is renamed to a Claude rule; the same
prompt is a native Copilot prompt but a compiled Claude /command. (Skills for the Copilot
family land in the cross-client .agents/skills/ home rather than a Copilot-only directory,
which is why that row's left cell reads .agents/, not .github/.) The intent is
identical everywhere; the file is whatever each harness natively reads.
Targets are the declaration; the harness is the runtime
You don't name a harness directly in the manifest — you list targets. A target
is “the declaration… the manifest or CLI selector for which harnesses to compile for,”
while “the harness is the runtime that consumes the compiled output”
(glossary). Eight
harnesses are configured as targets by default — copilot, claude,
cursor, codex, gemini, opencode,
windsurf, and kiro — which is why this book says “many
harnesses” and lists them rather than promising every tool ever built
(What is APM?).
Selecting and pinning targets is Chapter 5's job; here it is
enough to see the shape: one declaration, many native destinations.
Two of the book's four properties are already visible in this layer. Declaring context as typed primitives is the basis of Portability — one source set, compiled into every harness you target. And because each primitive is a named, typed unit, an organization can allow or deny it by category, which is what makes Governance discussable at all. The remaining two arrive downstream: the lockfile pins each deployed primitive by content hash — the basis of Reproducibility (Chapter 6) and of provenance (Chapter 8).
When to use / pitfalls
Which primitive for the job?
Distinct names prevent category errors. “Add a security review” is ambiguous until you say who triggers it: a persistent instruction that always warns about logging card data, a prompt the reviewer runs on a PR, a skill the model pulls in when it recognises a payment change, or an agent that owns review end to end. Each has a different cost and blast radius, so pick by trigger:
| If you want… | Reach for a… | Because |
|---|---|---|
| a rule enforced every turn that no one has to remember | instruction | it's ambient and always on |
| a named checklist a human kicks off on a PR | prompt | you run it, explicitly, by name |
| know-how the model should pull in only when a task matches | skill | the model reaches for it, keeping context lean |
| a bounded specialist that owns a task end to end | agent | it's a persona with its own tools and scope |
| deterministic automation around every tool call | hook | the runtime fires it at a lifecycle event |
| a governed connection to an external tool or dataset | MCP server | it's declared and gated, run elsewhere |
| several of the above shipped as one installable unit | plugin | it's a packaging format, unpacked into primitives |
Worked example
Meridian's context, finally typed
Here is Meridian's pile from Chapter 1, sorted into its primitive map. Nothing below is a manifest yet — it is the same inventory, now with a type and a trigger on every row. Read down the trigger column and the instruction/prompt/skill split snaps into focus: three of these are markdown, but one is always on, one you run, and one the model reaches for.
# meridian-checkout, now TYPED: source item -> primitive (who triggers it)
#
checkout backend guardrails (use Money) -> instruction nobody: read every turn (always-on)
fraud-review PR checklist -> prompt you: invoked by name, on demand
secure-review know-how -> skill the model: reached for on payment diffs
API-architect persona -> agent selected as the acting specialist
payment-sandbox tool connection -> mcp server the agent at runtime (declared + gated)
#
# not yet needed: plugin (no bundle to ship) . hook (no lifecycle automation)
That map is heading toward a manifest, but guard the distinction: it is not yet a manifest.
The shape it will take groups the five rows into two dependency buckets — apm for
primitives and mcp for MCP servers — plus the harness targets to build
for. Everything below is illustrative; Chapter 4 validates the
real syntax and pins each source, and Chapter 5 installs it.
name: meridian-checkout-agent-context
targets: [copilot, claude, cursor] # 3 of APM's 8 default harness targets
dependencies:
apm: [] # primitives -- declared for real in Chapter 4:
# - <checkout-domain instruction>
# - <fraud-review prompt>
# - <secure-review skill>
# - <api-architect agent>
mcp: [] # MCP servers -- declared + gated here, the server runs elsewhere:
# - <payment-sandbox>
Recap & next
Recap
- A primitive is APM's atomic, typed unit of agent context. Naming the primitives is the prerequisite for everything else — you can't package, pin, or govern what you can't name.
- There are seven types. The three that look alike differ by trigger: instruction = always on; prompt = you run it; skill = the model reaches for it. An agent is who acts; a plugin is packaging; an MCP server is an external tool; a hook is lifecycle automation.
-
APM is built on open standards — AGENTS.md, SKILL.md, and MCP — not a
replacement for them;
apm compileemits distributed AGENTS.md files. - One source primitive compiles into each harness's native files: an instruction becomes a Copilot instruction or a Claude rule; a prompt becomes a Copilot prompt or a Claude /command. Compiled is not byte-identical; parity across the eight default harnesses is high but bounded (native / compiled / unsupported).
- Targets are the declaration you list; the harness is the runtime that consumes the output.
- Typed primitives underpin Portability and make Governance a concrete checklist. Meridian typed its pile into a primitive map — the seed of the next chapter's manifest, but not yet a manifest.
Next
You now have the nouns and a typed map. Chapter 4 — The
Manifest: apm.yml turns Meridian's primitive map into a valid apm.yml: real dependency
syntax, pinned git sources, and the two buckets (apm and mcp) filled in for
the first time.