Skip to content

Commit 78a3412

Browse files
authored
fix: run migrations and sync when starting mcp (#88)
1 parent fa314b5 commit 78a3412

24 files changed

+508
-394
lines changed

docs/CLI Reference.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,22 @@ Options:
2929
- `--watch`: Continuously monitor for changes
3030
- `--verbose`: Show detailed output
3131

32+
**Note**:
33+
34+
As of the v0.12.0 release syncing will occur in real time when the mcp process starts.
35+
- The real time sync means that it is no longer necessary to run the `basic-memory sync --watch` process in a a terminal to sync changes to the db (so the AI can see them). This will be done automatically.
36+
37+
This behavior can be changed via the config. The config file for Basic Memory is in the home directory under `.basic-memory/config.json`.
38+
39+
To change the properties, set the following values:
40+
```
41+
~/.basic-memory/config.json
42+
{
43+
"sync_changes": false,
44+
}
45+
```
46+
47+
Thanks for using Basic Memory!
3248
### import
3349

3450
Imports external knowledge sources:

docs/Getting Started with Basic Memory.md

Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -89,22 +89,11 @@ Replace `/absolute/path/to/uvx` with the actual path you found in Step 1.
8989

9090
Close and reopen Claude Desktop for the changes to take effect.
9191

92-
### 3. Start the Sync Service
92+
### 3. Sync changes in real time
9393

94-
> Note the sync service is optional. You can run it if you want your local change to be available in Claude Desktop
95-
96-
Start the sync service to monitor your files for changes:
97-
98-
```bash
99-
# One-time sync
100-
basic-memory sync
101-
102-
# For continuous monitoring (recommended)
103-
basic-memory sync --watch
104-
```
105-
106-
The `--watch` flag enables automatic detection of file changes, updating your knowledge in real time.
94+
> **Note**: The service will sync changes from your project directory in real time so they available for the AI assistant.
10795
96+
To disable realtime sync, you can update the config. See [[CLI Reference#sync]].
10897
### 4. Staying Updated
10998

11099
To update Basic Memory when new versions are released:
@@ -145,8 +134,8 @@ If Claude cannot find Basic Memory tools:
145134
1. **Check absolute paths**: Ensure you're using complete absolute paths to uvx in the Claude Desktop configuration
146135
2. **Verify installation**: Run `basic-memory --version` in Terminal to confirm Basic Memory is installed
147136
3. **Restart applications**: Restart both Terminal and Claude Desktop after making configuration changes
148-
4. **Check sync status**: Ensure `basic-memory sync --watch` is running
149-
137+
4. **Check sync status**: You can view the sync status by running `basic-memory status
138+
.
150139
#### Permission Issues
151140

152141
If you encounter permission errors:
@@ -282,15 +271,15 @@ basic-memory import claude conversations
282271
basic-memory import chatgpt
283272
```
284273

285-
After importing, run `basic-memory sync` to index everything.
274+
After importing, the changes will be synced. Initial syncs may take a few moments. You can see info about your project by running `basic-memrory project info`.
286275

287276
## Quick Tips
288277

289-
- Keep `basic-memory sync --watch` running in a terminal window
278+
- Basic Memory will sync changes from your project in real time.
290279
- Use special prompts (Continue Conversation, Recent Activity, Search) to start contextual discussions
291280
- Build connections between notes for a richer knowledge graph
292-
- Use direct memory:// URLs when you need precise context
293-
- Use git to version control your knowledge base
281+
- Use direct `memory://` URLs with a permalink when you need precise context. See [[User Guide#Using memory // URLs]]
282+
- Use git to version control your knowledge base (git integration is on the roadmap)
294283
- Review and edit AI-generated notes for accuracy
295284

296285
## Next Steps

docs/Knowledge Format.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,19 @@ permalink: auth-approaches-2024
144144
---
145145
```
146146

147-
If not specified, one will be generated automatically from the title.
147+
If not specified, one will be generated automatically from the title, if the note has has a frontmatter section.
148+
149+
By default a notes' permalink value will not change if the file is moved. It's a **stable** identifier :). But if you'd rather permalinks are always updated when a file moves, you can set the config setting in the global config.
150+
151+
The config file for Basic Memory is in the home directory under `.basic-memory/config.json`.
152+
153+
To change the behavior, set the following value:
154+
```
155+
~/.basic-memory/config.json
156+
{
157+
"update_permalinks_on_move": true
158+
}
159+
```
148160

149161
### Using memory:// URLs
150162

src/basic_memory/api/app.py

Lines changed: 3 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
"""FastAPI application for basic-memory knowledge graph API."""
22

3-
import asyncio
43
from contextlib import asynccontextmanager
54

65
from fastapi import FastAPI, HTTPException
@@ -10,44 +9,14 @@
109
from basic_memory import db
1110
from basic_memory.api.routers import knowledge, memory, project_info, resource, search
1211
from basic_memory.config import config as project_config
13-
from basic_memory.config import config_manager
14-
from basic_memory.sync import SyncService, WatchService
15-
16-
17-
async def run_background_sync(sync_service: SyncService, watch_service: WatchService): # pragma: no cover
18-
logger.info(f"Starting watch service to sync file changes in dir: {project_config.home}")
19-
# full sync
20-
await sync_service.sync(project_config.home, show_progress=False)
21-
22-
# watch changes
23-
await watch_service.run()
12+
from basic_memory.services.initialization import initialize_app
2413

2514

2615
@asynccontextmanager
2716
async def lifespan(app: FastAPI): # pragma: no cover
2817
"""Lifecycle manager for the FastAPI app."""
29-
await db.run_migrations(project_config)
30-
31-
# app config
32-
basic_memory_config = config_manager.load_config()
33-
logger.info(f"Sync changes enabled: {basic_memory_config.sync_changes}")
34-
logger.info(f"Update permalinks on move enabled: {basic_memory_config.update_permalinks_on_move}")
35-
36-
watch_task = None
37-
if basic_memory_config.sync_changes:
38-
# import after migrations have run
39-
from basic_memory.cli.commands.sync import get_sync_service
40-
41-
sync_service = await get_sync_service()
42-
watch_service = WatchService(
43-
sync_service=sync_service,
44-
file_service=sync_service.entity_service.file_service,
45-
config=project_config,
46-
)
47-
watch_task = asyncio.create_task(run_background_sync(sync_service, watch_service))
48-
else:
49-
logger.info("Sync changes disabled. Skipping watch service.")
50-
18+
# Initialize database and file sync services
19+
watch_task = await initialize_app(project_config)
5120

5221
# proceed with startup
5322
yield

src/basic_memory/cli/app.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,11 @@ def version_callback(value: bool) -> None:
77
"""Show version and exit."""
88
if value: # pragma: no cover
99
import basic_memory
10+
from basic_memory.config import config
1011

1112
typer.echo(f"Basic Memory version: {basic_memory.__version__}")
13+
typer.echo(f"Current project: {config.project}")
14+
typer.echo(f"Project path: {config.home}")
1215
raise typer.Exit()
1316

1417

@@ -17,11 +20,12 @@ def version_callback(value: bool) -> None:
1720

1821
@app.callback()
1922
def app_callback(
23+
ctx: typer.Context,
2024
project: Optional[str] = typer.Option(
2125
None,
2226
"--project",
2327
"-p",
24-
help="Specify which project to use",
28+
help="Specify which project to use 1",
2529
envvar="BASIC_MEMORY_PROJECT",
2630
),
2731
version: Optional[bool] = typer.Option(
@@ -34,6 +38,7 @@ def app_callback(
3438
),
3539
) -> None:
3640
"""Basic Memory - Local-first personal knowledge management."""
41+
3742
# We use the project option to set the BASIC_MEMORY_PROJECT environment variable
3843
# The config module will pick this up when loading
3944
if project: # pragma: no cover
@@ -53,6 +58,13 @@ def app_callback(
5358

5459
config = new_config
5560

61+
# Run migrations for every command unless --version was specified
62+
if not version and ctx.invoked_subcommand is not None:
63+
from basic_memory.config import config
64+
from basic_memory.services.initialization import ensure_initialize_database
65+
66+
ensure_initialize_database(config)
67+
5668

5769
# Register sub-command groups
5870
import_app = typer.Typer(help="Import data from various sources")
Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
"""MCP server command."""
22

3-
from loguru import logger
4-
53
import basic_memory
64
from basic_memory.cli.app import app
7-
from basic_memory.config import config, config_manager
85

96
# Import mcp instance
107
from basic_memory.mcp.server import mcp as mcp_server # pragma: no cover
@@ -15,19 +12,24 @@
1512

1613
@app.command()
1714
def mcp(): # pragma: no cover
18-
"""Run the MCP server for Claude Desktop integration."""
19-
home_dir = config.home
20-
project_name = config.project
15+
"""Run the MCP server"""
16+
from basic_memory.config import config
17+
import asyncio
18+
from basic_memory.services.initialization import initialize_database
19+
20+
# First, run just the database migrations synchronously
21+
asyncio.run(initialize_database(config))
22+
23+
# Load config to check if sync is enabled
24+
from basic_memory.config import config_manager
2125

22-
# app config
2326
basic_memory_config = config_manager.load_config()
2427

25-
logger.info(f"Starting Basic Memory MCP server {basic_memory.__version__}")
26-
logger.info(f"Project: {project_name}")
27-
logger.info(f"Project directory: {home_dir}")
28-
logger.info(f"Sync changes enabled: {basic_memory_config.sync_changes}")
29-
logger.info(
30-
f"Update permalinks on move enabled: {basic_memory_config.update_permalinks_on_move}"
31-
)
28+
if basic_memory_config.sync_changes:
29+
# For now, we'll just log that sync will be handled by the MCP server
30+
from loguru import logger
31+
32+
logger.info("File sync will be handled by the MCP server")
3233

34+
# Start the MCP server
3335
mcp_server.run()

src/basic_memory/cli/commands/sync.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -179,14 +179,14 @@ async def run_sync(verbose: bool = False, watch: bool = False, console_status: b
179179
)
180180

181181
# full sync - no progress bars in watch mode
182-
await sync_service.sync(config.home, show_progress=False)
182+
await sync_service.sync(config.home)
183183

184184
# watch changes
185185
await watch_service.run() # pragma: no cover
186186
else:
187-
# one time sync - use progress bars for better UX
187+
# one time sync
188188
logger.info("Running one-time sync")
189-
knowledge_changes = await sync_service.sync(config.home, show_progress=True)
189+
knowledge_changes = await sync_service.sync(config.home)
190190

191191
# Log results
192192
duration_ms = int((time.time() - start_time) * 1000)
@@ -237,11 +237,11 @@ def sync(
237237
if not isinstance(e, typer.Exit):
238238
logger.exception(
239239
"Sync command failed",
240-
project=config.project,
241-
error=str(e),
242-
error_type=type(e).__name__,
243-
watch_mode=watch,
244-
directory=str(config.home),
240+
f"project={config.project},"
241+
f"error={str(e)},"
242+
f"error_type={type(e).__name__},"
243+
f"watch_mode={watch},"
244+
f"directory={str(config.home)}",
245245
)
246246
typer.echo(f"Error during sync: {e}", err=True)
247247
raise typer.Exit(1)

src/basic_memory/cli/main.py

Lines changed: 3 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
"""Main CLI entry point for basic-memory.""" # pragma: no cover
22

3-
import asyncio
4-
5-
import typer
6-
73
from basic_memory.cli.app import app # pragma: no cover
84

95
# Register commands
@@ -20,48 +16,11 @@
2016
tool,
2117
)
2218
from basic_memory.config import config
23-
from basic_memory.db import run_migrations as db_run_migrations
24-
25-
26-
# Version command
27-
@app.callback(invoke_without_command=True)
28-
def main(
29-
ctx: typer.Context,
30-
project: str = typer.Option( # noqa
31-
"main",
32-
"--project",
33-
"-p",
34-
help="Specify which project to use",
35-
envvar="BASIC_MEMORY_PROJECT",
36-
),
37-
version: bool = typer.Option(
38-
False,
39-
"--version",
40-
"-V",
41-
help="Show version information and exit.",
42-
is_eager=True,
43-
),
44-
):
45-
"""Basic Memory - Local-first personal knowledge management system."""
46-
if version: # pragma: no cover
47-
from basic_memory import __version__
48-
from basic_memory.config import config
49-
50-
typer.echo(f"Basic Memory v{__version__}")
51-
typer.echo(f"Current project: {config.project}")
52-
typer.echo(f"Project path: {config.home}")
53-
raise typer.Exit()
54-
55-
# Handle project selection via environment variable
56-
if project:
57-
import os
58-
59-
os.environ["BASIC_MEMORY_PROJECT"] = project
60-
19+
from basic_memory.services.initialization import ensure_initialization
6120

6221
if __name__ == "__main__": # pragma: no cover
63-
# Run database migrations
64-
asyncio.run(db_run_migrations(config))
22+
# Run initialization if we are starting as a module
23+
ensure_initialization(config)
6524

6625
# start the app
6726
app()

src/basic_memory/config.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ class ProjectConfig(BaseSettings):
3535

3636
# Watch service configuration
3737
sync_delay: int = Field(
38-
default=500, description="Milliseconds to wait after changes before syncing", gt=0
38+
default=1000, description="Milliseconds to wait after changes before syncing", gt=0
3939
)
4040

4141
# update permalinks on move
@@ -274,7 +274,7 @@ def setup_basic_memory_logging(): # pragma: no cover
274274
console=False,
275275
)
276276

277-
logger.info(f"Starting Basic Memory {basic_memory.__version__} (Project: {config.project})")
277+
logger.info(f"Basic Memory {basic_memory.__version__} (Project: {config.project})")
278278
_LOGGING_SETUP = True
279279

280280

0 commit comments

Comments
 (0)