fix(hermes): preload ~/.agentmemory/.env so status reflects service env (closes #250)#253
Conversation
…nv (closes #250) When agentmemory runs as a systemd user service (or any process manager that loads ~/.agentmemory/.env directly), the values never reach the shell that runs `hermes memory status`. Status then reads os.environ in the Hermes CLI process, finds AGENTMEMORY_URL / AGENTMEMORY_SECRET unset, and reports the plugin as "Missing" even though the service is healthy and live sessions can use it. Preload the documented config file at plugin-import time using os.environ.setdefault so anything explicitly set in the shell still wins. Best-effort: silently skip when the file is absent, unreadable, or malformed — the plugin falls back to its existing defaults. Both ~/.agentmemory/.env (primary, per agentmemory's own README) and $XDG_CONFIG_HOME/agentmemory/.env (fallback) are checked. Reported by @OptionalCoin. Tested: $ printf 'AGENTMEMORY_URL=http://example\nAGENTMEMORY_SECRET=s\n' \ > ~/.agentmemory/.env $ unset AGENTMEMORY_URL AGENTMEMORY_SECRET $ python -c "import sys; sys.path.insert(0, 'integrations'); \ import hermes; \ import os; \ print(os.environ['AGENTMEMORY_URL'])" http://example $ AGENTMEMORY_URL=http://shell-wins python -c "..." http://shell-wins # explicit shell value still wins
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 WalkthroughWalkthroughThe Hermes integration plugin now preloads AgentMemory runtime configuration from dotenv files at import time. A new helper function discovers files at ChangesAgentMemory Dotenv Preloading
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@integrations/hermes/__init__.py`:
- Line 84: The current expression value = value.strip().strip('"').strip("'")
removes unmatched or inner quotes; instead trim whitespace first then only
remove a surrounding quote pair when the first and last characters match and are
either " or ', e.g. after value = value.strip() test if len(value) >= 2 and
value[0] == value[-1] and value[0] in ('"', "'") and only then set value =
value[1:-1]; update the code replacing the chained strip call that sets variable
value so it preserves inner quotes and ignores mismatched single-end quotes.
In `@integrations/hermes/README.md`:
- Line 109: Update the README text to clarify that both files are read when
present (both ~/.agentmemory/.env and $XDG_CONFIG_HOME/agentmemory/.env) at
import time and that values are loaded into os.environ via
os.environ.setdefault(), so the first-processed file (currently
~/.agentmemory/.env) takes precedence; also note that shell-exported variables
override these files and mention this affects the output of the hermes memory
status command when agentmemory is started by a process manager.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: f7edcafa-1c45-4994-b80e-9a3b78cc609e
📒 Files selected for processing (2)
integrations/hermes/README.mdintegrations/hermes/__init__.py
| continue | ||
| key, _, value = line.partition("=") | ||
| key = key.strip() | ||
| value = value.strip().strip('"').strip("'") |
There was a problem hiding this comment.
Fix quote stripping to handle only matching pairs.
The current quote-stripping logic removes quotes from both ends independently, which can corrupt values:
FOO="it's"becomesit(removes outer"and inner')FOO="bar'becomesbar(removes mismatched quotes)FOO=value"becomesvalue(removes trailing quote)
Only matching quote pairs should be stripped.
🔧 Proposed fix to strip only matching quote pairs
key, _, value = line.partition("=")
key = key.strip()
- value = value.strip().strip('"').strip("'")
+ value = value.strip()
+ if len(value) >= 2 and value[0] == value[-1] and value[0] in ('"', "'"):
+ value = value[1:-1]
if key:
os.environ.setdefault(key, value)📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| value = value.strip().strip('"').strip("'") | |
| key, _, value = line.partition("=") | |
| key = key.strip() | |
| value = value.strip() | |
| if len(value) >= 2 and value[0] == value[-1] and value[0] in ('"', "'"): | |
| value = value[1:-1] | |
| if key: | |
| os.environ.setdefault(key, value) |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@integrations/hermes/__init__.py` at line 84, The current expression value =
value.strip().strip('"').strip("'") removes unmatched or inner quotes; instead
trim whitespace first then only remove a surrounding quote pair when the first
and last characters match and are either " or ', e.g. after value =
value.strip() test if len(value) >= 2 and value[0] == value[-1] and value[0] in
('"', "'") and only then set value = value[1:-1]; update the code replacing the
chained strip call that sets variable value so it preserves inner quotes and
ignores mismatched single-end quotes.
| | `AGENTMEMORY_URL` | `http://localhost:3111` | agentmemory server URL | | ||
| | `AGENTMEMORY_SECRET` | (none) | Auth token for protected instances | | ||
|
|
||
| The plugin reads `~/.agentmemory/.env` (or `$XDG_CONFIG_HOME/agentmemory/.env`) at import time and populates any missing values into the process environment via `os.environ.setdefault`. Anything you set in the shell takes precedence; the file is only used to fill gaps. This means `hermes memory status` reports the plugin as available even when the agentmemory service is launched by systemd or another process manager that loads `~/.agentmemory/.env` directly without exporting it to the Hermes CLI shell (#250). |
There was a problem hiding this comment.
Clarify that both .env files are read when both exist.
The documentation states "or" which suggests only one file is read, but the implementation reads both ~/.agentmemory/.env and $XDG_CONFIG_HOME/agentmemory/.env if both exist. Values from ~/.agentmemory/.env take precedence due to the order in which files are processed and the use of os.environ.setdefault().
📝 Proposed clarification
-The plugin reads `~/.agentmemory/.env` (or `$XDG_CONFIG_HOME/agentmemory/.env`) at import time and populates any missing values into the process environment via `os.environ.setdefault`.
+The plugin reads `~/.agentmemory/.env` and `$XDG_CONFIG_HOME/agentmemory/.env` (if they exist) at import time and populates any missing values into the process environment via `os.environ.setdefault`, with `~/.agentmemory/.env` taking precedence.📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| The plugin reads `~/.agentmemory/.env` (or `$XDG_CONFIG_HOME/agentmemory/.env`) at import time and populates any missing values into the process environment via `os.environ.setdefault`. Anything you set in the shell takes precedence; the file is only used to fill gaps. This means `hermes memory status` reports the plugin as available even when the agentmemory service is launched by systemd or another process manager that loads `~/.agentmemory/.env` directly without exporting it to the Hermes CLI shell (#250). | |
| The plugin reads `~/.agentmemory/.env` and `$XDG_CONFIG_HOME/agentmemory/.env` (if they exist) at import time and populates any missing values into the process environment via `os.environ.setdefault`, with `~/.agentmemory/.env` taking precedence. Anything you set in the shell takes precedence; the file is only used to fill gaps. This means `hermes memory status` reports the plugin as available even when the agentmemory service is launched by systemd or another process manager that loads `~/.agentmemory/.env` directly without exporting it to the Hermes CLI shell (`#250`). |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@integrations/hermes/README.md` at line 109, Update the README text to clarify
that both files are read when present (both ~/.agentmemory/.env and
$XDG_CONFIG_HOME/agentmemory/.env) at import time and that values are loaded
into os.environ via os.environ.setdefault(), so the first-processed file
(currently ~/.agentmemory/.env) takes precedence; also note that shell-exported
variables override these files and mention this affects the output of the hermes
memory status command when agentmemory is started by a process manager.
Bug-fix patch focused on search recall correctness and plugin compatibility. Pins iii-engine to v0.11.2 because v0.11.6 introduces a new sandbox-everything-via-`iii worker add` model that agentmemory hasn't been refactored for yet — pin lifts once that refactor lands. Adds a hard guard against silent vector-index corruption, fixes BM25 indexing for memories saved via memory_save, and lands four Hermes plugin fixes. Per AGENTS.md release checklist: - package.json version 0.9.4 -> 0.9.5 - src/version.ts VERSION constant - src/types.ts ExportData version union - src/functions/export-import.ts supportedVersions Set - test/export-import.test.ts assertion - plugin/.claude-plugin/plugin.json version - CHANGELOG.md detailed entries with contributor shoutouts Headlines (full detail in CHANGELOG): Fixed: - BM25 search now indexes memories saved via memory_save (#258, #257) Thanks @Nizar-BenHamida for the precise repro. - Embedding providers no longer silently corrupt the vector index when an API returns wrong-dimension vectors (#248, #247, #256) Thanks @AmmarSaleh50 for issue + fix + tests. - Hermes handle_tool_call returns JSON strings, not raw dicts (#255, #254) Thanks @KyoMio for the Anthropic-protocol repro. - Hermes status reflects real service state on systemd installs (#253, #250) Thanks @OptionalCoin for tracing it to env-source divergence. - Hermes hooks accept passthrough kwargs (#252, #249) Thanks @OptionalCoin again for the log analysis. - agentmemory demo now seeds observations correctly (#251, #229) Thanks @seishonagon for root-cause analysis. - LLM compression / summarization timeouts increased (#213) Thanks @xuli500177. - Pi / OpenClaw / Hermes integration plugin fixes (#230) Thanks @deepmroot. Changed: - iii-engine pinned to v0.11.2 across every install path (#260). v0.11.6 introduces a new `iii worker add` sandbox model that agentmemory still pre-dates; pin lifts when we refactor agentmemory to register as a sandboxed worker. Override with AGENTMEMORY_III_VERSION=<version> for users who've migrated manually. - README documents iii worker add extension surface (#242). - README iii Console install/launch commands corrected (#243). Validated: 852/852 tests pass, npm run build clean.
Bug-fix patch focused on search recall correctness and plugin compatibility. Pins iii-engine to v0.11.2 because v0.11.6 introduces a new sandbox-everything-via-`iii worker add` model that agentmemory hasn't been refactored for yet — pin lifts once that refactor lands. Adds a hard guard against silent vector-index corruption, fixes BM25 indexing for memories saved via memory_save, and lands four Hermes plugin fixes. Per AGENTS.md release checklist: - package.json version 0.9.4 -> 0.9.5 - src/version.ts VERSION constant - src/types.ts ExportData version union - src/functions/export-import.ts supportedVersions Set - test/export-import.test.ts assertion - plugin/.claude-plugin/plugin.json version - CHANGELOG.md detailed entries with contributor shoutouts Headlines (full detail in CHANGELOG): Fixed: - BM25 search now indexes memories saved via memory_save (#258, #257) Thanks @Nizar-BenHamida for the precise repro. - Embedding providers no longer silently corrupt the vector index when an API returns wrong-dimension vectors (#248, #247, #256) Thanks @AmmarSaleh50 for issue + fix + tests. - Hermes handle_tool_call returns JSON strings, not raw dicts (#255, #254) Thanks @KyoMio for the Anthropic-protocol repro. - Hermes status reflects real service state on systemd installs (#253, #250) Thanks @OptionalCoin for tracing it to env-source divergence. - Hermes hooks accept passthrough kwargs (#252, #249) Thanks @OptionalCoin again for the log analysis. - agentmemory demo now seeds observations correctly (#251, #229) Thanks @seishonagon for root-cause analysis. - LLM compression / summarization timeouts increased (#213) Thanks @xuli500177. - Pi / OpenClaw / Hermes integration plugin fixes (#230) Thanks @deepmroot. Changed: - iii-engine pinned to v0.11.2 across every install path (#260). v0.11.6 introduces a new `iii worker add` sandbox model that agentmemory still pre-dates; pin lifts when we refactor agentmemory to register as a sandboxed worker. Override with AGENTMEMORY_III_VERSION=<version> for users who've migrated manually. - README documents iii worker add extension surface (#242). - README iii Console install/launch commands corrected (#243). Validated: 852/852 tests pass, npm run build clean.
Bug-fix patch focused on search recall correctness and plugin compatibility. Pins iii-engine to v0.11.2 because v0.11.6 introduces a new sandbox-everything-via-`iii worker add` model that agentmemory hasn't been refactored for yet — pin lifts once that refactor lands. Adds a hard guard against silent vector-index corruption, fixes BM25 indexing for memories saved via memory_save, and lands four Hermes plugin fixes. Per AGENTS.md release checklist: - package.json version 0.9.4 -> 0.9.5 - src/version.ts VERSION constant - src/types.ts ExportData version union - src/functions/export-import.ts supportedVersions Set - test/export-import.test.ts assertion - plugin/.claude-plugin/plugin.json version - CHANGELOG.md detailed entries with contributor shoutouts Headlines (full detail in CHANGELOG): Fixed: - BM25 search now indexes memories saved via memory_save (#258, #257) Thanks @Nizar-BenHamida for the precise repro. - Embedding providers no longer silently corrupt the vector index when an API returns wrong-dimension vectors (#248, #247, #256) Thanks @AmmarSaleh50 for issue + fix + tests. - Hermes handle_tool_call returns JSON strings, not raw dicts (#255, #254) Thanks @KyoMio for the Anthropic-protocol repro. - Hermes status reflects real service state on systemd installs (#253, #250) Thanks @OptionalCoin for tracing it to env-source divergence. - Hermes hooks accept passthrough kwargs (#252, #249) Thanks @OptionalCoin again for the log analysis. - agentmemory demo now seeds observations correctly (#251, #229) Thanks @seishonagon for root-cause analysis. - LLM compression / summarization timeouts increased (#213) Thanks @xuli500177. - Pi / OpenClaw / Hermes integration plugin fixes (#230) Thanks @deepmroot. Changed: - iii-engine pinned to v0.11.2 across every install path (#260). v0.11.6 introduces a new `iii worker add` sandbox model that agentmemory still pre-dates; pin lifts when we refactor agentmemory to register as a sandboxed worker. Override with AGENTMEMORY_III_VERSION=<version> for users who've migrated manually. - README documents iii worker add extension surface (#242). - README iii Console install/launch commands corrected (#243). Validated: 852/852 tests pass, npm run build clean.
Closes #250.
What
When a user manages agentmemory's runtime config in
~/.agentmemory/.env(the file agentmemory's own README documents) and starts the service via systemd / launchd / docker compose, those values never reach Hermes. Hermes' canonical env source is~/.hermes/.env(per the Configuration page):The "happy path" Hermes expects is
hermes plugin configure agentmemory→ user enters URL + secret → Hermes writes them to~/.hermes/.env. But users running agentmemory as an external service skip that step, andhermes memory statusthen reports the plugin as "not available" + "Missing AGENTMEMORY_URL / AGENTMEMORY_SECRET" — even though the service is healthy and live conversations can use it.Fix
Preload
~/.agentmemory/.env(the agentmemory-side config) at plugin-import time usingos.environ.setdefault. This bridges the two source-of-truths cleanly:~/.hermes/.envand any explicitly-exported shell vars take precedence —setdefaultonly fills gaps.hermes plugin configure agentmemory..envis silently skipped; the plugin falls back to its existing defaults.~/.agentmemory/.env(primary) and$XDG_CONFIG_HOME/agentmemory/.env(XDG fallback).The parser is intentionally tiny —
KEY=VALUElines,#comments, blank lines, trim matching'/"quotes. Nopython-dotenvdependency; the rest ofintegrations/hermes/is zero-dep too.Why fix from the plugin side
The cleaner long-term fix would be Hermes'
memory statuscommand consulting the provider'sis_available()rather than treating env-var presence as a proxy. That's an upstream change. This PR closes the symptom from our side without waiting on it, mirroring the defensive pattern in #252 (**kwargseverywhere because Hermes' runtime contract drifts from its docs).Test plan
HOMEcontaining.agentmemory/.env, importing the plugin populatesos.environ.AGENTMEMORY_URLis preserved through plugin import; only missing keys are filled from the file.Credit to @OptionalCoin for the precise repro.