feat: wire skills.external_dirs into all remaining discovery paths

The config key skills.external_dirs and core resolution (get_all_skills_dirs,
get_external_skills_dirs in agent/skill_utils.py) already existed but several
code paths still only scanned SKILLS_DIR. Now external dirs are respected
everywhere:

- skills_categories(): scan all dirs for category discovery
- _get_category_from_path(): resolve categories against any skills root
- skill_manager_tool._find_skill(): search all dirs for edit/patch/delete
- credential_files.get_skills_directory_mount(): mount all dirs into
  Docker/Singularity containers (external dirs at external_skills/<idx>)
- credential_files.iter_skills_files(): list files from all dirs for
  Modal/Daytona upload
- tools/environments/ssh.py: rsync all skill dirs to remote hosts
- gateway _check_unavailable_skill(): check disabled skills across all dirs

Usage in config.yaml:
  skills:
    external_dirs:
      - ~/repos/agent-skills/hermes
      - /shared/team-skills
This commit is contained in:
Teknium 2026-04-03 21:14:34 -07:00
parent 5a98ce5973
commit ad4feeaf0d
No known key found for this signature in database
8 changed files with 149 additions and 86 deletions

View file

@ -203,14 +203,19 @@ def _resolve_skill_dir(name: str, category: str = None) -> Path:
def _find_skill(name: str) -> Optional[Dict[str, Any]]:
"""
Find a skill by name in ~/.hermes/skills/.
Returns {"path": Path} or None.
Find a skill by name across all skill directories.
Searches the local skills dir (~/.hermes/skills/) first, then any
external dirs configured via skills.external_dirs. Returns
{"path": Path} or None.
"""
if not SKILLS_DIR.exists():
return None
for skill_md in SKILLS_DIR.rglob("SKILL.md"):
if skill_md.parent.name == name:
return {"path": skill_md.parent}
from agent.skill_utils import get_all_skills_dirs
for skills_dir in get_all_skills_dirs():
if not skills_dir.exists():
continue
for skill_md in skills_dir.rglob("SKILL.md"):
if skill_md.parent.name == name:
return {"path": skill_md.parent}
return None