Skip to content

feat: support user-installed context engine plugins via $HERMES_HOME/plugins/ - #30761

Closed
whtoo wants to merge 1 commit into
NousResearch:mainfrom
whtoo:main
Closed

feat: support user-installed context engine plugins via $HERMES_HOME/plugins/#30761
whtoo wants to merge 1 commit into
NousResearch:mainfrom
whtoo:main

Conversation

@whtoo

@whtoo whtoo commented May 23, 2026

Copy link
Copy Markdown

Problem

Context engine plugins (plugins/context_engine/__init__.py) only support a single discovery path: plugins/context_engine/<name>/ inside the source tree. This is inconsistent with memory providers, which already scan both bundled (plugins/memory/<name>/) and user-installed ($HERMES_HOME/plugins/<name>/) directories.

Practical impact: user-installed context engines that live outside the hermes-agent git worktree (e.g., development symlinks) get destroyed by hermes update because git stash --include-untracked picks up untracked symlinks and git reset --hard discards them on stash-apply conflicts.

Solution

Mirror the memory provider discovery model:

  • Add _get_user_plugins_dir() — profile-aware $HERMES_HOME/plugins/ resolver
  • Add _is_context_engine_dir() — cheap text-scan heuristic (looks for ContextEngine or register_context_engine in __init__.py)
  • Add _find_engine_dir(name) — resolves bundled first, then user path, with bundled taking precedence
  • Update discover_context_engines() to scan both directories
  • Update load_context_engine() to use _find_engine_dir()
  • User-installed engines get isolated module namespace (_hermes_user_context_engine.*) to avoid sys.modules collisions

Behavior

  • Backward-compatible: existing bundled engines load exactly as before
  • Name collisions: bundled takes precedence (first-seen-wins, bundled scanned first)
  • User dirs are filtered by _is_context_engine_dir() so non-engine plugins (memory providers, general plugins) in the same $HERMES_HOME/plugins/ directory are skipped
  • Symlinks work: ln -s /path/to/engine ~/.hermes/profiles/main/plugins/spc_ctx survives hermes update

Files changed

File Lines Change
plugins/context_engine/__init__.py +132 -44 User-level discovery support

…plugins/

Context engine plugins were previously only discoverable from
plugins/context_engine/<name>/ (bundled in the source tree). This
mirrored how memory providers already support user-level installation
via $HERMES_HOME/plugins/<name>/.

Changes:
- Add _get_user_plugins_dir() helper (profile-aware)
- Add _is_context_engine_dir() heuristic to filter non-engine dirs
- Add _find_engine_dir() to resolve bundled vs user paths
- Update discover_context_engines() to scan both directories
- Update load_context_engine() to check both paths
- Use isolated module namespace (_hermes_user_context_engine.*)
  for user-installed engines to avoid sys.modules collisions

Bundled engines take precedence on name collisions.
Fixes symlinks in the git source tree being nuked by git stash
during 'hermes update' — users can now install context engines
under $HERMES_HOME/plugins/ which is outside the git worktree.
@alt-glitch alt-glitch added type/feature New feature or request P3 Low — cosmetic, nice to have comp/plugins Plugin system and bundled plugins labels May 23, 2026
@teknium1

Copy link
Copy Markdown
Contributor

Thanks for the contribution. Current main already provides this capability through the canonical user-plugin path, so this PR is redundant.

  • hermes_cli/plugins.py:1347-1352 scans $HERMES_HOME/plugins/ as the profile-scoped user plugin source.
  • hermes_cli/plugins.py:614-642 provides ctx.register_context_engine() for a user plugin to register a validated ContextEngine.
  • agent/agent_init.py:1755-1805 resolves context.engine through the general user-plugin system when no bundled directory engine is selected.
  • tests/hermes_cli/test_plugins.py:1950-1989 covers a user plugin under $HERMES_HOME/plugins/ registering and being returned as a context engine.

This is an automated hermes-sweeper review.

@teknium1 teknium1 closed this Jul 13, 2026
@teknium1 teknium1 added the sweeper:implemented-on-main Sweeper: behavior already present on current main label Jul 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/plugins Plugin system and bundled plugins P3 Low — cosmetic, nice to have sweeper:implemented-on-main Sweeper: behavior already present on current main type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants