This page documents the standalone terminal sender (qrsend native binary and the portable qrsend.wasm module, plus the thin qrsend-wasm.sh Wasmer launcher), including system config and auditing.
# Native binary
./qrsend [options] <file|->
# Wasmer
wasmer qrsend.wasm -- [options] --label file - < file
The terminal sender is quite low-bandwidth compared to the browser-based sender. On a 80x24 terminal, you can expect around 3-4 kB/s at the default 15 fps. Resizing the window and adjusting the font size can help (160x50 can get up to 15 kB/s).
Compress your data before sending to maximize throughput, for example using zstd -19.
Transparent compression in the qrsend protocol would be nice, but is not yet designed.
Because the transfers can take a long time at these kinds of bitrates, prop the receiving device in a stable position and consider using a stand or holder to keep the camera steady and the QR codes in view. It's one thing to go for a cup of coffee while waiting for a transfer to finish, and quite another to handhold a camera for five minutes.
| Option | Description |
|---|---|
--fps <hz> | Frame rate for terminal updates (default 15). |
--qrs-per-frame <n> | Force number of QR codes rendered per terminal frame. |
--packets-per-qr <n> | Target logical packet count per QR. |
--cols <n> --rows <n> | Override terminal dimensions. |
--label <name> | Transmitted filename/label. |
--ecc low|medium|quartile|high | QR error correction level. |
--stream-id <id> | Set transfer id (15-bit effective). |
--interactive | Show pre-send manifest and require confirmation. |
--manifest-only | Print manifest and exit without streaming. |
--log-audit <path> | Append JSON audit events to a file. |
--verbose | Emit JSON audit events to stderr. |
--invert, --fg, --bg | QR foreground/background color controls. |
Default config path (Unix): /etc/qrsend/send.cfg. Override at compile-time with QRSEND_CONFIG=/path/to/send.cfg.
send.cfg formatFormat is key=value. Empty lines and # comments are ignored.
interactive=true
verbose=false
audit_log=/var/log/qrsend-audit.jsonl
audit_syslog=true
audit_journald=false
fg=#111111
bg=white
whitelist_path=/srv/approved
blacklist_path=/srv/approved/secrets
Supported keys include:
interactive
verbose
audit_log
audit_syslog
audit_journald
invert
fg
bg
whitelist_path / allow_path
blacklist_path / deny_path
whitelist_paths / allow_paths # comma-separated
blacklist_paths / deny_paths # comma-separated
whitelist.d and blacklist.dqrsend also loads line-based policy files from:
/etc/qrsend/whitelist.d/
/etc/qrsend/blacklist.d/
Each non-empty, non-comment line is one absolute path prefix.
Audit events are JSON records (TRANSFER_REQUESTED / TRANSFER_COMMENCED / TRANSFER_COMPLETED / TRANSFER_INTERRUPTED).
--verbose or verbose=true in config.Use --log-audit /path/file.jsonl or audit_log=... in config.
Enable with audit_syslog=true. qrsend writes local syslog events directly via the OS syslog API.
Enable with audit_journald=true. qrsend writes to /run/systemd/journal/socket.
-) is rejected because path policy cannot be enforced.