mqhole
mqhole
mqhole is a small Crystal CLI for moving bytes between two parties that know the same CloudAMQP team API key and wormhole name. It provisions or reuses one shared LavinMQ CloudAMQP subscription, then uses AMQP(S) durable queues as the transport.
This is a transport tool, not a PAKE/encryption implementation like upstream magic-wormhole. The shared name is hashed into a queue name; anyone with the CloudAMQP API key can access the same broker.
Requirements
- Crystal 1.20.2 or newer
- A CloudAMQP team API key
Install dependencies and build:
make
The binary is written to bin/mqhole.
CloudAMQP
Set the API key in the environment:
export CLOUDAMQP_API_KEY=...
The send and receive commands default to scaleway::nl-ams, which CloudAMQP currently reports as supporting shared plans. List regions with shared plans and pass one with --region if you want a different broker location:
bin/mqhole regions --shared-only
bin/mqhole regions scaleway
mqhole creates an instance named after the selected region, for example mqhole-lavinmq-scaleway-nl-ams, and reuses it on later runs.
Usage
Send stdin:
printf 'hello\n' | bin/mqhole send demo
Receive and echo to stdout:
bin/mqhole receive demo
By default, receive exits after one transfer. Use --listen to keep receiving until you stop it, for example with Ctrl-C:
bin/mqhole receive demo --listen
In listen mode, transfer errors such as a bad decryption passphrase are logged and the failed transfer is dropped so later transfers can still be received.
Send and receive a file:
bin/mqhole send demo --file ./payload.bin
bin/mqhole receive demo --output ./received.bin --no-echo
Send encrypted data:
bin/mqhole send demo --encrypted --file ./payload.bin
The sender prints a generated passphrase as a logfmt line:
at=info event=encryption_passphrase passphrase=...
On an interactive terminal, send updates transfer progress in place on stderr. Use --verbose to write progress as logfmt lines instead. File and --data payloads include a known total size; stdin payloads report bytes and rate without a total:
at=info event=send_progress transfer_id=... bytes=... total=... percent=... rate=... rate_human=".../s"
at=info event=receive_progress transfer_id=... bytes=... total=... percent=... rate=... rate_human=".../s"
Receive progress is reported in verbose mode.
Receive encrypted data:
bin/mqhole receive demo --encrypted --output ./received.bin --no-echo
The receiver prompts for the passphrase without echoing it, then prints *** after the passphrase has been read. If encrypted data is received without --encrypted, or if the passphrase is wrong, mqhole exits with a clear error and leaves the AMQP messages unacknowledged so the receive can be retried.
Run a hook with the temporary payload path:
bin/mqhole receive demo --hook 'sha256sum' --hook-mode file --no-echo
Run a hook with the payload as one process argument:
bin/mqhole receive demo --hook 'printf %s' --hook-mode argument --no-echo
Argument hook mode is intended for text payloads. It rejects payloads containing NUL bytes because those cannot be represented safely as process arguments.
Payloads sent to the same name must be sent sequentially. The current protocol expects each transfer's AMQP messages to stay contiguous in the queue, so concurrent sends to the same name can fail with a transfer id mismatch. Use different names if you need overlapping transfers.
Development
Run the checks used by CI:
make check
The live smoke test used during development sent and received data through a real CloudAMQP LavinMQ instance in scaleway::nl-ams.
mqhole
- 0
- 0
- 0
- 0
- 2
- about 3 hours ago
- June 29, 2026
MIT License
Thu, 20 Aug 2026 18:10:53 GMT