Compare commits

...

1 Commits

Author SHA1 Message Date
claude[bot] adf5d7049b fix: Prevent 'main' project from being recreated after removal (#397)
Fixed the bug where removing a project (especially 'main') would cause
it to reappear in the project list on the next command execution.

Root cause: model_post_init() was forcing 'main' to exist on every
config load, even after explicit removal.

Changes:
- Updated model_post_init() to only create 'main' if no projects exist
- Fixed default_project handling to use first available project instead
  of always defaulting to 'main'
- Added integration test test_remove_default_project_issue_397() to
  verify the fix and prevent regression

The fix ensures users can remove any project (including 'main') as long
as they have at least one other project configured.

Co-authored-by: Paul Hernandez <phernandez@users.noreply.github.com>
2025-11-10 22:50:30 +00:00
2 changed files with 52 additions and 4 deletions
+5 -4
View File
@@ -192,15 +192,16 @@ class BasicMemoryConfig(BaseSettings):
def model_post_init(self, __context: Any) -> None:
"""Ensure configuration is valid after initialization."""
# Ensure main project exists
if "main" not in self.projects: # pragma: no cover
# Ensure at least one project exists
if not self.projects: # pragma: no cover
self.projects["main"] = (
Path(os.getenv("BASIC_MEMORY_HOME", Path.home() / "basic-memory"))
).as_posix()
# Ensure default project is valid
# Ensure default project is valid (points to an existing project)
if self.default_project not in self.projects: # pragma: no cover
self.default_project = "main"
# Set default to first available project
self.default_project = next(iter(self.projects.keys()))
@property
def app_database_path(self) -> Path:
@@ -119,3 +119,50 @@ def test_project_set_default(app_config, config_manager):
for line in lines:
if "another-project" in line:
assert "[X]" in line
def test_remove_default_project_issue_397(app_config, test_project, config_manager):
"""Test that a removed project does not reappear in project list (issue #397).
Reproduces the bug where removing a project would cause it to be
recreated on the next config load.
"""
runner = CliRunner()
# Use a separate temporary directory to avoid nested path conflicts
with tempfile.TemporaryDirectory() as temp_dir:
new_project_path = Path(temp_dir) / "newmain"
new_project_path.mkdir()
# Step 1: Add a new project
result = runner.invoke(app, ["project", "add", "newmain", str(new_project_path)])
if result.exit_code != 0:
print(f"STDOUT: {result.stdout}")
print(f"STDERR: {result.stderr}")
assert result.exit_code == 0
# Step 2: Set the new project as default
result = runner.invoke(app, ["project", "default", "newmain"])
if result.exit_code != 0:
print(f"STDOUT: {result.stdout}")
print(f"STDERR: {result.stderr}")
assert result.exit_code == 0
# Step 3: Remove the original default project
result = runner.invoke(app, ["project", "remove", "test-project"])
if result.exit_code != 0:
print(f"STDOUT: {result.stdout}")
print(f"STDERR: {result.stderr}")
assert result.exit_code == 0
# Step 4: Verify removed project does NOT appear in list
result = runner.invoke(app, ["project", "list"])
if result.exit_code != 0:
print(f"STDOUT: {result.stdout}")
print(f"STDERR: {result.stderr}")
assert result.exit_code == 0
# The removed project should NOT be in the list
assert "test-project" not in result.stdout
# The new project should be there and marked as default
assert "newmain" in result.stdout