Skip to content

feat: Promote sub-skills inside packages to top-level .github/skills/ entries#102

Merged
danielmeppiel merged 2 commits intomicrosoft:mainfrom
sergio-sisternes-epam:feat/promote-sub-skills
Feb 24, 2026
Merged

feat: Promote sub-skills inside packages to top-level .github/skills/ entries#102
danielmeppiel merged 2 commits intomicrosoft:mainfrom
sergio-sisternes-epam:feat/promote-sub-skills

Conversation

@sergio-sisternes-epam
Copy link
Collaborator

🚀 New Feature

Description

Promote sub-skills inside packages to top-level .github/skills/ entries.

When a package contains sub-skills under .apm/skills/<name>/SKILL.md, APM now promotes each one to an independent top-level entry in .github/skills/<name>/ during install. This allows Copilot to discover and invoke them independently.

Rationale

VS Code's skill discovery contract scans .github/skills/<name>/SKILL.md — direct children only, no recursion. Today, if a package ships sub-skills (e.g., a monorepo package with both modernization agents and an Azure naming skill), only the parent package's SKILL.md is discoverable. The sub-skills end up buried inside the parent tree and are invisible to the IDE.

This creates a gap for packages that want to bundle multiple independently-useful skills within a single installable unit. The only workaround today is to split them into separate packages and install each one individually — which adds friction and fights the natural monorepo structure many teams use.

Opinionated design — open to discussion

This PR introduces an opinionated convention: sub-skills live under .apm/skills/, matching the existing authoring namespace where all other primitives already reside (.apm/instructions/, .apm/agents/, .apm/prompts/). This is a design choice, not the only possible approach. Alternative patterns (e.g., top-level skills/ folder, manifest-driven declarations in apm.yml) could achieve similar results with different tradeoffs.

This PR is meant to showcase the usage pattern and validate the concept. The convention and implementation details are subject to discussion.

Changes Made

  • Feature implementation (skill_integrator.py — 56 lines added)
  • Tests added (test_skill_integrator.py — 7 new tests, 179 lines)
  • Documentation updated (docs/skills.md — Option 4 + Sub-skill Promotion section)

Implementation details

_integrate_native_skill() — After the existing copytree to .github/skills/, scans package_path / ".apm" / "skills" for subdirectories containing a SKILL.md. Each qualifying sub-skill is copied to .github/skills/<sub-name>/ (and .claude/skills/<sub-name>/ when .claude/ exists). Name collisions produce a warning and overwrite.

sync_integration() — When building the installed_skill_names set for orphan detection, also scans .apm/skills/ in installed packages so promoted sub-skills aren't marked as orphaned during apm deps sync.

Key design decisions:

  • Only directories containing a SKILL.md are promoted — other files/dirs are ignored
  • Purely additive: the feature is gated behind if sub_skills_dir.is_dir() — packages without .apm/skills/ behave identically to before
  • No existing code paths were modified, only new blocks added after existing logic

Testing

  • Manual testing completed (E2E with agent-library package containing .apm/skills/azure-naming/)
  • All existing tests pass (803/803)
  • New tests added and passing:
    • test_sub_skill_promoted_to_top_level
    • test_multiple_sub_skills_promoted
    • test_sub_skill_without_skill_md_not_promoted
    • test_sub_skill_name_collision_overwrites_with_warning
    • test_sub_skill_promoted_to_claude_skills
    • test_package_without_sub_skills_unchanged
    • test_sync_integration_preserves_promoted_sub_skills

Checklist

  • LABEL: Apply enhancement label to this PR
  • Code follows project style guidelines
  • Documentation updated
  • CHANGELOG.md updated (for significant features)

Fixes #101

…tries

Sub-skills placed under .apm/skills/<name>/SKILL.md are now promoted to
independent top-level entries in .github/skills/<name>/ during install.
This allows Copilot to discover them independently, since it only scans
direct children of .github/skills/.

Closes microsoft#101
Copilot AI review requested due to automatic review settings February 24, 2026 18:40
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a new feature that promotes sub-skills from .apm/skills/ to top-level .github/skills/ entries during package installation. This addresses a limitation in VS Code's Copilot skill discovery, which only scans direct children of .github/skills/ and doesn't recurse into nested directories. The feature enables packages to bundle multiple independently-discoverable skills within a single installable unit.

Changes:

  • Adds sub-skill promotion logic in _integrate_native_skill() to copy sub-skills from .apm/skills/* to top-level .github/skills/ and .claude/skills/ entries
  • Updates sync_integration() to include promoted sub-skills when determining which skills to preserve during cleanup
  • Adds comprehensive test coverage with 7 new tests covering promotion, name collisions, Claude integration, and orphan detection

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

File Description
src/apm_cli/integration/skill_integrator.py Implements sub-skill promotion in _integrate_native_skill() for both GitHub and Claude targets, and updates sync_integration() to preserve promoted sub-skills during cleanup
tests/unit/integration/test_skill_integrator.py Adds 7 comprehensive tests covering sub-skill promotion, multiple sub-skills, invalid directories, name collisions, Claude integration, backward compatibility, and sync preservation
docs/skills.md Documents the new Option 4 (Multi-skill Package) pattern and Sub-skill Promotion behavior with clear examples

- Exclude .apm/ from parent copy to avoid redundant storage
- Extract _promote_sub_skills() helper to eliminate duplication
- Assert warning is emitted on sub-skill name collision
- Add test for sub-skill name normalization (invalid → valid)
@danielmeppiel danielmeppiel self-requested a review February 24, 2026 20:48
Copy link
Collaborator

@danielmeppiel danielmeppiel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great and needed implementation, tested corner cases locally and it works well, thank you!

@danielmeppiel danielmeppiel added this to the 0.7.4 milestone Feb 24, 2026
@danielmeppiel danielmeppiel added the enhancement New feature or request label Feb 24, 2026
@sergio-sisternes-epam sergio-sisternes-epam changed the title [FEATURE] Promote sub-skills inside packages to top-level .github/skills/ entries feat: Promote sub-skills inside packages to top-level .github/skills/ entries Feb 24, 2026
@danielmeppiel danielmeppiel merged commit 035a83f into microsoft:main Feb 24, 2026
11 checks passed
@sergio-sisternes-epam sergio-sisternes-epam deleted the feat/promote-sub-skills branch February 26, 2026 18:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE] Promote sub-skills inside packages to top-level .github/skills/ entries

3 participants