New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details →
Socket
Book a DemoSign in
Socket

ccsync

Package Overview
Dependencies
Maintainers
1
Versions
19
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

ccsync

Fast rsync-powered two-way sync with SQLite metadata and SSH-friendly scanning.

Source
npmnpm
Version
0.4.1
Version published
Weekly downloads
3
-85%
Maintainers
1
Weekly downloads
 
Created
Source

ccsync

Fast, rsync-powered two-way file sync with SQLite metadata and optional SSH. Designed for very large trees, low RAM, and observability.

  • Rsync transport (latest rsync recommended)
  • SQLite indexes per side (alpha / beta) + base snapshot for true 3-way merges
  • Incremental scans with content hashes using XXH3 only when needed (based on ctime)
  • Realtime micro-sync for hot files (debounced, safe on partial edits)
  • SSH-friendly: stream remote deltas over stdin; no bespoke daemon required
  • Clean CLIs: ccsync scan /root, ccsync merge …, ccsync scheduler … (plus aliases)

Requires Node.js 24+.

LICENSE

Open source under the MIT License.

Status: NOT READY FOR PRODUCTION

ccsync is NOT READY FOR PRODUCTION USE YET! There is still a significant todo list of subtle edge cases to handle, features to implement, tests to put in place, etc. Do not use this. Our plan is to finish this quickly, then put this into major production on https://cocalc.com, and then I'll update this README when it is much safer to trust ccsync with your files.

Some differences compared to Mutagen, and todos:

  • the command line options are different -- it's just inspired by Mutagen, not a drop in replacement
  • conflicts are resolved using last write wins, with close ties resolved by one chosen side always wins. There is no manual resolution modes.
  • instead of Sha-256 we use XXH3 via @node-rs/xxhash. Using a very fast non-cryptographic hash is a good fit for file sync.
  • only supports macos and linux (currently)
  • timestamps are preserved instead of being ignored (like with Mutagen)
  • permissions are fully preserved instead of being partly ignored.

For more details, see Design Details.

Install

Project (local):

pnpm add ccsync
# or: npm i ccsync

Global (handy for ops boxes):

pnpm add -g ccsync
# then: ccsync help

Build from source (dev):

pnpm install
pnpm build

The package exposes the ccsync CLI (and aliases ccsync-scan, ccsync-ingest, ccsync-merge, ccsync-scheduler) via its bin map.

Quick start

1) One machine (both roots local)

# First full scan & sync loop
ccsync scheduler \
  --alpha-root /srv/alpha \
  --beta-root  /srv/beta  \
  --alpha-db   alpha.db   \
  --beta-db    beta.db    \
  --base-db    base.db    \
  --prefer     alpha      \
  --verbose    true
  • The scheduler runs a scan on each side, computes a 3-way plan, runs rsync, and repeats on an adaptive interval.
  • File changes are pushed quickly via a micro-sync path while the main loop verifies and updates the base snapshot.

2) One side over SSH

Two ways to do it:

a) Let the scheduler do the remote scan over SSH

ccsync scheduler \
  --alpha-root /srv/alpha --alpha-host user@alpha.example.com \
  --beta-root  /srv/beta \
  --alpha-db   alpha.db   --beta-db beta.db --base-db base.db \
  --prefer alpha --verbose true

The scheduler will SSH to alpha-host, run a remote scan that streams NDJSON deltas, and ingest them locally.

b) Manual pipe (useful to sanity-check)

ssh user@alpha 'env DB_PATH=~/.cache/ccsync/alpha.db ccsync scan /srv/alpha --emit-delta' \
  | ccsync ingest --db alpha.db --root /srv/alpha

Commands

ccsync scan <root> [--emit-delta]

Walks <root>, updates (or creates) the local SQLite DB at DB_PATH (env), hashing only when ctime changed. With --emit-delta, prints NDJSON events to stdout so a remote host can mirror into its DB.

  • Env: DB_PATH=/path/to/alpha.db (or beta.db), default ./alpha.db/./beta.db.

ccsync ingest --db <dbfile> --root <root>

Reads NDJSON deltas from stdin and mirrors them into the given files table. Intended to pair with a remote scan --emit-delta.

ccsync merge ...

3-way plan + rsync, then updates base.db to the merged state (relative paths). Typical flags:

--alpha-root /srv/alpha --beta-root /srv/beta
--alpha-db alpha.db --beta-db beta.db --base-db base.db
--prefer alpha|beta
[--dry-run true] [--verbose true]

ccsync scheduler ...

Adaptive watcher/scan/merge loop that ties everything together, including optional SSH for one side:

--alpha-root /srv/alpha [--alpha-host user@host]
--beta-root  /srv/beta  [--beta-host  user@host]
--alpha-db alpha.db --beta-db beta.db --base-db base.db
--prefer alpha|beta
[--dry-run true] [--verbose true]

The CLI shims for these commands are published in the bin field, so you can run them directly after install.

How it works (short)

  • Scan writes metadata (path, size, ctime, mtime, hash, deleted, last_seen, hashed_ctime) to SQLite. Hashing is streamed and parallelized; we only rehash when ctime changed since the last hash.
  • Merge builds temp tables with relative paths, computes the 3-way plan (changed A, changed B, deleted A/B, resolve conflicts by --prefer), then feeds rsync with NUL-separated --files-from lists.
  • Scheduler:
    • shallow root watchers + bounded deep “hot” watchers (recently touched subtrees),
    • micro-sync a small list of hot files immediately,
    • periodically run a full scan + merge; interval adapts to prior cycle time and recent rsync errors.

Environment & scripts

  • Node.js: >= 24 (set in engines).
  • Build: pnpm build (TypeScript → dist/), rootDir=src, outDir=dist.
  • Dev helpers: dev:scan, dev:ingest, dev:merge, dev:scheduler run the TS sources via tsx.

Typical file layout

You’ll end up with three DBs alongside your process (or wherever you point them):

  • alpha.db — metadata for alpha root
  • beta.db — metadata for beta root
  • base.db — 3-way merge base (relative paths)

This separation makes it easy to relocate/rotate databases, inspect state, and compute user-facing reports (e.g. “what changed recently”, “top space users”).

Examples

Run a full cycle once (no scheduler):

ccsync scan /srv/alpha   --db-path alpha.db
ccsync scan /srv/beta    --db-path beta.db
ccsync merge \
  --alpha-root /srv/alpha --beta-root /srv/beta \
  --alpha-db alpha.db --beta-db beta.db --base-db base.db \
  --prefer alpha --verbose true

Realtime development project (local):

ccsync scheduler \
  --alpha-root ~/src/project \
  --beta-root  /mnt/build-cache/project \
  --alpha-db alpha.db --beta-db beta.db --base-db base.db \
  --prefer alpha --verbose true

Troubleshooting

  • rsync exit 23/24 (vanished files): normal if files are being edited; scheduler backs off briefly and the next cycle will settle.

  • Inotify/FSEvents limits (Linux/macOS): scheduler uses shallow + bounded hot watchers. If you still hit limits, tune:

    • MAX_HOT_WATCHERS — cap number of deep watchers
    • SHALLOW_DEPTH — 0 or 1 recommended
    • HOT_DEPTH — typical 1–2
  • DB size: large trees create large but inexpensive DBs. Use WAL mode (default) and SSDs for best throughput.

Development

pnpm i
pnpm build
node dist/cli.js help      # or: pnpm exec ccsync help (after link/install)

TypeScript compiler outputs to dist/ mirroring src/ (see tsconfig.json).

Notes

  • Executables are provided via bin and linked to the compiled files in dist/. If you’re hacking locally in this repo, either run node dist/cli.js … or pnpm link --global to get ccsync on your PATH.
  • For SSH use, ensure the remote has Node 24+ and ccsync on PATH (installed or included in your SEA image). Then ccsync scan … --emit-delta | ccsync ingest … is all you need. Also, make sure you have ssh keys setup for passwordless login.

Here’s a drop-in README section you can paste in. I wrote it for external readers and kept the comparisons crisp.

Why ccsync?

ccsync is a two-way file sync tool with deterministic Last-Write-Wins (LWW) semantics, built on rsync for transfer and SQLite for state. It aims to be predictable, debuggable, and fast for the common case of two roots (e.g., laptop ↔ server, container bind-mount ↔ host, staging ↔ prod).

Key properties

  • Deterministic LWW: Changes are decided by content timestamps with a small configurable epsilon; ties break toward the preferred side you choose.
  • Hash-driven change detection: Content hashes, not “mtime only,” determine whether a file actually changed—keeps plans stable and reduces churn.
  • First-class symlinks: Links are scanned via lstat, targets are stored and hashed as link:<target>, and rsync preserves them.
  • Simple & inspectable: Uses SQLite tables and NDJSON deltas—easy to debug, test, and reason about.
  • MIT-licensed: Permissive for both open-source and commercial use.

When to use ccsync

Use ccsync when you want:

  • Two endpoints with predictable outcomes (no “conflict copies”).
  • Great performance on large files or incremental edits (thanks to rsync).
  • Transparent plans and state you can audit (SQLite + file lists).
  • Symlink-accurate behavior across platforms that support them.

Not a perfect fit if you need:

  • A multi-node mesh with discovery/relays (see Syncthing/Resilio).
  • Built-in version history or a cloud UI (see Nextcloud/Dropbox).
  • Interactive conflict resolution UX (see Unison); with ccsync there is never conflict resolution.

How it compares

ToolLicenseSync modelConflict policyNotes
ccsyncMITTwo-way between two rootsLWW (+ preferred side on tie)rsync transport; SQLite state; symlink-aware
UnisonGPL-3Two-wayInteractive or policy-drivenMature, formal; heavier UX for headless flows
SyncthingMPL-2.0Continuous P2P meshConflict copies on divergeGreat for many devices; background indexer
MutagenSource-available (see project docs)Dev-focused low-latency syncModes incl. “prefer side”Very fast for dev trees; custom protocol
lsyncdGPL-2.0+One-way (event → rsync)N/ASimple near-real-time mirroring

Philosophy difference: ccsync favors determinism without duplicates (LWW + preference). Tools like Syncthing/Dropbox prefer never lose data (create conflict files), which is ideal for less controlled, multi-party edits.

Semantics (brief)

  • Change detection: By content hash. Pure mtime bumps don’t count as edits.
  • Last write wins (LWW) resolution: The newer op timestamp wins; within --lww-epsilon-ms, the preferred side wins.
  • Type changes: File ↔ symlink ↔ dir follow the same LWW rule (so type can change if the winner differs).
  • Deletes: Deletions are first-class operations and replicate per LWW.
  • Symlinks: Stored with target string and hashed as link:<target>; preserved by rsync.

Performance notes

  • Large files / small edits: Excellent (rsync rolling checksums).
  • Many small files: Competitive when watch-driven; initial cold scans take longer than always-on indexers.
  • High-latency links: rsync is single-stream; consider batching file lists or running a few parallel rsyncs for huge trees.
  • Observability: Plans are explicit (toAlpha, toBeta, delete lists) and replayable.

Platform support

  • Linux/macOS: Fully supported (Node.js 24+). Uses lutimes where available for precise symlink mtimes.
  • Windows: Works best via WSL or an rsync port. Symlink behavior depends on platform capabilities and permissions.

Open Source

The MIT license is maximally permissive: embed, modify, and redistribute with minimal friction. This makes ccsync easy to adopt in both open-source stacks and commercial tooling.

Here’s a concise, copy-pasteable matrix for your README.

ccsync vs. X — choose-by-scenario

ScenarioRecommendedWhyNotes
Two endpoints; predictable outcome; no conflict copies wantedccsyncDeterministic LWW with explicit tie-preference; symlink-aware; transparent plansGreat for laptop↔server, container bind-mounts, staging↔prod
One-way near-real-time mirroring (e.g., deploy artifacts → webroot)lsyncdEvent→batch→rsync is simple and robustIf you still want ccsync, just run one side as authoritative (prefer-alpha)
Dev loop; tons of small files; low latencyMutagenPurpose-built for fast dev sync; very low overhead on editsLicense differs; protocol/agent required
Many devices; peer-to-peer mesh; zero central serverSyncthingDiscovery, relay, NAT traversal, continuousCreates conflict copies on diverge (safer for multi-writer)
Non-technical users; desktop + mobile; web UI; version historyNextcloud or DropboxTurnkey clients + history + sharingHeavier footprint; server (Nextcloud) or cloud (Dropbox)
CI/CD cache or artifacts between two machinesccsyncDeterministic, debuggable, rsync-efficient on large binariesKeep file lists tight; parallelize rsync if needed
Large binary files with small edits over LANccsyncrsync rolling checksum excelsConsider --inplace only if types won’t change and perms allow
Interactive conflict resolution preferredUnisonMature interactive/tunable policy engineMore friction in headless automation
Multi-writer folder; avoid any silent overwriteSyncthingUses conflict files rather than overwriteSafer for less-controlled edits; not deterministic
Windows-first environmentSyncthing / DropboxNative UX; no rsync/WSL neededccsync works best via WSL (document this path)
Air-gapped / restricted SSH onlyccsyncrsync over SSH; explicit file lists; easy to auditWorks well in regulated environments
Exact promotion between environments (e.g., staging → prod)ccsyncPrecise deletes; type changes honored; no conflict filesKeep backups if human edits happen in prod
One-way ingest to object storage (S3, etc.)rclone (adjacent tool)Direct backends; checksumming; retriesDifferent problem space; can be combined with ccsync locally

Legend:

  • LWW = Last-Write-Wins. In ccsync, ties within --lww-epsilon-ms break toward your preferred side (alpha/beta).
  • “Conflict copies” = tools that create duplicate files when both sides changed (e.g., filename (conflict copy).txt).

Rule of thumb

  • Want determinism between two roots → pick ccsync.
  • Want a mesh or never lose data via conflict files → pick Syncthing (or cloud sync).
  • Want dev-loop speed → pick Mutagen.
  • Want one-way mirroring → pick lsyncd.
  • Want history + sharing → pick Nextcloud/Dropbox.

Keywords

rsync

FAQs

Package last updated on 26 Oct 2025

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts