# FileFerry
FileFerry is a terminal-native local file transfer tool for moving files
between machines on the same network without a cloud account, relay, or GUI.
The command is `ferry`.
It is built around a single binary for Linux, macOS, and Windows that can:
- Discover nearby peers automatically on the local network.
- Send files and directories over a native QUIC fast path between `ferry`
instances.
- Receive transfers in foreground, TUI, or daemon mode.
- Provide clean human output by default and newline-delimited JSON when used
from scripts.
FileFerry is pre-1.0, but the native binary already supports native mDNS peer
discovery, direct-address and peer-targeted QUIC transfer, manifest-backed
skip/resume, scriptable CLI output, long-running daemon receive mode, an
interactive TUI send flow, foreground Ctrl+C transfer cancellation with
partial-file cleanup, release packaging automation, and the public website.
The remaining build plan lives in [`BUILD.md`](BUILD.md).
The public project site is live at [`https://fileferry.app/`](https://fileferry.app/).
A separate web send portal is planned for `send.fileferry.app` after the
native CLI, TUI, daemon, release, and documentation foundations are solid.
## Why
Local file transfer tools proved that discovery, trust, and receiving files
can feel simple. `ferry` brings that simplicity to a fast, scriptable,
terminal-native workflow.
FileFerry fills that gap:
- Move large files between machines at LAN line rate.
- Use aliases, fingerprint prefixes, or direct addresses instead of copy-paste
URLs.
- Run interactively when you want a file picker and transfer queue.
- Run quietly and predictably in scripts, SSH sessions, cron jobs, and
headless machines.
## Quick Start
```sh
ferry send stephen-mbp ./vacation.zip
ferry send pixel-9 ~/Downloads/report.pdf
ferry recv --accept-all --dest ~/Downloads/ferry
ferry peers
ferry peers trust 9a4f2c
ferry identity
ferry daemon
ferry tui
```
JSON mode is designed for tools:
```sh
ferry --json send pixel-9 ./backup.tar.zst
```
Events are emitted as one JSON object per line, including version, transfer
start, progress, completion, cancellation, and failure events for implemented
commands.
## Architecture
The project is one Cargo workspace with focused crates:
```text
crates/
ferry-core/ protocol, transport, discovery, crypto, filesystem engine
ferry-cli/ clap CLI, progress output, JSON events, daemon commands
ferry-tui/ ratatui interactive interface
ferry-site/ public fileferry.app project website (Leptos + Axum SSR)
ferry-send-web/ future send.fileferry.app web portal
xtask/ build, release, benchmark, and packaging automation
```
`ferry-site` is self-contained: its CSS and favicon are embedded with
`include_str!`, it listens on plain HTTP at `FERRY_SITE_ADDR` (default
`127.0.0.1:3000`), and the Ubuntu + Caddy deployment is documented in
[`docs/site-deployment.md`](docs/site-deployment.md). The native `ferry`
binary does not depend on the site at runtime.
`ferry-core` owns all network, protocol, filesystem, discovery, trust, and
resume behavior. Frontends should stay thin.
### Discovery
FileFerry advertises and browses native peers with mDNS:
- Service: `_ferry._udp.local`
- TXT records: protocol version, transport support, fingerprint, alias, and
ports
Discovered peers are unified into a single registry keyed by fingerprint.
Aliases, hostnames, and fingerprint prefixes are lookup hints only.
### Transport
Native `ferry` transfers use QUIC via `quinn`. The current protocol uses one
QUIC connection and one bidirectional stream per transfer session for
negotiation, manifest, receive plan, payload, and acknowledgement frames.
Transport selection is automatic:
- Discovered `ferry` peer: QUIC.
- Direct address: QUIC.
### Resume
Every transfer starts with a manifest containing session id, file entries,
sizes, hashes, permissions where supported, and modification times.
The receiver compares the manifest against the destination:
- Existing matching file: skip.
- Matching partial file: resume from verified offset.
- Anything else: transfer from byte zero.
BLAKE3 is used because it is fast, parallel-friendly, and suitable for cheap
prefix verification.
### Trust
FileFerry's target native trust model is trust-on-first-use:
- A persistent device key is generated on first run.
- Self-signed TLS certificates identify peers by public key fingerprint.
- First contact shows a short fingerprint for user confirmation.
- Known peers are pinned in the platform config directory.
- `ferry peers trust` can pin a full fingerprint or a discovered peer resolved
by alias, hostname, or unique fingerprint prefix.
- `ferry identity` prints the local alias and full device fingerprint for
explicit inspection or out-of-band confirmation.
- Discovered-peer sends and TUI sends require the receiver certificate
fingerprint to match the discovered peer fingerprint before payload bytes are
sent.
- Direct-address sends can require a specific receiver certificate with
`ferry send --fingerprint <full-fingerprint> <ip:port> <path>`.
- Optional PSK mode is planned for scripted and headless workflows.
Important current limitation: the transfer path is encrypted, persistent
identity and trust-store commands exist, and discovered-peer sends now verify
the advertised fingerprint before payload. Direct-address sends can be pinned
with an explicitly confirmed fingerprint, but full TOFU first-contact
prompting/persistence and explicit PSK mode are still planned. See
[`docs/security.md`](docs/security.md) for the exact current boundary.
## Target Commands
```text
ferry send <peer> <path>... Send files or directories
ferry recv [--accept-all] Receive in foreground
ferry recv --dest <dir> Receive into a specific directory
ferry peers List discovered peers
ferry peers trust <fingerprint> Trust a peer fingerprint
ferry peers forget <fingerprint> Remove a known peer
ferry daemon Run as a background receiver
ferry config Print or edit configuration
ferry identity Print the local alias and fingerprint
ferry version Print version information
ferry tui Force interactive TUI mode
```
Global flags:
```text
--port <PORT> Override default listen port
--bind <IFACE> Bind to a specific interface
--json Emit newline-delimited JSON events
--no-discovery Disable discovery
--quiet, -q Reduce output
--verbose, -v Increase output
```
Send-specific flags:
```text
--fingerprint <FINGERPRINT> Require a direct-address receiver certificate
to match this full fingerprint
```
Planned exit codes:
```text
0 success
1 generic error
2 peer not found
3 peer rejected transfer
4 transfer started but failed mid-flight
5 config or permission error
```
## Configuration
`ferry` uses platform-native config directories through `directories`.
Example:
```toml
alias = "stephen-desktop"
listen_port = 53317
quic_port = 53318
download_dir = "~/Downloads/ferry"
auto_accept_known = true
auto_accept_unknown = false
discovery = ["native"]
max_concurrent_files = 8
[trust]
require_fingerprint = true
psk = ""
```
## Web Surfaces
The public project website is [`fileferry.app`](https://fileferry.app/). It is
a Rust web app built with Leptos and Axum, deployed separately from the native
binary.
The later hosted send portal at `send.fileferry.app` is a separate product
surface. It is not part of the v1 LAN boundary and must keep its own trust,
relay, retention, abuse, and operating-cost design before any hosted transfer
capability ships.
## Performance Targets
On commodity desktop hardware with NVMe storage and 1GbE:
- Single large file: at least 110 MB/s on the wire.
- Many small files, 10k files at 4KB each: at least 50 MB/s effective.
- Resume detection for a 50 percent complete 10GB file: under 5 seconds.
Tuning knobs should include QUIC congestion behavior, stream buffer size,
hashing parallelism, chunk size, and concurrent files in flight.
## Possible Future Work
- Compatibility bridge for third-party LAN transfer tools.
- Mobile companion app.
## Development
The implementation plan lives in [`BUILD.md`](BUILD.md). The expected local
loop is:
```sh
cargo fmt --all
cargo clippy --workspace --all-targets --all-features
cargo test --workspace --all-features
cargo build --workspace
```
The command package is published on crates.io as `ferry-cli`, which installs
a binary named `ferry`:
```sh
cargo install ferry-cli --version 0.1.8
```
Tagged releases are built through cargo-dist for Linux, macOS, and Windows.
Crates are published in dependency order: `ferry-core`, `ferry-tui`, then
`ferry-cli`.
For docs-only changes, the narrow verification command is:
```sh
git diff --check
```
Durable implementation references now live under [`docs/`](docs/), including
the current architecture, native protocol, discovery contract, security state,
daemon/headless notes, performance plan, release plan, and CLI/JSON examples.
## License
MIT. See [`LICENSE`](LICENSE).