ferry

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.zst
ana@laptop
sam@desktop

ferry'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.

  1. Meet

    Both machines call out to a rendezvous. The code's number is the meeting place. Its words never leave your machine.

  2. 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.

  3. 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.

  4. 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.

The whole story, from first principles →

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

pathferryone TCP stream
loopback, one machine2.0 Gbit/s
LAN-like, through two NATs1.2–3.3 Gbit/s
40 ms round trip0.9–2.1 Gbit/s0.8 Gbit/s
40 ms, 0.5% loss0.64–0.69 Gbit/s0.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 mcp

Everything 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 →

tool calls
# 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.

Manifestchecked by test/harness.sh
  • 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.