hermes - 💡(How to fix) Fix skill_manager_tool._find_skill uses Path.rglob() which does not follow symlinks, making symlinked skills invisible to skill_manage

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

Fix Action

Fix

Replace rglob with iter_skill_index_files() from agent.skill_utils, which already uses os.walk(followlinks=True) and handles EXCLUDED_SKILL_DIRS filtering:

# Before
from agent.skill_utils import get_all_skills_dirs, is_excluded_skill_path
for skill_md in skills_dir.rglob("SKILL.md"):

# After
from agent.skill_utils import get_all_skills_dirs, is_excluded_skill_path, iter_skill_index_files
for skill_md in iter_skill_index_files(skills_dir, "SKILL.md"):

This aligns with how prompt_builder.py already discovers skills for the system prompt.

Code Example

# Setup: symlink a category dir containing skills
mkdir -p /tmp/skills_parent/category/my-skill
echo "--- name: my-skill ---" > /tmp/skills_parent/category/my-skill/SKILL.md

# In HERMES_HOME/skills, symlink the category
HERMES_HOME=~/.hermes
ln -s /tmp/skills_parent/category $HERMES_HOME/skills/category

# Verify rglob misses it (Python pathlib behavior)
python3 -c "
from pathlib import Path
matches = list(Path('$HERMES_HOME/skills').rglob('SKILL.md'))
print(f'rglob found: {len(matches)}')  # 0

import os
count = sum(1 for r,d,f in os.walk('$HERMES_HOME/skills', followlinks=True) for x in f if x=='SKILL.md')
print(f'os.walk found: {count}')  # 1
"

---

for skill_md in skills_dir.rglob("SKILL.md"):  # does NOT follow symlinks

---

for skill_md in skills_dir.rglob("SKILL.md"):  # does NOT follow symlinks

---

# Before
from agent.skill_utils import get_all_skills_dirs, is_excluded_skill_path
for skill_md in skills_dir.rglob("SKILL.md"):

# After
from agent.skill_utils import get_all_skills_dirs, is_excluded_skill_path, iter_skill_index_files
for skill_md in iter_skill_index_files(skills_dir, "SKILL.md"):

---

_trusted_dirs = [SKILLS_DIR.resolve()]  # e.g. /tmp/hermes_sessions/user/skills
skill_md.resolve().relative_to(_td)     # resolves symlink → /root/.hermes/skills/...
RAW_BUFFERClick to expand / collapse

Bug Description

_find_skill() and _find_skill_in_other_profiles() in tools/skill_manager_tool.py use Path.rglob("SKILL.md") to discover skills. Python's pathlib.rglob() does not follow symbolic links into directories. This causes skill_manage to fail with "Skill not found in active profile" for any skill located under a symlinked category directory.

Meanwhile, prompt_builder.py uses iter_skill_index_files()os.walk(followlinks=True), which does follow symlinks. This inconsistency means skills appear in the system prompt index but cannot be managed via skill_manage.

Reproduction

# Setup: symlink a category dir containing skills
mkdir -p /tmp/skills_parent/category/my-skill
echo "--- name: my-skill ---" > /tmp/skills_parent/category/my-skill/SKILL.md

# In HERMES_HOME/skills, symlink the category
HERMES_HOME=~/.hermes
ln -s /tmp/skills_parent/category $HERMES_HOME/skills/category

# Verify rglob misses it (Python pathlib behavior)
python3 -c "
from pathlib import Path
matches = list(Path('$HERMES_HOME/skills').rglob('SKILL.md'))
print(f'rglob found: {len(matches)}')  # 0

import os
count = sum(1 for r,d,f in os.walk('$HERMES_HOME/skills', followlinks=True) for x in f if x=='SKILL.md')
print(f'os.walk found: {count}')  # 1
"

Result: skill_manage(action="edit", name="my-skill")"Skill 'my-skill' not found in active profile 'default'"

Affected Code

tools/skill_manager_tool.py:290_find_skill():

for skill_md in skills_dir.rglob("SKILL.md"):  # does NOT follow symlinks

tools/skill_manager_tool.py:357_find_skill_in_other_profiles():

for skill_md in skills_dir.rglob("SKILL.md"):  # does NOT follow symlinks

Fix

Replace rglob with iter_skill_index_files() from agent.skill_utils, which already uses os.walk(followlinks=True) and handles EXCLUDED_SKILL_DIRS filtering:

# Before
from agent.skill_utils import get_all_skills_dirs, is_excluded_skill_path
for skill_md in skills_dir.rglob("SKILL.md"):

# After
from agent.skill_utils import get_all_skills_dirs, is_excluded_skill_path, iter_skill_index_files
for skill_md in iter_skill_index_files(skills_dir, "SKILL.md"):

This aligns with how prompt_builder.py already discovers skills for the system prompt.

Bonus: skills_tool.py false-positive security warning

tools/skills_tool.py (line 1022-1029) resolves symlinks before checking if a skill is inside the trusted directory:

_trusted_dirs = [SKILLS_DIR.resolve()]  # e.g. /tmp/hermes_sessions/user/skills
skill_md.resolve().relative_to(_td)     # resolves symlink → /root/.hermes/skills/...

When skills are shared via symlinks from a global directory, resolve() escapes the user's HERMES_HOME, triggering a spurious "skill file is outside the trusted skills directory" warning on every skill load. Consider checking the unresolved path first, or treating symlink targets within the global HERMES_HOME as trusted.

Environment

  • hermes-agent @ 9d4c81130
  • Python 3.11 (pathlib.rglob behavior)

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

hermes - 💡(How to fix) Fix skill_manager_tool._find_skill uses Path.rglob() which does not follow symlinks, making symlinked skills invisible to skill_manage