Skip to content

[Bug]: get_hermes_home() silently falls back to ~/.hermes in profile mode and causes cross-profile data corruption #18594

@ar-nim

Description

@ar-nim

Bug Description

In hermes_constants.py, the get_hermes_home() function silently falls back to Path.home() / ".hermes" when the HERMES_HOME environment variable is unset (line 17-18):

def get_hermes_home() -> Path:
val = os.environ.get("HERMES_HOME", "").strip()
return Path(val) if val else Path.home() / ".hermes"

This is correct for classic (non-profile) mode, but dangerous in profile mode (HERMES_HOME=<root>/profiles/<name>). When HERMES_HOME is unset or empty, the function returns ~/.hermes — which is the default profile, not the active profile. Any code path that relies on get_hermes_home() for data storage will silently read/write to the wrong profile.

Steps to Reproduce

  1. Run a cron job, skill, or sub-agent without HERMES_HOME set in the environment
  2. The agent calls get_hermes_home() for data paths (memory, state.db, etc.)
  3. Instead of failing or using the intended profile, it resolves to ~/.hermes (default profile)
  4. Result: data from Profile A is silently stored in Profile B's database

Real incident (May 1 2026): A holographic-memory-reflect cron job (running under a named profile) executed SQL queries with hardcoded ~/.hermes/memory_store.db paths from skill text. Because HERMES_HOME was not inherited by the sub-process, get_hermes_home() fell back to the default profile — contaminating the profile's memory with data that belonged to a user's personal data outside of the profile.

Expected Behavior

When HERMES_HOME is unset in profile mode, get_hermes_home() should raise an error (e.g., ValueError("HERMES_HOME not set — profile mode requires this env var")) rather than silently returning ~/.hermes.

Actual Behavior

Silently returns ~/.hermes as a fallback, causing silent cross-profile data corruption.

Affected Component

Agent Core (conversation loop, context compression, memory)

Messaging Platform (if gateway-related)

No response

Debug Report

https://paste.rs/KCA4w

Operating System

OpenSUSE Leap 16

Python Version

3.11.15

Hermes Version

0.12.0

Additional Logs / Traceback (optional)

Root Cause Analysis (optional)

In profile mode, HERMES_HOME is set by the CLI launcher to <root>/profiles/<name> before spawning sub-processes (cron jobs, skills, sub-agents). However, these sub-processes do not inherit the parent process's environment variables — they start with a clean or minimal environment. When get_hermes_home() is called without HERMES_HOME in the subprocess's own environment, it cannot distinguish between:

  1. Classic mode where ~/.hermes is the correct default
  2. Profile mode where HERMES_HOME should have been set and ~/.hermes is almost certainly wrong

Because there is no in-process signal indicating which mode is active, the function defaults to the classic-mode fallback. This makes the bug invisible — the code runs without errors while silently writing to the wrong profile's data directory.

Proposed Fix (optional)

def get_hermes_home() -> Path:
    val = os.environ.get("HERMES_HOME", "").strip()
    if not val:
        # In profile mode, ~/.hermes is almost never the right answer.
        # Raise to force the caller or operator to be explicit.
        raise ValueError(
            "HERMES_HOME is not set. "
            "In profile mode this should be set to the profile directory "
            "(e.g. ~/.hermes/profiles/<name>). "
            "Classic mode can set HERMES_HOME to ~/.hermes explicitly."
        )
    return Path(val)

Alternatively, if backward compatibility is needed, add a require_env=False kwarg that defaults to raising in profile-mode-detected contexts.

Are you willing to submit a PR for this?

  • I'd like to fix this myself and submit a PR

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1High — major feature broken, no workaroundarea/configConfig system, migrations, profilescomp/agentCore agent loop, run_agent.py, prompt buildertype/bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions