Files and messages, machine to machine
Hand a file across.
One small command. It goes straight from your machine to your friend's, as fast as the line allows, encrypted end to end. No accounts, no server in the middle, nothing to set up.
ferry send ./build.tar.zstferry's own output on both machines, with the waiting sped up; the boat follows the progress bar.
The route
How it works, in plain words
Between you and your friend are routers, providers and the server that helps you meet. ferry assumes any of them might be hostile, and builds a private connection from nothing but the short code you read aloud.
Meet
Both machines call out to a rendezvous. The code's number is the meeting place. Its words never leave your machine.
Agree on a key
A password key exchange (CPace) turns the words into a long secret key that never crosses the network. A wrong guess burns the code.
Connect directly
Sealed under that key, the machines swap how to reach each other and punch through both routers. Data goes machine to machine, never through a server.
Move and check
The file goes over up to 16 connections at once. Every piece and every file is hashed with BLAKE3 before it gets its name.
Crossing times
Fast on real lines
One connection over a long, slightly lossy path stalls each time a packet goes missing. ferry spreads the file over many, so the others keep going while one recovers.
1.6×
a single TCP stream, on a 40 ms path with 0.5% loss
| path | ferry | one TCP stream |
|---|---|---|
| loopback, one machine | 2.0 Gbit/s | |
| LAN-like, through two NATs | 1.2–3.3 Gbit/s | |
| 40 ms round trip | 0.9–2.1 Gbit/s | 0.8 Gbit/s |
| 40 ms, 0.5% loss | 0.64–0.69 Gbit/s | 0.4 Gbit/s |
Measured by the test harness: two NATed machines, shaped with netem. Method and raw numbers.
For agents
Two Claude Code sessions, one channel
ferry is also an MCP server. Pair two machines once, add one line, and the Claude Code sessions on them can message each other, wait for replies and hand over files, while the humans read along.
claude mcp add ferry -s user -- ferry mcpEverything is a plain command too, with --json output, stable exit codes and a manual written for models: ferry help --llm. What arrives is treated as data, never as orders. The agent guide →
# ana's session send_message { to: "sam", type: "request", text: "Pushed fix-resume. Run the integration tests?" } → { via: "direct" } wait_for_message { from: "sam", timeout_seconds: 600 } # sam's session send_message { to: "ana", text: "All 214 pass. Log attached." } send_file { to: "ana", path: "test.log" } # ana's session → { message: { text: "All 214 pass. Log attached." } }
Inspected
Built to be trusted
Every claim on this page is checked by an automated harness that builds two homes behind NATs and a rendezvous, then watches every packet.
- Nothing readable on the wireNot even the rendezvous: a sniffer counts zero plaintext across more than 40,000 frames.
- One guess per codeA wrong code is refused on both sides and the code is spent.
- Resumes, verifiedA 20 GiB file killed part way resumes where it stopped and arrives with a matching hash.
- Direct or not at allWith no direct path, ferry stops and says so. Your data never passes through a server.
- Nothing runs by itselfMessages and files are stored, never executed. Fetched files lose their execute bit.
- No new cryptographyCPace, ChaCha20-Poly1305, X25519, Ed25519, DTLS and BLAKE3, from well-known libraries. MIT licensed; read the threat model.