hermes - ✅(Solved) Fix curator restore: nested archive subdirs not found — restore_skill only scans top-level .archive/ [1 pull requests, 1 participants]

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…
GitHub stats
NousResearch/hermes-agent#17942Fetched 2026-05-01 05:54:58
View on GitHub
Comments
0
Participants
1
Timeline
6
Reactions
1
Participants
Timeline (top)
labeled ×3closed ×1cross-referenced ×1referenced ×1

Root Cause

Root cause restore_skill() in tools/skill_usage.py uses archive_root.iterdir() which only enumerates the immediate children of .archive/. It never descends into subdirectories like openclaw-imports/, hermes-agent/, etc.

Fix Action

Fix / Workaround

Patch applied locally:

-    candidates = [p for p in archive_root.iterdir() if p.is_dir() and p.name == skill_name]
+    # Recursive scan handles nested archive subdirs (e.g. .archive/openclaw-imports/cognitive-empathy).
+    candidates = [p for p in archive_root.rglob('*') if p.is_dir() and p.name == skill_name]
     if not candidates:
         candidates = sorted(
-            [p for p in archive_root.iterdir()
+            [p for p in archive_root.rglob('*')
              if p.is_dir() and p.name.startswith(f"{skill_name}-")],
             reverse=True,
         )

PR fix notes

PR #17951: fix(curator): scan nested archive subdirs in restore_skill

Description (problem / solution / changelog)

What does this PR do?

hermes curator restore <skill> was failing with skill '<name>' not found in archive whenever the archived skill lived under a nested category subdirectory (e.g. .archive/openclaw-imports/<skill>/, .archive/hermes-agent/<skill>/). The skill directory existed on disk but was invisible to the lookup because restore_skill() walked only the top level of .archive/.

tools/skill_usage.py:389,392 used archive_root.iterdir() for both the exact-name and prefix-match candidate scans. Switching both to archive_root.rglob("*") makes the lookup descend into nested subdirs while preserving the existing is_dir() and p.name == skill_name (and prefix) filter, so the scan still picks up only matching skill directories.

Related Issue

Fixes #17942

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✨ New feature (non-breaking change that adds functionality)
  • 🔒 Security fix
  • 📝 Documentation update
  • ✅ Tests (adding or improving test coverage)
  • ♻️ Refactor (no behavior change)
  • 🎯 New skill (bundled or hub)

Changes Made

  • tools/skill_usage.pyrestore_skill(): switched the exact-match and prefix-match candidate scans from archive_root.iterdir() to archive_root.rglob("*") so nested archive subdirectories are searched.
  • tests/tools/test_skill_usage.py — added test_restore_skill_finds_nested_archive_subdir (exact match under a nested category) and test_restore_skill_finds_nested_timestamped_prefix (timestamped-dupe prefix match under a nested category) to lock in the recursive-walk behaviour.

How to Test

  1. Place an archived skill under a nested category, e.g.:
    ~/.hermes/skills/.archive/openclaw-imports/cognitive-empathy/SKILL.md
  2. Run hermes curator restore cognitive-empathy — before this patch this returned "not found in archive"; after, the skill is moved back to ~/.hermes/skills/cognitive-empathy/ and its state flips to active.
  3. pytest tests/tools/test_skill_usage.py -q — 37 tests pass (35 prior + 2 new).

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 <!-- skill_usage / curator suites pass cleanly; broader baseline failures on this branch (e.g. tts-kittentts, web_server, terminal-tool requirements) reproduce on `upstream/main` without this patch and are unrelated optional-dep / env issues -->
  • I've added tests for my changes (required for bug fixes, strongly encouraged for features)
  • I've tested on my platform: macOS 15 (Darwin 23.2)

Documentation & Housekeeping

  • I've updated relevant documentation (README, docs/, docstrings) — N/A (no user-visible API change; the docstring on restore_skill already covers behaviour)
  • I've updated cli-config.yaml.example if I added/changed config keys — N/A
  • I've updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows — N/A
  • I've considered cross-platform impact (Windows, macOS) per the compatibility guiderglob is pathlib-portable; tests use tmp_path and avoid OS-specific paths
  • I've updated tool descriptions/schemas if I changed tool behavior — N/A

Changed files

  • tests/tools/test_skill_usage.py (modified, +35/-0)
  • tools/skill_usage.py (modified, +5/-3)

Code Example

-    candidates = [p for p in archive_root.iterdir() if p.is_dir() and p.name == skill_name]
+    # Recursive scan handles nested archive subdirs (e.g. .archive/openclaw-imports/cognitive-empathy).
+    candidates = [p for p in archive_root.rglob('*') if p.is_dir() and p.name == skill_name]
     if not candidates:
         candidates = sorted(
-            [p for p in archive_root.iterdir()
+            [p for p in archive_root.rglob('*')
              if p.is_dir() and p.name.startswith(f"{skill_name}-")],
             reverse=True,
         )
RAW_BUFFERClick to expand / collapse

Describe the bug hermes curator restore <skill> fails with "skill '<name>' not found in archive" when the skill was archived under a nested subdirectory inside .archive/, e.g. .archive/openclaw-imports/<skill>/.

Root cause restore_skill() in tools/skill_usage.py uses archive_root.iterdir() which only enumerates the immediate children of .archive/. It never descends into subdirectories like openclaw-imports/, hermes-agent/, etc.

Reproduction

  1. Have an agent-created skill archived under a nested path: .archive/<category>/<skill>/
  2. Run hermes curator restore <skill> → fails with "not found"
  3. The skill directory exists at that nested path but is never found

Fix Change archive_root.iterdir() to archive_root.rglob('*') in both the exact-match and prefix-match candidate scans, so it recurses through all nested subdirectories.

Patch applied locally:

-    candidates = [p for p in archive_root.iterdir() if p.is_dir() and p.name == skill_name]
+    # Recursive scan handles nested archive subdirs (e.g. .archive/openclaw-imports/cognitive-empathy).
+    candidates = [p for p in archive_root.rglob('*') if p.is_dir() and p.name == skill_name]
     if not candidates:
         candidates = sorted(
-            [p for p in archive_root.iterdir()
+            [p for p in archive_root.rglob('*')
              if p.is_dir() and p.name.startswith(f"{skill_name}-")],
             reverse=True,
         )

Environment

  • Hermes Agent (local install)
  • restore_skill() at tools/skill_usage.py:389

extent analysis

TL;DR

To fix the issue with hermes curator restore <skill> failing to find skills archived in nested subdirectories, update the restore_skill() function in tools/skill_usage.py to use archive_root.rglob('*') for recursive directory scanning.

Guidance

  • Verify that the skill directory exists in the expected nested path under .archive/ to ensure the issue is related to directory scanning.
  • Apply the suggested patch to tools/skill_usage.py to modify the restore_skill() function, replacing archive_root.iterdir() with archive_root.rglob('*') for both exact-match and prefix-match scans.
  • After applying the patch, re-run hermes curator restore <skill> to test if the skill can now be found and restored correctly.
  • Ensure that the Hermes Agent is updated or reinstalled after modifying the tools/skill_usage.py file to reflect the changes.

Example

The provided patch snippet demonstrates the necessary change:

-    candidates = [p for p in archive_root.iterdir() if p.is_dir() and p.name == skill_name]
+    candidates = [p for p in archive_root.rglob('*') if p.is_dir() and p.name == skill_name]

This update allows the function to recursively scan through all subdirectories within .archive/.

Notes

This fix assumes that the issue is solely due to the non-recursive scanning of the archive directory. If other issues persist, further investigation into the hermes curator restore command and the archive structure may be necessary.

Recommendation

Apply the workaround by patching tools/skill_usage.py as described, since it directly addresses the identified root cause of the problem.

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 - ✅(Solved) Fix curator restore: nested archive subdirs not found — restore_skill only scans top-level .archive/ [1 pull requests, 1 participants]