hermes - 💡(How to fix) Fix [Bug/UX] Three config semantic traps for users debugging memory / multi-profile: silent failure of memory_enabled, profile config override, and per-profile log paths [1 pull requests]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

While debugging a real Hermes-agent deployment, we accumulated ~14 hours of wasted investigation time that turned out to be caused by three independent but stacked UX/docs problems in Hermes config handling. None of them are functional bugs in the strict sense — every individual code path does what it says in the source — but the user-facing names and behaviors don't match what the names imply, so users (and other agents like Codex/Claude when asked to "disable memory" or "fix the agent") write changes that have no effect.

This issue bundles the three traps because they reinforce each other; fixing any one in isolation still leaves users hitting the other two.


Error Message

The fix is also coherent: it's a "make Hermes self-explaining" UX project — print what file you're using, warn on suspicious config combinations, expose CLIs that abstract paths away. All three traps go away if the user can never doubt which file is in play.

Root Cause

While debugging a real Hermes-agent deployment, we accumulated ~14 hours of wasted investigation time that turned out to be caused by three independent but stacked UX/docs problems in Hermes config handling. None of them are functional bugs in the strict sense — every individual code path does what it says in the source — but the user-facing names and behaviors don't match what the names imply, so users (and other agents like Codex/Claude when asked to "disable memory" or "fix the agent") write changes that have no effect.

Fix Action

Fixed

Code Example

memory:
  memory_enabled: false        # user expects: memory subsystem OFF
  user_profile_enabled: false  # user expects: persona writes OFF
  provider: memory_tencentdb
  # ... other fields

---

memory:
  memory_tool_in_system_prompt: false  # was memory_enabled
  user_profile_in_system_prompt: false # was user_profile_enabled

---

WARNING: config has memory.provider = '<name>' but memory_enabled = false.
  This combination loads the memory plugin (cost: watchdog, recall, capture, persona writes)
  but does NOT tell the LLM that memory tools are available.
  To fully disable the memory plugin, set memory.provider = '' instead.

---

Starting Hermes Gateway
  Active profile:  taleb
  Config file:     /Users/<user>/.hermes/profiles/taleb/config.yaml
  Log file:        /Users/<user>/.hermes/profiles/taleb/logs/agent.log
  (root ~/.hermes/config.yaml is NOT being used; run `hermes profile use default` to switch)
RAW_BUFFERClick to expand / collapse

Summary

While debugging a real Hermes-agent deployment, we accumulated ~14 hours of wasted investigation time that turned out to be caused by three independent but stacked UX/docs problems in Hermes config handling. None of them are functional bugs in the strict sense — every individual code path does what it says in the source — but the user-facing names and behaviors don't match what the names imply, so users (and other agents like Codex/Claude when asked to "disable memory" or "fix the agent") write changes that have no effect.

This issue bundles the three traps because they reinforce each other; fixing any one in isolation still leaves users hitting the other two.


Trap 1 — memory.memory_enabled: false does not disable the memory plugin

What users assume

Given config:

memory:
  memory_enabled: false        # user expects: memory subsystem OFF
  user_profile_enabled: false  # user expects: persona writes OFF
  provider: memory_tencentdb
  # ... other fields

users (and assistant agents asked to disable memory) reasonably interpret memory_enabled: false as "the entire memory subsystem is off". This is what the field name literally says.

What actually happens (observation- and source-grounded)

Based on the code paths we inspected and on what we observed at runtime:

  • agent/agent_init.py:967: reads memory_enabled into agent._memory_enabled.
  • agent/system_prompt.py:244: if agent._memory_enabled: ... — decides whether the LLM is told in the system prompt that it has a memory tool.
  • agent/background_review.py:409: review agent copies the flag.
  • agent/memory_manager.py:258-302 (full body of MemoryManager.add_provider() on v2026.5.7): rejects a second external provider but does not check memory_enabled or user_profile_enabled before appending the provider and emitting Memory provider '%s' registered (%d tools).

We have not exhaustively audited the plugin discovery path that decides whether to instantiate a memory provider in the first place; that decision sits one level above add_provider and appears (per plugins/memory/__init__.py:316-318) to be gated by memory.provider, not memory_enabled.

The runtime evidence, after a user set memory_enabled: false and user_profile_enabled: false in the active profile's config.yaml and the gateway restarted:

  • memory_tencentdb registered (2 tools) continued to appear in agent.log at every new session — i.e., the memory provider plugin was still being registered.
  • The TencentDB watchdog kept ticking (multiple memory-tencentdb watchdog: Gateway unreachable; attempting to resurrect. lines over the following hours).
  • The Node gateway was respawned on port 8420 multiple times (Starting memory-tencentdb Gateway followed by Gateway is ready).
  • Persona / scene files under ~/.memory-tencentdb/memory-tdai/ (persona.md, scene_blocks/*.md) had mtime later than the disable change, indicating the L2 extractor was still writing.

In our setup, what did stop these behaviors was setting memory.provider: "" — consistent with plugins/memory/__init__.py:316-318, which reads memory.provider to decide whether to load a memory plugin at all.

Observed impact

A user (or another agent acting on the user's behalf) wrote memory_enabled: false to disable memory after observing that the memory plugin was misbehaving. Over the next 14+ hours, with that config in place and the host gateway restarted, the four runtime symptoms listed above all kept happening. The user only realized the disable hadn't worked when they started reading hermes source for the actual plugin-loading code.

Suggested fix options

A. Rename the field to something that matches its real semantics, e.g.:

memory:
  memory_tool_in_system_prompt: false  # was memory_enabled
  user_profile_in_system_prompt: false # was user_profile_enabled

Keep memory_enabled as a deprecated alias for one or two releases.

B. Add a config validator warning at load time. If memory.provider is non-empty AND (memory_enabled is false OR user_profile_enabled is false), emit:

WARNING: config has memory.provider = '<name>' but memory_enabled = false.
  This combination loads the memory plugin (cost: watchdog, recall, capture, persona writes)
  but does NOT tell the LLM that memory tools are available.
  To fully disable the memory plugin, set memory.provider = '' instead.

C. Make memory_enabled: false actually gate plugin loading. This would be a behavior change — currently any user who deliberately wants "plugin runs in the background but LLM doesn't see memory tools" (which is a niche but legitimate use case) would break. Probably less preferred than A/B.

Recommendation: B + A together. B is purely additive (no behavior change, only a warning), so it can ship immediately. A can ride a deprecation cycle.


Trap 2 — sticky/active profile silently overrides root config.yaml

What users assume

~/.hermes/config.yaml is the master config. Edits to it are what take effect.

What actually happens

When the user has previously run hermes profile use <name> (or otherwise set a sticky profile), a sticky profile state is recorded. From that point on:

  • hermes gateway run (without --profile) reads ~/.hermes/profiles/<active>/config.yaml, not the root.
  • The two configs are independent files, not layered. Root config edits affect nothing the active gateway sees.

In our case, this was directly visible: the running gateway process had ~/.hermes/profiles/taleb/gateway.lock, ~/.hermes/profiles/taleb/state.db, and ~/.hermes/profiles/taleb/logs/agent.log open (verified via lsof -p <pid>), while edits to ~/.hermes/config.yaml had no effect on its behavior. We did not see any startup log line in our incident explicitly announcing which profile/config the gateway was using — the Session storage: <path> line emitted at startup does encode the active profile in its path, but a user has to know to read it that way.

The redirection is queryable via existing CLI commands:

  • hermes profile list shows the active profile (marked with ) and per-profile model/gateway state
  • hermes profile show <name> shows that profile's Path:, model, gateway state, etc.

But the user has to know to query them. In the default "I just edited ~/.hermes/config.yaml and restarted" workflow — which is where most config debugging happens — there is no touchpoint that would prompt the user to first check hermes profile. hermes status (which is the natural place to look) does not surface the resolved config path either.

Observed impact (verbatim from real incident)

  1. Day 0: user runs hermes profile use taleb to try out a persona.
  2. Day 5: user (or assistant agent) wants to disable memory plugin. Edits ~/.hermes/config.yaml's memory.memory_enabled to false (which is Trap 1's mistake, but compounded by Trap 2).
  3. User restarts gateway. Expects clean state.
  4. Active gateway is still reading ~/.hermes/profiles/taleb/config.yaml, where memory_enabled is still true.
  5. User spends hours reading agent.log ([wrong file too — see Trap 3]) trying to understand why nothing changed.

Suggested fix

A. Print active profile + config path at gateway startup:

Starting Hermes Gateway
  Active profile:  taleb
  Config file:     /Users/<user>/.hermes/profiles/taleb/config.yaml
  Log file:        /Users/<user>/.hermes/profiles/taleb/logs/agent.log
  (root ~/.hermes/config.yaml is NOT being used; run `hermes profile use default` to switch)

B. hermes status should display the same trio. Currently hermes status shows the active profile name but, in our test, did not show the resolved file paths alongside.

C. CLI subcommand hermes config edit that opens the correct file for the active profile in $EDITOR. This is the friendliest fix — users don't even need to know the path.


Trap 3 — per-profile log files are not surfaced

What users assume

~/.hermes/logs/agent.log is the log file.

What actually happens

When a named profile is active, the gateway writes to ~/.hermes/profiles/<name>/logs/agent.log instead. The root agent.log is left as a stale file from before the profile switch.

grep memory_tencentdb ~/.hermes/logs/agent.log will show old data and zero recent activity even while the live gateway is actively processing memory operations.

Observed impact

In our incident, an investigator (another agent) initially read 433 occurrences of memory_tencentdb from ~/.hermes/logs/agent.log and thought they were investigating recent behavior. They were actually reading data from a previous run, days before the active profile switch. The current taleb gateway's actual log at ~/.hermes/profiles/taleb/logs/agent.log contained different and current data.

This problem is the corollary of Trap 2 — same root cause (profile redirection invisible to user) but specifically on the log surface.

Suggested fix

Subsumed by Trap 2's fix A/B: any place that prints "active profile" should also print the log path. Plus:

A. Symlink heuristic: when a profile is activated, also symlink ~/.hermes/logs/agent.logprofiles/<active>/logs/agent.log. Users who tail the root path always get the right data. (May complicate log rotation — feature-flag it.)

B. hermes logs CLI: a hermes logs [agent|gateway|errors] [--profile <name>] subcommand that follows the right file for the active profile. Removes the need for users to know paths at all.


Why bundle these into one issue

All three traps share a meta-pattern: Hermes config / log surface area silently redirects user intent without any UI signal we noticed. Fixing any one of them in isolation still leaves the others, and we observed real users (including ourselves and AI assistant agents acting on our behalf) get bitten by all three in the same debugging session.

The fix is also coherent: it's a "make Hermes self-explaining" UX project — print what file you're using, warn on suspicious config combinations, expose CLIs that abstract paths away. All three traps go away if the user can never doubt which file is in play.

Happy to split into three separate issues if maintainers prefer.

Environment

  • macOS 26.x
  • Hermes Agent v2026.5.7 (e19fc91) at incident time; the same code paths for Traps 1–3 also appear in main (4fdfdf6) at time of filing based on our spot-check, but we have not exhaustively re-tested all three behaviors against main.
  • Multi-profile setup: default + 7 named profiles (taleb, jobs, elon, trump, naval, munger, birkin, hamlet-ops)

Related

  • #21549 — launchd double-spawn death spiral. The multi-profile setup that creates conditions for Trap 2/3 is also the setup that creates conditions for #21549. I left a separate comment there with additional incident-specific data: #21549 (comment).
  • #25091api_key_env alias bug, already fixed and closed. That was a fourth config trap in the same family — silent failure of a documented alias in one config section but not another. The fact that we keep finding adjacent failures of this kind suggests the config surface as a whole deserves dedicated UX attention.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING