Skip to content

APM integration — a few alignment notes from the APM side #1015

Description

@danielmeppiel

Hey Squad team — first off, thanks for shipping #876 and following up so cleanly with #963. Squad reaching for APM as the distribution layer is a milestone, and the framing in the PR description (".squad/ remains the source of truth — APM is an export layer") nails the architecture I'd hoped third-party tools would land on.

I'm Daniel, the maintainer of microsoft/apm. Working through the merged code, I noticed the integration drifts from APM's current contract in a handful of spots. Each one has a documented APM-side answer, and most would simplify Squad's code in the process. Writing this up so it's all in one place — happy to send a PR for the mechanical bits if it's useful.

Summary

# Area Squad today APM contract
1 apm.yml schema Top-level skills: / instructions: / prompts: Not valid keys; primitives are discovered from .apm/
2 Install Reimplemented via gh api + a regex YAML parser Shell out to apm install owner/repo[/skill-name]
3 Publish/portability Custom apm.yml regen apm pack --format plugin produces a portable bundle
4 Distribution model "APM registry" / apm publish Git-native; no registry; apm publish doesn't exist
5 Skill source path .copilot/skills/<name>/skill.md .apm/skills/<name>/SKILL.md (then APM deploys to .copilot/, .github/, etc.)

1. apm.yml doesn't have skills: / instructions: / prompts: top-level keys

The manifest only recognizes name, version, description, author, license, target, type, scripts, dependencies, devDependencies, compilation (manifest-schema §2). Primitives aren't declared in the manifest — they're discovered from .apm/<primitive>/ directories (primitive-types). The blocks Squad emits are silently ignored by apm install, and the target: paths inside them aren't honored — APM's integrators decide deployment paths based on the consumer's target: setting.

Suggested: emit only the fields APM reads — typically name, version, and (when relevant) a dependencies.apm: block. Skill content goes in .apm/skills/<name>/SKILL.md and is picked up automatically.


2. squad skill install reimplements apm install

The current path uses gh api to fetch the upstream apm.yml, parses it with a regex YAML reader, then gh api-fetches each skill.md. APM's apm install already does this and a lot more (cli-commands):

apm install owner/repo                  # whole package
apm install owner/repo/skill-name       # virtual subdirectory (selective)
apm install owner/repo/path/skill.md    # single file

You also get lockfile pinning (apm.lock.yaml), transitive resolution, content-hash verification, and security scanning — none of which are reachable via the gh api path. The lockfile also tracks provenance, so .apm-source.json becomes redundant.

Suggested: swap the install internals for execFile('apm', ['install', source]). Drops ~200 LOC including the YAML parser flagged in #963.


3. The actual feature for "make this Squad portable" is apm pack --format plugin

squad skill publish regenerates apm.yml to advertise local skills. The intent — "make this skill bundle portable so others can use it" — is exactly what apm pack --format plugin solves (pack-distribute §plugin format):

"apm pack --format plugin transforms your project into a standalone plugin directory consumable by Copilot CLI, Claude Code, or other plugin hosts. The output contains no APM-specific files."

Mapping:

Source Plugin output
.apm/skills/*/SKILL.md skills/*/SKILL.md
.apm/agents/*.agent.md agents/*.agent.md
.apm/prompts/*.prompt.md commands/*.md
.apm/instructions/*.instructions.md instructions/*.instructions.md

Suggested: squad skill publish shells out to apm pack --format plugin after laying skills out under .apm/skills/<name>/SKILL.md. Users git push the resulting bundle. This also unlocks "hybrid mode" (guides/plugins) — Squad packages can declare dev-only deps that get excluded from the published bundle.


4. There's no APM registry and no apm publish

A few user-facing strings reference both:

  • skill.ts:173"push to GitHub to share via APM registry"
  • skill.ts:183"Run 'apm publish' to push to the APM registry"
  • skill.ts:298 (help) — "APM registry: https://github.com/microsoft/apm"

APM is git-native by design (what-is-apm):

"Distribute. Any git repository is a valid APM package. Publish by pushing to a git remote — no registry required."

microsoft/apm is the source repo, not a registry endpoint. Marketplaces (guides/marketplaces) exist as optional curated indexes for discovery, but there's no apm publish and no plan to add one — the model is intentionally git push.

Suggested: update the strings to "Run apm pack --format plugin to produce a portable bundle, then git push to share."


5. Skill source location: .apm/skills/, not .copilot/skills/

Worth being precise on the directory model since the doc has been ambiguous on this:

  • .apm/<primitive>/ is where a project's own primitives live (the project itself is a package). APM discovers them automatically.
  • .copilot/, .github/, .claude/, .cursor/ are deploy targets that apm install populates, both from local .apm/ content and from installed dependencies. They're outputs, not sources.

Today resolveSkillsDir writes skills to .copilot/skills/<name>/skill.md as the source location, which inverts that model. (Side note: @Omzig already noted in #924 that Copilot CLI doesn't actually read .copilot/skills/ either, so users probably aren't getting what they expect on the consumer side.)

Suggested: treat .apm/skills/<name>/SKILL.md as the source of truth. APM's integrators handle the per-target deployment.


On the APM side

A few things shipping in parallel that should make this easier going forward:

  • JSON Schema for apm.yml (warns rather than errors on unknown top-level keys, so existing Squad-generated manifests in the wild won't break overnight).
  • A short doc page aimed at framework authors integrating with APM, with Squad as the worked example if you're OK with that.

Offer

Items 1, 2, 4, 5 are mechanical and I'd estimate ~150 LOC net delta (negative once the YAML parser comes out). Happy to PR them in one or split across a few. Item 3 is a UX shift for squad skill publish so I'd defer to you on direction before opening anything.

Let me know what's useful — no obligation either way, and again, really nice to see APM integration in Squad.

— Daniel

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions