hermes - 💡(How to fix) Fix sync_skills writes into profile homes that delegate to default via external_dirs, causing skill name collisions that crash worker agents

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…

When a non-default profile's config.yaml has skills.external_dirs: ["~/.hermes/skills"] (delegating skill resolution to the default profile's tree), but sync_skills runs against that profile, it writes the entire bundled skills set into <profile_home>/skills/. This shadows the canonical tree the profile was intended to delegate to.

Result: every bundled skill ends up resolved twice — once from the profile-local shadow, once from the external dir. The skill loader detects the collision and refuses to load. Any worker agent that auto-loads one of the colliding skills crashes on startup with Error: Unknown skill(s): <name>.

This is particularly painful for kanban worker profiles, where the Kanban dispatcher auto-passes --skills kanban-worker to every worker. As soon as sync_skills shadows kanban-worker, every dispatched worker for that profile crashes, exhausts retries, and the task lands in blocked state with a generic "Agent crashed 2x: exit 1" diagnostic that doesn't surface the real cause.

Error Message

Result: every bundled skill ends up resolved twice — once from the profile-local shadow, once from the external dir. The skill loader detects the collision and refuses to load. Any worker agent that auto-loads one of the colliding skills crashes on startup with Error: Unknown skill(s): <name>. 4. Run any agent in that profile that auto-loads a bundled skill (e.g. kanban worker with --skills kanban-worker). Agent exits 1 with Error: Unknown skill(s): kanban-worker. sync_skills should detect that the target profile's config delegates to another home via external_dirs and skip writing bundled skills that would collide with those external sources. Alternatively, the skill loader should resolve external_dirs skills with lower priority than profile-local, OR the warning about collisions should be elevated to an error the dispatcher surfaces clearly (instead of "Agent crashed 2x: exit 1").

  • Worker process exits with Error: Unknown skill(s): <name> and a 1 exit code.
  • #27136 (fix(cli): unknown skills should warn instead of crash...) — addresses the downstream symptom (worker crashes on Unknown skill). Complementary to this issue. Even after #27136 lands and workers stop crashing, the underlying collision still produces stale shadows the loader has to refuse. Both fixes are needed.

Root Cause

  • #21810 (skill_manage(action='create') ignores skills.external_dirs...) — sibling bug, same anti-pattern: a skills-tooling code path operates on HERMES_HOME/skills/ without consulting skills.external_dirs. Different operation (create vs sync) but identical root cause shape.

Fix Action

Workaround

Manual cleanup: for every profile that delegates via external_dirs, recursively remove every SKILL.md directory under <profile_home>/skills/ whose contents match (or are a stub of) the canonical version in the external dir. This restores correct resolution but the next hermes update will re-create the mess.

Code Example

# ~/.hermes/profiles/myprofile/config.yaml
   skills:
     external_dirs:
       - "~/.hermes/skills"

---

WARNING tools.skills_tool: Skill name collision for 'kanban-worker': 2 candidates —
     <profile_home>/skills/devops/kanban-worker/SKILL.md;
     ~/.hermes/skills/devops/kanban-worker/SKILL.md
RAW_BUFFERClick to expand / collapse

sync_skills writes into profile homes that delegate to default via external_dirs, causing skill name collisions that crash worker agents

Summary

When a non-default profile's config.yaml has skills.external_dirs: ["~/.hermes/skills"] (delegating skill resolution to the default profile's tree), but sync_skills runs against that profile, it writes the entire bundled skills set into <profile_home>/skills/. This shadows the canonical tree the profile was intended to delegate to.

Result: every bundled skill ends up resolved twice — once from the profile-local shadow, once from the external dir. The skill loader detects the collision and refuses to load. Any worker agent that auto-loads one of the colliding skills crashes on startup with Error: Unknown skill(s): <name>.

This is particularly painful for kanban worker profiles, where the Kanban dispatcher auto-passes --skills kanban-worker to every worker. As soon as sync_skills shadows kanban-worker, every dispatched worker for that profile crashes, exhausts retries, and the task lands in blocked state with a generic "Agent crashed 2x: exit 1" diagnostic that doesn't surface the real cause.

Repro

  1. Create a profile that delegates to default:

    # ~/.hermes/profiles/myprofile/config.yaml
    skills:
      external_dirs:
        - "~/.hermes/skills"
  2. Trigger any code path that calls tools.skills_sync.sync_skills() while HERMES_HOME resolves to that profile. The simplest triggers:

    • hermes update (runs scripts/install.sh which invokes tools/skills_sync.py, then per-profile post-install also re-syncs via hermes_cli/profiles.py:695)
    • Profile init via hermes profile create / first launch
  3. Observe <profile_home>/skills/ is now populated with bundled stubs.

  4. Run any agent in that profile that auto-loads a bundled skill (e.g. kanban worker with --skills kanban-worker). Agent exits 1 with Error: Unknown skill(s): kanban-worker.

  5. The kanban log surfaces:

    WARNING tools.skills_tool: Skill name collision for 'kanban-worker': 2 candidates —
      <profile_home>/skills/devops/kanban-worker/SKILL.md;
      ~/.hermes/skills/devops/kanban-worker/SKILL.md

Expected

sync_skills should detect that the target profile's config delegates to another home via external_dirs and skip writing bundled skills that would collide with those external sources. Alternatively, the skill loader should resolve external_dirs skills with lower priority than profile-local, OR the warning about collisions should be elevated to an error the dispatcher surfaces clearly (instead of "Agent crashed 2x: exit 1").

Actual

  • sync_skills blindly writes into HERMES_HOME/skills/ regardless of external_dirs config.
  • Skill loader treats both candidates as equal-priority and refuses to load on collision.
  • Worker process exits with Error: Unknown skill(s): <name> and a 1 exit code.
  • Kanban dispatcher records this as a generic "Agent crashed" event without surfacing the underlying skill-collision warning, making it hard to diagnose.

Suspected cause

tools/skills_sync.py does not consult skills.external_dirs from the target profile's config before deciding what to write. The function operates purely on the resolved HERMES_HOME path.

Multiple call sites trigger the sync against profile homes:

  • hermes_cli/main.py:1411, 6379, 8092 — various CLI flows
  • hermes_cli/profiles.py:695 — explicit per-profile invocation
  • scripts/install.sh:1481 — install/upgrade

The profiles.py call site uses a subprocess specifically to refresh module-level HERMES_HOME caching, confirming sync is intentionally invoked against profile homes. The bug is that this is wrong when the profile config delegates skill resolution elsewhere.

Workaround

Manual cleanup: for every profile that delegates via external_dirs, recursively remove every SKILL.md directory under <profile_home>/skills/ whose contents match (or are a stub of) the canonical version in the external dir. This restores correct resolution but the next hermes update will re-create the mess.

Related issues

  • #27136 (fix(cli): unknown skills should warn instead of crash...) — addresses the downstream symptom (worker crashes on Unknown skill). Complementary to this issue. Even after #27136 lands and workers stop crashing, the underlying collision still produces stale shadows the loader has to refuse. Both fixes are needed.

  • #21810 (skill_manage(action='create') ignores skills.external_dirs...) — sibling bug, same anti-pattern: a skills-tooling code path operates on HERMES_HOME/skills/ without consulting skills.external_dirs. Different operation (create vs sync) but identical root cause shape.

  • #16176 (hermes update skips bundled skill sync for the active profile) — adjacent, opposite symptom (sync skipped where it should run vs sync run where it shouldn't). Both stem from sync_skills not having a coherent policy for when to operate against a given HERMES_HOME.

  • #28121 (show names of user-modified skills kept during bundled skill sync) — surfacing-level adjacent.

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