fix: disabled skills respected across banner, system prompt, slash commands, and skill_view (#1897)

* fix: banner skill count now respects disabled skills and platform filtering

The banner's get_available_skills() was doing a raw rglob scan of
~/.hermes/skills/ without checking:
- Whether skills are disabled (skills.disabled config)
- Whether skills match the current platform (platforms: frontmatter)

This caused the banner to show inflated skill counts (e.g. '100 skills'
when many are disabled) and list macOS-only skills on Linux.

Fix: delegate to _find_all_skills() from tools/skills_tool which already
handles both platform gating and disabled-skill filtering.

* fix: system prompt and slash commands now respect disabled skills

Two more places where disabled skills were still surfaced:

1. build_skills_system_prompt() in prompt_builder.py — disabled skills
   appeared in the <available_skills> system prompt section, causing
   the agent to suggest/load them despite being disabled.

2. scan_skill_commands() in skill_commands.py — disabled skills still
   registered as /skill-name slash commands in CLI help and could be
   invoked.

Both now load _get_disabled_skill_names() and filter accordingly.

* fix: skill_view blocks disabled skills

skill_view() checked platform compatibility but not disabled state,
so the agent could still load and read disabled skills directly.

Now returns a clear error when a disabled skill is requested, telling
the user to enable it via hermes skills or inspect the files manually.

---------

Co-authored-by: Test <test@test.com>
This commit is contained in:
Teknium 2026-03-18 03:17:37 -07:00 committed by GitHub
parent 011ed540dd
commit b70dd51cfa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 190 additions and 30 deletions

View file

@ -374,6 +374,35 @@ class TestSkillView:
result = json.loads(raw)
assert result["success"] is False
def test_view_disabled_skill_blocked(self, tmp_path):
"""Disabled skills should not be viewable via skill_view."""
with (
patch("tools.skills_tool.SKILLS_DIR", tmp_path),
patch(
"tools.skills_tool._is_skill_disabled",
return_value=True,
),
):
_make_skill(tmp_path, "hidden-skill")
raw = skill_view("hidden-skill")
result = json.loads(raw)
assert result["success"] is False
assert "disabled" in result["error"].lower()
def test_view_enabled_skill_allowed(self, tmp_path):
"""Non-disabled skills should be viewable normally."""
with (
patch("tools.skills_tool.SKILLS_DIR", tmp_path),
patch(
"tools.skills_tool._is_skill_disabled",
return_value=False,
),
):
_make_skill(tmp_path, "active-skill")
raw = skill_view("active-skill")
result = json.loads(raw)
assert result["success"] is True
class TestSkillViewSecureSetupOnLoad:
def test_requests_missing_required_env_and_continues(self, tmp_path, monkeypatch):