CLI reference
Setup & licensing
cdsync --version # Show version + licensed email + license state
cdsync install # Interactive wizard: deps + config + systemd + tray
cdsync activate # Activate license (browser or headless URL+code);
# auto-self-installs if run from outside ~/.cdsync/bin/
Daemon internals (called by systemd, also usable manually)
cdsync watcher # systemd ExecStart: inotify loop (daemon)
cdsync poll # systemd ExecStart: rclone bisync (timer)
cdsync poll --smart-sync # Targeted single-file upload (internal)
cdsync poll --dir-event # Full bisync for directory changes (internal)
cdsync poll --force-resync # Manual database repair (internal)
cdsync poll --dedupe # Remote dedupe: rename | newest (internal)
cdsync tray # Autostart: GTK3 tray applet (also implicit when
# launching cdsync-tray with no arguments)
Service control (mirrors systemctl --user + tray lifecycle)
| Command | Daemon | Tray |
|---|---|---|
cdsync stop |
systemctl --user stop cdsync-watcher.service cdsync-poll.timer (+ poll.service) |
SIGTERM → wait 3 s → SIGKILL if needed; PID file removed |
cdsync start |
systemctl --user enable --now cdsync-watcher.service cdsync-poll.timer |
Launch ~/.cdsync/bin/cdsync-tray detached, PID file written |
cdsync restart |
stop + start (preserves enable state) | stop + start |
cdsync status |
systemctl --user is-active cdsync-watcher.service |
Check PID file + pgrep fallback |
Why stop/start instead of systemctl directly? Because the tray isn't a systemd unit. cdsync stop ensures both the daemon (via systemctl) and the tray (via PID file + pgrep) get the message — running systemctl --user stop cdsync-watcher.service alone would leave a zombie tray icon pointing at a service that's no longer running.
The tray PID file lives at ~/.cdsync/log/tray.pid. The tray also writes its own PID on startup (belt-and-suspenders), so even if the file is stale (e.g. process crashed and PID got recycled), the pgrep -f cdsync-tray fallback finds it.
Removal
| Command | Action |
|---|---|
cdsync uninstall |
Remove CDSync (services + binaries); prompts whether to also wipe ~/.cdsync/ (license, OAuth, config, logs) |
cdsync uninstall --purge |
Skip the prompt — full purge of ~/.cdsync/. Destructive: license.lic + OAuth tokens are lost; re-activation requires a valid license.lic for this machine's fingerprint. |
Tray applet
The tray icon (cdsync tray) runs in your session's systray:
| Icon | Meaning |
|---|---|
| 🟢 green | Sync idle, all good |
| ⚡ yellow | Sync in progress |
| 🔴 red | Disabled / error |
| 🔒 lock | License invalid — click Reactivate... |
Menu actions
- Activity → recent file events (create/update/delete/move)
- Sync Now → immediate manual sync
- Config → Set Interval → change poll frequency
- Config → Force Resync → repair corrupted database
- Config → Force Sync Newer → toggle conflict strategy
- Config → Notifications → All / Errors only / Silent
- Config → Deduplicate Remote → Rename / Keep Newest
- Reactivate... → launches
cdsync activatein a terminal (only appears when license is invalid) - Quit Tray → stops the applet only (daemon continues)
Configuration
File: ~/.cdsync/config/config.env (written by the install wizard; overridable for testing via the CDSYNC_HOME environment variable).
# Required (set by the install wizard from the rclone remote created by cdsync activate)
RCLONE_REMOTE="gdrive:" # rclone remote name (with trailing colon)
LOCAL_SYNC_DIR="$HOME/gdrive" # local directory to mirror
LOCK_FILE="/tmp/cdsync_default.lock" # flock mutual-exclusion lock file
# Optional
CUSTOM_LOG_FILE="" # default: ~/.cdsync/log/cdsync.log
RCLONE_CONFIG_PATH="" # default: ~/.config/rclone/rclone.conf
NOTIFY_LEVEL=2 # 0=Off, 1=Errors, 2=All (default)
POLL_INTERVAL=5 # minutes between periodic bisync
FORCE_SYNC_NEWER=true # conflict: newer wins (true) vs .conflict files (false)
ENABLE_NOTIFICATIONS=true # legacy key; mapped to NOTIFY_LEVEL when unset
First-run auto-resync
When cdsync poll runs for the first time on a fresh install, it checks three safety gates before bootstrapping the bisync database with --resync:
- No existing bisync state in
~/.cache/rclone/bisync/for this remote - The rclone remote is reachable (
rclone lsdsucceeds) - The local sync directory is empty (refuses to auto-resync into a non-empty folder — could silently propagate local deletions to the cloud)
If all gates pass, the first poll runs rclone bisync --resync automatically (no Must run --resync error on the first run), and touches ~/.cdsync/config/.first_sync_done so subsequent polls run normal bisync. If any gate fails, the first poll is skipped with a clear log message — run cdsync poll --force-resync manually after verifying the config.