Skip to content

[Bug]: resolve_skill_config_values() uses wrong HOME semantics for ~ expansion — expands against Python process HOME instead of Hermes subprocess HOME #12260

@charlielin

Description

@charlielin

Bug Description

resolve_skill_config_values() in agent/skill_utils.py expands ~ in skill config default values using os.path.expanduser(), which resolves against the Python process's own HOME (/opt/data in containerized setups). However, Hermes independently sets a
different HOME ({HERMES_HOME}/home/) for terminal/background subprocesses via get_subprocess_home().

Steps to Reproduce

  1. Start Hermes in a Docker environment with HERMES_HOME=/opt/data
  2. Verify that the entrypoint has created {HERMES_HOME}/home/:
    ls -d /opt/data/home
  3. Confirm the Python process HOME differs from the subprocess HOME:
    import os
    from hermes_constants import get_subprocess_home

print(f"Python process HOME: {os.environ.get('HOME')}") # e.g. /opt/data
print(f"Subprocess HOME: {get_subprocess_home()}") # e.g. /opt/data/home
4. Trigger skill config resolution (e.g. via prompt injection with an enabled llm-wiki skill that declares default: "~/wiki"):
[Skill config ... wiki.path = /opt/data/wiki]
5. Observe that the injected path uses the Python process HOME (/opt/data/wiki) instead of the subprocess HOME (/opt/data/home/wiki)
6. Any file-creating tool (e.g. wiki init) will write to /opt/data/wiki/ on disk, but subprocesses will look for their configs at /opt/data/home/wiki/

Expected Behavior

wiki.path = /opt/data/home/wiki

Actual Behavior

wiki.path = /opt/data/wiki

Affected Component

Skills (skill loading, skill hub, skill guard)

Messaging Platform (if gateway-related)

No response

Debug Report

Report       https://paste.rs/oO3UO
agent.log    https://paste.rs/AO4i6
gateway.log  https://paste.rs/ZEJeP

Operating System

macOS 26.4.1

Python Version

3.13.5

Hermes Version

v0.10.0 (2026.4.16)

Additional Logs / Traceback (optional)

Root Cause Analysis (optional)

agent/skill_utils.py:406-408:

  if isinstance(value, str) and ("~" in value or "${" in value):
      value = os.path.expanduser(os.path.expandvars(value))

os.path.expanduser() uses the Python process's HOME env var, which is never modified by Hermes. Meanwhile, hermes_constants.get_subprocess_home() (which returns {HERMES_HOME}/home/ when that directory exists) governs the actual HOME seen by tools
spawned in terminals or background processes.

Evidence

  • entrypoint.sh creates {HERMES_HOME}/home/ explicitly for subprocess use: "home/ subdirectory is a per-profile HOME for subprocesses"
  • tools/environments/local.py injects get_subprocess_home() as HOME into subprocess environments
  • hermes_constants.get_subprocess_home() docstring explicitly states: "The Python process's own os.environ["HOME"] and Path.home() are never modified — only subprocess environments should inject this value."

Yet resolve_skill_config_values() silently uses the Python process HOME instead.

Impact

Any skill declaring a ~/... default path in metadata.hermes.config is affected, including:

  • llm-wiki (default: ~/wiki)
  • Any other skill using ~/cache, ~/notes, ~/workspace, etc.

The skill config injection block in prompts shows an incorrect path that doesn't match the actual runtime environment.

Proposed Fix (optional)

In resolve_skill_config_values(), prefer get_subprocess_home() over raw os.path.expanduser() when expanding ~/ paths:

from hermes_constants import get_config_path, get_skills_dir, get_subprocess_home
subprocess_home = get_subprocess_home()


if isinstance(value, str) and ("~" in value or "${" in value):
    expanded = os.path.expandvars(value)
    if subprocess_home and expanded.startswith("~/"):
        value = os.path.join(subprocess_home, expanded[2:])
    elif subprocess_home and expanded == "~":
        value = subprocess_home
    else:
        value = os.path.expanduser(expanded)

This ensures ~/wiki injected as /opt/data/home/wiki (matching subprocess HOME) instead of /opt/data/wiki (matching Python process HOME).

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

    type/bugSomething isn't working

    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