Skip to content

sanchezalvarez/CrowSync

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

28 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

CrowSync

Simple file versioning and locking for game dev teams. SVN-inspired. Works with Unity, Godot, Unreal — any binary files.

Each member keeps a local working copy on their own disk; the server is a dumb blob + metadata store that never reads anyone's filesystem. The desktop app scans your folder natively, diffs it against the server, and pushes/pulls per file.

CrowSync desktop app

Features

  • File locking — nobody overwrites your work (HTTP 423 on locked uploads, auto-unlock after a timeout)
  • Version history — every upload is a new version; revert to any previous one
  • Push / Pull — client-side sync of your local folder against the server, with delete propagation in both directions (a removed file stays removed instead of resurrecting)
  • Resumable uploads — a dropped connection resumes a multi-GB asset from the last received byte instead of restarting (tus-lite session flow)
  • Conflict detection — stale uploads are rejected (HTTP 409) until you force or pull; each file carries a sync base so changes are attributed to the side that actually moved
  • Unity-aware locking — auto-pairs an asset with its .meta, locks dependencies as a group, and suggests GUID-referenced assets to lock together; warns when a scene/prefab is edited without a lock
  • Ignore patterns — Unity/Godot/Unreal junk skipped by default, extendable via .crowsyncignore
  • Real-time notifications — WebSocket events when teammates lock/upload/revert
  • Activity log — full audit trail per project
  • Riso-styled desktop UI — custom dark/light themeable window chrome; collapsible side panels

Quick start (Docker server)

docker-compose up -d

Server runs on http://localhost:8001, data lives in the named volume crowsync-data.

Note: to allow registering members after the first one, the server needs CROWSYNC_ADMIN_TOKEN set in its environment. Add it to the environment: section of docker-compose.yml — a .env file next to the compose file is not passed into the container by itself.

Quick start (local dev)

Backend

pip install -r server/requirements.txt
python -m server.main

Serves on http://localhost:8001 (auto-reload enabled).

Frontend (browser dev mode)

npm install
npm run dev

Opens at http://localhost:1420. Browser mode has no native filesystem access — scan/push/pull are disabled and the UI degrades to read-only-ish (lock, unlock, manual upload/download, history and activity still work).

Desktop app (Tauri — full sync)

npm run tauri dev

Running the server (Windows / macOS / Linux)

The server is pure Python — no compiled dependencies — so it runs natively on all three OSes, not just Linux. Pick whichever fits:

  • Docker (Linux, or Docker Desktop on Windows/macOS) — docker-compose up -d. Most reproducible; same image everywhere.
  • Helper script (creates a venv, installs deps, starts the server):
    ./scripts/run-server.sh      # macOS / Linux
    scripts\run-server.bat       # Windows
  • Plain Python (Python 3.11+):
    pip install -r server/requirements.txt
    python -m server.main
  • Standalone binary — download crowsync-server-<os>-x64 from a GitHub Release (built by the release workflow); no Python install needed. Run it directly; it honours the same CROWSYNC_* env vars below.

Configuration (server env vars)

Variable Default Purpose
CROWSYNC_PORT 8001 HTTP port
CROWSYNC_DB_PATH ./crowsync.db SQLite database file
CROWSYNC_STORAGE_ROOT ./storage Versioned blob storage (overridable at runtime via the storage_root setting)
CROWSYNC_ADMIN_TOKEN (empty) Required as X-Admin-Token header to register members once the first member exists. Generate with python -c "import secrets; print(secrets.token_hex(32))"
CROWSYNC_OPEN_REGISTRATION 0 1/true = trusted-LAN mode: anyone on the network registers (or recovers a lost key) with just a name, no admin token. For firewalled teams only — never a public server. Destructive ops still require the admin token.

Members & authentication

  • Every API request needs two headers: X-Member-Name + X-Api-Key.
  • The API key is generated by the server on POST /members and returned only then — store it. Only a SHA-256 hash of the key is kept in the database, so a DB leak doesn't expose keys.
  • The first member registers without any token (bootstrap mode). Every following registration requires the X-Admin-Token header matching CROWSYNC_ADMIN_TOKEN.
  • Open LAN mode (CROWSYNC_OPEN_REGISTRATION=1) skips the token entirely so anyone on a trusted/firewalled network can register or recover by name. The setup screen detects this (via /health) and hides the admin-token field.
  • Re-posting /members with an existing name (with a valid admin token) issues a fresh API key — the recovery path for a new machine. Because only the hash is stored the old key can't be returned, so any previous machine's key stops working after a recovery. The admin token is a master key; keep it secret.
  • Destructive operations — deleting a project (DELETE /projects/{id}), deactivating a member (DELETE /members/{id}) and changing server settings (PUT /settings) require the X-Admin-Token header too.
  • WebSocket auth is sent in the first message after connecting (not the URL), so keys don't leak into access logs.

TLS (run this before exposing the server to the internet)

API keys cross the network in the X-Api-Key header / WS auth message. Put the server behind a TLS-terminating reverse proxy so that link is encrypted — a ready-to-use Caddy config is included:

# 1. set your domain (and ideally an ACME email) in a sibling .env:
#      CROWSYNC_DOMAIN=crowsync.example.com
#      CROWSYNC_ACME_EMAIL=ops@example.com
# 2. start backend + Caddy (auto HTTPS via Let's Encrypt):
docker compose -f docker-compose.yml -f docker-compose.tls.yml up -d

Then point the desktop app at https://your-domain (no :8001). For local testing leave CROWSYNC_DOMAIN unset — it defaults to localhost, where Caddy issues a locally-trusted cert. The TLS compose file stops publishing :8001, so the backend is only reachable through Caddy. See AUDIT.md S3 and .env.example.

Connect from the desktop app

  • Server URL: http://YOUR-SERVER-IP:8001
  • Name: your member name (the API key is fetched and stored automatically on first registration)

Ignore patterns

Defaults cover Unity (Library/, Temp/…), Godot (.godot/…), Unreal (Binaries/, Saved/…) and common junk — see DEFAULT_IGNORE_PATTERNS in server/file_manager.py (served to clients via GET /ignore-patterns). Per-project additions go into a .crowsyncignore file in your local project root (gitignore-like syntax, see .crowsyncignore.example).

Repository layout

server/      Python FastAPI backend — SQLite + on-disk versioned blobs
src/         React 19 + Vite + Tailwind v4 frontend
src-tauri/   Tauri v2 Rust shell + native scan/upload/download commands

See CLAUDE.md for the full architecture notes and AUDIT.md for the current list of known issues and limitations.

Tech stack

  • Backend: Python FastAPI + SQLite (raw SQL, no ORM)
  • Frontend: Tauri v2 + React 19 + TypeScript + Tailwind CSS v4
  • Native layer: Rust (walkdir + MD5 manifest scan, streaming transfers via reqwest)
  • Real-time: WebSocket

License

MIT — see LICENSE.

About

Simple file versioning and locking for game dev teams. SVN-inspired. Works with Unity, Godot, Unreal — any binary files.

Topics

Resources

License

Stars

Watchers

Forks

Contributors