Multicast only finds peers on the same LAN. Reach off-LAN boxes by probing them directly over unicast (works over any routable address; Tailscale is the easy, secure choice): - discovery.Probe: unicast POST /register (https->http fallback) with a two-way handshake, so send and receive both work; offline peers age out. - internal/tailscale: Peers() shells `tailscale status --json` for online peers. - config.KnownPeers: persisted manual remotes. - main.go: watchRemotes goroutine probes knownPeers ∪ tailscale peers every 10s, in both the normal TUI path and quick-send. - TUI: `+` on Devices opens an add-remote modal (host/IP/Tailscale name). - install.sh: interactive local/remote install prompt; remote mode locks port 53317 to the Tailscale interface (ufw), with container/userspace-networking detection. README documents remote devices. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
11 KiB
Omarchy-Send (omarchy-send)
A LocalSend-compatible file-transfer client with a terminal UI, built for headless Arch / Omarchy servers used over SSH — no desktop environment, no clipboard, no browser. It interoperates with the stock LocalSend mobile and desktop apps on the same LAN, including their default encrypted (HTTPS) mode.
Features
- Discovery — multicast announce/listen on
224.0.0.167:53317plus the HTTP/registerhandshake, with peer aging. - Remote devices — reach boxes that aren't on your LAN (multicast can't find
them) by probing them directly over unicast. If Tailscale
is running, online tailnet peers are discovered automatically; you can also add
a device by host/IP/name with the
+key, saved for next time. - Receive — incoming files are accepted via a prompt (or auto-accepted) and written to the receive directory, with live progress.
- Send — pick a peer, then find what to send with a built-in recursive fuzzy finder: type part of a name to match files (and folders) anywhere under your home directory, stage them, and upload with progress, rate and ETA. Folders are sent recursively with their structure preserved on the receiver.
- Right-click in Nautilus (Omarchy desktop) — "Send via Omarchy-Send" on any file or folder opens the picker in a floating terminal with your selection already staged; just pick a device. Installed only where Nautilus is present.
- Messages — send a plain-text message to a peer (LocalSend-compatible) and
read messages others send you in a dedicated Messages tab. Send the system
clipboard as a message, or copy a received one back to the clipboard (uses
wl-clipboard/xclip/xsel, or tmux's paste buffer when run inside tmux on a headless box). - Desktop notifications — on a graphical session (e.g. Omarchy/Hyprland with
mako), an incoming message or file offer raises a desktop notification vianotify-send, so a backgrounded receiver still gets your attention. Best-effort and self-disabling on headless boxes; turn it off with--no-notifyor thenkey in Settings. - Manage — browse the receive folder, mark received files (or whole folders) and delete the ones you no longer want, behind a confirmation prompt.
- HTTPS — generates a self-signed certificate whose fingerprint matches the scheme the official client pins (uppercase-hex SHA-256 of the cert DER), so stock encrypted peers talk to it with no configuration.
- Single static binary, pure-stdlib protocol layer; the only external
dependencies are the Charm TUI libraries and
sahilm/fuzzy(the send finder's matcher) — both compiled in, so headless boxes need nothing extra.
Install
One line, nothing to clone:
curl -fsSL https://raw.githubusercontent.com/28allday/omarchy-send/main/install.sh | bash
This downloads the right binary for your architecture into ~/.local/bin, and on
Omarchy also adds a floating Walker entry (search Omarchy-Send) and the
Nautilus right-click integration. Override the location with BIN_DIR=/usr/local/bin,
or pin a version with OMARCHY_SEND_VERSION=v0.1.0.
Local or remote? When run interactively the installer asks whether this is a
local machine (home/LAN) or a remote server (public IP). Local installs as
above. For a remote server it additionally locks port 53317 to the Tailscale
interface in the firewall (ufw), so the box is reachable over your tailnet only —
not the open internet. Non-interactive installs (e.g. piped curl | bash) default
to local; force a choice with OMARCHY_SEND_MODE=local or OMARCHY_SEND_MODE=remote.
The installer is a short shell script fetched over HTTPS; read it first if you prefer — it lives at
install.shin this repo.
Build from source
git clone https://github.com/28allday/omarchy-send
cd omarchy-send
go build -o omarchy-send ./cmd/omarchy-send # or: ./install.sh
Run from a clone, ./install.sh builds with your local Go toolchain instead of
downloading.
Usage
omarchy-send # uses config / sensible defaults
omarchy-send --alias my-server # override the advertised device name
omarchy-send --port 53317 # override the listen port
omarchy-send --dir ~/Downloads # override the receive directory
omarchy-send --auto-accept # accept incoming transfers without a prompt
omarchy-send --pin 2468 # require senders to supply this PIN
omarchy-send --no-icons # drop Nerd Font glyphs (non-Nerd-Font terminals)
omarchy-send --no-notify # don't raise desktop notifications on incoming
Headless send (no TUI)
Send a one-off message to a peer by name, with no terminal UI — handy from scripts, cron, or an SSH session with no TTY:
omarchy-send --to "Strong Onion" --message "hello"
omarchy-send --to "Strong Onion" --message "deploy finished" --wait 20s
omarchy-send --to "Strong Onion" --message "hi" --send-pin 2468 # if the peer requires a PIN
The target is matched against the peer's display name, case-insensitively. The
command discovers the peer over multicast (waiting up to --wait, default 15s),
sends the message, prints a one-line result, and exits non-zero if the peer
isn't found or the send fails. It starts discovery only — not the receiver — so
it's safe to run while another omarchy-send instance is up. Both --to and
--message are required; file sending stays in the TUI for now.
Sending files
Select a device on the Devices tab and press enter to open the send
finder. It indexes files and folders under your home directory and fuzzy-matches
as you type, so you can jump straight to what you want instead of browsing
folder by folder:
- type to filter ·
↑/↓move ·enterstage the highlighted file or folder ctrl+dshow folders only (to send a whole directory) ·ctrl+ssend ·ctrl+umove the search root up a level ·escback
Staging a folder sends it whole (its structure is recreated on the receiver).
Matching is case-insensitive, and noisy directories (.git, node_modules,
caches, dotfiles…) are skipped to keep the index fast.
Remote devices (over Tailscale)
Multicast discovery only finds peers on the same LAN. To send to / receive from a box elsewhere, omarchy-send probes it directly over unicast — which works over anything routable, Tailscale being the easy, secure choice (stable addresses, end-to-end encryption, no port-forwarding):
tailscale upon both devices (one-time).- Either let omarchy-send auto-discover online tailnet peers (it probes them
every few seconds; any running omarchy-send/LocalSend appears in Devices), or
press
+on the Devices tab and enter a host, IP, or Tailscale name (e.g.colossus). Added devices are saved toknownPeersin the config and re-probed on every launch.
The receiver already listens on all interfaces, so it's reachable at its Tailscale IP with nothing else to configure. Sending and receiving both work, because the probe is a two-way handshake (each side learns the other).
On a box with a public IP, don't leave
53317open to the internet — install in remote mode (above) to firewall it to the tailnet, and/or set a--pin.
Right-click send (Nautilus)
On an Omarchy desktop, the installer adds a "Send via Omarchy-Send" entry to the Nautilus context menu. Right-click one or more files or folders (multi-select works) and choose it: a floating terminal opens with your selection pre-staged on the device list — pick a device and it sends, then the window closes itself once the transfer finishes.
This is a graphical convenience and is desktop-only: it's installed only when
Nautilus is present, so headless servers don't get it (and don't need it — use
the TUI or headless send there). Under the hood it just runs
omarchy-send <paths…>, which you can call yourself from any terminal.
Theming
On Omarchy, the TUI reads the active theme's ~/.config/omarchy/current/theme/colors.toml
and matches it. Elsewhere (headless / over SSH) it falls back to ANSI palette
colours, so it tracks whatever colour scheme the connecting terminal uses.
Device name
On first run, each device is given a random, friendly display name such as
"Crimson Quasar" (a colour + a celestial object), generated once and saved.
This avoids broadcasting your machine's hostname to everyone on the network —
handy on a laptop joining untrusted Wi-Fi. The hostname is still carried in the
device-model field, and you can set any name you like with --alias or the e
key in the Settings tab.
Config (including the generated TLS identity) is stored at
~/.config/omarchy-send/config.json. Received files default to ~/Omarchy-Send/.
Unattended / headless mode
For a server that should accept files without anyone at the keyboard, combine auto-accept with a PIN so only senders who know the code can push to it:
omarchy-send --auto-accept --pin 2468
Keys
1–5ortab— switch between Devices / Transfers / Manage / Messages / Settings- Peers:
entersend to the selected peer ·mmessage ·vsend clipboard ·+add a remote device ·rrefresh ·/filter - PIN-protected peers: messages prompt for the PIN and retry, just like file sends
- Send finder: type to fuzzy-filter ·
enterstage file/folder ·ctrl+dfolders-only ·ctrl+ssend ·ctrl+uup a dir ·escback - Incoming prompt:
yaccept ·nreject - Transfers:
cclear finished - Messages:
enterread the full message ·ycopy it to the clipboard ·ddelete it (incoming messages arrive automatically, with a footer notice) - Manage:
spacemark file/folder ·amark all ·ddelete marked (or the one under the cursor) ·rrefresh ·/filter — deletion asks to confirm first - Settings:
eedit (alias / receive dir / PIN) ·atoggle auto-accept ·itoggle icons ·ntoggle notifications - Sending to a PIN-protected peer prompts for the PIN and retries
qquit
Debugging
Set OMARCHY_SEND_LOG=/path/to/log to record discovery/transfer events to a file.
Notes on iOS
iOS LocalSend decides whether received media lands in the Photo Library based on its own in-app settings; its post-receive "open file" prompt can fail to open files from the app cache. Both behaviours occur identically with the official desktop client and are not controlled by the sender.
License
MIT — see LICENSE. Omarchy-Send is an independent implementation of the published LocalSend protocol; it is not affiliated with the LocalSend project. The terminal UI is built on the Charm libraries (also MIT).