Commands

Three programs. filesync runs on each client, filesync-admin on the server, and filesync-server is started by sshd, never by hand.

On this page

filesync

filesync init --repo NAME --root DIR --server USER@HOST [--remote-repo NAME]
              [--id ID] [--role client|replica] [--port N] [--identity FILE]
              [--accept-host-key] [--known-hosts FILE] [--server-command PATH]
              [--snapshot-mode hardlink|copy]
filesync init --repo NAME --root DIR --transport local --server-root DIR
              [--remote-repo NAME] [--id ID] [--role client|replica]
filesync sync   [--repo NAME]... [--dry-run] [--force] [--verbose] [--quiet]
                [--json] [--no-prune] [--no-delta]
filesync status [--repo NAME] [--json]
filesync log    [--repo NAME] [-n N] [--since YYYY-MM-DD|EPOCH]
                [--until YYYY-MM-DD|EPOCH] [--exit N]... [--warnings] [--json]
filesync settings [--config FILE] [--json]
filesync verify [--repo NAME] [--deep] [--json]
filesync restore PATH [--repo NAME] [--to DIR] [--list]
filesync snapshot [--repo NAME] [--keep N]
filesync snapshot list [--repo NAME]
filesync snapshot restore DATE [PATH] [--repo NAME] [--to DIR]
filesync version

The sync root must contain the .filesync-root marker created by filesync init. Diagnostics go to standard error; command output, including any --json document, goes to standard output, so a cron job can separate the two.

filesync init

Registers a directory in this client's configuration. It creates the root if needed and writes the .filesync-root marker.

OptionMeaning
--repo NAMEThe repo name, as the server knows it.
--root DIRThe local directory to keep in step; created if needed.
--server HOSTThe ssh server, as host or user@host.
--server-root DIRThe server root, for --transport local.
--remote-repo NAMEThe repo name on the server, if it differs from --repo.
--id IDThe id the server knows this client by.
--transport ssh|localHow the server is reached; the default is ssh, or local when --server-root is given.
--role client|replicaWhat this client may do; the default is client. Only a replica may take snapshots.
--identity FILEssh identity file.
--known-hosts FILEssh known_hosts file.
--port Nssh port.
--accept-host-keyTrust an unknown host key on first use.
--server-command PATHThe server program to run over ssh.
--snapshot-mode MODEhardlink or copy, for filesync snapshot.
--config FILEThe client configuration file to write.

The id defaults to this machine's host name. That is the name the server keeps this client's base, journal entries and conflict copies under, and the name filesync-admin client allow must list. Pass --id only to override it — for two machines with the same host name, say. It is not a login, and it does not divide the repo: every client of a repo syncs the whole tree.

filesync sync

OptionMeaning
--repo NAMESync this repo; repeatable to sync several. Default: every repo in the client configuration.
--dry-runPrint the planned actions without changing either side.
--forceProceed despite the deletion limits that normally stop a suspicious run.
--no-pruneDo not prune this repo's local trash during the run.
--no-deltaSend whole files instead of block deltas.
--verboseRaise the log level to debug for this run.
--quietLower the log level to error. The summary line is still printed when the sync did something; a repo where nothing happened prints nothing.
--jsonPrint one JSON document instead of text.

Each run reports what moved and what it cost:

documents: pulled 2, pushed 1, deleted 0, conflicts 0
  transfer: sent 12.4 KiB, received 96.1 KiB, 1 file by delta

Every attempt, successful or not, is appended to ~/.filesync/logs/REPO.jsonl. A lock refusal is reported as exit code 2 rather than an error, because cron starting a run while the previous one is finishing is normal.

status, log, settings, verify

filesync status

When each repo last synced, how big it is, and what the last transfer cost. --repo limits it and --json makes it machine readable.

filesync log

OptionMeaning
-n NShow at most N runs; the default is 20.
--since, --untilInclusive window, as YYYY-MM-DD or an epoch. A date means midnight UTC; --until includes the whole day.
--exit NOnly runs that ended with this code; repeatable.
--warningsOnly runs that recorded a warning, conflict or skipped path.
--jsonOne JSON document.

All filters apply before the limit. Runs are listed oldest first, and a torn final line from a killed run is skipped.

filesync settings

Prints every process setting, its effective value, and where that value came from — built-in default, settings file, or environment. See Settings. --config FILE names the settings file; --json prints the report as data.

filesync verify

Compares the local tree with the base the last successful sync recorded. Drift means the tree changed without being synced. It works offline: the ignore list is the one cached by the last sync.

OptionMeaning
--deepHash every file rather than trusting size and mtime.
--jsonOne JSON document.

Exit code 4 means verification found drift.

restore and snapshots

filesync restore

Puts a path back from this repo's local trash. The newest stored version wins; --list shows them all instead. Versions are searched in this repo's trash first, then in the shared trash that releases before 0.001.1 used, so files trashed before an upgrade can still be restored.

OptionMeaning
--to DIRCopy the version into DIR instead of back into the sync root.
--listList the stored versions; restore nothing.

The trash entry is kept, so a restore is repeatable. The destination must not already exist.

filesync snapshot

Takes today's snapshot of a replica, pruning old ones. Snapshots are for the replica role only. --keep N sets how many to keep, defaulting to the repo's snapshot_keep and then to 14; 0 keeps all.

filesync snapshot --repo offsite --keep 7
filesync snapshot list --repo offsite
filesync snapshot restore 2026-10-20 --repo offsite --to /tmp/export
filesync snapshot restore 2026-10-20 notes --repo offsite

snapshot restore copies a whole snapshot, or one relative path of it, back. Without --to it restores into the sync root, which rolls the replica back to that date. It holds the repo lock while it works.

filesync-admin

filesync-admin --root DIR <command>

  repo create NAME [--trash-days N] [--max-deletes N] [--max-delete-percent N]
                   [--ignore PATTERN]...
  repo list
  repo show NAME
  client allow ID --repo NAME [--role client|replica]
  client list --repo NAME
  client forget ID --repo NAME
  reindex NAME [--dry-run] [--json]
  verify NAME [--deep] [--sample N] [--json]
  restore NAME PATH [--to DIR] [--list] [--date YYYY-MM-DD]
  log NAME... [-n N] [--client ID] [--since YYYY-MM-DD|EPOCH]
              [--until YYYY-MM-DD|EPOCH] [--exit N]... [--warnings] [--json]

--root is read only before the command name.

CommandWhat it does
repo createCreates the master tree, the metadata directory, the policy and an empty index. --trash-days sets retention, --max-deletes and --max-delete-percent the per-session deletion limits, and --ignore replaces the default ignore list.
repo listLists the repos under the root.
repo showPrints one repo's policy.
client allowAdmits a client id to a repo, as client or replica. A repo with no listed clients admits every client.
client listLists a repo's admitted clients.
client forgetRemoves a client from the list.
reindexRebuilds the master index by hashing every file. Holds the repo lock. Used after a manual repair such as a rollback from backup; --dry-run reports without writing.
verifyCompares the master with its index. --deep hashes every file; --sample N hashes N of them.
restorePuts a path back from the server trash, into the master by default or into --to as an export. --date picks the newest version from that day; --list lists versions. Restoring into the master rebuilds the index.
logThe server's journal, for one or more repos, with the same time, exit and warning filters as filesync log plus --client.

If the server root cannot be written, repo create names the directory that blocks it and says to chown it to the running account or to use --root elsewhere. That advice is given only when a directory really is unwritable, so a full disk or a root that is a file keeps its own error.

filesync-server

command="filesync-server --repo docs --client laptop --role client" ssh-ed25519 AAAA...

It is not run by hand: sshd starts it with the arguments pinned in authorized_keys. The session carries only the repo, the client id and the role, which is why the client cannot choose the server root and why the wrapper exists. It refuses to speak the protocol on a terminal unless FILESYNC_ALLOW_TTY is set.

Exit codes

CodeMeaningApplies to
0Success.both
1Fatal error.both
2Another run holds the lock.client
3Completed with warnings.client
4Verification found drift.both

Library errors are raised with croak, but the commands strip the at FILE line N suffix before printing. Set FILESYNC_TRACE=1 to keep the full stack trace.