Skip to content

fix: replace hardcoded ~/.hermes paths with get_hermes_home() for profile support - #3575

Merged
teknium1 merged 3 commits into
mainfrom
hermes/hermes-e6f1d362
Mar 28, 2026
Merged

fix: replace hardcoded ~/.hermes paths with get_hermes_home() for profile support#3575
teknium1 merged 3 commits into
mainfrom
hermes/hermes-e6f1d362

Conversation

@teknium1

Copy link
Copy Markdown
Contributor

Summary

Prep work for the upcoming profiles feature. Profiles give each agent its own HERMES_HOME directory, so all path references must respect the HERMES_HOME env var rather than hardcoding ~/.hermes.

Changes

Hardcoded path fixes (3 files):

  • gateway/platforms/matrix.py — Matrix E2EE store was hardcoded to ~/.hermes/matrix/store. Now uses get_hermes_home().
  • gateway/platforms/telegram.py — Two locations reading config.yaml via Path.home()/.hermes instead of get_hermes_home(). DM topic persistence and hot-reload would read the wrong config.
  • tools/file_tools.py — Security path for hub index blocking was hardcoded to ~/.hermes.

Service naming improvements (gateway.py):

  • New _profile_suffix() helper: detects ~/.hermes/profiles/<name> → returns profile name; other custom paths → returns hash.
  • get_service_name() now returns hermes-gateway-coder instead of hermes-gateway-a1b2c3d4 for profile dirs.
  • get_launchd_plist_path() now scoped per profile: ai.hermes.gateway-coder.plist.
  • New get_launchd_label() — all launchctl commands in gateway.py, main.py, and status.py updated to use it.

macOS launchd fix (pre-existing bug):

  • Launchd plist was missing HERMES_HOME in EnvironmentVariables. Custom HERMES_HOME has always been broken on macOS launchd — this fixes it.

Test plan

  • Full suite: 6537 passed, 201 skipped (1 pre-existing flaky failure unrelated to this PR)
  • DM topic tests updated to set HERMES_HOME env var alongside Path.home() mock
  • Launchd test updated to use get_launchd_label() for expected commands

Two changes to improve tool reliability, especially for OpenAI GPT models:

1. GPT tool-use enforcement prompt: Adds GPT_TOOL_USE_GUIDANCE to the
   system prompt when the model name contains 'gpt' and tools are loaded.
   This addresses a known behavioral pattern where GPT models describe
   intended actions ('I will run the tests') instead of actually making
   tool calls. Inspired by similar steering in OpenCode (beast.txt) and
   Cline (GPT-5.1 variant).

2. Budget warning history stripping: Budget pressure warnings injected by
   _get_budget_warning() into tool results are now stripped when
   conversation history is replayed via run_conversation(). Previously,
   these turn-scoped signals persisted across turns, causing models to
   avoid tool calls in all subsequent messages after any turn that hit
   the 70-90% iteration threshold.
…file support

Prep for the upcoming profiles feature — each profile is a separate
HERMES_HOME directory, so all paths must respect the env var.

Fixes:
- gateway/platforms/matrix.py: Matrix E2EE store was hardcoded to
  ~/.hermes/matrix/store, ignoring HERMES_HOME. Now uses
  get_hermes_home() so each profile gets its own Matrix state.

- gateway/platforms/telegram.py: Two locations reading config.yaml via
  Path.home()/.hermes instead of get_hermes_home(). DM topic thread_id
  persistence and hot-reload would read the wrong config in a profile.

- tools/file_tools.py: Security path for hub index blocking was
  hardcoded to ~/.hermes, would miss the actual profile's hub cache.

- hermes_cli/gateway.py: Service naming now uses the profile name
  (hermes-gateway-coder) instead of a cryptic hash suffix. Extracted
  _profile_suffix() helper shared by systemd and launchd.

- hermes_cli/gateway.py: Launchd plist path and Label now scoped per
  profile (ai.hermes.gateway-coder.plist). Previously all profiles
  would collide on the same plist file on macOS.

- hermes_cli/gateway.py: Launchd plist now includes HERMES_HOME in
  EnvironmentVariables — was missing entirely, making custom
  HERMES_HOME broken on macOS launchd (pre-existing bug).

- All launchctl commands in gateway.py, main.py, status.py updated
  to use get_launchd_label() instead of hardcoded string.

Test fixes: DM topic tests now set HERMES_HOME env var alongside
Path.home() mock. Launchd test uses get_launchd_label() for expected
commands.
@teknium1
teknium1 merged commit e97c0cb into main Mar 28, 2026
4 checks passed
ethernet8023 added a commit that referenced this pull request Aug 11, 2026
- no-hardcoded-hermes-home: the Known Pitfalls rule (source of 5 bugs
  in PR #3575). flags Path.home()/'.hermes' + expanduser variants in
  production code; a get_hermes_home()/HERMES_HOME mention within 8
  lines counts as a guard hint (fallbacks and deliberate HOME anchors
  like the desktop-ssh token root pass untouched), '# hermes-home: ok'
  is the explicit override. found and fixed one real bug: the telegram
  adapter's gmail-triage script path ignored the active profile.
- no-ansi-erase-eol: \033[K leaks as literal ?[K under prompt_toolkit
  patch_stdout; comments documenting the pitfall are exempt.
- skill-frontmatter-standards: the HARDLINE authoring rules that were
  review-only — description <=60 chars/ends with period/no marketing
  words, name present, platforms: required when skill scripts import
  POSIX-only primitives. live tree already clean on all three.
ethernet8023 added a commit that referenced this pull request Aug 14, 2026
- no-hardcoded-hermes-home: the Known Pitfalls rule (source of 5 bugs
  in PR #3575). flags Path.home()/'.hermes' + expanduser variants in
  production code; a get_hermes_home()/HERMES_HOME mention within 8
  lines counts as a guard hint (fallbacks and deliberate HOME anchors
  like the desktop-ssh token root pass untouched), '# hermes-home: ok'
  is the explicit override. found and fixed one real bug: the telegram
  adapter's gmail-triage script path ignored the active profile.
- no-ansi-erase-eol: \033[K leaks as literal ?[K under prompt_toolkit
  patch_stdout; comments documenting the pitfall are exempt.
- skill-frontmatter-standards: the HARDLINE authoring rules that were
  review-only — description <=60 chars/ends with period/no marketing
  words, name present, platforms: required when skill scripts import
  POSIX-only primitives. live tree already clean on all three.
zons-zhaozhy pushed a commit to zons-zhaozhy/hermes-agent that referenced this pull request Aug 17, 2026
…d content, tool_args, profile-aware marker

影响面 [源码确认]:
- agent/tool_executor.py execute_tool_calls_sequential — 单工具调用(写工具
  最常见形态)必走路径,此前零 gate 接线
- agent/tool_executor.py execute_tool_calls_segmented — SimpleNamespace
  segment 视图丢 content,_scan_four_axis(None) 首行 return
- agent/read_think_gate.py + plugins/four-axis-guard — marker 路径硬编码
  Path.home()/.hermes,违反 profile 规约(PR NousResearch#3575 同类)

原意图 git log 851bdcf:
双防线设计——Gate 扫描 assistant content 四轴证据写 marker,插件读 marker
拦写工具。不变量: gate crash 永不阻断执行;同一 assistant_message 只 check
一次;四轴证据按 turn 累积。

根因: 03ddfe1 恢复了并发路径+agent_init+turn_context 三接线,但漏了
sequential 路径(单调用必经)与 segmented 的 content 传递;check_batch 三处
均未传 tool_args,terminal 写文件检测死。

修复:
- segmented: segment 视图补 content 属性
- sequential: 补 check_batch 接线,block 经 scope_block 通道注入(12 处
  消费点,tool-scope 优先、gate 不覆盖已有 block)
- 并发/顺序两路径 check_batch 均传 tool_args
- marker 路径+豁免前缀改 get_hermes_home() 延迟解析(gate 写端+插件读端
  一致)
- 新增 tests/agent/test_read_think_gate_wiring.py 10 项回归锁四缺口
- guardrail_runtime 测试隔离 gate(正交关注点,config read_think_gate.enabled=false)

风险: 并发竞争下 marker 竞写为最后写者胜,可恢复(git revert 单 commit)。

tests: 4393 passed (tests/agent/ 全量 + tool_call 相关), 新增 10 wiring 回归全绿
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant