docs: update README with SSH transport, status/verify/bwlimit sections
- Transport section: TCP, QUIC, and SSH with comparison table - SSH subsection: on-demand server via --stdio, CLAWSYNC_SSH_COMMAND override - New sections: status, verify, watch, serve-all, pull-fs, serve-all - Remote address format table covering TCP/QUIC/SSH syntax - Test count updated to ~617 default / ~633 with simd-cdc - --bwlimit, --dry-run, --verbose, --stdio options documented throughout Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
a24eb86544
commit
50001b64ac
@@ -9,6 +9,9 @@ clawsync push weights.h5 server:9999/weights.h5 # push only new revisions
|
||||
clawsync pull server:9999/weights.h5 weights.h5 # pull only missing revisions
|
||||
clawsync hdf5-sync model.h5 server:9997/model.h5 # dataset-granular HDF5 sync
|
||||
clawsync sync ./data/ server:9998/remote/data/ # CDC delta for any file type
|
||||
clawsync sync ./data/ user@host:/remote/data/ # same, via SSH (no pre-running server)
|
||||
clawsync status ./data/ # local change report vs last sync
|
||||
clawsync verify ./data/ server:9998/remote/data/ # diff against remote, no transfer
|
||||
```
|
||||
|
||||
---
|
||||
@@ -21,16 +24,21 @@ clawsync sync ./data/ server:9998/remote/data/ # CDC delta for any file t
|
||||
4. [Installation](#installation)
|
||||
5. [Quick Start](#quick-start)
|
||||
6. [Command Reference](#command-reference)
|
||||
- [Remote address format](#remote-address-format)
|
||||
- [push / pull / serve](#push--pull--serve)
|
||||
- [hdf5-sync / serve-hdf5](#hdf5-sync--serve-hdf5)
|
||||
- [sync / serve-fs](#sync--serve-fs)
|
||||
- [sync / serve-fs / pull-fs](#sync--serve-fs--pull-fs)
|
||||
- [watch](#watch)
|
||||
- [serve-all](#serve-all)
|
||||
- [status](#status)
|
||||
- [verify](#verify)
|
||||
- [list-revisions](#list-revisions)
|
||||
- [rollback](#rollback)
|
||||
- [export-revision](#export-revision)
|
||||
- [snapshot](#snapshot)
|
||||
- [gc](#gc)
|
||||
- [branch](#branch)
|
||||
7. [Transport: TCP and QUIC](#transport-tcp-and-quic)
|
||||
7. [Transport: TCP, QUIC, and SSH](#transport-tcp-quic-and-ssh)
|
||||
8. [Sync Protocols](#sync-protocols)
|
||||
9. [Performance](#performance)
|
||||
10. [Development](#development)
|
||||
@@ -243,14 +251,28 @@ clawsync gc weights.h5 --keep-last 100
|
||||
|
||||
### Remote address format
|
||||
|
||||
All network commands use `host:port/path` as the remote address:
|
||||
All network commands accept three remote formats:
|
||||
|
||||
```
|
||||
server.local:9999/path/to/file.h5
|
||||
127.0.0.1:9999/relative/path.h5
|
||||
| Format | Transport | Example |
|
||||
|--------|-----------|---------|
|
||||
| `host:port/path` | TCP (default) | `server.local:9999/models/model.h5` |
|
||||
| `host:port/path` + `--quic` | QUIC (TLS 1.3) | `server.local:9999/models/model.h5 --quic` |
|
||||
| `[user@]host:path` | SSH (no server setup needed) | `alice@train-node:/data/models/` |
|
||||
|
||||
**SSH remote:** ClawSync spawns the appropriate `serve` command on the remote machine via SSH with `--stdio` and wires its stdin/stdout directly to the protocol. No pre-running server or open port required — only SSH access and `clawsync` on the remote `PATH`.
|
||||
|
||||
```bash
|
||||
# TCP (explicit server needed on remote)
|
||||
clawsync sync ./data/ server:9998/data/
|
||||
|
||||
# SSH (no server setup — clawsync spawns one over SSH)
|
||||
clawsync sync ./data/ user@host:/remote/data/
|
||||
clawsync push model.h5 user@host:/models/model.h5
|
||||
clawsync pull user@host:/models/model.h5 model.h5
|
||||
clawsync hdf5-sync model.h5 user@host:/models/model.h5
|
||||
```
|
||||
|
||||
The path is always relative to the server's serve root (for `serve-hdf5` and `serve-fs`) or an absolute path for `serve` (single-file mode).
|
||||
Set `CLAWSYNC_SSH_COMMAND` to override the SSH binary (useful for testing with a custom shim or `mosh`).
|
||||
|
||||
---
|
||||
|
||||
@@ -260,19 +282,22 @@ Revision-aware sync for HDF5 files with `.onion` sidecars. Transfers only the on
|
||||
|
||||
```bash
|
||||
# Push new revisions to a remote server
|
||||
clawsync push <LOCAL.h5> <HOST:PORT/REMOTE.h5> [--branch NAME] [--quic]
|
||||
clawsync push <LOCAL.h5> <REMOTE> [--branch NAME] [--quic]
|
||||
|
||||
# Pull revisions from a remote server
|
||||
clawsync pull <HOST:PORT/REMOTE.h5> <LOCAL.h5> [--branch NAME] [--quic]
|
||||
clawsync pull <REMOTE> <LOCAL.h5> [--branch NAME] [--quic]
|
||||
|
||||
# Serve a local HDF5 file (accepts push and pull)
|
||||
clawsync serve <LOCAL.h5> [--bind ADDR] [--quic]
|
||||
clawsync serve <LOCAL.h5> [--bind ADDR] [--quic] [--stdio]
|
||||
# default bind: 0.0.0.0:9999
|
||||
```
|
||||
|
||||
`<REMOTE>` is either `host:port/path.h5` (TCP/QUIC) or `[user@]host:path.h5` (SSH).
|
||||
|
||||
**Options:**
|
||||
- `--branch NAME` — push/pull only revisions on the named branch
|
||||
- `--quic` — use QUIC transport with self-signed TLS (for testing; configure certificates for production)
|
||||
- `--quic` — use QUIC transport with self-signed TLS
|
||||
- `--stdio` — read/write protocol on stdin/stdout (used automatically by SSH clients)
|
||||
|
||||
**What gets transferred:** Only `OnionLayerPacket` entries the remote lacks. Pre-flight uses IBLT (Invertible Bloom Lookup Table) sketch exchange — cost is O(revision count), not O(file size).
|
||||
|
||||
@@ -280,7 +305,7 @@ clawsync serve <LOCAL.h5> [--bind ADDR] [--quic]
|
||||
```bash
|
||||
# First push — cold copy of all revisions
|
||||
clawsync push model.h5 server:9999/model.h5
|
||||
# Pushing model.h5 → server:9999 (TCP) ...
|
||||
# Pushing model.h5 → server:9999/model.h5 (TCP) ...
|
||||
# Remote has 0 revision(s) (IBLT). Pushing 150 revision(s).
|
||||
# Push complete: 150 revision(s), 614400 bytes.
|
||||
|
||||
@@ -288,6 +313,10 @@ clawsync push model.h5 server:9999/model.h5
|
||||
clawsync push model.h5 server:9999/model.h5
|
||||
# Remote has 150 revision(s) (IBLT). Pushing 3 revision(s).
|
||||
# Push complete: 3 revision(s), 12288 bytes.
|
||||
|
||||
# Push over SSH — no server setup needed on remote
|
||||
clawsync push model.h5 alice@train-node:/models/model.h5
|
||||
# Pushing model.h5 → alice@train-node:/models/model.h5 (SSH) ...
|
||||
```
|
||||
|
||||
---
|
||||
@@ -298,16 +327,19 @@ Dataset-granular HDF5 sync. No `.onion` sidecar required on either side. Compare
|
||||
|
||||
```bash
|
||||
# Sync a local HDF5 file to a remote server (only changed datasets)
|
||||
clawsync hdf5-sync <LOCAL.h5> <HOST:PORT/REMOTE.h5> [--delete] [--quic]
|
||||
clawsync hdf5-sync <LOCAL.h5> <REMOTE> [--delete] [--quic]
|
||||
|
||||
# Serve a directory of HDF5 files
|
||||
clawsync serve-hdf5 <DIR> [--bind ADDR] [--allow-delete] [--quic]
|
||||
clawsync serve-hdf5 <DIR> [--bind ADDR] [--allow-delete] [--quic] [--stdio]
|
||||
# default bind: 0.0.0.0:9997
|
||||
```
|
||||
|
||||
`<REMOTE>` is `host:port/relative.h5` (TCP/QUIC) or `[user@]host:/abs/path.h5` (SSH).
|
||||
|
||||
**Options:**
|
||||
- `--delete` (client) — request removal of datasets absent from the local file
|
||||
- `--allow-delete` (server) — permit clients to request dataset deletion
|
||||
- `--stdio` — (server) read/write protocol on stdin/stdout for SSH sessions
|
||||
- Deletion requires **both** `--delete` (client) and `--allow-delete` (server)
|
||||
|
||||
**What gets transferred:** Only datasets whose BLAKE3 hash differs between local and remote. A warm sync of an unchanged file transfers nothing and completes in 1 RTT.
|
||||
@@ -333,34 +365,164 @@ clawsync hdf5-sync model.h5 server:9997/models/model.h5
|
||||
|
||||
---
|
||||
|
||||
### sync / serve-fs
|
||||
### sync / serve-fs / pull-fs
|
||||
|
||||
CDC-based delta sync for any file type — not just HDF5. Handles directory trees. Uses Content-Defined Chunking (FastCDC) so chunk boundaries are insertion-stable: adding 1 byte at the start of a file does not invalidate the rest.
|
||||
|
||||
```bash
|
||||
# Sync a local directory to a remote path
|
||||
clawsync sync <LOCAL_PATH> <HOST:PORT/REMOTE_PATH> [--delete] [--exclude GLOB]... [--quic]
|
||||
# Push local directory to remote (client → server)
|
||||
clawsync sync <LOCAL> <REMOTE> [--delete] [--dry-run] [-v] [--exclude GLOB]... [--bwlimit KBPS] [--quic]
|
||||
|
||||
# Pull remote directory to local (server → client)
|
||||
clawsync pull-fs <REMOTE> <LOCAL> [--delete] [--exclude GLOB]... [--quic]
|
||||
|
||||
# Serve a local directory
|
||||
clawsync serve-fs <DIR> [--bind ADDR] [--allow-delete] [--exclude GLOB]... [--quic]
|
||||
clawsync serve-fs <DIR> [--bind ADDR] [--allow-delete] [--exclude GLOB]... [--quic] [--stdio]
|
||||
# default bind: 0.0.0.0:9998
|
||||
```
|
||||
|
||||
**Options:**
|
||||
- `--delete` — delete files on the server that don't exist locally (requires `--allow-delete` on server)
|
||||
- `--exclude GLOB` — skip files matching the glob (e.g. `"*.tmp"`, `"**/.git/**"`)
|
||||
- `--allow-delete` — (server) permit client-requested deletions
|
||||
`<REMOTE>` is `host:port/path` (TCP/QUIC) or `[user@]host:path` (SSH).
|
||||
|
||||
**Options for `sync`:**
|
||||
- `--delete` — delete files on the remote that don't exist locally (requires `--allow-delete` on server)
|
||||
- `--dry-run` — report what would change without transferring anything
|
||||
- `-v` / `--verbose` — print each file as it completes with byte count
|
||||
- `--exclude GLOB` — skip files matching the glob (may be repeated)
|
||||
- `--bwlimit KBPS` — cap outbound bandwidth in KiB/s (e.g. `--bwlimit 1024` = 1 MiB/s)
|
||||
- `--quic` — use QUIC transport
|
||||
|
||||
**Protocol:** 2-RTT for incremental and cold copy; 1-RTT for warm no-op. W=16 pipelining on the second RTT.
|
||||
**Options for `serve-fs`:**
|
||||
- `--allow-delete` — permit client-requested deletions
|
||||
- `--stdio` — read/write protocol on stdin/stdout for SSH sessions
|
||||
- `--exclude GLOB` — exclude paths from serving (may be repeated)
|
||||
|
||||
**Example:**
|
||||
**State cache:** After each sync, ClawSync writes `.clawsync.state` in the local directory — a tab-separated index of `(path, mtime_ns, size, blake3)`. On the next run, files whose mtime and size are unchanged have their BLAKE3 reused from cache, making warm syncs proportional to the number of *changed* files rather than total bytes.
|
||||
|
||||
**Protocol:** 2-RTT for incremental and cold copy; 1-RTT for warm no-op. W=16 pipelining on the second RTT. Delta savings are reported as `Sync complete: N added, M modified, R removed, B bytes.`
|
||||
|
||||
**Examples:**
|
||||
```bash
|
||||
# TCP server
|
||||
clawsync serve-fs /training-data --bind 0.0.0.0:9998 --allow-delete &
|
||||
|
||||
clawsync sync ./checkpoints/ server:9998/checkpoints/ \
|
||||
--delete --exclude "*.tmp" --exclude "**/__pycache__/**"
|
||||
# Sync complete: 0 added, 2 modified, 1 removed, 4096 bytes.
|
||||
|
||||
# SSH — no server setup needed
|
||||
clawsync sync ./checkpoints/ alice@gpu-node:/training/checkpoints/
|
||||
|
||||
# Bandwidth-limited sync (512 KiB/s max upload)
|
||||
clawsync sync ./data/ server:9998/data/ --bwlimit 512
|
||||
|
||||
# Dry-run: show what would change without syncing
|
||||
clawsync sync ./data/ server:9998/data/ --dry-run
|
||||
|
||||
# Pull (reverse direction: remote sends to local)
|
||||
clawsync pull-fs server:9998/remote/data/ ./local/data/
|
||||
clawsync pull-fs alice@gpu-node:/training/data/ ./local/data/ # SSH pull
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### watch
|
||||
|
||||
Watch a local directory for changes and re-sync to a remote automatically.
|
||||
|
||||
```bash
|
||||
clawsync watch <LOCAL> <REMOTE> [--delete] [--exclude GLOB]... [--debounce-ms N] [--quic]
|
||||
```
|
||||
|
||||
Uses OS filesystem events (inotify on Linux, kqueue/FSEvents on macOS) with a configurable debounce window before triggering a sync. Reconnects automatically after network errors. Runs until `Ctrl-C`.
|
||||
|
||||
```bash
|
||||
clawsync watch ./experiments/ server:9998/experiments/ \
|
||||
--delete --debounce-ms 500
|
||||
# Watching ./experiments/ → server:9998/experiments/ (TCP), debounce 500ms ...
|
||||
# Watching for changes. Press Ctrl-C to stop.
|
||||
# Sync complete: 1 added, 0 modified, 0 removed, 12288 bytes.
|
||||
```
|
||||
|
||||
**Options:**
|
||||
- `--debounce-ms N` — wait N milliseconds after the last event before syncing (default: 200)
|
||||
- Other options same as `sync`
|
||||
|
||||
---
|
||||
|
||||
### serve-all
|
||||
|
||||
Universal server that handles onion-revision (`push`/`pull`), HDF5-dataset (`hdf5-sync`), and FS-sync (`sync`/`pull-fs`) clients on a **single port**, dispatching on the first message.
|
||||
|
||||
```bash
|
||||
clawsync serve-all <DIR> [--bind ADDR] [--allow-delete] [--exclude GLOB]... [--quic] [--stdio]
|
||||
# default bind: 0.0.0.0:9996
|
||||
```
|
||||
|
||||
- Onion clients: files are looked up as `<DIR>/<agent-id>.claws`
|
||||
- HDF5 and FS clients: `<DIR>` is used as the root directory
|
||||
|
||||
Useful for deploying a single server that multiple client types can connect to.
|
||||
|
||||
```bash
|
||||
clawsync serve-all /models --bind 0.0.0.0:9996 --allow-delete
|
||||
# ClawSync server listening on 0.0.0.0:9996
|
||||
|
||||
# Onion revision push
|
||||
clawsync push weights.h5 server:9996/weights.h5
|
||||
|
||||
# HDF5 dataset sync
|
||||
clawsync hdf5-sync model.h5 server:9996/model.h5
|
||||
|
||||
# General file sync
|
||||
clawsync sync ./data/ server:9996/data/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### status
|
||||
|
||||
Show local changes since the last sync — no server connection required.
|
||||
|
||||
```bash
|
||||
clawsync status <DIR>
|
||||
```
|
||||
|
||||
Compares the current directory tree against the `.clawsync.state` cache written by the last `sync`, `pull-fs`, or `watch` run. Useful for checking what has changed before pushing.
|
||||
|
||||
```bash
|
||||
clawsync status ./checkpoints/
|
||||
# A new_experiment.py
|
||||
# M config.yaml
|
||||
# D old_run/weights.pt
|
||||
|
||||
clawsync status ./checkpoints/
|
||||
# Nothing changed since last sync.
|
||||
```
|
||||
|
||||
Output prefix: `A` = added (new file), `M` = modified (mtime or size changed), `D` = deleted (was in cache, gone from disk).
|
||||
|
||||
If `.clawsync.state` is absent (never synced), all files are reported as `A`.
|
||||
|
||||
---
|
||||
|
||||
### verify
|
||||
|
||||
Compare a local directory against a remote without transferring anything.
|
||||
|
||||
```bash
|
||||
clawsync verify <LOCAL> <REMOTE> [--delete] [--exclude GLOB]... [--quic]
|
||||
```
|
||||
|
||||
Performs the manifest exchange (1 RTT) and reports which files would be added, modified, or removed on the remote if `sync` were run. No files are written on either side. Supports TCP, QUIC, and SSH remotes.
|
||||
|
||||
```bash
|
||||
clawsync verify ./data/ server:9998/data/
|
||||
# A new_file.bin
|
||||
# M weights.pt
|
||||
# (no output for D if --delete not set)
|
||||
|
||||
clawsync verify ./data/ alice@host:/remote/data/
|
||||
# Remote is up to date.
|
||||
```
|
||||
|
||||
---
|
||||
@@ -480,17 +642,19 @@ clawsync branch merge model.h5 experiment --into main --strategy latest-wins
|
||||
|
||||
---
|
||||
|
||||
## Transport: TCP and QUIC
|
||||
## Transport: TCP, QUIC, and SSH
|
||||
|
||||
All network commands support both TCP (default) and QUIC via the `--quic` flag.
|
||||
All network commands support TCP (default), QUIC (`--quic`), and SSH (automatic when the remote address contains `@`).
|
||||
|
||||
| | TCP | QUIC |
|
||||
|---|---|---|
|
||||
| Default | ✓ | add `--quic` |
|
||||
| TLS | ✗ | ✓ (TLS 1.3) |
|
||||
| Multiplexing | single stream | per-message streams |
|
||||
| Connection setup | fast | slightly slower (TLS handshake) |
|
||||
| Production use | plaintext LAN | encrypted WAN |
|
||||
| | TCP | QUIC | SSH |
|
||||
|---|---|---|---|
|
||||
| Address format | `host:port/path` | `host:port/path --quic` | `user@host:path` |
|
||||
| TLS | ✗ | ✓ (TLS 1.3) | ✓ (SSH layer) |
|
||||
| Requires pre-running server | ✓ | ✓ | ✗ |
|
||||
| Firewall-friendly | needs open port | needs open port | SSH port (22) only |
|
||||
| Production use | plaintext LAN | encrypted WAN | encrypted WAN, no daemon |
|
||||
|
||||
### TCP / QUIC
|
||||
|
||||
QUIC in development mode uses `QuicConfig::self_signed()` (auto-generated certificate). For production, provide a signed certificate via the configuration API.
|
||||
|
||||
@@ -499,6 +663,37 @@ clawsync serve model.h5 --bind 0.0.0.0:9999 --quic
|
||||
clawsync push model.h5 server:9999/model.h5 --quic
|
||||
```
|
||||
|
||||
### SSH
|
||||
|
||||
When the remote address starts with `user@host:`, ClawSync spawns the remote binary over SSH rather than connecting to a TCP/QUIC port. No pre-running server is needed — the remote `clawsync` binary is started on-demand with `--stdio` and the protocol runs over stdin/stdout.
|
||||
|
||||
```bash
|
||||
# push/pull over SSH — no clawsync daemon needed on server
|
||||
clawsync push model.h5 user@server:models/model.h5
|
||||
clawsync pull user@server:models/model.h5 local.h5
|
||||
|
||||
# general file sync over SSH
|
||||
clawsync sync ./data/ user@server:backup/data/
|
||||
|
||||
# HDF5 dataset sync over SSH
|
||||
clawsync hdf5-sync local.h5 user@server:hdf5/local.h5
|
||||
```
|
||||
|
||||
The SSH command used is `ssh` by default. Override it by setting `CLAWSYNC_SSH_COMMAND` (useful for testing or when using a custom SSH wrapper):
|
||||
|
||||
```bash
|
||||
CLAWSYNC_SSH_COMMAND=/usr/local/bin/my-ssh clawsync push model.h5 user@server:path/model.h5
|
||||
```
|
||||
|
||||
The `--stdio` flag on server commands exposes the same protocol over stdin/stdout, enabling use with any pipe-based transport:
|
||||
|
||||
```bash
|
||||
# serve over a named pipe or custom tunnel
|
||||
clawsync serve model.h5 --stdio
|
||||
clawsync serve-fs ./data/ --stdio
|
||||
clawsync serve-hdf5 ./hdf5/ --stdio
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Sync Protocols
|
||||
@@ -579,7 +774,7 @@ cargo build --workspace --release
|
||||
### Testing
|
||||
|
||||
```bash
|
||||
# All tests (~573 default, ~589 with SIMD CDC)
|
||||
# All tests (~617 default, ~633 with SIMD CDC)
|
||||
cargo test --workspace
|
||||
cargo test --workspace --features simd-cdc
|
||||
|
||||
|
||||
Reference in New Issue
Block a user