Skip to content

Commit 70bb10b

Browse files
authored
fix: respect --project flag in background sync (fixes #434) (#436)
Signed-off-by: Cedric Hurst <cedric@spantree.net>
1 parent fbf9045 commit 70bb10b

2 files changed

Lines changed: 75 additions & 0 deletions

File tree

src/basic_memory/services/initialization.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"""
66

77
import asyncio
8+
import os
89
from pathlib import Path
910

1011
import logfire
@@ -108,6 +109,12 @@ async def initialize_file_sync(
108109
# Get active projects
109110
active_projects = await project_repository.get_active_projects()
110111

112+
# Filter to constrained project if MCP server was started with --project
113+
constrained_project = os.environ.get("BASIC_MEMORY_MCP_PROJECT")
114+
if constrained_project:
115+
active_projects = [p for p in active_projects if p.name == constrained_project]
116+
logger.info(f"Background sync constrained to project: {constrained_project}")
117+
111118
# Start sync for all projects as background tasks (non-blocking)
112119
async def sync_project_background(project: Project):
113120
"""Sync a single project in the background."""

tests/services/test_initialization.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,3 +178,71 @@ async def test_initialize_file_sync_background_tasks(
178178

179179
# Watch service should still be started
180180
mock_watch_service.run.assert_called_once()
181+
182+
183+
@pytest.mark.asyncio
184+
@patch("basic_memory.services.initialization.db.get_or_create_db")
185+
@patch("basic_memory.cli.commands.sync.get_sync_service")
186+
@patch("basic_memory.sync.WatchService")
187+
@patch("basic_memory.services.initialization.asyncio.create_task")
188+
@patch.dict("os.environ", {"BASIC_MEMORY_MCP_PROJECT": "project1"})
189+
async def test_initialize_file_sync_respects_project_constraint(
190+
mock_create_task, mock_watch_service_class, mock_get_sync_service, mock_get_db, app_config
191+
):
192+
"""Test that file sync only syncs the constrained project when BASIC_MEMORY_MCP_PROJECT is set."""
193+
# Setup mocks
194+
mock_session_maker = AsyncMock()
195+
mock_get_db.return_value = (None, mock_session_maker)
196+
197+
mock_watch_service = AsyncMock()
198+
mock_watch_service.run = AsyncMock()
199+
mock_watch_service_class.return_value = mock_watch_service
200+
201+
mock_repository = AsyncMock()
202+
mock_project1 = MagicMock()
203+
mock_project1.name = "project1"
204+
mock_project1.path = "/path/to/project1"
205+
mock_project1.id = 1
206+
207+
mock_project2 = MagicMock()
208+
mock_project2.name = "project2"
209+
mock_project2.path = "/path/to/project2"
210+
mock_project2.id = 2
211+
212+
mock_project3 = MagicMock()
213+
mock_project3.name = "project3"
214+
mock_project3.path = "/path/to/project3"
215+
mock_project3.id = 3
216+
217+
mock_sync_service = AsyncMock()
218+
mock_sync_service.sync = AsyncMock()
219+
mock_get_sync_service.return_value = mock_sync_service
220+
221+
# Mock background tasks
222+
mock_task = MagicMock()
223+
mock_create_task.return_value = mock_task
224+
225+
# Mock the repository
226+
with patch("basic_memory.services.initialization.ProjectRepository") as mock_repo_class:
227+
mock_repo_class.return_value = mock_repository
228+
# Return all 3 projects from get_active_projects
229+
mock_repository.get_active_projects.return_value = [
230+
mock_project1,
231+
mock_project2,
232+
mock_project3,
233+
]
234+
235+
# Run the function
236+
result = await initialize_file_sync(app_config)
237+
238+
# Assertions
239+
mock_repository.get_active_projects.assert_called_once()
240+
241+
# Should only create 1 background task for project1 (the constrained project)
242+
assert mock_create_task.call_count == 1
243+
244+
# Verify the function returns None
245+
assert result is None
246+
247+
# Watch service should still be started
248+
mock_watch_service.run.assert_called_once()

0 commit comments

Comments
 (0)