A Rust-based filesystem-to-CouchDB synchronization engine with bidirectional sync and conflict detection.
Important
This is very alpha software. Use at your own risk. It is in very early testing. You have been warned!
| Status | Feature | Description |
|---|---|---|
| ✅ | Bidirectional Sync | Changes on either side propagate to the other |
| ✅ | Conflict Detection | Automatically detects when files change on both sides |
| ✅ | Conflict Resolution | CLI commands to resolve conflicts with multiple strategies |
| ✅ | Smart Ignore Patterns | Gitignore-style .sync-ignore file support |
| ✅ | Authoritative Rebuilds | Rebuild the remote from local or rebuild the local tree from remote |
| ✅ | Telegram Notifications | Get notified when conflicts are detected |
| Flexible Configuration | CLI args, YAML config, and environment variables | |
| Conflict File Preservation (optional) | Keep-both resolution saves remote file as filename.remote |
|
| ❌ | Live Mode | Optional filesystem watcher + CouchDB changes feed for low-latency sync |
| Detailed Sync Logs | sync and daemon write detailed logs to $XDG_STATE_HOME/couchdb-file-sync/couchdb-file-sync.log by default (override via logging.file) |
git clone https://gitea.hnrglobal.com/HNR-Global/couchdb-file-sync.git
cd couchdb-file-sync
cargo build --releaseThe binary will be at target/release/couchdb-file-sync.
To install it for the current user and create a user-level systemd service:
./target/release/couchdb-file-sync installThis installs the binary to ~/.local/bin/couchdb-file-sync, writes the config file to ~/.config/couchdb-file-sync/couchdb-file-sync.yaml if it does not already exist, and enables ~/.config/systemd/user/couchdb-file-sync.service.
Enable the repo's pre-commit hook to run formatting, clippy, and tests before each commit:
git config core.hooksPath .githooksTo measure scanner performance, run:
cargo run --bin scanner-perf --releaseThe helper creates a synthetic dataset, reports one cold scan, one initial warm scan, then repeats the warm scan 1000 times by default and prints min/median/avg/max timings. Override the dataset size or repeat count with SCANNER_PERF_FILES, SCANNER_PERF_BYTES, and SCANNER_PERF_ITERATIONS.
Create ~/.config/couchdb-file-sync/couchdb-file-sync.yaml (or use environment variables) and define your sync paths.
mkdir -p ~/.config/couchdb-file-sync
cp /path/to/couchdb-file-sync.yaml.example ~/.config/couchdb-file-sync/couchdb-file-sync.yaml
# Edit ~/.config/couchdb-file-sync/couchdb-file-sync.yaml with your CouchDB credentials and pathsUse the couchdb-file-sync.yaml.example in the repository as a starting point if you installed from source.
couchdb-file-sync initThis initializes all paths defined in your config. You can also pass a single path:
couchdb-file-sync init ~/my-documentsIf you pass a path that is not listed in your config, init will warn and you should add it to paths before syncing.
This creates:
.couchdb-file-sync/directory for state storage.sync-ignorefile for ignore patterns
couchdb-file-sync synccouchdb-file-sync daemon --interval 60For low-latency sync using a filesystem watcher and CouchDB changes feed:
couchdb-file-sync sync
couchdb-file-sync daemon --liveConfiguration is loaded in this precedence order (highest to lowest):
- CLI arguments
- Environment variables (
COUCHDB_FILE_SYNC_*) - YAML config file (
~/.config/couchdb-file-sync/couchdb-file-sync.yaml) - Default values
export COUCHDB_FILE_SYNC_DB_URL="http://localhost:5984"
export COUCHDB_FILE_SYNC_DB_USERNAME="admin"
export COUCHDB_FILE_SYNC_DB_PASSWORD="secret"
export COUCHDB_FILE_SYNC_DB_NAME="couchdb_file_sync_files"
export COUCHDB_FILE_SYNC__SYNC__POLL_INTERVAL="60"couchdb:
url: "http://localhost:5984"
username: "admin"
password: "${COUCHDB_PASSWORD}"
database: "couchdb_file_sync_files"
paths:
- local: "/absolute/or/relative/path"
remote: "notes/"
sync:
poll_interval: 60
debounce_ms: 500
notifications:
enabled: true
telegram:
bot_token: "${TELEGRAM_BOT_TOKEN}"
chat_id: "${TELEGRAM_CHAT_ID}"
slack:
webhook_url: "${SLACK_WEBHOOK_URL}"
notify_on_conflict: true
notify_on_sync_error: true
logging:
level: "info" # error, warn, info, debug, trace
format: "pretty" # pretty, json, compact
file: "~/.local/state/couchdb-file-sync/couchdb-file-sync.log" # Optional file output (used by sync/daemon)
rotated_logs: "delete" # delete, keep (daemon rotates every 24 hours)Initialize a new sync directory. If PATH is omitted, all paths from the config are initialized.
If you pass a path not listed in the config, init will warn so you can add it to paths.
couchdb-file-sync init ~/documentsRun a one-time sync.
couchdb-file-sync sync ~/documents --dry-run
couchdb-file-sync sync ~/documentsRun continuous sync daemon.
couchdb-file-sync daemon ~/documents --interval 60If the process panics, the binary attempts to send a Slack alert through notifications.slack.webhook_url. This uses the config already loaded from YAML or environment variables and is separate from the normal sync/conflict Telegram notifications.
For live mode (watcher + changes feed):
couchdb-file-sync sync
couchdb-file-sync daemon ~/documents --liveReplace the remote scope with the current local filesystem for that path. Every non-ignored local file is uploaded, and remote files that no longer exist locally are deleted.
couchdb-file-sync rebuild-remote ~/documentsReplace the local filesystem with the current remote scope for that path. Existing non-ignored local files are removed first, then live remote files are downloaded.
couchdb-file-sync rebuild-local ~/documentsList pending conflicts.
couchdb-file-sync conflicts
couchdb-file-sync conflicts --jsonResolve a conflict.
# Keep local version
couchdb-file-sync resolve docs/report.pdf --strategy keep-local
# Keep remote version
couchdb-file-sync resolve docs/report.pdf --strategy keep-remote
# Keep both (saves remote as .remote file)
couchdb-file-sync resolve docs/report.pdf --strategy keep-bothShow sync status.
couchdb-file-sync status
couchdb-file-sync status --jsonInstall the current binary to the standard user location, create a user-level systemd service, and point it at ~/.config/couchdb-file-sync/couchdb-file-sync.yaml.
couchdb-file-sync installRemove the user-level systemd service and the installed binary from ~/.local/bin. The config file in ~/.config/couchdb-file-sync/couchdb-file-sync.yaml is kept.
couchdb-file-sync uninstallCreate a .sync-ignore file in your sync root with gitignore-style patterns:
# Ignore all log files
*.log
# Ignore directories
build/
target/
node_modules/
# Ignore specific files
secret-config.toml
# Negation (un-ignore)
!important.log
# Match at any depth
**/cache/When a file is modified on both sides, CouchDB File Sync:
- Detects the conflict
- Records the conflict in the database
- Sends Telegram notification (if configured)
Resolve conflicts with:
couchdb-file-sync conflicts # List all conflicts
couchdb-file-sync resolve <path> --strategy <strategy>- keep-local: Upload local version to CouchDB
- keep-remote: Download remote version, overwriting local
- keep-both: Save remote as
.remote, keep local as-is
couchdb-file-sync/
├── src/
│ ├── main.rs # CLI entry point
│ ├── lib.rs # Library exports
│ ├── config.rs # Configuration handling
│ ├── couchdb/ # CouchDB client
│ ├── sync/ # Sync engine
│ ├── local/ # Local filesystem operations
│ ├── cli/ # CLI commands
│ ├── models/ # Data models
│ └── telegram/ # Telegram notifications
├── Cargo.toml
├── couchdb-file-sync.yaml.example
└── README.md
┌─────────────────────────────────────────────────────────────┐
│ CouchDB File Sync Daemon │
├─────────────────────────────────────────────────────────────┤
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ File Watcher │ │ Sync Engine │ │ CouchDB │ │
│ │ (notify) │ │ │ │ Client │ │
│ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │
│ │ │ │ │
│ ┌──────▼─────────────────▼──────────────────▼──────┐ │
│ │ State Manager │ │
│ │ (SQLite local cache) │ │
│ └───────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
cargo testcargo build --releaseMIT
Nina Těšková nina.marie.teskova@gmail.com