Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions docs/CLI Reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,22 @@ Options:
- `--watch`: Continuously monitor for changes
- `--verbose`: Show detailed output

**Note**:

As of the v0.12.0 release syncing will occur in real time when the mcp process starts.
- 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.

This behavior can be changed via the config. The config file for Basic Memory is in the home directory under `.basic-memory/config.json`.

To change the properties, set the following values:
```
~/.basic-memory/config.json
{
"sync_changes": false,
}
```

Thanks for using Basic Memory!
### import

Imports external knowledge sources:
Expand Down
29 changes: 9 additions & 20 deletions docs/Getting Started with Basic Memory.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,22 +89,11 @@ Replace `/absolute/path/to/uvx` with the actual path you found in Step 1.

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

### 3. Start the Sync Service
### 3. Sync changes in real time

> Note the sync service is optional. You can run it if you want your local change to be available in Claude Desktop

Start the sync service to monitor your files for changes:

```bash
# One-time sync
basic-memory sync

# For continuous monitoring (recommended)
basic-memory sync --watch
```

The `--watch` flag enables automatic detection of file changes, updating your knowledge in real time.
> **Note**: The service will sync changes from your project directory in real time so they available for the AI assistant.

To disable realtime sync, you can update the config. See [[CLI Reference#sync]].
### 4. Staying Updated

To update Basic Memory when new versions are released:
Expand Down Expand Up @@ -145,8 +134,8 @@ If Claude cannot find Basic Memory tools:
1. **Check absolute paths**: Ensure you're using complete absolute paths to uvx in the Claude Desktop configuration
2. **Verify installation**: Run `basic-memory --version` in Terminal to confirm Basic Memory is installed
3. **Restart applications**: Restart both Terminal and Claude Desktop after making configuration changes
4. **Check sync status**: Ensure `basic-memory sync --watch` is running

4. **Check sync status**: You can view the sync status by running `basic-memory status
.
#### Permission Issues

If you encounter permission errors:
Expand Down Expand Up @@ -282,15 +271,15 @@ basic-memory import claude conversations
basic-memory import chatgpt
```

After importing, run `basic-memory sync` to index everything.
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`.

## Quick Tips

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

## Next Steps
Expand Down
14 changes: 13 additions & 1 deletion docs/Knowledge Format.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,19 @@ permalink: auth-approaches-2024
---
```

If not specified, one will be generated automatically from the title.
If not specified, one will be generated automatically from the title, if the note has has a frontmatter section.

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.

The config file for Basic Memory is in the home directory under `.basic-memory/config.json`.

To change the behavior, set the following value:
```
~/.basic-memory/config.json
{
"update_permalinks_on_move": true
}
```

### Using memory:// URLs

Expand Down
37 changes: 3 additions & 34 deletions src/basic_memory/api/app.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
"""FastAPI application for basic-memory knowledge graph API."""

import asyncio
from contextlib import asynccontextmanager

from fastapi import FastAPI, HTTPException
Expand All @@ -10,44 +9,14 @@
from basic_memory import db
from basic_memory.api.routers import knowledge, memory, project_info, resource, search
from basic_memory.config import config as project_config
from basic_memory.config import config_manager
from basic_memory.sync import SyncService, WatchService


async def run_background_sync(sync_service: SyncService, watch_service: WatchService): # pragma: no cover
logger.info(f"Starting watch service to sync file changes in dir: {project_config.home}")
# full sync
await sync_service.sync(project_config.home, show_progress=False)

# watch changes
await watch_service.run()
from basic_memory.services.initialization import initialize_app


@asynccontextmanager
async def lifespan(app: FastAPI): # pragma: no cover
"""Lifecycle manager for the FastAPI app."""
await db.run_migrations(project_config)

# app config
basic_memory_config = config_manager.load_config()
logger.info(f"Sync changes enabled: {basic_memory_config.sync_changes}")
logger.info(f"Update permalinks on move enabled: {basic_memory_config.update_permalinks_on_move}")

watch_task = None
if basic_memory_config.sync_changes:
# import after migrations have run
from basic_memory.cli.commands.sync import get_sync_service

sync_service = await get_sync_service()
watch_service = WatchService(
sync_service=sync_service,
file_service=sync_service.entity_service.file_service,
config=project_config,
)
watch_task = asyncio.create_task(run_background_sync(sync_service, watch_service))
else:
logger.info("Sync changes disabled. Skipping watch service.")

# Initialize database and file sync services
watch_task = await initialize_app(project_config)

# proceed with startup
yield
Expand Down
14 changes: 13 additions & 1 deletion src/basic_memory/cli/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@ def version_callback(value: bool) -> None:
"""Show version and exit."""
if value: # pragma: no cover
import basic_memory
from basic_memory.config import config

typer.echo(f"Basic Memory version: {basic_memory.__version__}")
typer.echo(f"Current project: {config.project}")
typer.echo(f"Project path: {config.home}")
raise typer.Exit()


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

@app.callback()
def app_callback(
ctx: typer.Context,
project: Optional[str] = typer.Option(
None,
"--project",
"-p",
help="Specify which project to use",
help="Specify which project to use 1",
envvar="BASIC_MEMORY_PROJECT",
),
version: Optional[bool] = typer.Option(
Expand All @@ -34,6 +38,7 @@ def app_callback(
),
) -> None:
"""Basic Memory - Local-first personal knowledge management."""

# We use the project option to set the BASIC_MEMORY_PROJECT environment variable
# The config module will pick this up when loading
if project: # pragma: no cover
Expand All @@ -53,6 +58,13 @@ def app_callback(

config = new_config

# Run migrations for every command unless --version was specified
if not version and ctx.invoked_subcommand is not None:
from basic_memory.config import config
from basic_memory.services.initialization import ensure_initialize_database

ensure_initialize_database(config)


# Register sub-command groups
import_app = typer.Typer(help="Import data from various sources")
Expand Down
30 changes: 16 additions & 14 deletions src/basic_memory/cli/commands/mcp.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
"""MCP server command."""

from loguru import logger

import basic_memory
from basic_memory.cli.app import app
from basic_memory.config import config, config_manager

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

@app.command()
def mcp(): # pragma: no cover
"""Run the MCP server for Claude Desktop integration."""
home_dir = config.home
project_name = config.project
"""Run the MCP server"""
from basic_memory.config import config
import asyncio
from basic_memory.services.initialization import initialize_database

# First, run just the database migrations synchronously
asyncio.run(initialize_database(config))

# Load config to check if sync is enabled
from basic_memory.config import config_manager

# app config
basic_memory_config = config_manager.load_config()

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

logger.info("File sync will be handled by the MCP server")

# Start the MCP server
mcp_server.run()
16 changes: 8 additions & 8 deletions src/basic_memory/cli/commands/sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,14 +179,14 @@ async def run_sync(verbose: bool = False, watch: bool = False, console_status: b
)

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

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

# Log results
duration_ms = int((time.time() - start_time) * 1000)
Expand Down Expand Up @@ -237,11 +237,11 @@ def sync(
if not isinstance(e, typer.Exit):
logger.exception(
"Sync command failed",
project=config.project,
error=str(e),
error_type=type(e).__name__,
watch_mode=watch,
directory=str(config.home),
f"project={config.project},"
f"error={str(e)},"
f"error_type={type(e).__name__},"
f"watch_mode={watch},"
f"directory={str(config.home)}",
)
typer.echo(f"Error during sync: {e}", err=True)
raise typer.Exit(1)
Expand Down
47 changes: 3 additions & 44 deletions src/basic_memory/cli/main.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
"""Main CLI entry point for basic-memory.""" # pragma: no cover

import asyncio

import typer

from basic_memory.cli.app import app # pragma: no cover

# Register commands
Expand All @@ -20,48 +16,11 @@
tool,
)
from basic_memory.config import config
from basic_memory.db import run_migrations as db_run_migrations


# Version command
@app.callback(invoke_without_command=True)
def main(
ctx: typer.Context,
project: str = typer.Option( # noqa
"main",
"--project",
"-p",
help="Specify which project to use",
envvar="BASIC_MEMORY_PROJECT",
),
version: bool = typer.Option(
False,
"--version",
"-V",
help="Show version information and exit.",
is_eager=True,
),
):
"""Basic Memory - Local-first personal knowledge management system."""
if version: # pragma: no cover
from basic_memory import __version__
from basic_memory.config import config

typer.echo(f"Basic Memory v{__version__}")
typer.echo(f"Current project: {config.project}")
typer.echo(f"Project path: {config.home}")
raise typer.Exit()

# Handle project selection via environment variable
if project:
import os

os.environ["BASIC_MEMORY_PROJECT"] = project

from basic_memory.services.initialization import ensure_initialization

if __name__ == "__main__": # pragma: no cover
# Run database migrations
asyncio.run(db_run_migrations(config))
# Run initialization if we are starting as a module
ensure_initialization(config)

# start the app
app()
4 changes: 2 additions & 2 deletions src/basic_memory/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class ProjectConfig(BaseSettings):

# Watch service configuration
sync_delay: int = Field(
default=500, description="Milliseconds to wait after changes before syncing", gt=0
default=1000, description="Milliseconds to wait after changes before syncing", gt=0
)

# update permalinks on move
Expand Down Expand Up @@ -274,7 +274,7 @@ def setup_basic_memory_logging(): # pragma: no cover
console=False,
)

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


Expand Down
Loading
Loading