Skip to content

Fix --skill filter silent no-op: warn when zero skills match (#2116)#2117

Open
sergio-sisternes-epam wants to merge 1 commit into
mainfrom
sergio-sisternes-epam-fix-install-skill-silent-noop-2116
Open

Fix --skill filter silent no-op: warn when zero skills match (#2116)#2117
sergio-sisternes-epam wants to merge 1 commit into
mainfrom
sergio-sisternes-epam-fix-install-skill-silent-noop-2116

Conversation

@sergio-sisternes-epam

Copy link
Copy Markdown
Collaborator

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 whose plugin.json declares an explicit skills array, 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 in plugin.json), zero skills are promoted -- but the exit code stays 0 and no diagnostic is printed. The output is indistinguishable from a successful install.

"Running apm install <plugin> --skill <name> reports success and deploys nothing when <name> is not exposed by the plugin's plugin.json skills array." -- #2116


Approach (WHAT)

Add a post-loop guard in the two code paths that consume name_filter:

Code path Package type Skills source
_integrate_skill_bundle SKILL_BUNDLE package_root/skills/
_promote_sub_skills_standalone INSTRUCTIONS / others .apm/skills/

After the targets loop completes, if name_filter was set (--skill was passed) and total_promoted == 0, call _rich_warning listing 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_SKILL warning precedent at line 1358.


Implementation (HOW)

src/apm_cli/integration/skill_integrator.py
  _integrate_skill_bundle         -- post-loop zero-match guard
  _promote_sub_skills_standalone  -- post-loop zero-match guard

tests/unit/integration/test_skill_integrator_hermetic.py
  TestIntegrateSkillBundleSubsetNoMatch         -- 2 cases
  TestPromoteSubSkillsStandaloneSubsetNoMatch   -- 2 cases

packages/apm-guide/.apm/skills/apm-usage/commands.md
  -- extend --skill description with zero-match warning note

Example output after fix

[!] --skill filter matched no skills in this package. Requested: engineering/resolving-merge-conflicts. Available: ask-matt, code-review, ..., tdd, teach, ..., writing-great-skills.

Trade-offs

  • Not an error (exit 1): A zero-match is a user-intent mismatch, not a system failure. The install contract still holds -- nothing unexpected was deployed.
  • plugin_parser.py path-remap logic untouched: The separate design tension (plugin.json skills array narrowing what is installable vs. auto-discovery) is flagged in the issue as a separate concern and is not addressed here.
  • Warning shows staged available names, not source-repo names: For MARKETPLACE_PLUGIN the available list reflects what plugin.json exposed, which is the correct actionable list for --skill.

Validation evidence

uv run --extra dev pytest tests/unit/integration/test_skill_integrator_hermetic.py -x -q
# 46 passed

uv run --extra dev ruff check src/ tests/
# All checks passed!

uv run --extra dev ruff format --check src/ tests/
# 1417 files already formatted

uv run --extra dev python -m pylint --disable=all --enable=R0801 --min-similarity-lines=10 --fail-on=R0801 src/apm_cli/
# Your code has been rated at 10.00/10

bash scripts/lint-auth-signals.sh
# [+] auth-signal lint clean

How to test

  1. Create a temp project with an apm.yml targeting claude.
  2. Install mattpocock/skills --skill engineering/resolving-merge-conflicts (not in plugin.json).
  3. Confirm a [!] --skill filter matched no skills warning is printed and .claude/skills/ remains empty.
  4. Install mattpocock/skills --skill tdd (listed in plugin.json).
  5. Confirm .claude/skills/tdd/ is populated with no warning.

Closes #2116

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>
Copilot AI review requested due to automatic review settings July 10, 2026 11:02

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 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_bundle and SkillIntegrator._promote_sub_skills_standalone.
  • Add hermetic unit tests covering the warning/no-warning cases for both code paths.
  • Update the apm install --skill flag 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.

Comment on lines +902 to +904
available_str = ", ".join(available) if available else "(none)"
requested_str = ", ".join(sorted(name_filter))
_rich_warning(
Comment on lines +1255 to +1257
available_str = ", ".join(available) if available else "(none)"
requested_str = ", ".join(sorted(_name_filter))
_rich_warning(
@Addono

Addono commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Not an error (exit 1): A zero-match is a user-intent mismatch, not a system failure. The install contract still holds -- nothing unexpected was deployed.

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 --skill flag), then a no-op means invalid user input, thus warrants returning an error.

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 --skill acts like a a filter, but that requires reading a bit in-between the lines of the --help docs [highlight is mine]:

  --skill NAME                    Install **only** named skill(s) from a
                                  SKILL_BUNDLE. Repeatable. Persisted in
                                  apm.yml and apm.lock so bare 'apm install'
                                  is deterministic. Additive across installs:
                                  a later --skill X adds X to the existing pin
                                  (union) rather than replacing it. Use
                                  --skill '*' (quote the asterisk in your
                                  shell) to reset to all skills; to drop a
                                  single skill, edit the skills: list in
                                  apm.yml then re-run apm install.
``

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] apm install --skill <name> is a silent no-op when the skill is not in the plugin.json skills array

3 participants