From 78453a779e79e31efe9ee76dce6fcbe7bdaeff23 Mon Sep 17 00:00:00 2001 From: sanjibani <18418553+sanjibani@users.noreply.github.com> Date: Mon, 29 Jun 2026 21:12:46 +0530 Subject: [PATCH 1/2] docs: fix 3 broken links in README and cloud-cli The basicmemory.com docs site restructured: /getting-started/note-formatting and /guides/cli-reference both 404, replaced with the canonical /concepts/knowledge-format and /reference/cli-reference paths (the old /guides prefix was renamed to /reference). The basicmemory.com/subscribe landing page was retired and now redirects to /pricing. Verified via curl: GET on the new URLs returns 200. Signed-off-by: sanjibani <18418553+sanjibani@users.noreply.github.com> --- README.md | 4 ++-- docs/cloud-cli.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 57a6abd7e..8374c13d2 100644 --- a/README.md +++ b/README.md @@ -479,7 +479,7 @@ multi-word ones. Bare `- [[Target]]` and prose `- Worth checking out [[Target]]` index as `links_to`. Full reference in the -[docs](https://docs.basicmemory.com/getting-started/note-formatting/?utm_source=github&utm_medium=referral&utm_campaign=readme). +[docs](https://docs.basicmemory.com/concepts/knowledge-format?utm_source=github&utm_medium=referral&utm_campaign=readme). ## MCP tools @@ -525,7 +525,7 @@ basic-memory import memory-json Routing flags (`--local` / `--cloud`) force a target when you're in mixed mode. Full CLI reference in the -[docs](https://docs.basicmemory.com/guides/cli-reference/?utm_source=github&utm_medium=referral&utm_campaign=readme). +[docs](https://docs.basicmemory.com/reference/cli-reference?utm_source=github&utm_medium=referral&utm_campaign=readme). ## Auto-updates diff --git a/docs/cloud-cli.md b/docs/cloud-cli.md index ae93ed357..5ba501520 100644 --- a/docs/cloud-cli.md +++ b/docs/cloud-cli.md @@ -32,7 +32,7 @@ The transfer commands fall into two groups: Before using Basic Memory Cloud, you need: - **Active Subscription**: An active Basic Memory Cloud subscription is required to access cloud features -- **Subscribe**: Visit [https://basicmemory.com/subscribe](https://basicmemory.com/subscribe) to sign up +- **Subscribe**: Visit [https://basicmemory.com/pricing](https://basicmemory.com/pricing) to sign up - **Optional**: Cloud is optional. Local-first open-source usage continues without cloud. - **OSS Discount**: Use code `{{OSS_DISCOUNT_CODE}}` for 20% off for 3 months. From 39a66bee8dff1ebe7e8bf348b81ced19d21c8814 Mon Sep 17 00:00:00 2001 From: sanjibani <18418553+sanjibani@users.noreply.github.com> Date: Thu, 2 Jul 2026 21:16:00 +0530 Subject: [PATCH 2/2] fix(config): stop recreating phantom ~/basic-memory on load_config The env-default probe in ConfigManager.load_config instantiates a throwaway BasicMemoryConfig to dump env-derived field values. model_post_init seeds a default 'main' project at ~/basic-memory (when BASIC_MEMORY_HOME is unset), and ensure_project_paths_exists then mkdirs it. That writes to disk against a path the user never selected. Fix: pass skip_initialization_sync=True on the throwaway. Pydantic Settings still reads env vars as field defaults, so env_dict reflects env-derived values. model_post_init and ensure_project_paths_exists both gate on skip_local_initialization and now stay no-ops. Regression test asserts load_config does not recreate ~/basic-memory when a config file already specifies the user's chosen project path. Fixes #1029 Signed-off-by: sanjibani <18418553+sanjibani@users.noreply.github.com> --- src/basic_memory/config.py | 9 +++++-- tests/test_config.py | 52 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 2 deletions(-) diff --git a/src/basic_memory/config.py b/src/basic_memory/config.py index 14f74d8a9..61832c773 100644 --- a/src/basic_memory/config.py +++ b/src/basic_memory/config.py @@ -959,8 +959,13 @@ def load_config(self) -> BasicMemoryConfig: # Then overlay with file data for fields that aren't set via env vars # This ensures env vars take precedence - # Get env-based config fields that are actually set - env_config = BasicMemoryConfig() + # Get env-based config fields that are actually set. + # skip_initialization_sync=True keeps this probe side-effect-free: + # model_post_init won't seed a default project, and + # ensure_project_paths_exists won't mkdir. Pydantic Settings still + # reads env vars as field defaults, so env_dict reflects env-derived + # values without writing to the filesystem. See GH#1029. + env_config = BasicMemoryConfig(skip_initialization_sync=True) env_dict = env_config.model_dump() # Merge: file data as base, but only use it for fields not set by env diff --git a/tests/test_config.py b/tests/test_config.py index b6bc34913..1dbc22412 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -366,6 +366,58 @@ def test_config_file_without_default_project_key(self, config_home, monkeypatch) loaded = config_manager.load_config() assert loaded.default_project == "work" + def test_load_config_does_not_recreate_phantom_home_dir( + self, config_home, monkeypatch, tmp_path + ): + """Regression for GH#1029: load_config must not recreate ~/basic-memory. + + When BASIC_MEMORY_HOME is unset, loading a config that already specifies + a user-chosen project path must not also seed the default ~/basic-memory + directory as a side effect of probing env vars. + """ + import json + import basic_memory.config + + # HOME is set by config_home; phantom lives at $HOME/basic-memory. + monkeypatch.delenv("BASIC_MEMORY_HOME", raising=False) + monkeypatch.delenv("BASIC_MEMORY_CLOUD_MODE", raising=False) + + phantom = Path(os.environ["HOME"]) / "basic-memory" + user_project = config_home / "user" / "vault" + # Force the phantom path to live inside tmp_path so the test never touches + # the real $HOME (the user may have a real ~/basic-memory vault). + # We do this by repointing Path.home() to a fresh tmp dir. + phantom_home = tmp_path / "real_home" + phantom = phantom_home / "basic-memory" + monkeypatch.setattr(Path, "home", classmethod(lambda cls: phantom_home)) + + config_manager = ConfigManager() + config_manager.config_dir = config_home / ".basic-memory" + config_manager.config_file = config_manager.config_dir / "config.json" + config_manager.config_dir.mkdir(parents=True, exist_ok=True) + + config_data = { + "projects": {"main": {"path": str(user_project), "mode": "local"}}, + "default_project": "main", + } + config_manager.config_file.write_text(json.dumps(config_data, indent=2)) + basic_memory.config._CONFIG_CACHE = None + basic_memory.config._CONFIG_MTIME = None + basic_memory.config._CONFIG_SIZE = None + + assert not phantom.exists() + + loaded = config_manager.load_config() + + # User's project is preserved — never replaced by a phantom seed. + assert Path(loaded.projects["main"].path) == user_project + assert loaded.default_project == "main" + # The phantom ~/basic-memory dir must not have been created as a side effect. + assert not phantom.exists(), ( + f"load_config recreated {phantom} as a side effect of probing env vars " + f"(see GH#1029)" + ) + class TestDataDirHelpers: """Module-level helpers that resolve the Basic Memory data directory."""