Installing APM Packages and Primitives

This page is for consumers — repositories that depend on APM content. Authors should read Publishing instead.


Prerequisites

RequirementHow to get it
gh CLI authenticated against github.com with repo scope on calab-aigh auth login and gh auth refresh -h github.com -s repo
gh-calab extension installedgh extension install calab-ai/gh-calab
Optional: a clean working treegh calab apm sync writes files; commit or stash local changes first

Sanity-check everything in one command:

gh calab doctor

doctor exits 0 when the toolchain is healthy and 7 if gh lacks the required scopes.


Initialize the workspace

If your repo doesn’t already have an apm.yml:

gh calab workspace init --tool copilot

This writes a minimal apm.yml. Add --force (-f) only when you intentionally want to overwrite an existing manifest.

Supported --tool values today: copilot (default). The flag tags the generated manifest with the target AI tool so the catalog can filter.


Install — three forms

A. Single-arg install (auto-detect, GA)

gh calab apm install <id-or-name>

The argument is auto-classified by shape:

  • A bare package name like calab-workspace-base → resolved as a package.
  • A reverse-domain id matching ^calab\.package\.[a-z][a-z0-9-]+$ → package.
  • A reverse-domain id matching ^calab\.(agent|instructions|prompt|skill|hook|init)\.[a-z][a-z0-9-]+$ → primitive.

Both forms are accepted for packages. Existing handbook docs (e.g. the Marketplace, [Decision 11](../../../00 Governance/Decisions/11 APM CLI Direction.md), and the APM sequence diagrams) use the short package name (calab-workspace-base) and that is the preferred form for packages. Primitives must use the reverse-domain id because the short name alone is ambiguous across primitive types.

Examples (against the current GA catalog):

# Packages — short name (preferred) or reverse-domain id both work
gh calab apm install calab-workspace-base
gh calab apm install calab-org-agents
gh calab apm install calab.package.workspace-base   # equivalent
 
# Primitives — reverse-domain id (required)
gh calab apm install calab.agent.build
gh calab apm install calab.agent.plan
gh calab apm install calab.instructions.coding-standards
gh calab apm install calab.instructions.security
gh calab apm install calab.skill.az-cli
gh calab apm install calab.skill.gh-cli
gh calab apm install calab.skill.summarise
gh calab apm install calab.skill.export-to-pdf
gh calab apm install calab.skill.todo-cli
gh calab apm install calab.skill.repo-calab-handbook
gh calab apm install calab.skill.repo-github-private
gh calab apm install calab.init.cloud-agent-setup

Unrecognised id shapes exit 2 (usage error). Names or ids that don’t exist in the catalog exit 3 (not found).

B. Explicit subcommands (landing in calab-ai/gh-calab#7)

These make the intent unambiguous and let CI assert the kind:

gh calab apm install package   <package-id>
gh calab apm install primitive <primitive-id>

A subcommand asserts the kind. Mismatch — for example gh calab apm install package calab.skill.az-cli — exits 4 (validation error) rather than silently doing the wrong thing.

C. The --kind flag (also in PR #7)

For one-shot scripts where you want kind-checking without using the subcommand form:

gh calab apm install --kind package   calab-workspace-base
gh calab apm install --kind primitive calab.skill.az-cli
gh calab apm install --kind=primitive calab.skill.az-cli   # `=` form also works

Same exit-4 contract on mismatch.

Status: PR #7 is open (not yet merged) at the time of writing. Until it merges, only form A is live; form B/C will start working immediately on merge with no apm.yml migration required.


What apm install actually does

For each install:

  1. Resolves the id against the current catalog (portal-data.json, falling back to Git tag enumeration).
  2. Adds a dependency entry to apm.yml:
    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
  3. Resolves the manifest into apm.lock.yaml (commit SHA + per-file SHA-256 hashes).
  4. Writes the resolved files to the declared targets.
  5. Records every written file in .generated-from-apm.json (provenance).

The JSON envelope (with --json) returns:

{
  "ok": true,
  "command": "apm install",
  "data": {
    "kind": "package",
    "kind_detected": true,
    "installed": [
      {
        "id": "calab.package.workspace-base",
        "ref": "refs/tags/packages/calab-workspace-base/v1.0.0",
        "commit": "8f3c2a1...",
        "files": [".github/copilot/agents/build/agent.md", "..."]
      }
    ]
  }
}

kind_detected is false when the kind was asserted via subcommand or --kind.


Browsing the catalog

gh calab apm catalog                # human-readable
gh calab apm catalog --json         # machine-readable, schema in apm-cli-contract.md

The handbook also renders a current snapshot at APM Marketplace, and the live portal lives at https://cautious-adventure-p3oze29.pages.github.io/.


Verifying the install

gh calab apm validate          # schema + policy checks
gh calab apm validate --verify # also re-downloads + re-hashes every installed file

Validate exits non-zero on any drift (lockfile vs manifest, missing files, branch ref where tags are required, hash mismatch).


Common patterns

Install the org base for a brand-new consumer repo

gh calab workspace init --tool copilot
gh calab apm install calab-workspace-base
git add apm.yml apm.lock.yaml .github/copilot .generated-from-apm.json
git commit -m "chore(apm): adopt calab-workspace-base v1.0.0"

Add a single skill to an existing manifest

gh calab apm install calab.skill.export-to-pdf
git add apm.yml apm.lock.yaml .github/copilot .generated-from-apm.json
git commit -m "chore(apm): add export-to-pdf skill"

CI-side install from the lockfile (no manifest edit)

- name: Install APM dependencies
  run: gh calab apm sync
  env:
    GH_TOKEN: ${{ github.token }}

apm sync reads apm.lock.yaml and reproduces a byte-identical tree. Never call apm install from CI.