Skip to content

feat: Move APM dependency resolution to activation job via pack/unpack #20380

@danielmeppiel

Description

@danielmeppiel

Context

The dependencies: frontmatter field already exists (pkg/workflow/apm_dependencies.go) and generates a single microsoft/apm-action@v1 step in the agent job. This works but has three problems:

  1. Slow agent startup — The agent job installs APM + resolves dependencies at runtime. Every retry re-resolves from scratch.
  2. Network-dependent — Dependency resolution requires network access during the agent job, which is the most restricted phase.
  3. Non-deterministic across retries — If a package updates between agent job retries, the agent gets different primitives.

Proposal

Resolve and pack in the activation job; unpack in the agent job.

This follows the same pattern already used for prompt.txt and aw_info.json: the activation job generates artifacts, uploads them, and the agent job downloads and uses them.

┌──────────────────────────────────────────────────────┐
│ ACTIVATION JOB                                       │
│                                                      │
│  1. Install APM + resolve dependencies               │
│  2. apm pack → /tmp/gh-aw/apm-bundle/*.tar.gz       │
│  3. Upload bundle inside the "activation" artifact   │
└─────────────────────┬────────────────────────────────┘
                      │ artifact: "activation"
                      ▼
┌──────────────────────────────────────────────────────┐
│ AGENT JOB                                            │
│                                                      │
│  1. Download "activation" artifact (already exists)  │
│  2. apm-action restore from bundle → deploys to .    │
│     Primitives land in .github/{instructions,skills,…}│
│  3. Agent sees primitives naturally                  │
└──────────────────────────────────────────────────────┘

The bundle rides the existing activation artifact — just add the bundle path to the existing upload's path list. No separate artifact, no extra download step.

Frontmatter API (No Breaking Changes)

The existing array format continues to work unchanged. An optional object format adds isolated and target:

# Simple (90% of cases) — additive, target=copilot
dependencies:
  - microsoft/compliance-rules@v2
  - myorg/security-scanning-skill

# Extended — object format with options
dependencies:
  packages:
    - microsoft/compliance-rules@v2
    - myorg/security-scanning-skill
  isolated: true      # default: false — clear repo primitives before unpack
  target: claude      # default: copilot

Defaults:

  • isolated: false — Additive by default. The unpacked bundle merges on top of the repo's existing .github/ primitives. Users who want the repo's own instructions + workflow-specific deps get that naturally.
  • target: copilot — Packs only .github/ prefix files. Can be set to claude or all.

Compiled Output: Before → After

BEFORE (current) — single step in agent job:

# agent job
- name: Install APM dependencies
  uses: microsoft/apm-action@<sha>
  with:
    dependencies: |
      - microsoft/compliance-rules
      - myorg/security-skill

AFTER — pack in activation, unpack in agent:

# ── activation job (new steps, before artifact upload) ──

- name: Install and pack APM dependencies
  uses: microsoft/apm-action@<sha>
  with:
    dependencies: |
      - microsoft/compliance-rules
      - myorg/security-skill
    isolated: true        # activation has no repo context to preserve
    pack: true
    archive: true
    target: copilot
    working-directory: /tmp/gh-aw/apm-workspace

- name: Upload activation artifact          # MODIFIED — add bundle path
  uses: actions/upload-artifact@<sha>
  with:
    name: activation
    path: |
      /tmp/gh-aw/aw_info.json
      /tmp/gh-aw/aw-prompts/prompt.txt
      ${{ steps.apm_pack.outputs.bundle-path }}    # ← NEW
    retention-days: 1

# ── agent job (replace current install step) ──

- name: Restore APM dependencies
  uses: microsoft/apm-action@<sha>
  with:
    bundle: /tmp/gh-aw/apm-bundle/*.tar.gz

When isolated: true is set in frontmatter, the agent restore step also passes isolated: true (to clear repo primitive dirs before unpack):

- name: Restore APM dependencies
  uses: microsoft/apm-action@<sha>
  with:
    bundle: /tmp/gh-aw/apm-bundle/*.tar.gz
    isolated: true

Design Notes

Activation sparse checkout

The activation job sparse-checkouts only .github/ and .agents/ — it does not have apm.yml from the repo root. This is fine because apm-action receives packages via the dependencies: input directly (no apm.yml needed). The activation-side isolated: true is always set because there's no repo context to preserve there. The frontmatter isolated flag is a separate concern — it controls whether the agent job clears repo primitives before unpacking.

apm-action compatibility

microsoft/apm-action@v1 already supports all required inputs: dependencies, isolated, pack, archive, target, bundle. isolated: true + bundle: works together (clears dirs before restore). No apm-action changes needed.

Acceptance Criteria

  • dependencies: [array] format continues to work (backward compatible)
  • dependencies: {packages, isolated, target} object format works
  • Pack step emitted in activation job (before artifact upload)
  • Activation artifact upload includes APM bundle path
  • Unpack step emitted in agent job (after activation artifact download)
  • isolated: false (default): agent unpack is additive to repo context
  • isolated: true: agent clears .github/ primitive dirs before unpack
  • target defaults to copilot
  • No APM steps generated when dependencies: is absent or empty
  • make agent-finish passes
  • Existing compilation tests updated and passing

Metadata

Metadata

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions