Sync private scratch/ folders across machines using Syncthing over Tailscale
Many developers use a scratch/ folder in their repos for notes, experiments, and work-in-progress that shouldn't be in git but should sync across their machines.
scratch-sync uses Syncthing to sync these folders peer-to-peer over your Tailscale network — no cloud storage, no configuration hell.
Works on macOS, Linux, and Windows with native installers.
Peer-to-peer sync over Tailscale. No cloud relay, no third parties.
Auto-discovers Tailscale peers. One command to pair devices.
Works with your existing .gitignore. scratch/ stays local.
The key insight: Syncthing folder IDs just need to match across devices. The actual filesystem paths can be completely different.
Before installing, make sure you have Tailscale installed and connected on all machines you want to sync.
curl -LsSf https://scratch.tlab.sh/install.sh | sh
iwr -useb https://scratch.tlab.sh/install.ps1 | iex
This downloads Syncthing and sets it up as a background service. Want to inspect the script first? Run curl -LsSf https://scratch.tlab.sh/install.sh | less
The CLI requires uv. Install globally:
uv tool install scratch-sync
Or run without installing:
uvx scratch-sync --help
Update: uv tool upgrade scratch-sync | Uninstall: uv tool uninstall scratch-sync
cd ~/code/my-project
scratch-sync init
scratch-sync pair
The pair command discovers all Syncthing instances on your Tailscale network and pairs them automatically. Once paired, scratch/ folders sync whenever devices have matching folder IDs.
Initialize scratch-sync in a git repository. Adds the scratch/ folder to Syncthing.
scratch-sync init [PATH] [--name NAME]
| Argument | Description |
|---|---|
PATH |
Path to the git repository (default: current directory) |
--name, -n |
Custom name for the sync folder (default: repo name) |
What it does:
scratch/ directoryscratch-{reponame}.stignore filescratch/ to .gitignore if not already presentDiscover and pair with other devices running scratch-sync on your Tailscale network.
scratch-sync pair [--timeout SECONDS]
| Option | Description |
|---|---|
--timeout, -t |
Discovery timeout in seconds (default: 3.0) |
What it does:
Show the current sync status of all scratch-sync managed folders.
scratch-sync status
List all scratch-sync managed folders.
scratch-sync list
macOS / Linux:
| Option | Description |
|---|---|
--status |
Show dependency status without installing |
--uninstall |
Remove Syncthing and the auto-start service |
--upgrade |
Upgrade to the latest Syncthing version |
-y, --yes |
Skip confirmation prompts |
Windows (set before running iwr | iex):
| Variable | Description |
|---|---|
$env:STATUS=1 |
Show dependency status without installing |
$env:UNINSTALL=1 |
Remove Syncthing and scheduled task |
$env:ALLUSERS=1 |
Install as Windows service (requires admin) |
Important: After installation, set up a password for the Syncthing dashboard at http://127.0.0.1:8384/
Go to Actions > Settings > GUI and set a username and password.
scratch-sync is a wrapper around Syncthing. For advanced use:
syncthing cli config folders list
syncthing cli config devices list
syncthing cli show folder-status scratch-my-project
syncthing cli operations scan --folder scratch-my-project
syncthing cli config folders remove --id scratch-my-project
Syncthing not in PATH:
export PATH="$HOME/.local/bin:$PATH"
Service not starting (Linux):
systemctl --user status syncthing
journalctl --user -u syncthing -f
systemctl --user start syncthing
Service not starting (macOS):
launchctl list | grep syncthing
tail -f ~/Library/Logs/syncthing.log
launchctl load ~/Library/LaunchAgents/com.syncthing.syncthing.plist