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 supported context is projected or
registered for selected harnesses. Naming the primitives is what makes a context declaration
portable and a security decision
governable in the chapters ahead.
Version scope: the inspected CLI for this update is
apm v0.31.0. Material labeled v0.23.1 is a retained historical
snapshot, not evidence of a fresh v0.31.0 execution.
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 and can bundle
many primitives. An apm.yml is one supported package signal, not a prerequisite for every
consumable skill or plugin. Nor is every repository file a primitive: declarations, supported layouts,
and classification determine what can deploy
(v0.31.0 package types).
The declaration-first boundary below makes that distinction concrete.
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.
The seven primitive types APM manages, by trigger. Definitions condensed from APM's
“what APM manages” table and primitive catalogue
(What is APM?,
primitives
and targets).
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
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 target-specific callback at a harness event, such as session start or a tool call
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 packaging, not another trigger. Legacy Claude-compatible plugins project
into individual primitives; recognized Agent Plugins 1.0 follow a
whole-unit registration path instead.
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.md file” 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?).
A harness is the agent runtime that consumes primitives — Meridian uses
GitHub Copilot, Claude Code, and Cursor — and “each harness has
its own primitive directory layout and file format”
(glossary).
A primitive's intent can be harness-independent, but its support and delivery are target-specific.
APM sits between the two. Authoring under .apm/ is a useful convention, not the only
supported source layout. APM “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?).
Declarations before directories
A directory is a discovery convention; a declaration states what the author intends to ship.
For the APM-versus-plugin choice, an apm.yml is eligible when the root
also has .apm/ or the manifest declares APM or MCP dependencies. That eligible manifest
takes precedence over a co-located plugin marker. A metadata-only manifest with neither does not.
Root SKILL.md bundles and nested skill collections are separate supported signals, so
this is not an “any apm.yml wins” rule
(package layouts and precedence).
A legacy plugin's explicit component declaration replaces discovery for that component.
In the controlled example, "skills": ["./skills/kept", "./extra/custom"] deployed only
those two skills, not the extra skills/unlisted directory. "skills": []
means no skills; omitting the key permits conventional discovery. A missing
declared skill failed installation rather than silently widening the selection. Declarations are
exhaustive, not hints. The worked layout check shows the
other side of this rule: a supported skill need not be moved into .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 following historical snapshot makes that visible: the public
microsoft/apm-sample-package supplied four primitive types, installed at v0.23.1 once
with --target copilot and once with --target claude, with no source edits.
It is not a new v0.31.0 full-package run.
One source primitive set → two harnesses, two on-disk layouts — and even two different
names. Historical install of microsoft/apm-sample-package, 2026-07-02;
public network access used.
apm v0.23.1
Source primitive (.apm/…)
Copilot (.github/…) — native
Claude Code (.claude/…) — compiled
instructioninstructions/*.instructions.md
.github/instructions/*.instructions.md
.claude/rules/*.md — renamed to a rule
promptprompts/*.prompt.md
.github/prompts/*.prompt.md
.claude/commands/*.md — a /command (mode key dropped)
agentagents/*.agent.md
.github/agents/*.agent.md
.claude/agents/*.md
skillskills/<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
shared; the native representation differs. Materializing these files does not establish identical
agent behavior.
Two plugin delivery contracts
Legacy Claude-compatible plugins are decomposed into target-specific primitives.
A root plugin.json declaring the
Agent Plugins 1.0 schema
selects a different contract: for Copilot, the recognized plugin stays whole under
apm_modules/. The local example registered checkout-plugin@apm through
APM's generated marketplace and .github/copilot/settings.local.json; it did not create
a loose .agents/skills/retry/SKILL.md duplicate. Non-Copilot targets do not receive an
automatic flattened fallback
(native registration contract).
Loading that registration requires stable Copilot CLI 1.0.81 or newer; APM need
not locate or execute Copilot to register it. Registration success is not runtime success.
There is also a known v0.31.0 local-path limitation: the tested native plugin installed, but
apm audit --ci failed during replay with
Native Agent Plugin canonical IR is missing. That is not a network skip or an
audit-clean example, nor evidence that every Git-sourced plugin fails.
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).
In the exact v0.31.0 catalog, all expands to nine default stable targets:
copilot, claude,
cursor, codex, gemini, opencode,
windsurf, kiro, and grok-build. This describes catalog expansion,
not a promise that bare install selects all nine. Pin your team's actual targets;
package and per-dependency restrictions narrow the authorized set, not expand it.
The versioned matrix also documents stable, explicit-only hermes,
antigravity, and the agent-skills meta-target; experimental targets such as
grok-cloud stay outside all. IntelliJ-specific integration is MCP-only;
its file primitives use Copilot's profile. Kiro now supports agents. For Codex, Gemini, OpenCode,
and Hermes, dependency instructions need a separate apm compile for root context
(exact v0.31.0 matrix).
These are support boundaries, not claims of live runtime tests.
Chapter 5 covers target selection in the consumer loop.
Two of the book's four properties are already visible in this layer. Declaring context as typed
primitives is the basis of Portability — one
declared source set, delivered where its primitive and format are supported. 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 records source identity and deployment ownership, with hashes where
applicable — the basis of
Reproducibility
(Chapter 6) and of
provenance
(Chapter 8).
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:
Choosing a primitive by who — or what — triggers it.
If you want…
Reach for a…
Because
persistent guidance that no one has to invoke manually
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 at a supported agent-runtime event
hook
the harness fires it at that event, not at package installation
a governed connection to an external tool or dataset
MCP server
connection configuration is separate from server execution
several of the above shipped as one installable unit
plugin
its format determines projection versus whole-unit registration
Harness hooks are not APM lifecycle scripts
A hook is a callback for the agent runtime. In the current hook fixture,
.apm/hooks/notice.json's SessionStart became Copilot
sessionStart but remained Claude SessionStart; APM deployed the callback
without running a harness. The event names and native settings are target-specific
(hook projections).
By contrast, a manifest's lifecycle section can run commands such as the fixture's
python record.py on post-install. That is package-manager
automation: automatic project execution requires separate lifecycle trust, and changing the
lifecycle subtree revokes that trust
(lifecycle scripts).
APM is not an agent runtime, but “APM never executes code” would be wrong.
The same declaration boundary limits the install-time content scan: APM scans the
authorized deployable source set before agent-readable deployment, not every file
in the downloaded cache. A source-only README and an unselected skill were outside that set in the
controlled probes. Neither a clean Unicode scan nor a content hash proves benign intent or runtime
safety
(security scope).
Here is Meridian's pile from Chapter 1, sorted into its
primitive map. This map is not a manifest — 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's primitive map — every scattered file from Chapter 1, now typed. A map, not yet a
manifest or CLI output. Retained conceptual snapshot.
apm v0.23.1
# 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. The next sketch is illustrative; Chapter 4 teaches the
real syntax and pins each source, and Chapter 5 installs it.
Conceptual only — the same map as a manifest shape, showing the two dependency buckets
and harness targets. Historical sketch, not a validated project; the eight-target comment describes
that snapshot, not the v0.31.0 catalog. apm v0.23.1
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>
One skill, a different source layout
Meridian's result here is still a typed inventory. A separate, current fixture makes the
package/layout distinction tangible: its existing skill lives
at .claude/skills/checkout-review/SKILL.md, without a package manifest beside it.
The consumer declares that directory as a local dependency and selects Copilot as its destination.
Complete apm.yml from core/onboard-skill — a local skill reference,
not a source-layout conversion. Existing execution evidence; no network dependency.
apm v0.31.0
# Reference an existing skill without moving or translating its source.
name: core-onboard-skill
version: 1.0.0
targets: [copilot]
dependencies:
apm:
- path: ./.claude/skills/checkout-review
Run in a scratch copy of backend/examples/updates/1.2/core/onboard-skill, including
its hidden .claude directory. Observed exit 0; no agent or server execution.
apm v0.31.0
apm install
APM materialized .agents/skills/checkout-review/SKILL.md, leaving the authored skill in
its existing layout. The source happened to be Claude-shaped; the declared
destination was Copilot. You did not need a second hand-maintained copy or an
.apm/ directory, and installing the skill did not invoke it.
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 connection; a hook responds to
harness events, not APM package lifecycle events.
APM is built on open standards — AGENTS.md, SKILL.md, and MCP — not a
replacement for them; apm compile emits distributed AGENTS.md files.
Supported source primitives project into 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 or universally supported.
Recognized Agent Plugins 1.0 instead stay whole for native Copilot registration.
Targets are the declaration you list; the harness is the runtime
that consumes the output. The v0.31.0 catalog is not a promise
that every target supports every primitive.
Declarations govern discovery: .apm/ is one supported source layout, and an explicit
plugin skill list is exhaustive — an empty list means none. Registration, content checks,
and connection configuration are not proof of successful or safe runtime behavior.
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.