feat: profile-isolated memory via HERMES_HOME - #37
Open
brian-doherty wants to merge 1 commit into
Open
Conversation
Hermes Agent supports multiple profiles — when a non-default profile is
active, Hermes sets HERMES_HOME to <root>/profiles/<name>. Previously
Memory OS hardcoded ~/.hermes everywhere, so every profile stomped on
the default profile's memory (fabric, state.db, memory_store.db, logs,
wiki state, DLQ, SOUL.md).
This change makes all Hermes-owned paths resolve through HERMES_HOME:
- New scripts/hermes_env.py: single resolution module (hermes_home(),
fabric_dir(), state_db(), memory_store_db(), logs_dir(), wiki/DLQ
paths). Honors HERMES_HOME, falls back to ~/.hermes.
- icarus/state.py: FABRIC_DIR defaults to <profile-home>/fabric when a
profile is active; agent name auto-detected from modern
profiles/<name> and legacy .hermes-<name> layouts; icarus state
files (training job, model registry, telemetry, creative state) now
resolve under the active home. Profile detection (hermes_home /
profile_name / is_profile) is imported from scripts/hermes_env
instead of being duplicated, so there's one source of truth.
- icarus/hooks.py + fabric-retrieve.py: state.db / memory_store.db /
fabric resolved profile-aware.
- All maintenance scripts (decay_scanner, semantic_dedup, dlq_manager,
wiki_continuous_ingest, reflection_trigger, context_enhancer,
verify_soul_config, backfill_decay_metadata) and setup/setup_db.py
now use hermes_env paths.
- setup.sh: new --profile <name> flag installs into
~/.hermes/profiles/<name>. HERMES_HOME is now exported so subprocesses
(setup_db.py) actually see it, the profile name is validated against a
safe charset, the generated wiki-watcher cron entry carries HERMES_HOME
inline and uses a per-profile marker (system crontab doesn't propagate
env the way Hermes cron does), and FABRIC_DIR is no longer force-written
into a profile's .env — profiles now default to their own
<HERMES_HOME>/fabric instead of colliding on the shared
${VAULT_PATH}/fabric.
- Docs: icarus/README.md profile section rewritten for the modern
layout; explains per-profile isolation and how to deliberately share
a fabric via explicit FABRIC_DIR.
- Tests: _test_hermes_env.py covers hermes_env/state.py path resolution
(default, modern profiles/<name>, legacy .hermes-<name>, FABRIC_DIR
override); _test_setup_profile.py covers setup.sh's --profile parsing,
validation, HERMES_HOME export, and per-profile cron marker in
isolation.
Backwards compatible: with HERMES_HOME unset everything resolves to
~/.hermes exactly as before; an explicit FABRIC_DIR env var still wins
(cross-profile fabric sharing).
brian-doherty
force-pushed
the
feat/profile-isolated-memory
branch
from
August 3, 2026 18:13
168aeb8 to
fc3634c
Compare
Contributor
Author
|
@ClaudioDrews For your consideration. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Hermes Agent supports multiple profiles (
hermes profile create <name>). When a non-default profile is active, Hermes setsHERMES_HOMEto<root>/profiles/<name>(e.g.~/.hermes/profiles/fpvdeals) and propagates it into subprocess/cron environments.Previously Memory OS hardcoded
~/.hermesin 15+ places, so every profile stomped on the default profile's memory — shared (colliding) fabric,state.db,memory_store.db, logs, wiki state, DLQ, and SOUL.md. This PR makes Memory OS profile-aware so separate profiles get separate memories.What changed
scripts/hermes_env.py— single resolution module:hermes_home()honorsHERMES_HOME(fallback~/.hermes), plusfabric_dir(),state_db(),memory_store_db(),logs_dir(), wiki/DLQ/SOUL path helpers.icarus/state.py—FABRIC_DIRdefaults to<profile-home>/fabricwhen a profile is active; agent name auto-detected from modernprofiles/<name>and legacy.hermes-<name>layouts; icarus state files (training job, model registry, telemetry, creative state) resolve under the active home (previously fell back to~whenHERMES_HOMEwas unset).icarus/hooks.py+icarus/fabric-retrieve.py—state.db/memory_store.db/ fabric resolved profile-aware.decay_scanner,semantic_dedup,dlq_manager,wiki_continuous_ingest,reflection_trigger,context_enhancer,verify_soul_config,backfill_decay_metadata) andsetup/setup_db.pynow usehermes_envpaths.setup.sh— new--profile <name>flag installs into~/.hermes/profiles/<name>.icarus/README.mdprofile section rewritten for the modern layout.Behavior
~/.hermes/state.db,~/fabricfpvdeals~/.hermes/state.db,~/fabric(collision!)~/.hermes/profiles/fpvdeals/state.db,.../fpvdeals/fabricFABRIC_DIRFully backwards compatible: with
HERMES_HOMEunset, every path resolves to~/.hermesexactly as before.Test plan
python -m compileall -q icarus scripts setup _test_collapse.py _test_sanitize.py✅python _test_collapse.py— all pass ✅python _test_sanitize.py— all 24 pass ✅