Skip to content

CLI: support cloud → local direction in bm cloud sync #858

Description

@phernandez

Summary

bm cloud sync --name X is currently hardcoded as a one-way local → cloud mirror (makes the cloud bucket identical to local). Underlying rclone sync supports a remote as either the source or the destination, so we can expose the reverse direction (one-way cloud → local) without changing transport.

Motivation

Today the only way to pull cloud state down to local is bm cloud bisync (two-way) or a snapshot restore. There's no one-way pull equivalent of the upload sync. Useful cases:

  • Hydrating a fresh machine from cloud without establishing a bisync baseline
  • Forcing local to match cloud after manual cloud edits (e.g., web UI, API)
  • Recovery / re-mirror when local bisync state is corrupt and --resync is too risky
  • Symmetry with bm cloud sync (upload) — a bm cloud pull (download) reads naturally

Current state

project_sync() in src/basic_memory/cli/commands/cloud/rclone_commands.py:187 builds:

rclone sync <local_path> <remote_path> ...

…with source/dest hardcoded.

Proposed change

Add a direction option. Two reasonable shapes — pick one:

Option A — flag on existing command:

bm cloud sync --name research                       # default: local → cloud (unchanged)
bm cloud sync --name research --direction pull      # cloud → local

Option B — separate command (clearer intent, harder to misuse):

bm cloud sync  --name research   # local → cloud (unchanged)
bm cloud pull  --name research   # cloud → local

Either way, the implementation in project_sync() swaps the source/dest args to rclone sync. Because rclone sync is destructive on the destination, the cloud → local direction will delete local files not present in the cloud — --dry-run must be the default suggestion in the docs and surfaced prominently in the command help.

Open questions

  • Should --direction pull be gated behind a confirmation prompt (or require --force) given it can delete local files?
  • Does the existing bisync filter (get_bmignore_filter_path()) compose correctly when the cloud side is source? (Likely yes, since filters apply to both sides — worth verifying.)
  • Interaction with per-project cloud routing and bisync state: pulling should probably not touch bisync metadata, but we should think through whether a subsequent bisync needs --resync after a pull.

Test plan

  • One-way cloud → local with a clean local dir matches cloud contents
  • One-way cloud → local with extra local files deletes them (and --dry-run reports it without doing so)
  • .bmignore filters apply correctly with cloud as source
  • Subsequent bm cloud bisync behavior after a pull is documented and sane

Metadata

Metadata

Assignees

Labels

cloudBasic Memory CloudenhancementNew feature or request

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions