Fix --skill filter silent no-op: warn when zero skills match (#2116)#2117
Fix --skill filter silent no-op: warn when zero skills match (#2116)#2117sergio-sisternes-epam wants to merge 1 commit into
--skill filter silent no-op: warn when zero skills match (#2116)#2117Conversation
When --skill <name> is passed but no skill in the package matches the filter, _integrate_skill_bundle and _promote_sub_skills_standalone now emit _rich_warning listing the requested names and available skill names. Exit code stays 0; only the missing diagnostic is added. Mirrors the existing warning precedent for --skill on a native CLAUDE_SKILL (skill_integrator.py:1358). Closes #2116 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR improves apm install --skill UX by warning (instead of silently succeeding) when a requested skill filter matches zero promotable skills for SKILL_BUNDLE and standalone sub-skill promotion paths.
Changes:
- Add post-loop zero-match warnings in
SkillIntegrator._integrate_skill_bundleandSkillIntegrator._promote_sub_skills_standalone. - Add hermetic unit tests covering the warning/no-warning cases for both code paths.
- Update the
apm install--skillflag documentation to mention the zero-match warning behavior.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
src/apm_cli/integration/skill_integrator.py |
Emits a [!] warning when --skill is provided but no skills are promoted in the relevant promotion paths. |
tests/unit/integration/test_skill_integrator_hermetic.py |
Adds regression tests asserting warnings are emitted only for subset filters that match nothing. |
packages/apm-guide/.apm/skills/apm-usage/commands.md |
Documents the new zero-match warning behavior for --skill. |
| available_str = ", ".join(available) if available else "(none)" | ||
| requested_str = ", ".join(sorted(name_filter)) | ||
| _rich_warning( |
| available_str = ", ".join(available) if available else "(none)" | ||
| requested_str = ", ".join(sorted(_name_filter)) | ||
| _rich_warning( |
I disagree with this statement. It misses the point, especially with "the contract still holds - nothing unexpected was deployed": the user's query expects "something" to be deployed, yet the tool doesn't.* IMO it should do more than warn in this case, because when the user clearly intends to install something (by virtue of setting an explicit value for the This will also greatly help automation, including agents, to get a signal that their input was invalid. A zero-code with warning still hints at success and requires additional reasoning to understand that it didn't actually achieve what the original command seemed to indicate it would. [Didn't want to get too deep into solutioning on the issue :), but happy to chip in my thoughts here.] *Except if the contract of the tool is that |
TL;DR
apm install <pkg> --skill <name>now emits a[!]warning when the filter matches zero available skills instead of silently succeeding with nothing deployed.Problem (WHY)
When
--skill <name>is specified for a SKILL_BUNDLE or a MARKETPLACE_PLUGIN whoseplugin.jsondeclares an explicitskillsarray, the filter is applied against the staged set. If the requested name is absent (e.g. it exists in the source repo but is not listed inplugin.json), zero skills are promoted -- but the exit code stays 0 and no diagnostic is printed. The output is indistinguishable from a successful install.Approach (WHAT)
Add a post-loop guard in the two code paths that consume
name_filter:_integrate_skill_bundlepackage_root/skills/_promote_sub_skills_standalone.apm/skills/After the targets loop completes, if
name_filterwas set (--skillwas passed) andtotal_promoted == 0, call_rich_warninglisting what was requested and what was available. Exit code is unchanged (0).This mirrors the existing
--skill filter ignored for '<pkg>': package is a single CLAUDE_SKILLwarning precedent at line 1358.Implementation (HOW)
Example output after fix
Trade-offs
plugin_parser.pypath-remap logic untouched: The separate design tension (plugin.jsonskillsarray narrowing what is installable vs. auto-discovery) is flagged in the issue as a separate concern and is not addressed here.plugin.jsonexposed, which is the correct actionable list for--skill.Validation evidence
How to test
apm.ymltargetingclaude.mattpocock/skills --skill engineering/resolving-merge-conflicts(not inplugin.json).[!] --skill filter matched no skillswarning is printed and.claude/skills/remains empty.mattpocock/skills --skill tdd(listed inplugin.json)..claude/skills/tdd/is populated with no warning.Closes #2116