Skip to content

Skills overlay architecture: separate bundled (upstream) from custom (user) layers #16852

@Xiaoxin1117

Description

@Xiaoxin1117

Problem

Currently, bundled skills and user customizations live in the same flat directory (~/.hermes/skills/) without any distinction. When a user edits a bundled skill directly, the sync mechanism detects the hash mismatch and permanently skips upstream updates for that skill (see tools/skills_sync.py lines 256-261).

This means:

  • User who customizes a skill loses all future upstream improvements to it. The "fix" is to run hermes skills reset --restore, which destroys the customization entirely.
  • No way to layer a small user tweak on top of a skill that the upstream actively evolves.
  • No namespace separation between bundled skills and user-created skills — they coexist in the same tree, making it unclear what will be overwritten on next update.
  • The user has no way to know what upstream changed when their custom version was skipped.

Proposed Architecture: Overlay Layers

~/.hermes/skills/
├── bundled/              ← managed, read-only for users, fully replaced on each update
│   ├── mlops/axolotl/
│   ├── media/youtube-content/
│   └── ...
├── custom/               ← user territory, never touched by update
│   ├── my-psychoanalysis-skill/
│   └── youtube-content.diff     ← patch against bundled version
└── .bundled_manifest

At runtime, skill resolution works in layers:

  1. Load the bundled skill (fresh copy every time after update)
  2. If a corresponding patch file exists in custom/, apply it in-memory before returning the skill to the agent
  3. Pure custom skills (no bundled counterpart) load directly from custom/

Key Design Decisions to Resolve

1. Patch Format

  • Full-copy approach: custom/ stores the complete modified SKILL.md + supporting files. Simplest to implement, but means the user misses upstream changes to non-edited parts of the skill (e.g., upstream adds a new section: user never sees it).
  • Patch/diff approach: custom/ stores only the diff against the current bundled version. When upstream updates, the patch is re-applied. If the patch fails to apply (context changed), the system flags a conflict and falls back to keeping the user version.
  • Hybrid: Store the full modified copy, but also track which bundled version it was based on. On update, show the user a structured diff of upstream changes they missed.

2. Conflict Detection

When upstream changes conflict with a user patch, the system needs a fallback strategy:

  • Keep user version, mark conflict in CLI output
  • Offer a hermes skills merge <name> command that shows both versions side-by-side

3. CLI Commands

Current commands like hermes skills reset would need to be reframed for the overlay model. Suggested additions:

  • hermes skills diff <name> — show changes between bundled and user version
  • hermes skills patch <name> — create/edit a patch
  • hermes skills conflicts — list skills with unapplied patches

Scope

This touches:

  • tools/skills_sync.py — rewrite of sync logic for layered structure
  • agent/skill_commands.py — slash command resolution changes
  • cli.py / hermes_cli/ — update or add hermes skills subcommands
  • Migration: existing ~/.hermes/skills/ structure needs a one-time migration script

References

  • Current sync logic: tools/skills_sync.py lines 240-261 (user-modified skip)
  • Manifest-based tracking: .bundled_manifest with MD5 hashes
  • Skills load path: agent/skill_commands.py, tools/skills_tool.py

Metadata

Metadata

Assignees

No one assigned

    Labels

    P3Low — cosmetic, nice to havetool/skillsSkills system (list, view, manage)type/featureNew feature or request

    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