{"repo":"NousResearch/hermes-agent","public_id":"10313","display_label":"External skills resolving incorrect skill_dir in _load_skill_payload","summary":"The three members share one theme: _load_skill_payload reportedly rebuilds the wrong skill_dir for skills from skills.external_dirs. One is a bug report and two are fix proposals, one of which uses an absolute skill_dir; titles alone do not show their status or outcome.","subsystem":null,"counts":{"members":3,"open_issues":0,"open_issues_distinct":0,"open_prs":0,"closed_issues":1,"merged_prs":1,"attempt_prs":1},"landed_fix":{"status":"merged_to_main","basis":"structural","pr":10587,"merged_at":"2026-04-16T00:22:55+00:00"},"resolution":{"state":"resolved","by":"pr-10587"},"freshness":{"state":"stale","last_verified_at":"2026-04-16T00:22:55+00:00","is_stale":true},"grouping":{"backbone":"STRUCTURAL_SPANNING","link_density":0.6666666666666666},"fix_edges":[{"issue_number":10313,"pr_number":10587,"tier":"verified","basis":"closing_ref","confidence":0.95,"recoverable_from_timeline":true,"pr_merged_at":"2026-04-16T00:22:55+00:00"}],"members":[{"kind":"issue","number":10313,"title":"Bug: _load_skill_payload rebuilds wrong skill_dir for external skills (from skills.external_dirs)","url":null,"state":"closed"},{"kind":"pr","number":10348,"title":"fix(skills): resolve correct skill_dir for external skills in _load_skill_payload","url":null,"state":"closed","close_reason":{"refs":[{"kind":"commit","value":"4fdcae6c9","number":0},{"kind":"pr","value":"#10313","number":10313},{"kind":"pr","value":"#10587","number":10587}],"category":"implemented_elsewhere","implication":"superseded"},"merged":false},{"kind":"pr","number":10587,"title":"fix: use absolute skill_dir for external skills","url":null,"state":"merged","close_reason":{"category":"merged"},"merged":true,"is_fix_pr":true,"fix_tier":"verified","files_changed":["agent/skill_commands.py","tools/skills_tool.py"],"fix_hunks":[{"file":"agent/skill_commands.py","hunks":["@@ -72,7 +72,14 @@ def _load_skill_payload(skill_identifier: str, task_id: str | None = None) -> tu\n     skill_name = str(loaded_skill.get(\"name\") or normalized)\n     skill_path = str(loaded_skill.get(\"path\") or \"\")\n     skill_dir = None\n-    if skill_path:\n+    # Prefer the absolute skill_dir returned by skill_view() — this is\n+    # correct for both local and external skills.  Fall back to the old\n+    # SKILLS_DIR-relative reconstruction only when skill_dir is absent\n+    # (e.g. legacy skill_view responses).\n+    abs_skill_dir = loaded_skill.get(\"skill_dir\")\n+    if abs_skill_dir:\n+        skill_dir = Path(abs_skill_dir)\n+    elif skill_path:\n         try:\n             skill_dir = SKILLS_DIR / Path(skill_path).parent\n         except Exception:"]},{"file":"tools/skills_tool.py","hunks":["@@ -1263,6 +1263,7 @@ def skill_view(name: str, file_path: str = None, task_id: str = None) -> str:\n             \"related_skills\": related_skills,\n             \"content\": content,\n             \"path\": rel_path,\n+            \"skill_dir\": str(skill_dir) if skill_dir else None,\n             \"linked_files\": linked_files if linked_files else None,\n             \"usage_hint\": \"To view linked files, call skill_view(name, file_path) where file_path is e.g. 'references/api.md' or 'assets/config.yaml'\"\n             if linked_files\n"]}]}],"trust":{"default_tier":"verified","includes_suggested":false}}