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

@ -920,6 +920,20 @@ def skill_view(name: str, file_path: str = None, task_id: str = None) -> str:
ensure_ascii=False,
)
# Check if the skill is disabled by the user
resolved_name = parsed_frontmatter.get("name", skill_md.parent.name)
if _is_skill_disabled(resolved_name):
return json.dumps(
{
"success": False,
"error": (
f"Skill '{resolved_name}' is disabled. "
"Enable it with `hermes skills` or inspect the files directly on disk."
),
},
ensure_ascii=False,
)
# If a specific file path is requested, read that instead
if file_path and skill_dir:
# Security: Prevent path traversal attacks