fix: rglob follow symlinks for skill discovery - #35299
Conversation
Python's Path.rglob() does not descend into symlinked directories (see https://bugs.python.org/issue40358). This means skills in ~/.hermes/skills/redpiggy/ (a symlink to ~/Documents/redpiggy-workspace/skills/) are invisible to skill_manage and skill usage tools. Add a rglob_follow() helper in agent/skill_utils.py that uses os.walk(followlinks=True) to traverse symlinked skill directories, matching the behavior already used by iter_skill_index_files(). Update all four rglob('SKILL.md') call sites across tools/skill_manager_tool.py and tools/skill_usage.py to use rglob_follow() instead.
Morad37
left a comment
There was a problem hiding this comment.
The rglob_follow helper looks right — os.walk with followlinks=True is the standard workaround for Python's rglob not descending into symlinked dirs. The dirnames pruning for EXCLUDED_SKILL_DIRS inside walk is a nice touch. One thing I noticed: followlinks=True means a symlink-to-excluded-dir by a non-excluded name bypasses the pruning — but the original rglob has the same limitation, so this doesn't introduce a regression.
Automated Triage: Competing PRs DetectedThree PRs are independently fixing the same issue (symlink-discovery in skills, #35184):
They all modify |
teknium1
left a comment
There was a problem hiding this comment.
Thanks for tracing the Path.rglob() / symlink-discovery mismatch. The premise is still valid on current main: tools/skill_manager_tool.py:597 uses rglob("SKILL.md"), while agent/skill_utils.py:796 uses os.walk(..., followlinks=True).
Problems
- Please reuse
iter_skill_index_files()rather than add a parallelrglob_follow()walker. The existing helper atagent/skill_utils.py:785-807already follows links, returns sorted paths, and prunes support directories. - Current-head sibling paths remain unaddressed:
tools/skill_usage.py:858searches configured external directories withrglob(), andtools/skill_usage.py:925does the same forusage_report(). - The diff adds no regression tests. Symlink tests should gracefully skip where link creation is unsupported, following
tests/tools/test_skill_manager_tool.py:357-360.
Suggested changes
- Salvage this using
iter_skill_index_files()at the applicable current-head call sites and add management/usage symlink regressions.
Automated hermes-sweeper review.
| return any(part in EXCLUDED_SKILL_DIRS for part in parts) | ||
|
|
||
|
|
||
| def rglob_follow(root: Path, pattern: str): |
There was a problem hiding this comment.
iter_skill_index_files() already follows symlinks and also preserves sorted output plus support-directory pruning (agent/skill_utils.py:785-807 on current main). Reuse that existing iterator at these exact SKILL.md call sites rather than adding a divergent walker.
Problem
Python's
Path.rglob()does not descend into symlinked directories (see python/cpython#77609). This means skills located behind a symlink — such as~/.hermes/skills/redpiggy -> ~/Documents/redpiggy-workspace/skills/— are invisible toskill_manageandskill_usagetools.The root cause is that
iter_skill_index_files()usesos.walk(followlinks=True)(which follows symlinks), but_find_skill()and related functions in the skill manager and usage tools usePath.rglob()(which does not).Fix
Add a
rglob_follow()helper inagent/skill_utils.pythat usesos.walk(followlinks=True)to traverse symlinked directories, matching the behavior already used byiter_skill_index_files().Update all four
rglob('SKILL.md')call sites across:tools/skill_manager_tool.py—_find_skill()and_find_skill_in_other_profiles()tools/skill_usage.py—list_agent_created_skill_names()and_find_skill_dir()Testing
redpiggy) are now discoverable byskill_manageandskill_usagetools.rglob_follow()helper also prunes excluded directories (.git,.venv,node_modules, etc.) during traversal, consistent withis_excluded_skill_path().