From 187e90e4254c461e72d211564a44678f9626ffac Mon Sep 17 00:00:00 2001 From: Teknium Date: Tue, 7 Apr 2026 10:40:34 -0700 Subject: [PATCH] refactor: replace inline HERMES_HOME re-implementations with get_hermes_home() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 16 callsites across 14 files were re-deriving the hermes home path via os.environ.get('HERMES_HOME', ...) instead of using the canonical get_hermes_home() from hermes_constants. This breaks profiles — each profile has its own HERMES_HOME, and the inline fallback defaults to ~/.hermes regardless. Fixed by importing and calling get_hermes_home() at each site. For files already inside the hermes process (agent/, hermes_cli/, tools/, gateway/, plugins/), this is always safe. Files that run outside the process context (mcp_serve.py, mcp_oauth.py) already had correct try/except ImportError fallbacks and were left alone. Skipped: hermes_constants.py (IS the implementation), env_loader.py (bootstrap), profiles.py (intentionally manipulates the env var), standalone scripts (optional-skills/, skills/), and tests. --- agent/context_references.py | 5 ++--- agent/model_metadata.py | 4 ++-- agent/models_dev.py | 5 ++--- gateway/builtin_hooks/boot_md.py | 3 ++- gateway/platforms/webhook.py | 6 ++---- hermes_cli/commands.py | 6 ++---- hermes_cli/memory_setup.py | 10 ++++++---- hermes_cli/plugins.py | 4 ++-- hermes_cli/plugins_cmd.py | 5 +++-- hermes_cli/webhook.py | 5 ++--- plugins/memory/hindsight/__init__.py | 3 +-- plugins/memory/retaindb/__init__.py | 3 ++- tools/credential_files.py | 3 ++- tools/env_passthrough.py | 4 ++-- 14 files changed, 32 insertions(+), 34 deletions(-) diff --git a/agent/context_references.py b/agent/context_references.py index 8222dc33a..1b8ac9481 100644 --- a/agent/context_references.py +++ b/agent/context_references.py @@ -343,10 +343,9 @@ def _resolve_path(cwd: Path, target: str, *, allowed_root: Path | None = None) - def _ensure_reference_path_allowed(path: Path) -> None: + from hermes_constants import get_hermes_home home = Path(os.path.expanduser("~")).resolve() - hermes_home = Path( - os.getenv("HERMES_HOME", str(home / ".hermes")) - ).expanduser().resolve() + hermes_home = get_hermes_home().resolve() blocked_exact = {home / rel for rel in _SENSITIVE_HOME_FILES} blocked_exact.add(hermes_home / ".env") diff --git a/agent/model_metadata.py b/agent/model_metadata.py index 62dfb2b82..50245a7c9 100644 --- a/agent/model_metadata.py +++ b/agent/model_metadata.py @@ -510,8 +510,8 @@ def fetch_endpoint_model_metadata( def _get_context_cache_path() -> Path: """Return path to the persistent context length cache file.""" - hermes_home = Path(os.environ.get("HERMES_HOME", Path.home() / ".hermes")) - return hermes_home / "context_length_cache.yaml" + from hermes_constants import get_hermes_home + return get_hermes_home() / "context_length_cache.yaml" def _load_context_cache() -> Dict[str, int]: diff --git a/agent/models_dev.py b/agent/models_dev.py index a23ce74b2..d3de50619 100644 --- a/agent/models_dev.py +++ b/agent/models_dev.py @@ -185,9 +185,8 @@ def _get_reverse_mapping() -> Dict[str, str]: def _get_cache_path() -> Path: """Return path to disk cache file.""" - env_val = os.environ.get("HERMES_HOME", "") - hermes_home = Path(env_val) if env_val else Path.home() / ".hermes" - return hermes_home / "models_dev_cache.json" + from hermes_constants import get_hermes_home + return get_hermes_home() / "models_dev_cache.json" def _load_disk_cache() -> Dict[str, Any]: diff --git a/gateway/builtin_hooks/boot_md.py b/gateway/builtin_hooks/boot_md.py index fced0b5e1..c4b6c2d46 100644 --- a/gateway/builtin_hooks/boot_md.py +++ b/gateway/builtin_hooks/boot_md.py @@ -24,7 +24,8 @@ from pathlib import Path logger = logging.getLogger("hooks.boot-md") -HERMES_HOME = Path(os.environ.get("HERMES_HOME", Path.home() / ".hermes")) +from hermes_constants import get_hermes_home +HERMES_HOME = get_hermes_home() BOOT_FILE = HERMES_HOME / "BOOT.md" diff --git a/gateway/platforms/webhook.py b/gateway/platforms/webhook.py index ae2e7f27a..daaf4f5dc 100644 --- a/gateway/platforms/webhook.py +++ b/gateway/platforms/webhook.py @@ -203,10 +203,8 @@ class WebhookAdapter(BasePlatformAdapter): def _reload_dynamic_routes(self) -> None: """Reload agent-created subscriptions from disk if the file changed.""" - from pathlib import Path as _Path - hermes_home = _Path( - os.getenv("HERMES_HOME", str(_Path.home() / ".hermes")) - ).expanduser() + from hermes_constants import get_hermes_home + hermes_home = get_hermes_home() subs_path = hermes_home / _DYNAMIC_ROUTES_FILENAME if not subs_path.exists(): if self._dynamic_routes: diff --git a/hermes_cli/commands.py b/hermes_cli/commands.py index 9bce834d0..ecf4d0d6b 100644 --- a/hermes_cli/commands.py +++ b/hermes_cli/commands.py @@ -294,10 +294,8 @@ def _resolve_config_gates() -> set[str]: return set() try: import yaml - config_path = os.path.join( - os.getenv("HERMES_HOME", os.path.expanduser("~/.hermes")), - "config.yaml", - ) + from hermes_constants import get_hermes_home + config_path = str(get_hermes_home() / "config.yaml") if os.path.exists(config_path): with open(config_path, encoding="utf-8") as f: cfg = yaml.safe_load(f) or {} diff --git a/hermes_cli/memory_setup.py b/hermes_cli/memory_setup.py index c174d2b4b..2843f4f44 100644 --- a/hermes_cli/memory_setup.py +++ b/hermes_cli/memory_setup.py @@ -12,6 +12,8 @@ import os import sys from pathlib import Path +from hermes_constants import get_hermes_home + # --------------------------------------------------------------------------- # Curses-based interactive picker (same pattern as hermes tools) @@ -275,7 +277,7 @@ def cmd_setup_provider(provider_name: str) -> None: config["memory"] = {} if hasattr(provider, "post_setup"): - hermes_home = str(Path(os.environ.get("HERMES_HOME", os.path.expanduser("~/.hermes")))) + hermes_home = str(get_hermes_home()) provider.post_setup(hermes_home, config) return @@ -326,7 +328,7 @@ def cmd_setup(args) -> None: # If the provider has a post_setup hook, delegate entirely to it. # The hook handles its own config, connection test, and activation. if hasattr(provider, "post_setup"): - hermes_home = str(Path(os.environ.get("HERMES_HOME", os.path.expanduser("~/.hermes")))) + hermes_home = str(get_hermes_home()) provider.post_setup(hermes_home, config) return @@ -336,7 +338,7 @@ def cmd_setup(args) -> None: if not isinstance(provider_config, dict): provider_config = {} - env_path = Path(os.environ.get("HERMES_HOME", os.path.expanduser("~/.hermes"))) / ".env" + env_path = get_hermes_home() / ".env" env_writes = {} if schema: @@ -400,7 +402,7 @@ def cmd_setup(args) -> None: save_config(config) # Write non-secret config to provider's native location - hermes_home = str(Path(os.environ.get("HERMES_HOME", os.path.expanduser("~/.hermes")))) + hermes_home = str(get_hermes_home()) if provider_config and hasattr(provider, "save_config"): try: provider.save_config(provider_config, hermes_home) diff --git a/hermes_cli/plugins.py b/hermes_cli/plugins.py index ce57695fa..23a655aa3 100644 --- a/hermes_cli/plugins.py +++ b/hermes_cli/plugins.py @@ -38,6 +38,7 @@ from dataclasses import dataclass, field from pathlib import Path from typing import Any, Callable, Dict, List, Optional, Set, Union +from hermes_constants import get_hermes_home from utils import env_var_enabled try: @@ -258,8 +259,7 @@ class PluginManager: manifests: List[PluginManifest] = [] # 1. User plugins (~/.hermes/plugins/) - hermes_home = os.environ.get("HERMES_HOME", os.path.expanduser("~/.hermes")) - user_dir = Path(hermes_home) / "plugins" + user_dir = get_hermes_home() / "plugins" manifests.extend(self._scan_directory(user_dir, source="user")) # 2. Project plugins (./.hermes/plugins/) diff --git a/hermes_cli/plugins_cmd.py b/hermes_cli/plugins_cmd.py index 5bfc488e3..4727d4b71 100644 --- a/hermes_cli/plugins_cmd.py +++ b/hermes_cli/plugins_cmd.py @@ -16,6 +16,8 @@ import subprocess import sys from pathlib import Path +from hermes_constants import get_hermes_home + logger = logging.getLogger(__name__) # Minimum manifest version this installer understands. @@ -26,8 +28,7 @@ _SUPPORTED_MANIFEST_VERSION = 1 def _plugins_dir() -> Path: """Return the user plugins directory, creating it if needed.""" - hermes_home = os.environ.get("HERMES_HOME", os.path.expanduser("~/.hermes")) - plugins = Path(hermes_home) / "plugins" + plugins = get_hermes_home() / "plugins" plugins.mkdir(parents=True, exist_ok=True) return plugins diff --git a/hermes_cli/webhook.py b/hermes_cli/webhook.py index 15f5ec43a..8ff135e29 100644 --- a/hermes_cli/webhook.py +++ b/hermes_cli/webhook.py @@ -25,9 +25,8 @@ _SUBSCRIPTIONS_FILENAME = "webhook_subscriptions.json" def _hermes_home() -> Path: - return Path( - os.getenv("HERMES_HOME", str(Path.home() / ".hermes")) - ).expanduser() + from hermes_constants import get_hermes_home + return get_hermes_home() def _subscriptions_path() -> Path: diff --git a/plugins/memory/hindsight/__init__.py b/plugins/memory/hindsight/__init__.py index 140aa1ea0..e10a14a84 100644 --- a/plugins/memory/hindsight/__init__.py +++ b/plugins/memory/hindsight/__init__.py @@ -290,8 +290,7 @@ class HindsightMemoryProvider(MemoryProvider): if self._mode == "local": def _start_daemon(): import traceback - from pathlib import Path - log_dir = Path(os.environ.get("HERMES_HOME", os.path.expanduser("~/.hermes"))) / "logs" + log_dir = get_hermes_home() / "logs" log_dir.mkdir(parents=True, exist_ok=True) log_path = log_dir / "hindsight-embed.log" try: diff --git a/plugins/memory/retaindb/__init__.py b/plugins/memory/retaindb/__init__.py index 69b8a8cf5..72ff9d77c 100644 --- a/plugins/memory/retaindb/__init__.py +++ b/plugins/memory/retaindb/__init__.py @@ -504,7 +504,8 @@ class RetainDBMemoryProvider(MemoryProvider): self._user_id = kwargs.get("user_id", "default") or "default" self._agent_id = kwargs.get("agent_id", "hermes") or "hermes" - hermes_home_path = Path(os.environ.get("HERMES_HOME", Path.home() / ".hermes")) + from hermes_constants import get_hermes_home + hermes_home_path = get_hermes_home() db_path = hermes_home_path / "retaindb_queue.db" self._queue = _WriteQueue(self._client, db_path) diff --git a/tools/credential_files.py b/tools/credential_files.py index 49768bff4..eafd5ea23 100644 --- a/tools/credential_files.py +++ b/tools/credential_files.py @@ -48,7 +48,8 @@ _config_files: List[Dict[str, str]] | None = None def _resolve_hermes_home() -> Path: - return Path(os.environ.get("HERMES_HOME", Path.home() / ".hermes")) + from hermes_constants import get_hermes_home + return get_hermes_home() def register_credential_file( diff --git a/tools/env_passthrough.py b/tools/env_passthrough.py index 1c70d518f..0e883babd 100644 --- a/tools/env_passthrough.py +++ b/tools/env_passthrough.py @@ -66,8 +66,8 @@ def _load_config_passthrough() -> frozenset[str]: result: set[str] = set() try: - hermes_home = Path(os.environ.get("HERMES_HOME", Path.home() / ".hermes")) - config_path = hermes_home / "config.yaml" + from hermes_constants import get_hermes_home + config_path = get_hermes_home() / "config.yaml" if config_path.exists(): import yaml