# FileFerry
FileFerry is a terminal-native local file transfer tool for people who want
zero-config peer discovery, native QUIC transfers, resumable manifests,
scriptable output, and TUI/daemon modes.
The goal is a single static binary named `ferry` 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 early-stage. The repository currently contains native mDNS peer
discovery, direct-address and peer-targeted QUIC transfer, manifest-backed
skip/resume, a scriptable CLI, long-running daemon receive mode, an
interactive TUI send flow with trust confirmation and visible transfer errors,
foreground Ctrl+C transfer cancellation with partial-file cleanup,
crate metadata for crates.io publishing, release packaging automation, the
public website, and the remaining build plan 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.
## Planned UX
```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 daemon
ferry tui
```
JSON mode is designed for tools:
```sh
ferry --json send pixel-9 ./backup.tar.zst
```
Each event will be emitted as one JSON object per line, including peer
discovery, transfer start, progress, completion, rejection, and failure events.
## 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 will advertise and browse 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`, with one transfer session per
connection, one stream per file, and a control stream for the manifest.
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 the planned hash because it is fast, parallel-friendly, and suitable
for cheap prefix verification.
### Trust
FileFerry uses trust-on-first-use for native peers:
- 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.
- Optional PSK mode supports scripted and headless workflows.
## 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 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
```
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` will use 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 Roadmap
The first web surface should be the public project and marketing website at
`fileferry.app`. It should be built as early as practical with a Rust-first
stack, currently planned as Leptos with Axum for server-rendered pages,
hydration where useful, and shared Rust domain types where that stays clean.
The later web send portal at `send.fileferry.app` is a separate final-phase
product surface. It should take cues from tools like Wormhole, but must get
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 prepared for crates.io as `ferry-cli`, which installs a
binary named `ferry`:
```sh
cargo install ferry-cli --version 0.1.2
```
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).