Getting Started

Introduction

What Porter is, what it deliberately isn't, and when it's the right tool.

Porter moves a file between two machines with no network between them. The sending machine renders the file as a slideshow of QR codes in a terminal; a phone camera scans them and reassembles the original bytes.

That's the entire transport. No pairing, no accounts, no server, no cloud.

Principles

The air gap is the feature

Porter is not a faster way to send a file — it is a way to send one when no other path exists. A machine with no network interface, an isolated lab network, a device you will not plug a USB stick into.

No back-channel, so no retries

The receiver cannot ask for a frame again. Fountain coding removes the need: every frame is an XOR of a random subset of the file's blocks, so any sufficient pile of frames reconstructs it and no individual frame matters.

One binary on the sending side

The sending machine is often not the one you keep a runtime on. The sender is a single static Rust binary — no Node.js, no Python, nothing to install first.

Two implementations, one wire format

A Rust sender and a Dart receiver must derive fountain symbols identically from the frame's sequence number. The format is specified normatively and checked against shared fixtures, not by trusting the two to stay in step.

Nothing written unless asked

No telemetry, no analytics, no history file by default. --resume opts into persisting slideshow position; without it, the sender leaves no disk trace.

When to use something else

Porter is honest about being slow. QR codes are a low-bandwidth, line-of-sight, lossy link, and a 109 MB file is around 26,000 chunks — a real transfer that has been run, and also a long time holding a phone at a screen.

If the two machines can see each other over a network, use a network. porter-sender serve is in the box for exactly that case: an HTTP receiver that accepts uploads and QR-scan JSON alike, so you can start with the camera and finish over a wire when one turns out to be available.

The pieces

ComponentRole
rust-sender/The QR slideshow sender, plus serve and join. Single static binary.
flutter/The receiver app for Android and macOS. Scans, decodes, verifies, saves.
The sender was TypeScript until ADR-0004 and ADR-0006 moved it to Rust and deleted the Node package outright. The repo now contains no JavaScript.
Copyright © 2026