Problem
skill_manage operations (patch, edit, delete, write_file, remove_file) fail with "Skill not found" for skills loaded from external_dirs.
The root cause is that _find_skill() in tools/skill_manager_tool.py only scans SKILLS_DIR (~/.hermes/skills/) via rglob("SKILL.md"), but:
rglob does not follow symlinks on Python 3.11+, so symlinked skill directories (pointing to an external git repo) are invisible
external_dirs are never scanned by _find_skill(), even though _find_all_skills() (used for listing/viewing) correctly scans them
This creates an inconsistency where skills are visible and loadable, but not editable via skill_manage.
Steps to Reproduce
# 1. Set up external_dirs in config.yaml
# skills:
# external_dirs:
# - ~/skills/skills
# 2. Skills from external_dirs are visible
# hermes skills list # shows all skills from external_dirs ✅
# 3. But skill_manage can't find them
# In a session:
skill_manage(action='patch', name='cron-gateway-restart', old_string='...', new_string='...')
# → {"success": false, "error": "Skill 'cron-gateway-restart' not found."} ❌
Relevant Code
_find_skill() at tools/skill_manager_tool.py:209 — only uses SKILLS_DIR.rglob()
_find_all_skills() at tools/skills_tool.py:512 — correctly scans both SKILLS_DIR and external_dirs
_resolve_skill_dir() at tools/skill_manager_tool.py:197 — only builds paths under SKILLS_DIR
Expected Behavior
skill_manage should be able to patch/edit/delete skills that are discoverable via _find_all_skills(). If a skill appears in the skill list, all operations should work on it.
Possible Approaches
- Reuse
_find_all_skills() lookup — _find_skill() could leverage the same scanning logic (or its result) to locate skill directories, including external_dirs
- Add external_dirs scanning to
_find_skill() — mirror the dirs_to_scan pattern from _find_all_skills()
- Resolve symlink paths — use
os.walk(followlinks=True) instead of rglob to follow symlinks
Note: Approach 1 would also need to return the actual Path to the skill directory (not just metadata), which _find_all_skills() currently does not do.
Environment
- Python 3.11.15
- Hermes Agent v0.6.0 (latest main as of 2026-04-03)
- OS: Oracle Linux 9 (aarch64)
Problem
skill_manageoperations (patch, edit, delete, write_file, remove_file) fail with "Skill not found" for skills loaded fromexternal_dirs.The root cause is that
_find_skill()intools/skill_manager_tool.pyonly scansSKILLS_DIR(~/.hermes/skills/) viarglob("SKILL.md"), but:rglobdoes not follow symlinks on Python 3.11+, so symlinked skill directories (pointing to an external git repo) are invisibleexternal_dirsare never scanned by_find_skill(), even though_find_all_skills()(used for listing/viewing) correctly scans themThis creates an inconsistency where skills are visible and loadable, but not editable via
skill_manage.Steps to Reproduce
Relevant Code
_find_skill()attools/skill_manager_tool.py:209— only usesSKILLS_DIR.rglob()_find_all_skills()attools/skills_tool.py:512— correctly scans bothSKILLS_DIRand external_dirs_resolve_skill_dir()attools/skill_manager_tool.py:197— only builds paths underSKILLS_DIRExpected Behavior
skill_manageshould be able to patch/edit/delete skills that are discoverable via_find_all_skills(). If a skill appears in the skill list, all operations should work on it.Possible Approaches
_find_all_skills()lookup —_find_skill()could leverage the same scanning logic (or its result) to locate skill directories, including external_dirs_find_skill()— mirror thedirs_to_scanpattern from_find_all_skills()os.walk(followlinks=True)instead ofrglobto follow symlinksNote: Approach 1 would also need to return the actual
Pathto the skill directory (not just metadata), which_find_all_skills()currently does not do.Environment