APM Concepts

This page is the shared vocabulary for everything else in this onboarding set. Read it once; the rest will make sense.

At a glance

TermOne-line definitionLives in
PrimitiveA single, independently versioned building block (agent, instructions, prompt, skill, hook, or init script).primitives/<type>/<name>/ in calab-ai/apm-registry
PackageA named, versioned bundle that composes one or more primitives.packages/<name>/ in calab-ai/apm-registry
RegistryThe Git-backed source of truth for primitives and packages.calab-ai/apm-registry
CatalogA versioned snapshot (portal-data.json) of everything published.catalog/ in the registry, attached to each release
Manifest (apm.yml)The desired-state dependency list authored in a consumer repo.Consumer repository root
Lockfile (apm.lock.yaml)The fully resolved tag → commit SHA + file-hash record.Consumer repository root
Provenance (.generated-from-apm.json)Per-file record of where every installed file came from.Consumer repository root

Primitives

A primitive is the smallest unit APM ships. It lives at primitives/<type>/<name>/ and always carries an apm-primitive.json manifest validated against schemas/apm-primitive.schema.json.

The six primitive type values, with the directory each maps to:

typeDirectoryTypical entrypointWhat it is
agentsprimitives/agents/<name>/agent.mdA Copilot/Claude/Codex agent definition (frontmatter + system prompt).
instructionsprimitives/instructions/<name>/instructions.mdAlways-on guidance scoped by glob (e.g. coding standards, security rules).
promptsprimitives/prompts/<name>/prompt.mdReusable, parameterized prompt template.
skillsprimitives/skills/<name>/SKILL.mdA Copilot skill (capability + invocation contract + supporting files).
hooksprimitives/hooks/<name>/hook.ps1 / hook.shPre- or post-task local automation invoked by the agent runtime.
initprimitives/init/<name>/init.ps1 / init.shFirst-run workspace setup (e.g. cloud-agent-setup).

The id pattern is ^[a-z][a-z0-9]*\.(agent|instructions|prompt|skill|hook|init)\.[a-z][a-z0-9-]+$ — note the singular type segment in the id (calab.agent.build) versus the plural directory (primitives/agents/build/).

Primitives are independently versioned; each release gets a tag of shape refs/tags/primitives/<type>/<name>/v<version>.

Packages

A package at packages/<name>/ composes primitives into a named, installable bundle. Its apm-package.json is validated against schemas/apm-package.schema.json and lists primitives by registry-relative path:

{
  "id": "calab.package.workspace-base",
  "name": "calab-workspace-base",
  "version": "1.0.0",
  "primitives": [
    { "ref": "primitives/agents/build" },
    { "ref": "primitives/agents/plan" },
    { "ref": "primitives/instructions/coding-standards" },
    { "ref": "primitives/skills/gh-cli" }
  ]
}

Packages have their own version (and tag, refs/tags/packages/<name>/v<version>) independent of the primitives they reference. A package version bump is required whenever the primitive set changes or a referenced primitive bumps a major version.

The two GA packages today are:

Registry

The registry is just the repo: calab-ai/apm-registry. It owns:

  • primitives/ and packages/ — source of truth for content.
  • schemas/ — JSON Schema files for every manifest type.
  • catalog/ — generator script and the latest portal-data.json snapshot.
  • distribution/ — release artefacts (e.g. payload for .github-private in [Decision 14](../../../00 Governance/Decisions/14 APM GitHub Private Distribution.md)).

There is no runtime registry service today. Per [Decision 15](../../../00 Governance/Decisions/15 APM Future Registry Service.md), Git tags + gh api + portal-data.json are the protocol.

Catalog and portal-data.json

Each apm-registry release attaches a portal-data.json artifact (≈6 KB at v1.6.1) that lists every published primitive and package with its current GA version, ref, and metadata. The schema is schemas/portal-data.schema.json.

gh calab apm catalog reads portal-data.json (falling back to Git tag enumeration if absent) and powers both:

Manifest (apm.yml)

apm.yml is the single human-authored file in a consumer repo. It declares dependencies as (repo, ref, path) tuples:

version: "1"
name: my-consumer-repo
dependencies:
  - id: calab.package.workspace-base
    source:
      repo: calab-ai/apm-registry
      ref: refs/tags/packages/calab-workspace-base/v1.0.0
      path: packages/calab-workspace-base
    targets:
      - path: .github/copilot

Schema: schemas/apm-manifest.schema.json.

Production manifests must use tag refs. Branch refs are rejected by default (override only in dev with policy.allow_branch_refs: true).

Lockfile (apm.lock.yaml)

apm.lock.yaml is the machine-generated derived file produced by gh calab apm resolve. For every dependency it records:

  • the resolved commit SHA the tag pointed at,
  • a SHA-256 hash of every file in the dependency,
  • the policy snapshot at resolve time.

Schema: schemas/apm-lock.schema.json.

Two consumers running apm sync against the same lockfile produce byte-identical trees. That is the whole reason it exists.

Provenance (.generated-from-apm.json)

Every file apm sync writes is recorded in .generated-from-apm.json with its source ref, commit, path, and hash. This is what makes safe deletion possible: apm sync only removes files it previously wrote.

Schema: schemas/generated-from-apm.schema.json.


Tag-ref convention

APM uses three tag prefixes — never overlap them:

refs/tags/catalog/v<version>                      # whole-catalog snapshot
refs/tags/packages/<name>/v<version>              # one package
refs/tags/primitives/<type>/<name>/v<version>     # one primitive

See docs/apm-tag-ref-conventions.md in the registry for the canonical rules.