Skip to content

fix(skills): follow symlinks when discovering skills in external dirs - #54200

Closed
liuhao1024 wants to merge 4 commits into
NousResearch:mainfrom
liuhao1024:liuhao/cron-bugfix-54195-skill-manage-symlink
Closed

liuhao1024 wants to merge 4 commits into
NousResearch:mainfrom
liuhao1024:liuhao/cron-bugfix-54195-skill-manage-symlink

Conversation

@liuhao1024

Copy link
Copy Markdown
Contributor

What does this PR do?

_find_skill and _find_skill_in_other_profiles used Path.rglob("SKILL.md") which does not follow symlinks. Skills installed as directory symlinks in skills.external_dirs were visible to skills_list and skill_view (which use os.walk(followlinks=True) via iter_skill_index_files) but invisible to skill_manage operations like patch, edit, delete, and write_file.

This PR replaces both rglob calls with iter_skill_index_files from agent.skill_utils, which already handles symlink traversal and directory exclusion consistently with the rest of the skill system.

Related Issue

Fixes #54195

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)

Changes Made

  • tools/skill_manager_tool.py: Replace skills_dir.rglob("SKILL.md") with iter_skill_index_files(skills_dir, "SKILL.md") in _find_skill() and _find_skill_in_other_profiles() to follow symlinks during skill discovery
  • tests/tools/test_skill_manager_tool.py: Add TestFindSkillSymlinkedExternalDir with 2 tests — symlink discovery and direct-dir regression guard

How to Test

  1. Create a real skill directory: mkdir -p /tmp/project/skills/my-skill && echo -e '---\nname: my-skill\ndescription: test\n---\n\nBody.' > /tmp/project/skills/my-skill/SKILL.md
  2. Create an external skills dir with a symlink: mkdir -p ~/.agents/skills && ln -s /tmp/project/skills/my-skill ~/.agents/skills/my-skill
  3. Add to config.yaml: skills:\n external_dirs:\n - ~/.agents/skills
  4. Verify skills_list() includes my-skill — should pass (already worked before)
  5. Verify skill_manage(action="patch", name="my-skill", old_string="__DOES_NOT_EXIST__", new_string="x") finds the skill and reports "Could not find a match" instead of "Skill 'my-skill' not found"
  6. Run: python -m pytest tests/tools/test_skill_manager_tool.py::TestFindSkillSymlinkedExternalDir -xvs — should pass

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits (fix(scope):, feat(scope):, etc.)
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix/feature (no unrelated commits)
  • I've run pytest tests/ -q and all tests pass
  • I've added tests for my changes (required for bug fixes, strongly encouraged for features)
  • I've tested on my platform: macOS 26.4.1

Documentation & Housekeeping

  • I've updated relevant documentation (README, docs/, docstrings) — or N/A
  • I've updated cli-config.yaml.example if I added/changed config keys — or N/A
  • I've updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows — or N/A
  • I've considered cross-platform impact (Windows, macOS) per the compatibility guide — N/A
  • I've updated tool descriptions/schemas if I changed tool behavior — or N/A

`_find_skill` and `_find_skill_in_other_profiles` used
`Path.rglob("SKILL.md")` which does not follow symlinks.  Skills
installed as directory symlinks in `skills.external_dirs` were
visible to `skills_list` and `skill_view` (which use
`os.walk(followlinks=True)` via `iter_skill_index_files`) but
invisible to `skill_manage` operations.

Replace both `rglob` calls with `iter_skill_index_files` from
`agent.skill_utils`, which already handles symlink traversal and
directory exclusion.

Fixes NousResearch#54195
@alt-glitch alt-glitch added type/bug Something isn't working tool/skills Skills system (list, view, manage) P3 Low — cosmetic, nice to have duplicate This issue or pull request already exists labels Jun 28, 2026
@alt-glitch

Copy link
Copy Markdown

This was generated by AI during triage.

Duplicate of #35244 — same fix (swap Path.rglob('SKILL.md') for iter_skill_index_files in _find_skill/_find_skill_in_other_profiles), which is the earliest open PR for this. Both target #35184 / #54195. Cross-linking so a maintainer can pick the canonical one.

@tonydwb tonydwb left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixes skill discovery to follow symlinks in external dirs (57 additions). Uses iter_skill_index_files instead of rglob to match the behavior of skills_list and skill_view. Includes tests for both symlinked and direct directories.

Reviewed by Hermes Agent

…in_other_profiles

The iter_skill_index_files migration removed the hermes_constants import
but the function still calls get_default_hermes_root() to locate profile
directories. Without the import, NameError is caught by the bare except
and _find_skill_in_other_profiles always returns empty, breaking the
cross_profile=True hint in _skill_not_found_error.
@liuhao1024

Copy link
Copy Markdown
Contributor Author

This appears to duplicate #35244 (by Linux2010, opened 2026-05-30) — same fix (rglobiter_skill_index_files in _find_skill and _find_skill_in_other_profiles), same test structure.

#35244 has slightly broader test coverage (4 tests including nested symlink scenario). Both PRs touch tools/skill_manager_tool.py and tests/tools/test_skill_manager_tool.py.

Recommend closing this one in favor of #35244 since it was opened first and has more comprehensive tests.

@liuhao1024

Copy link
Copy Markdown
Contributor Author

Duplicate of #35244 by @Linux2010 — same fix (replace Path.rglob('SKILL.md') with iter_skill_index_files in _find_skill / _find_skill_in_other_profiles), same test coverage. #35244 was opened earlier (2026-05-30) and is ready for review.

Closing this PR in favor of #35244.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

duplicate This issue or pull request already exists P3 Low — cosmetic, nice to have tool/skills Skills system (list, view, manage) type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

skill_manage cannot find symlinked skills in skills.external_dirs

3 participants