Summary
Several modules hardcode Path.home() / \".basic-memory\" to locate Basic Memory state instead of using BasicMemoryConfig.data_dir_path / ConfigManager.config_dir. This means they ignore the BASIC_MEMORY_CONFIG_DIR environment variable, which users/tests rely on to redirect Basic Memory state (for isolated worktrees, containerized runs, multi-instance setups, etc.).
Any feature accessed through these call sites will silently read/write the wrong directory when BASIC_MEMORY_CONFIG_DIR is set.
Known offending call sites
src/basic_memory/utils.py:284 — log_path = Path.home() / \".basic-memory\" / log_filename (file logging)
src/basic_memory/ignore_utils.py:66 — return Path.home() / \".basic-memory\" / \".bmignore\" (global ignore file lookup)
src/basic_memory/sync/watch_service.py:92 — self.status_path = Path.home() / \".basic-memory\" / WATCH_STATUS_JSON
src/basic_memory/services/project_service.py:1140 — watch_status_path = Path.home() / \".basic-memory\" / WATCH_STATUS_JSON
src/basic_memory/cli/commands/cloud/rclone_commands.py:147 — return Path.home() / \".basic-memory\" / \"bisync-state\" / project_name
Example impact
If a user runs with BASIC_MEMORY_CONFIG_DIR=/opt/bm-sandbox:
- Config and the SQLite DB live under
/opt/bm-sandbox/ (correct — honors the env var).
- But the watch status file, log file,
.bmignore, and rclone bisync state all end up under ~/.basic-memory/ (wrong).
This causes split state, stale watchers, log leakage across isolated instances, and broken .bmignore behavior depending on which code path the user hits first.
Proposed fix
Follow-up to #741:
#741 introduces resolve_data_dir() as a module-level helper in config.py (the single source of truth, honoring BASIC_MEMORY_CONFIG_DIR).
- This issue: update every call site above to use
resolve_data_dir() (or an equivalent already-available config accessor) instead of hardcoding Path.home() / \".basic-memory\".
- Add a regression test that exercises each of those code paths under a non-default
BASIC_MEMORY_CONFIG_DIR and asserts the file/dir they touch lives under the redirected data dir.
Keeping it out of #741 to avoid scope creep on the FastEmbed cache fix.
Summary
Several modules hardcode
Path.home() / \".basic-memory\"to locate Basic Memory state instead of usingBasicMemoryConfig.data_dir_path/ConfigManager.config_dir. This means they ignore theBASIC_MEMORY_CONFIG_DIRenvironment variable, which users/tests rely on to redirect Basic Memory state (for isolated worktrees, containerized runs, multi-instance setups, etc.).Any feature accessed through these call sites will silently read/write the wrong directory when
BASIC_MEMORY_CONFIG_DIRis set.Known offending call sites
src/basic_memory/utils.py:284—log_path = Path.home() / \".basic-memory\" / log_filename(file logging)src/basic_memory/ignore_utils.py:66—return Path.home() / \".basic-memory\" / \".bmignore\"(global ignore file lookup)src/basic_memory/sync/watch_service.py:92—self.status_path = Path.home() / \".basic-memory\" / WATCH_STATUS_JSONsrc/basic_memory/services/project_service.py:1140—watch_status_path = Path.home() / \".basic-memory\" / WATCH_STATUS_JSONsrc/basic_memory/cli/commands/cloud/rclone_commands.py:147—return Path.home() / \".basic-memory\" / \"bisync-state\" / project_nameExample impact
If a user runs with
BASIC_MEMORY_CONFIG_DIR=/opt/bm-sandbox:/opt/bm-sandbox/(correct — honors the env var)..bmignore, and rclone bisync state all end up under~/.basic-memory/(wrong).This causes split state, stale watchers, log leakage across isolated instances, and broken
.bmignorebehavior depending on which code path the user hits first.Proposed fix
Follow-up to #741:
#741introducesresolve_data_dir()as a module-level helper inconfig.py(the single source of truth, honoringBASIC_MEMORY_CONFIG_DIR).resolve_data_dir()(or an equivalent already-available config accessor) instead of hardcodingPath.home() / \".basic-memory\".BASIC_MEMORY_CONFIG_DIRand asserts the file/dir they touch lives under the redirected data dir.Keeping it out of #741 to avoid scope creep on the FastEmbed cache fix.