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
- Have multiple profiles: e.g.
default, bit, bitek, etc.
hermes profile use bit (or any non-default profile).
hermes update.
- Inspect
update.log — the → Syncing bundled skills to other profiles... block lists every profile except bit.
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:
- 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.
- 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.
- 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
Summary
hermes updatesyncs 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.pythe per-profile sync explicitly excludes the active profile: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_HOMEpoints 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'sskills/dir is skipped.Reproduction
default,bit,bitek, etc.hermes profile use bit(or any non-default profile).hermes update.update.log— the→ Syncing bundled skills to other profiles...block lists every profile exceptbit.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-codeskill on a pre-deprecation version (818 lines) on thebitprofile 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:
if p.name != activefilter 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 bysync_skills()via the~ user-modified (kept)path, so no in-flight customizations are lost.⚠ Skills for active profile '<name>' were not synced. Run "hermes profile use default && hermes update" to update.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_skillsis 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
454d883e6(main, 2026-04-26)