Skip to content

hermes update skips bundled skill sync for the active profile #16176

@simplenamebox-ops

Description

@simplenamebox-ops

Summary

hermes update syncs bundled skills to all profiles except the currently active one. The active profile silently drifts out of sync until the user switches to a different active profile and runs the update again. This can leave a profile running stale or pre-deprecation skill content for an arbitrary length of time without any warning.

Where the bug lives

In hermes_cli/main.py the per-profile sync explicitly excludes the active profile:

active = get_active_profile_name()
other_profiles = [p for p in list_profiles() if p.name != active]
if other_profiles:
    print()
    print("→ Syncing bundled skills to other profiles...")
    for p in other_profiles:
        ...
        r = seed_profile_skills(p.path, quiet=True)

The first sync step (→ Syncing bundled skills...) does run for the active profile and updates \$HERMES_HOME/skills/, but for non-default named profiles \$HERMES_HOME points at ~/.hermes/profiles/<active>/, so ~/.hermes/skills/ (the default profile's skills directory) is treated as "other" and gets updated, while the active named profile's skills/ dir is skipped.

Reproduction

  1. Have multiple profiles: e.g. default, bit, bitek, etc.
  2. hermes profile use bit (or any non-default profile).
  3. hermes update.
  4. Inspect update.log — the → Syncing bundled skills to other profiles... block lists every profile except bit.
  5. diff ~/.hermes/skills/<some-skill>/SKILL.md ~/.hermes/profiles/bit/skills/<some-skill>/SKILL.md — they diverge if any skill was updated upstream.

In my case, this left the autonomous-ai-agents/claude-code skill on a pre-deprecation version (818 lines) on the bit profile while the global and all 10 other profiles were on a newer 797-line version. I only noticed because the active profile's agent was still emitting deprecated guidance from the old skill content.

Suggested fix

A few options, ordered by intrusiveness:

  1. Sync the active profile too — drop the if p.name != active filter and just sync everything. The active profile's ~/.hermes/skills/ (or ~/.hermes/profiles/<active>/skills/ depending on \$HERMES_HOME) gets the same treatment as the others. User-modified skills are already preserved by sync_skills() via the ~ user-modified (kept) path, so no in-flight customizations are lost.
  2. Warn explicitly — keep the current skip but print a clear notice: ⚠ Skills for active profile '<name>' were not synced. Run "hermes profile use default && hermes update" to update.
  3. Sync, then notify — sync the active profile first (so its skills are up to date), then loop the others. Reorder rather than skip.

Option 1 is the cleanest in my opinion — the rationale for the original skip is unclear (presumably to avoid races with a running gateway?), but seed_profile_skills is a one-shot file copy and shouldn't conflict with a long-lived gateway process.

Workaround until fixed

After every hermes update, run:

```
hermes profile use default
hermes update # refreshes skills for the previously-active profile
hermes profile use
```

…or manually cp -r ~/.hermes/hermes-agent/skills/. ~/.hermes/profiles/<active>/skills/ (preserving any user-modified files) after each update.

Environment

  • Hermes commit: 454d883e6 (main, 2026-04-26)
  • macOS 14.x (Darwin 23.6.0), Python 3.11.15
  • 11 named profiles + default

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Medium — degraded but workaround existscomp/cliCLI entry point, hermes_cli/, setup wizardtool/skillsSkills system (list, view, manage)type/bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions