Releases: polius/fsend
v1.7.0
Summary
Before a transfer starts, fsend now shows you exactly what's about to move — the file list with sizes, on both the sender and the receiver — so you can confirm you're sending (and receiving) the right thing.
See what you're transferring
Run fsend on a folder and you get a preview before anything leaves your machine:
Sending proj/ · 4 files · 1.3 MB
921.6 KB video.mp4
307.2 KB audio.m4a
51.2 KB notes/outline.md
11 B README
The receiver sees the same list before accepting. Largest files come first (trimmed to the top 10, with a … and N more line), and the sizes always add up to the total in the header.
Machine-readable output for scripts
When you're driving fsend from a script rather than watching the terminal, two new flags hand you the file list as plain CSV — one for each side of a transfer:
- On the sending side,
--previewlists every file fsend would send —path,size— then exits. No code, no transfer, nothing leaves your machine:It prints to standard output, so redirect it to a file when you want to keep it, e.g.fsend --preview proj/fsend --preview proj/ > files.csv. - On the receiving side,
--manifestwrites a record after the transfer finishes: each received file aspath,size,status, where status isnew,identical,overwritten,kept, orresumed:fsend abc-defg-jkm --manifest record.csv
Symlinks are followed
fsend now sends what a symlink points to, not the link itself, so the receiver ends up with a real file instead of a link that dangles on their machine. In the preview the file shows where it came from, like latest (→ video.mp4).
A link whose target is missing, unreadable, or loops back on itself stops the send with a clear error (E036) rather than being silently dropped — fix the link or skip it with --exclude.
Fixes
- Large transfers no longer drop. A packet-demultiplexing collision between STUN and QUIC could tear down big transfers mid-flight over the internet path.
- Share codes shrug off stray whitespace and capitalization. A code pasted with a trailing space or newline — a Windows
CRLF, or one a chat app auto-capitalized — is now accepted instead of failing with a confusing "no such file." Only the code argument is normalized; filenames are left exactly as typed.
Changelog
- f95ac50: Replace --dry-run with --preview (send) and --manifest (receive) (#85) (@polius)
- 7dfcfd9: demo: add mp4/gif raster exports of the README animation (Claude Opus 4.8 (1M context) noreply@anthropic.com)
- 1a9660f: demo: replace WebP README animation with reproducible animated SVG (Claude Opus 4.8 (1M context) noreply@anthropic.com)
- fa7a246: feat: annotate every symlink-derived file with its real source (Claude Opus 4.8 (1M context) noreply@anthropic.com)
- 5488f75: feat: follow symlinks to their content when sending (Claude Opus 4.8 (1M context) noreply@anthropic.com)
- 591f9ec: feat: pre-transfer file preview with reconciled sizes (Claude Opus 4.8 (1M context) noreply@anthropic.com)
- 35d6bc1: feat: regroup --help flags by role and show -h/-v shorthands (Claude Opus 4.8 (1M context) noreply@anthropic.com)
- 98a716e: fix: also lowercase a whitespace-wrapped code (Claude Opus 4.8 (1M context) noreply@anthropic.com)
- 2a7a740: fix: check fmt.Fprint return values in renderPreview (errcheck) (Claude Opus 4.8 (1M context) noreply@anthropic.com)
- 5210e59: fix: prevent STUN/QUIC demux collision dropping large transfers (Claude Opus 4.8 (1M context) noreply@anthropic.com)
- af7cf49: fix: tolerate surrounding whitespace on a share code (Claude Opus 4.8 (1M context) noreply@anthropic.com)
- bd34b17: logo: balance the wordmark spacing (Claude Opus 4.8 (1M context) noreply@anthropic.com)
- 964b1f6: logo: lighten and shorten the wordmark chevron (Claude Opus 4.8 (1M context) noreply@anthropic.com)
- 6b0bc6a: refactor: scope code-whitespace fix to the auto-detect path (Claude Opus 4.8 (1M context) noreply@anthropic.com)
How to update
Note
To update, run fsend --update, or re-run the command from the Install section.
v1.6.0
Summary
Re-sending is now incremental: fsend transfers only the files the receiver doesn't already have, instead of sending the whole set every time.
How it works
Before transferring, fsend checks each file against the receiver and sends only the ones that aren't already there — anything it already has is left as is.
- A file that exists but is different is never replaced unless you add
--overwrite, so you can't accidentally clobber someone's local edits. - fsend never deletes anything on the receiver.
For example, say you send a folder of 500 files:
fsend ./project
The first run transfers all 500. If you add a couple of files and run the same command again, fsend sends just those new files and skips the other 500.
New options
| Option | What it does |
|---|---|
--dry-run |
Show what would be sent (new / unchanged / different) without transferring anything. |
--checksum |
Use this when timestamps can't be trusted (files were copied, restored from backup, or regenerated). It compares actual file contents instead of size and date — slower, but accurate. (Same idea as rsync's -c.) |
Reliability & security
This release also lands a round of hardening:
- Crash-safe writes. Received files are flushed to disk before fsend marks them complete, so a crash or power loss mid-transfer can't leave a file that looks finished but is silently corrupt.
- Signed installs and updates. The installer and
fsend --updatenow verify the release's cryptographic signature (cosign), not just its checksum — a tampered download is rejected, not only a corrupted one. - Up-to-date runtime. Built on the latest Go patch release, clearing every known vulnerability in the underlying libraries, with an automated check to keep it that way.
- Steadier connections. Retries now spread out to avoid hammering a busy server, the local-network fast path shrugs off a misbehaving device on the same Wi-Fi, pressing Ctrl-C during a transfer stops promptly instead of hanging, and
fsend --uninstallreturns a proper error code when it can't remove the binary. - Sturdier self-hosted server. If you run your own pairing/relay server, it now shuts down gracefully — draining in-flight relayed transfers before stopping, so upgrades don't cut active transfers — recovers from a malformed packet instead of crashing, and reports an unhealthy status when its relay has failed so your orchestrator can restart it.
- Hardened against hostile peers. The protocol parsers are now fuzz-tested and the work a peer can request is bounded, so a malicious party on the other end can't exhaust memory or crash your transfer. A related fix: files and folders whose names start with two dots (like the
..datadirectories Kubernetes creates) now transfer correctly instead of being wrongly rejected.
Compatibility
Important
This version isn't compatible with older versions of fsend, so the sender and the receiver both need to be on v1.6.0 or newer. Update with fsend --update.
Changelog
- a2b7769: build(deps): bump actions/checkout from 6 to 7 (@dependabot[bot])
- 45176a4: build(deps): bump github.com/pion/stun/v3 (#61) (@dependabot[bot])
- a495b17: demo: bigger font/header, tighter width, faster mobile playback (Claude Opus 4.8 (1M context) noreply@anthropic.com)
- afd1c0f: demo: tighten layout one more line (Claude Opus 4.8 (1M context) noreply@anthropic.com)
- 2e58e33: docs(readme): label the hero block's two machines as Sender/Receiver (Claude Fable 5 noreply@anthropic.com)
- a226bae: feat: skip unchanged files on re-send; drop tar bundling (Claude Opus 4.8 (1M context) noreply@anthropic.com)
- 4197a44: fix(install): verify cosign signature on checksums.txt before trusting it (Claude Opus 4.8 (1M context) noreply@anthropic.com)
- 797f214: fix(server): panic recovery, graceful relay drain, honest health (Claude Opus 4.8 (1M context) noreply@anthropic.com)
- 01a5015: fix(transfer): bind stream I/O to context for prompt cancellation (Claude Opus 4.8 (1M context) noreply@anthropic.com)
- f07437c: fix(transfer): fsync received files before commit for crash durability (Claude Opus 4.8 (1M context) noreply@anthropic.com)
- 332b3b0: fix: bump Go toolchain to 1.26.4, add govulncheck CI job (Claude Opus 4.8 (1M context) noreply@anthropic.com)
- e56fa19: fix: portable ancestor-conflict detection (Windows hang) (Claude Opus 4.8 (1M context) noreply@anthropic.com)
- 17ca6ea: fix: robustness cluster from the production audit (Claude Opus 4.8 (1M context) noreply@anthropic.com)
- b3ceedf: test+fix: harden against malicious peer input (negotiation cap, fuzzing) (Claude Opus 4.8 (1M context) noreply@anthropic.com)
v1.5.0
Changelog
- ce259a8: feat(ux): tighten the send/receive transfer screens (Claude Fable 5 noreply@anthropic.com)
- 1816703: fix(send): keep the code redeemable after the receiver dies mid-transfer (Claude Fable 5 noreply@anthropic.com)
v1.4.0
Changelog
- 1365a67: docs(cli): trim --help to the essentials (Claude Fable 5 noreply@anthropic.com)
- 08ba2a5: feat(cli): add --update to self-update via the platform installer (Claude Fable 5 noreply@anthropic.com)
- 706fcda: feat(ux): name the connection path on both sides at connect time (Claude Fable 5 noreply@anthropic.com)
- dae4403: fix(install): fall back to openssl for checksum verification (Claude Fable 5 noreply@anthropic.com)
- 79b68db: refactor(ux): neutral ✓ for the relay connect line (Claude Fable 5 noreply@anthropic.com)
v1.3.0
v1.2.0
v1.1.0
Changelog
- 4f4233f: feat(install): add openbsd/amd64 + openbsd/arm64 targets (Claude Opus 4.8 (1M context) noreply@anthropic.com)
- ac4d11f: fix(install): repair extraction clobber; add linux armv6 + riscv64 (Claude Opus 4.8 (1M context) noreply@anthropic.com)
v1.0.0
Send a file straight from one machine to another with a single command — no accounts, no uploads to the cloud, no third party ever touching your data.
$ fsend report.pdf # home Wi-Fi
Share this code: abc-defg-jkm
$ fsend abc-defg-jkm # café Wi-Fi, two continents away
✓ Saved report.pdf to ~/Downloads · 2.4 MB · 1.3s · Direct over the internetOne code. Bytes flow straight between the two machines at your own speed — encrypted end-to-end the whole way.
Install
curl -fsSL https://getfsend.alzina.dev | shLinux · macOS · FreeBSD · Windows — x86 and ARM. A single static binary, nothing else to set up.
About
- 🔗 Truly peer-to-peer — fsend races a LAN path, a direct internet path, and a relay, and the bytes take the best one. The relay is a last resort and never sees your file.
- 🔒 End-to-end encrypted — TLS 1.3 between peers, authenticated by your share code (PAKE). Hardened against tomorrow's quantum computers with X25519 + ML-KEM-768.
- 📦 Send anything — files, whole folders, several paths at once, a piped stream, or a line of text. Drops mid-transfer? Rerun the command and it resumes.
- 🔑 Optional password — gate any transfer with
--pass. - 🪶 Lives nowhere but the two ends — no servers storing files, no metadata trails. Self-host the pairing server in minutes if you want full control.
Full usage, architecture, and self-hosting docs live in the README. Questions or bugs? Open an issue. MIT licensed.