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
Summary
bm cloud sync --name Xis currently hardcoded as a one-way local → cloud mirror (makes the cloud bucket identical to local). Underlyingrclone syncsupports 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:--resyncis too riskybm cloud sync(upload) — abm cloud pull(download) reads naturallyCurrent state
project_sync()in src/basic_memory/cli/commands/cloud/rclone_commands.py:187 builds:…with source/dest hardcoded.
Proposed change
Add a direction option. Two reasonable shapes — pick one:
Option A — flag on existing command:
Option B — separate command (clearer intent, harder to misuse):
Either way, the implementation in
project_sync()swaps the source/dest args torclone sync. Becauserclone syncis destructive on the destination, the cloud → local direction will delete local files not present in the cloud —--dry-runmust be the default suggestion in the docs and surfaced prominently in the command help.Open questions
--direction pullbe gated behind a confirmation prompt (or require--force) given it can delete local files?get_bmignore_filter_path()) compose correctly when the cloud side is source? (Likely yes, since filters apply to both sides — worth verifying.)bisyncneeds--resyncafter a pull.Test plan
--dry-runreports it without doing so).bmignorefilters apply correctly with cloud as sourcebm cloud bisyncbehavior after a pull is documented and sane