☁️ Cloud Sync¶
Declarative, multi-remote file synchronization using
rcloneandpueue. Pin directories with.cloud-pinfiles to control how they sync.
🔗 Related documents¶
| Config | User Config · Sample cloud-sync.toml |
| CLI | CLI Tools · Functions · Hooks |
| Architecture | Architecture |
In this doc: Quick Start · Concepts · Commands · Configuration · rclone Discovery · Pin Files · Troubleshooting
Quick Start¶
# 1. Copy the sample config
cp $ZSHAND/samples/user-config/cloud-sync/cloud-sync.toml \
$ZSHAND_CONFIG_DIR/cloud-sync/cloud-sync.toml
# 2. Create an env file for your remote (fast detection)
mkdir -p $ZSHAND_CONFIG_DIR/cloud-sync/env
cat > $ZSHAND_CONFIG_DIR/cloud-sync/env/gdrive.env <<EOF
REMOTE=gdrive
MOUNT_POINT=~/GoogleDrive
LOCAL_MIRROR=~/Local_Work/gdrive
EOF
# 3. Pin a directory for bisync
cd ~/GoogleDrive/Projects/myapp
pin # interactive — choose mirror or cache
# — or —
pin_mirror . gdrive # non-interactive
# 4. Run a sync scan
cloudsync scan --dry-run # preview what would happen
cloudsync scan # queue real sync jobs via pueue
# 5. Check status
cloudsync status
# — or push (scan + wait + report in one) —
cloudsync push admsep # sync admsep and wait for completion
cloudsync watch admsep # same, with live progress bar
cloudsync recover # diagnose and fix any sync issues
Concepts¶
Two Sync Strategies¶
| Strategy | Command | Use Case |
|---|---|---|
| mirror | rclone bisync | Code, git repos, config — bidirectional sync to local ext4 |
| cache | rclone rc vfs/refresh | Media, docs — pre-heat the VFS cache (rclone-mount only) |
Two Remote Types¶
| Type | Config Keys | Description |
|---|---|---|
| rclone-mount | mount_point, local_mirror | FUSE-mounted cloud drive (Google Drive, Dropbox, etc.) |
| rclone-sftp | local_path, remote_path | SFTP/SSH remote (NAS, server) — no VFS, mirror only |
Settings Cascade¶
Settings resolve through 4 layers. Scalar values replace (non-empty wins). Exclude arrays merge:
[defaults]— global defaults for all pins[defaults.mirror]/[defaults.cache]— strategy-specific defaults[remotes.NAME]— per-remote overrides.cloud-pin— per-directory overrides (pin wins)
Safety Net¶
When you cd into a FUSE-mounted cloud directory that has no .cloud-pin (no local safety net), the chpwd hook warns:
☁️ Cloud-only on gdrive (no local safety net)
Use 'pin_mirror' for code/git or 'pin_cache' for media
This warning only appears for true cloud-only FUSE mounts — local mirrors and SFTP local paths are already safe.
Commands¶
cloudsync — Sync Engine CLI¶
| Subcommand | Usage | Purpose |
|---|---|---|
scan | cloudsync scan [NAME\|all] [--dry-run] | Find .cloud-pin files and queue sync jobs |
push | cloudsync push [NAME\|all] [--dry-run] | Scan, wait for completion, and show status |
watch | cloudsync watch [NAME\|all] | Scan with live progress bar (spinner + progress) |
recover | cloudsync recover | Diagnose, fix, and report sync health |
status | cloudsync status | Show sync dashboard (last sync, results, pauses) |
pause | cloudsync pause [DURATION] [--remote R] | Pause syncing (e.g. 2h, 30m, 1d) |
resume | cloudsync resume [--remote R] | Resume syncing |
migrate | cloudsync migrate [DIR] | Convert legacy .mirror/.cache → .cloud-pin |
Pin Functions¶
| Function | Usage | Purpose |
|---|---|---|
pin | pin [dir] | Interactive pin menu (choose strategy via gum) |
pin_mirror | pin_mirror [dir] [remote] | Create/update mirror pin |
pin_cache | pin_cache [dir] [remote] | Create/update cache pin |
unpin | unpin [dir] [remote\|all] | Remove pins (per-remote or all; cleans cache files) |
Configuration¶
cloud-sync.toml¶
Located at $ZSHAND_CONFIG_DIR/cloud-sync/cloud-sync.toml. See the sample config for full documentation of every field.
Key sections:
| Section | Purpose |
|---|---|
[defaults] | Global sync defaults (exclude, conflict_resolve, max_delete, etc.) |
[defaults.mirror] | Mirror-specific defaults (compare, sync_direction) |
[defaults.cache] | Cache-specific defaults (vfs_refresh_async) |
[remotes.NAME] | Per-remote config (type, paths, overrides) |
[queue] | Pueue group names and parallelism |
[schedule] | Scan interval, boot delay, quiet hours |
[notifications] | Desktop notification settings |
Env Files¶
Located at $ZSHAND_CONFIG_DIR/cloud-sync/env/*.env. One per remote, KEY=VALUE format:
These are read by the chpwd hook and pin functions for fast detection (no TOML parsing).
rclone Binary Discovery¶
When multiple rclone installations exist (mise, cargo, system package manager), cloudsync may pick the wrong one — or fail to find any if the binary isn't on PATH during a pueue job or systemd timer. The discovery system solves this by searching known installation locations in a configurable priority order.
Configuration¶
Add an [rclone] section to cloud-sync.toml:
[rclone]
# Optional: Absolute path to rclone binary (overrides all discovery)
binary = "/custom/path/to/rclone"
# Optional: Preferred installation source when multiple exist
# Values: "auto" (default), "mise", "cargo", "system"
prefer = "mise"
# Optional: Minimum required rclone version
min_version = "1.60.0"
| Key | Type | Default | Description |
|---|---|---|---|
binary | string | (none) | Absolute path to rclone; skips all discovery if set and valid |
prefer | string | "auto" | Which installation source to try first: mise, cargo, system, or auto |
min_version | string | (none) | Minimum rclone version (e.g. 1.60.0); binaries below this are skipped |
Environment Variable¶
As an alternative to the config file, set the CLOUDSYNC_RCLONE_BIN environment variable:
This is useful for one-off overrides or CI environments where you don't want to modify the TOML config.
Discovery Priority Order¶
cloudsync resolves the rclone binary in this order, stopping at the first valid match:
| Priority | Source | How |
|---|---|---|
| 1 | Config rclone::binary | Absolute path from [rclone] binary in cloud-sync.toml |
| 2 | $CLOUDSYNC_RCLONE_BIN | Environment variable |
| 3 | Preference-based discovery | Tries mise → cargo → system (default auto order), or the custom order set by prefer |
| 4 | Common hardcoded paths | /usr/local/bin/rclone, /opt/homebrew/bin/rclone, /usr/bin/rclone |
Every candidate is validated before use — cloudsync runs rclone version to confirm the binary is real rclone, and checks min_version if configured. Invalid or too-old binaries are silently skipped.
Verifying Which rclone Is Used¶
During cloudsync scan, the resolved binary path is printed at the start:
Use --dry-run to check without queuing any jobs:
If no rclone is found at any priority level, cloudsync exits with an error listing all sources it tried.
.cloud-pin Files¶
Placed in any synced directory. TOML format, one section per remote:
- Valid strategies:
mirror,cache - Cache is only valid for
rclone-mountremotes (needs VFS) - Per-pin
excludearrays merge with all upstream layers - Per-pin scalar overrides (e.g.
conflict_resolve) replace upstream values
Troubleshooting¶
"Not in a managed cloud folder"¶
The directory isn't under any configured remote's MOUNT_POINT, LOCAL_MIRROR, or LOCAL_PATH. Check your env file at $ZSHAND_CONFIG_DIR/cloud-sync/env/.
"rclone not found" / "pueue not found"¶
Install the missing dependency. Use --dry-run to preview without pueue.
Sync paused permanently¶
If disk filled up and the cache dir became read-only, the expired pause marker couldn't be deleted. The system now treats expired pauses as resumed regardless. Run cloudsync resume to clear the marker manually.
First bisync fails¶
The first run of a mirror pin always includes --resync to establish a baseline. If rclone bisync reports conflicts, review the --backup-dir and resolve manually.
Conflicts detected¶
cloudsync status shows ⚠ (N conflicts) when rclone output contained conflict messages. Desktop notifications are sent for conflicts (configurable via notifications::on_conflict). Review the pueue job log for details: pueue log <id>.
Status shows stale entries¶
unpin automatically cleans matching status/filter cache files. For manual cleanup, delete files in $XDG_CACHE_HOME/zshand/cloud-sync/status/.
Dependencies¶
| Tool | Required | Purpose |
|---|---|---|
rclone | Yes | Sync engine (bisync, sync, copy, rc) |
pueue | For non-dry-run | Job queue with group isolation |
gum | Optional | Interactive pin menu |
🔗 Related Documents¶
| Document | Purpose |
|---|---|
| 📟 CLI Tools | All bin/ scripts |
| 🛠️ Functions | Shell functions |
| 🪝 Hooks | Startup and chpwd hooks |
| 📂 Config | User configuration |