flyfile
Agent-native data transfer. Push/pull anything (text, files, directories) through a central server, or stream it directly client-to-client. Built for AI agents: JSON output everywhere, stable exit codes, content-addressed dedup, burn-after-read.
pip install flyfile
# server (single worker; data lives in LMDB via flaxkv2)
flyfile serve --port 8632 --token SECRET
# client
export FLYFILE_SERVER=http://host:8632 FLYFILE_TOKEN=SECRET
echo "build log" | flyfile push - --name buildlog --tag ci --ttl 2h
flyfile push ./model.bin --reads 1 # burn after one read
flyfile push ./dataset/ # dirs stream as tar, no temp files
flyfile push ./release.tar --keep # objects expire in 7d unless --keep
flyfile ls --tag ci --json # → {"total": N, "items": [...]}
flyfile rm --until 30d --dry-run # bulk delete by filters, preview first
flyfile preview k3x9m2pq # peek without consuming reads
flyfile pull k3x9m2pq -o ./model.bin
# client → client (server relays the stream, nothing is stored)
flyfile send ./results/ # prints: code: amber-falcon
flyfile recv amber-falcon # on the other machine
Agent contract
- JSON everywhere:
--json, or automatic when stdout is not a TTY. Progress goes to stderr, data to stdout. Never prompts. - Exit codes (stable): 0 ok · 2 usage · 3 not found · 4 auth · 5 conflict · 6 expired/burned · 7 network (retryable) · 1 other.
- Errors are JSON on stderr:
{"error", "message", "retryable", "suggestion"}. - Idempotent push: content-addressed (sha256). Re-pushing the same bytes is instant
(
"deduped": true). - Default retention is 7 days, enforced server-side (so the HTTP API and the Python
client behave the same).
--ttladjusts it;--keepstores forever. flyfile preview <id>reads the head of an object (or a dir's file manifest) without downloading and without consuming burn-after-read counts. Because it does not consume a read, the response is capped at 64 KiB and setstruncatedwhen it clips.flyfile schema [cmd]dumps the command tree as JSON for introspection.flyfile send --jsonemits NDJSON events; thecodeevent arrives before the transfer starts, so an agent can hand it to the receiver immediately.
Breaking changes in 0.3.0
- The on-disk format changed and is not backward compatible. Chunks are now
namespaced by upload rather than by content hash, which is what makes concurrent
uploads of the same content safe and makes abandoned chunks reclaimable. A server
started against a 0.2.x data directory fails at startup with instructions rather
than corrupting or silently leaking data. To upgrade: pull anything you still need
with 0.2.x, then delete the data directory (default
~/.local/share/flyfile). GET /objects/{id}/chunks/{idx}foridx > 0now requires thex-ff-leaseheader issued with chunk 0. Previously any caller could fetch later chunks without claiming a read, which made--reads 1meaningless for multi-chunk objects. The bundled client handles this transparently; custom clients that fetch chunks directly must pass the lease through.
Breaking changes in 0.2.0
GET /objects(andFlyfileClient.ls()) now returns{"total": N, "items": [...]}instead of a bare list, so a paged query can report how many objects matched.flyfile ls --jsonchanges shape accordingly. Upgrade server and clients together.- Uploads without an explicit TTL now expire after 7 days instead of being kept forever.
Pass
--keep(CLI) orttl=0(client/x-ff-ttl: 0) for the old behavior.
Design notes
- Storage is flaxkv2 (LMDB): metadata and 8 MiB content chunks in one env. The LMDB file does not shrink after deletes (free pages are reused; file size ≈ historical peak).
- Compression (zstd-3) happens on the client; the server stores/relays compressed bytes. Each 8 MiB chunk of a large upload is an independent zstd frame, so parallel upload, resume, and parallel download all work per-chunk.
- Burn-after-read: the read is claimed atomically when chunk 0 (or
/content) is fetched. That claim issues a short-lived lease (x-ff-lease, default 5 min) which an in-flight parallel download presents to fetch the remaining chunks, so a burnt object stays unreadable to everyone else while the legitimate download finishes. A sweeper grace period (default 15 min) keeps the chunks around for the life of the lease. - Every chunk belongs to exactly one owner at all times — an upload ledger entry or a
blob record — and ownership moves in a single transaction. That invariant is what
makes crashes, aborted uploads, and concurrent uploads of the same content unable to
strand or clobber data. See
docs/architecture.md. - Run exactly one uvicorn worker: relay pairing and the burn-claim lock are in-process.
Development
uv venv && uv pip install -e ".[dev]"
.venv/bin/pytest
scripts/bench.sh # 1 GiB loopback throughput smoke test
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file flyfile-0.3.0.tar.gz.
File metadata
- Download URL: flyfile-0.3.0.tar.gz
- Upload date:
- Size: 56.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b9e14f70b499dbe6758bb8b9731bc89bba9ae96725477445316a120254eabe7e
|
|
| MD5 |
68b70b10574b1142a34c86230c5d5ddd
|
|
| BLAKE2b-256 |
ef2e3a0fbe08689aa78dfd950a55b11f0b18124cfab898c24ab1fa964e97385e
|
Provenance
The following attestation bundles were made for flyfile-0.3.0.tar.gz:
Publisher:
python-publish.yml on KenyonY/flyfile
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
flyfile-0.3.0.tar.gz -
Subject digest:
b9e14f70b499dbe6758bb8b9731bc89bba9ae96725477445316a120254eabe7e - Sigstore transparency entry: 2278880419
- Sigstore integration time:
-
Permalink:
KenyonY/flyfile@cbcc19926b31233e5f7055068690b1a0aa80a545 -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/KenyonY
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@cbcc19926b31233e5f7055068690b1a0aa80a545 -
Trigger Event:
push
-
Statement type:
File details
Details for the file flyfile-0.3.0-py3-none-any.whl.
File metadata
- Download URL: flyfile-0.3.0-py3-none-any.whl
- Upload date:
- Size: 42.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
266272e74756380634ff10e7dc17acdae3a72fa628e69d4d895c516504cf13fd
|
|
| MD5 |
15d07f8f7bd6bc1b771e167eef8a43af
|
|
| BLAKE2b-256 |
86c3f625ab0fa07108e4b6ffd90a7bf005c9fac61f2e2eb6b26a5b7ca3f7fc81
|
Provenance
The following attestation bundles were made for flyfile-0.3.0-py3-none-any.whl:
Publisher:
python-publish.yml on KenyonY/flyfile
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
flyfile-0.3.0-py3-none-any.whl -
Subject digest:
266272e74756380634ff10e7dc17acdae3a72fa628e69d4d895c516504cf13fd - Sigstore transparency entry: 2278880469
- Sigstore integration time:
-
Permalink:
KenyonY/flyfile@cbcc19926b31233e5f7055068690b1a0aa80a545 -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/KenyonY
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@cbcc19926b31233e5f7055068690b1a0aa80a545 -
Trigger Event:
push
-
Statement type: