Skip to content

Commit 195229f

Browse files
phernandezclaude
andcommitted
fix: resolve default_project returning null in cloud mode (#644)
In cloud mode, ConfigManager has no local config file so default_project always returned None. Add async get_default_project_name() on ProjectService that falls back to the database is_default flag when ConfigManager returns None. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: phernandez <paul@basicmachines.co>
1 parent d15f6a8 commit 195229f

3 files changed

Lines changed: 34 additions & 3 deletions

File tree

src/basic_memory/api/v2/routers/project_router.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ async def list_projects(
4848
A list of all projects with metadata
4949
"""
5050
projects = await project_service.list_projects()
51-
default_project = project_service.default_project
51+
default_project = await project_service.get_default_project_name()
5252

5353
project_items = [
5454
ProjectItem(

src/basic_memory/services/project_service.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,21 @@ def default_project(self) -> Optional[str]:
8282
"""
8383
return self.config_manager.default_project
8484

85+
async def get_default_project_name(self) -> str:
86+
"""Get the default project name, falling back to the database.
87+
88+
ConfigManager reads from the local config file, which doesn't exist
89+
in cloud mode. When it returns None, fall back to the is_default
90+
flag stored in the database.
91+
"""
92+
default = self.config_manager.default_project
93+
if default is not None:
94+
return default
95+
db_default = await self.repository.get_default_project()
96+
if db_default is not None:
97+
return db_default.name
98+
raise ValueError("No default project configured")
99+
85100
@property
86101
def current_project(self) -> Optional[str]:
87102
"""Get the name of the currently active project.

tests/api/v2/test_project_router.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,21 @@
1111
from basic_memory.schemas.v2 import ProjectResolveResponse
1212

1313

14+
@pytest.mark.asyncio
15+
async def test_list_projects(client: AsyncClient, test_project: Project, v2_projects_url):
16+
"""Test listing projects returns default_project from the database."""
17+
response = await client.get(f"{v2_projects_url}/")
18+
19+
assert response.status_code == 200
20+
data = response.json()
21+
22+
# default_project must be populated from the is_default flag in the database
23+
assert data["default_project"] == test_project.name
24+
25+
project_names = [p["name"] for p in data["projects"]]
26+
assert test_project.name in project_names
27+
28+
1429
@pytest.mark.asyncio
1530
async def test_get_project_by_id(client: AsyncClient, test_project: Project, v2_projects_url):
1631
"""Test getting a project by its external_id UUID."""
@@ -361,9 +376,10 @@ async def test_legacy_v1_list_projects_endpoint(client: AsyncClient, test_projec
361376
assert response.status_code == 200
362377
data = response.json()
363378
assert "projects" in data
364-
assert "default_project" in data
365379

366-
# Verify the test project is in the list
380+
# default_project must be populated, not null
381+
assert data["default_project"] == test_project.name
382+
367383
project_names = [p["name"] for p in data["projects"]]
368384
assert test_project.name in project_names
369385

0 commit comments

Comments
 (0)