- Rust 100%
| src | ||
| Cargo.lock | ||
| Cargo.toml | ||
| README.md | ||
localsend-cli
A command-line client for LocalSend written in Rust. Send files and clipboard text to other devices on your local network, or run in receive mode to accept transfers from the official LocalSend app and other compatible clients.
This tool implements the LocalSend v2 protocol over HTTPS with UDP multicast discovery.
Features
- Receive mode — Run as a headless LocalSend node that accepts incoming file transfers
- Send files — Push a file to another device on the LAN
- Clipboard sharing — Send the current clipboard contents as text to a remote device
- Device discovery — Automatically scan the network for nearby LocalSend peers, or target a device by address
- Protocol v2 — Compatible with the LocalSend v2 API (
/api/localsend/v2/...) - TLS — Self-signed certificates generated at startup, matching LocalSend's fingerprint-based trust model
Requirements
- Rust 1.70+ (edition 2021)
- Linux (tested on Arch; uses X11 for clipboard access via
arboard) - Devices must be on the same local network
- UDP port
53317and TCP port53317must be available
Installation
Clone the repository and build a release binary:
git clone https://git.sethhurst.com/seth/localsend-cli.git
cd localsend-cli
cargo build --release
The binary is placed at target/release/localsend-cli. You can copy it anywhere on your PATH.
Usage
Receive files (default)
Running without a subcommand starts the node in receive mode. It listens on https://0.0.0.0:53317, announces itself on the network, and saves incoming files to a downloads/ directory in the current working directory.
localsend-cli
Set a custom device name with --alias:
localsend-cli --alias "My Linux Box"
When a text file is received, its contents are also copied to your system clipboard automatically.
Send a file
localsend-cli send /path/to/file.pdf
If no target is given, the CLI scans the network for 3 seconds and prompts you to pick a device:
Scanning for devices (3s)...
Discovered devices:
1: Alice's Phone (Pixel 8) - 192.168.1.42:53317
2: Bob's Laptop (MacBook) - 192.168.1.55:53317
Enter the number of the device to send to: 1
To skip discovery, pass the target address directly:
localsend-cli send /path/to/file.pdf 192.168.1.42:53317
Send clipboard text
localsend-cli clipboard
This reads the current clipboard and sends it as a text/plain transfer. Like send, you can omit the target to use interactive device selection:
localsend-cli clipboard 192.168.1.42:53317
How it works
┌─────────────┐ UDP multicast ┌─────────────┐
│ Device A │ ◄──── 224.0.0.167 ────► │ Device B │
│ (sender) │ :53317 │ (receiver) │
└──────┬──────┘ └──────┬──────┘
│ │
│ HTTPS POST /api/localsend/v2/ │
│ prepare-upload │
│ HTTPS POST /api/localsend/v2/ │
└──────── upload ─────────────────────►│
▼
downloads/
- Discovery — Devices announce themselves via UDP multicast on
224.0.0.167:53317with a JSON payload describing the device (alias, fingerprint, port, protocol). - Prepare upload — The sender POSTs file metadata to the receiver's
/api/localsend/v2/prepare-uploadendpoint and receives a session ID and per-file tokens. - Upload — The sender streams each file to
/api/localsend/v2/uploadwith the session ID, file ID, and token as query parameters. - Receive — The server writes files to
downloads/and copies text content to the clipboard.
Each run generates a fresh self-signed TLS certificate. The SHA-256 fingerprint of the certificate DER is used as the device identity, consistent with how LocalSend identifies peers.
Development
# Build
cargo build
# Run tests
cargo test
# Run in receive mode (debug build)
cargo run
# Run with a subcommand
cargo run -- send ./example.txt
cargo run -- --alias "Dev Node" clipboard
Project structure
src/
├── main.rs # CLI entry point and command routing
├── client/ # Outbound file and text upload logic
├── server/ # HTTPS server (receive mode)
├── discovery/ # UDP multicast announce and scan
├── protocol/ # LocalSend v2 request/response types
└── crypto/ # Self-signed TLS certificate generation
Compatibility
Designed to interoperate with the official LocalSend desktop and mobile apps. Both sides must be on the same subnet and able to reach each other on port 53317.
When sending to a manually specified address, HTTPS is assumed. When a device is selected from the discovery scan, the protocol advertised by that device (HTTP or HTTPS) is used automatically.
License
No license file is included yet. Add one before distributing.