From 41d12cba95c9c4c633766e64fc95d097e3e5ff4e Mon Sep 17 00:00:00 2001 From: Drew Cain Date: Tue, 26 May 2026 13:10:21 -0500 Subject: [PATCH] docs(cli): document personal workspace sync Signed-off-by: Drew Cain --- docs/cloud-cli.md | 112 ++++++++++-------- .../cli/commands/cloud/project_sync.py | 25 +++- tests/cli/cloud/test_project_sync_command.py | 15 +++ 3 files changed, 95 insertions(+), 57 deletions(-) diff --git a/docs/cloud-cli.md b/docs/cloud-cli.md index 0314ed2c5..52c0b637f 100644 --- a/docs/cloud-cli.md +++ b/docs/cloud-cli.md @@ -1,6 +1,6 @@ # Basic Memory Cloud CLI Guide -The Basic Memory Cloud CLI provides seamless integration between local and cloud knowledge bases using **project-scoped synchronization**. Each project can optionally sync with the cloud, giving you fine-grained control over what syncs and where. +The Basic Memory Cloud CLI provides seamless integration between local and cloud knowledge bases using **project-scoped synchronization**. Personal workspaces can optionally use local rclone mirrors, giving you fine-grained control over what syncs and where. ## Overview @@ -8,9 +8,13 @@ The cloud CLI enables you to: - **Authenticate cloud access** - OAuth/API key credentials are stored locally for cloud operations - **Project-scoped sync** - Each project independently manages its sync configuration - **Explicit operations** - Sync only what you want, when you want -- **Bidirectional sync** - Keep local and cloud in sync with rclone bisync +- **Bidirectional sync** - Keep Personal workspace local mirrors and cloud in sync with rclone bisync - **Offline access** - Work locally, sync when ready +Team workspaces are accessed through the cloud API/MCP and do not support local +multi-user rclone sync/bisync. Use `bm project list --workspace ` to +inspect Team projects. + ## Prerequisites Before using Basic Memory Cloud, you need: @@ -39,7 +43,7 @@ If you attempt to log in without an active subscription, you'll receive a "Subsc **Projects can exist in three states:** 1. **Cloud-only** - Project exists on cloud, no local copy -2. **Cloud + Local (synced)** - Project has a local working directory that syncs +2. **Cloud + Local (synced)** - Personal workspace project has a local working directory that syncs 3. **Local-only** - Project exists locally and is not routed to cloud **Example:** @@ -55,8 +59,8 @@ bm project add work --cloud --local-path ~/work-notes bm project add temp --cloud # No local sync # Now you can sync individually (after initial --resync): -bm project bisync --name research -bm project bisync --name work +bm cloud bisync --name research +bm cloud bisync --name work # temp stays cloud-only ``` @@ -87,7 +91,7 @@ Apply OSS discount code `{{OSS_DISCOUNT_CODE}}` during checkout to receive 20% o ### 2. Set Up Sync -Install rclone and configure credentials: +Install rclone and configure Personal workspace sync credentials: ```bash bm cloud setup @@ -99,7 +103,7 @@ bm cloud setup 3. Generates scoped S3 credentials for sync 4. Configures single rclone remote: `basic-memory-cloud` -**Result:** You're ready to sync projects. No sync directories created yet - those come with project setup. +**Result:** You're ready to sync Personal workspace projects. No sync directories created yet - those come with project setup. Rclone setup uses package managers such as Homebrew, MacPorts, apt, dnf, yum, pacman, zypper, snap, winget, Chocolatey, or Scoop when available. It does not run remote @@ -108,7 +112,7 @@ manual install instructions. ### 3. Add Projects with Sync -Create projects with optional local sync paths: +Create Personal workspace projects with optional local sync paths: ```bash # Create cloud project without local sync @@ -137,10 +141,10 @@ Establish the initial sync baseline. **Best practice:** Always preview with `--d ```bash # Step 1: Preview the initial sync (recommended) -bm project bisync --name research --resync --dry-run +bm cloud bisync --name research --resync --dry-run # Step 2: If all looks good, run the actual sync -bm project bisync --name research --resync +bm cloud bisync --name research --resync ``` **What happens under the covers:** @@ -167,7 +171,7 @@ This will effectively make both Path1 and Path2 filesystems contain a matching s After the first sync, just run bisync without `--resync`: ```bash -bm project bisync --name research +bm cloud bisync --name research ``` **What happens:** @@ -235,7 +239,7 @@ bm project add research --cloud --local-path ~/Documents/research - Stores sync config in `~/.basic-memory/config.json` - Prepares for bisync (but doesn't sync yet) -**Result:** Project ready to sync. Run `bm project bisync --name research --resync` to establish baseline. +**Result:** Project ready to sync. Run `bm cloud bisync --name research --resync` to establish baseline. **Use case 3: Add sync to existing cloud project** @@ -292,20 +296,24 @@ For MCP stdio, routing is always local. ## File Synchronization +Local rclone sync/bisync is supported only for Personal workspaces. Team +workspaces are cloud-only for local CLI usage; access them through cloud API/MCP +routing instead of a local multi-user rclone mirror. + ### Understanding the Sync Commands **There are three sync-related commands:** -1. `bm project sync` - One-way: local → cloud (make cloud match local) -2. `bm project bisync` - Two-way: local ↔ cloud (recommended) -3. `bm project check` - Verify files match (no changes) +1. `bm cloud sync` - One-way: local → cloud (make cloud match local) +2. `bm cloud bisync` - Two-way: local ↔ cloud (recommended) +3. `bm cloud check` - Verify files match (no changes) ### One-Way Sync: Local → Cloud **Use case:** You made changes locally and want to push to cloud (overwrite cloud). ```bash -bm project sync --name research +bm cloud sync --name research ``` **What happens:** @@ -327,10 +335,10 @@ bm project sync --name research ```bash # First time - establish baseline -bm project bisync --name research --resync +bm cloud bisync --name research --resync # Subsequent syncs -bm project bisync --name research +bm cloud bisync --name research ``` **What happens:** @@ -349,7 +357,7 @@ echo "Local change" > ~/Documents/research/notes.md # Cloud now has: "Cloud change" # Run bisync -bm project bisync --name research +bm cloud bisync --name research # Result: Newer file wins (based on modification time) # If cloud was more recent, cloud version kept @@ -366,7 +374,7 @@ bm project bisync --name research **Use case:** Check if local and cloud match without making changes. ```bash -bm project check --name research +bm cloud check --name research ``` **What happens:** @@ -378,7 +386,7 @@ bm project check --name research ```bash # One-way check (faster) -bm project check --name research --one-way +bm cloud check --name research --one-way ``` ### Preview Changes (Dry Run) @@ -386,7 +394,7 @@ bm project check --name research --one-way **Use case:** See what would change without actually syncing. ```bash -bm project bisync --name research --dry-run +bm cloud bisync --name research --dry-run ``` **What happens:** @@ -432,20 +440,20 @@ bm project add work --cloud --local-path ~/work-notes bm project add personal --cloud --local-path ~/personal # Establish baselines -bm project bisync --name research --resync -bm project bisync --name work --resync -bm project bisync --name personal --resync +bm cloud bisync --name research --resync +bm cloud bisync --name work --resync +bm cloud bisync --name personal --resync # Daily workflow: sync everything -bm project bisync --name research -bm project bisync --name work -bm project bisync --name personal +bm cloud bisync --name research +bm cloud bisync --name work +bm cloud bisync --name personal ``` **Future:** `--all` flag will sync all configured projects: ```bash -bm project bisync --all # Coming soon +bm cloud bisync --all # Coming soon ``` ### Mixed Usage @@ -462,8 +470,8 @@ bm project add archive --cloud bm project add temp-notes --cloud # Sync only the configured ones -bm project bisync --name research -bm project bisync --name work +bm cloud bisync --name research +bm cloud bisync --name work # Archive and temp-notes stay cloud-only ``` @@ -661,7 +669,7 @@ code ~/.basic-memory/.bmignore echo "*.tmp" >> ~/.basic-memory/.bmignore # Next sync uses updated patterns -bm project bisync --name research +bm cloud bisync --name research ``` ## Troubleshooting @@ -724,7 +732,7 @@ bm cloud login **Solution:** ```bash -bm project bisync --name research --resync +bm cloud bisync --name research --resync ``` **What this does:** @@ -747,7 +755,7 @@ bm project bisync --name research --resync echo "# Research Notes" > ~/Documents/research/README.md # Now run bisync -bm project bisync --name research --resync +bm cloud bisync --name research --resync ``` **Why this happens:** Bisync creates listing files that track the state of each side. When both directories are completely empty, these listing files are considered invalid by rclone. @@ -764,10 +772,10 @@ bm project bisync --name research --resync ```bash # Clear bisync state -bm project bisync-reset research +bm cloud bisync-reset research # Re-establish baseline -bm project bisync --name research --resync +bm cloud bisync --name research --resync ``` **What this does:** @@ -787,16 +795,16 @@ bm project bisync --name research --resync ```bash # Check what would be deleted -bm project bisync --name research --dry-run +bm cloud bisync --name research --dry-run # If correct, establish new baseline -bm project bisync --name research --resync +bm cloud bisync --name research --resync ``` **Solution 2:** Use one-way sync if you know local is correct: ```bash -bm project sync --name research +bm cloud sync --name research ``` ### Project Not Configured for Sync @@ -809,7 +817,7 @@ bm project sync --name research ```bash bm cloud sync-setup research ~/Documents/research -bm project bisync --name research --resync +bm cloud bisync --name research --resync ``` ### Connection Issues @@ -881,19 +889,19 @@ bm project set-local # Revert project to local mode ```bash # One-way sync (local → cloud) -bm project sync --name -bm project sync --name --dry-run -bm project sync --name --verbose +bm cloud sync --name +bm cloud sync --name --dry-run +bm cloud sync --name --verbose # Two-way sync (local ↔ cloud) - Recommended -bm project bisync --name # After first --resync -bm project bisync --name --resync # First time / force baseline -bm project bisync --name --dry-run -bm project bisync --name --verbose +bm cloud bisync --name # After first --resync +bm cloud bisync --name --resync # First time / force baseline +bm cloud bisync --name --dry-run +bm cloud bisync --name --verbose # Integrity check -bm project check --name -bm project check --name --one-way +bm cloud check --name +bm cloud check --name --one-way # List project files by route bm project ls --name # Default target: local @@ -909,9 +917,9 @@ bm project ls --name --cloud --path 1. **Authenticate cloud access** - `bm cloud login` 2. **Install rclone** - `bm cloud setup` 3. **Add projects with sync** - `bm project add research --cloud --local-path ~/Documents/research` -4. **Preview first sync** - `bm project bisync --name research --resync --dry-run` -5. **Establish baseline** - `bm project bisync --name research --resync` -6. **Daily workflow** - `bm project bisync --name research` +4. **Preview first sync** - `bm cloud bisync --name research --resync --dry-run` +5. **Establish baseline** - `bm cloud bisync --name research --resync` +6. **Daily workflow** - `bm cloud bisync --name research` **Key benefits:** - ✅ Each project independently syncs (or doesn't) diff --git a/src/basic_memory/cli/commands/cloud/project_sync.py b/src/basic_memory/cli/commands/cloud/project_sync.py index e18620da5..7538915df 100644 --- a/src/basic_memory/cli/commands/cloud/project_sync.py +++ b/src/basic_memory/cli/commands/cloud/project_sync.py @@ -95,7 +95,10 @@ def sync_project_command( dry_run: bool = typer.Option(False, "--dry-run", help="Preview changes without syncing"), verbose: bool = typer.Option(False, "--verbose", "-v", help="Show detailed output"), ) -> None: - """One-way sync: local -> cloud (make cloud identical to local). + """Personal workspace local mirror only. + + One-way sync: local -> cloud (make cloud identical to local). + Not supported for Team workspaces - use cloud API/MCP routing instead. Example: bm cloud sync --name research @@ -143,7 +146,10 @@ def bisync_project_command( resync: bool = typer.Option(False, "--resync", help="Force new baseline"), verbose: bool = typer.Option(False, "--verbose", "-v", help="Show detailed output"), ) -> None: - """Two-way sync: local <-> cloud (bidirectional sync). + """Personal workspace local mirror only. + + Two-way sync: local <-> cloud (bidirectional sync). + Not supported for Team workspaces - use cloud API/MCP routing instead. Examples: bm cloud bisync --name research --resync # First time @@ -203,7 +209,10 @@ def check_project_command( name: str = typer.Option(..., "--name", help="Project name to check"), one_way: bool = typer.Option(False, "--one-way", help="Check one direction only (faster)"), ) -> None: - """Verify file integrity between local and cloud. + """Personal workspace local mirror only. + + Verify file integrity between local and cloud. + Not supported for Team workspaces - use cloud API/MCP routing instead. Example: bm cloud check --name research @@ -246,7 +255,10 @@ def check_project_command( def bisync_reset( name: str = typer.Argument(..., help="Project name to reset bisync state for"), ) -> None: - """Clear bisync state for a project. + """Personal workspace local mirror only. + + Clear bisync state for a project. + Not supported for Team workspaces - use cloud API/MCP routing instead. This removes the bisync metadata files, forcing a fresh --resync on next bisync. Useful when bisync gets into an inconsistent state or when remote path changes. @@ -277,7 +289,10 @@ def setup_project_sync( name: str = typer.Argument(..., help="Project name"), local_path: str = typer.Argument(..., help="Local sync directory"), ) -> None: - """Configure local sync for an existing cloud project. + """Personal workspace local mirror only. + + Configure local sync for an existing cloud project. + Not supported for Team workspaces - use cloud API/MCP routing instead. Example: bm cloud sync-setup research ~/Documents/research diff --git a/tests/cli/cloud/test_project_sync_command.py b/tests/cli/cloud/test_project_sync_command.py index 93166138f..bef61b28c 100644 --- a/tests/cli/cloud/test_project_sync_command.py +++ b/tests/cli/cloud/test_project_sync_command.py @@ -12,6 +12,21 @@ runner = CliRunner() +@pytest.mark.parametrize( + "command", + ["sync", "bisync", "check", "bisync-reset", "sync-setup"], +) +def test_cloud_sync_command_help_marks_personal_workspace_only(command): + """Cloud sync help should explain that local mirrors are Personal-only.""" + importlib.import_module("basic_memory.cli.commands.cloud.project_sync") + + result = runner.invoke(app, ["cloud", command, "--help"]) + + assert result.exit_code == 0, result.output + assert "Personal workspace local mirror only" in result.output + assert "Not supported for Team workspaces" in result.output + + @pytest.mark.parametrize( "argv", [