Skip to content

apm.yml inside collections/<name>/ is ignored — Collection detector preempts package resolution #1094

@lirantal

Description

@lirantal

Summary

Two related gaps prevent a natural "meta-package" mental model — i.e., a sub-path inside a monorepo whose apm.yml purely declares dependencies on other skills/MCPs/packages:

  1. /collections/ path segment hard-routes to the .collection.yml parser, shadowing any apm.yml that lives at <repo>/collections/<name>/apm.yml.
  2. Pure dependency-only apm.yml (no .apm/ directory) fails validation, even though APM correctly resolves and installs the declared transitive deps before erroring out.

The first was acknowledged inline on closed issue #74 by @danielmeppiel:

when the subfolder is under a collections/ path, APM currently forces collection detection. I'll make sure apm.yml takes priority there too.

The second is a separate constraint that surfaces as soon as you work around the first.

Mental model the user expects

A monorepo of skills where each subfolder is a curated bundle with its own apm.yml listing transitive deps — installable by sub-path:

lirantal/skills/                          (one repo)
├── skills/                               (authored skills, single SKILL.md each)
│   ├── writing-style-explainer/
│   └── gh-bulk-repo-edit/
└── bundles/                              (curated meta-packages)
    └── writing/
        └── apm.yml                       ← lists skills + 3rd-party deps + MCPs

bundles/writing/apm.yml:

name: writing
version: 1.0.0
dependencies:
  apm:
    - lirantal/skills/skills/writing-style-explainer
    - blader/humanizer
  mcp: []

Goal: from a fresh project, apm install lirantal/skills/bundles/writing should pull in the two skills declared above.

Gap 1 — /collections/ shadowing

Repro

With the bundle at collections/writing/apm.yml:

$ apm install lirantal/skills/collections/writing --verbose
[*] Validating 1 package...
[x] lirantal/skills/collections/writing -- not accessible or doesn't exist

(The "Authentication failed" hint in --verbose is misleading — auth is fine.)

Object form exposes the real cause:

- git: https://github.com/lirantal/skills
  path: collections/writing
Failed to download dependency lirantal/skills: Collection manifest not found:
collections/writing.collection.yml (also tried .yaml)

APM hard-routes any /collections/ path to src/apm_cli/deps/collection_parser.py and never considers that a real apm.yml lives at collections/writing/apm.yml.

Why .collection.yml isn't a substitute

.collection.yml (per collection_parser.py) is a flat list of in-repo primitive files with kind ∈ {prompt, instruction, chat-mode, agent, context}. It cannot express skill deps, MCP server deps, or transitive apm: package deps.

Workaround

Rename collections/bundles/ (or any segment that doesn't contain collections). The /collections/ heuristic stops firing and APM proceeds to the subdirectory-package code path. ✅ Verified empirically.

Gap 2 — pure dependency-only meta-package fails validation

After the rename workaround, apm install lirantal/skills/bundles/writing correctly resolves and installs the two transitive deps:

[+] github.com/lirantal/skills/bundles/writing (cached)
[+] blader/humanizer (cached)
|-- Skill integrated -> .github/skills/
[+] github.com/lirantal/skills/skills/writing-style-explainer (cached)
|-- Skill integrated -> .github/skills/

But the meta-package itself fails post-validation:

Failed to download dependency lirantal/skills: Subdirectory is not a valid APM
package or Claude Skill: Not a valid APM package: writing has apm.yml but is
missing the required .apm/ directory. Add .apm/ with primitives (instructions,
skills, etc.) or add skills/<name>/SKILL.md for a skill bundle.

The install ends with [!] Installed 2 APM dependencies with 1 error(s). — non-zero status, CI-failing — even though the user-visible outcome is correct.

The validator currently rejects an apm.yml whose only role is to declare dependencies. There's no way to express "this is a meta-package, no own primitives, just a curated dependency set."

Workaround

Adding an empty .apm/ directory (committed via .gitkeep) silences the validator and produces a clean install:

$ apm install lirantal/skills/bundles/writing
[*] Installed 3 APM dependencies.

But this is a wart — users have to commit a placeholder file just to satisfy a structural check that doesn't reflect any real requirement, and it pollutes the repo with empty directories that exist only to humor the tool.

Suggested fix

For Gap 1

  1. apm.yml should take priority over the /collections/ heuristic. If <path>/apm.yml exists in the target ref, treat it as a Subdirectory APM package and run the normal resolver. Only fall back to .collection.yml detection when no apm.yml is present.
  2. (Optional) An object-form opt-out, e.g. kind: package, that disables auto-classification.

For Gap 2

  1. Recognize dependency-only meta-packages as a valid package shape. When an apm.yml declares dependencies but no .apm/ content (and is not a skill bundle), don't treat it as malformed — just resolve its deps and exit cleanly. There is no good reason to require an empty .apm/ directory; the CLI should figure this out for users.
  2. (Optional) If a marker is wanted for clarity, allow type: meta (or similar) in apm.yml to make intent explicit, rather than inferring shape from on-disk layout.

Together these would make the user's mental model — "a monorepo of bundles, each a curated dep set, installable by sub-path" — work natively, without renames or placeholder files.

Environment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status

    In Progress

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions