omarchy-send/README.md
28allday e66662feb9 Headless one-shot message send + desktop notifications on incoming
Two related additions for using omarchy-send beyond the focused TUI:

Headless send (no TUI / no TTY) — for scripts, cron, SSH sessions:
  omarchy-send --to "<alias>" --message "<text>" [--send-pin N] [--wait 15s]
Resolves the peer by alias over multicast (discovery only, not the HTTP
receiver, so it co-exists with a running instance), sends, prints a
one-line result, and exits non-zero on not-found / failure. New
discovery.FindPeer/Snapshot and client.SendMessageSync (returns the error
directly, incl. ErrPinRequired).

Bugfix surfaced by the above: the official LocalSend client answers a
message prepare-upload with HTTP 204 No Content (the text rides in the
preview field, nothing to upload). prepareUpload only accepted 200, so
message sends to official peers failed with "prepare-upload status 204"
in BOTH the new headless path and the existing TUI. Now treats 204 as
success (empty response).

Desktop notifications: a running receiver raises a notify-send
notification on an incoming message or file offer, so mako shows it on
Omarchy/Hyprland even when the TUI isn't focused. New internal/notify
(best-effort; self-disabling on headless boxes with no notify-send /
session bus). Off-switch: --no-notify flag, cfg.NoNotify, and a Settings
'n' toggle wired to a live atomic gate via Controller.SetNotify so it
takes effect without a restart.

Tests: discovery/find_test, client/message_sync_test,
client/prepare_204_test, app/events_test. Race-clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-29 14:13:43 +01:00

6.9 KiB
Raw Blame History

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:53317 plus the HTTP /register handshake, with peer aging.
  • Receive — incoming files are accepted via a prompt (or auto-accepted) and written to the receive directory, with live progress.
  • Send — pick a peer, stage files (or whole folders) with a built-in file picker, and upload them with progress, rate and ETA. Folders are sent recursively with their structure preserved on the receiver.
  • 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 via notify-send, so a backgrounded receiver still gets your attention. Best-effort and self-disabling on headless boxes; turn it off with --no-notify or the n key 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; only the Charm TUI libraries are external dependencies.

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). Override the location with BIN_DIR=/usr/local/bin, or pin a version with OMARCHY_SEND_VERSION=v0.1.0.

The installer is a short shell script fetched over HTTPS; read it first if you prefer — it lives at install.sh in 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.

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

  • 15 or tab — switch between Devices / Transfers / Manage / Messages / Settings
  • Peers: enter send to the selected peer · m message · v send clipboard · r refresh · / filter
  • PIN-protected peers: messages prompt for the PIN and retry, just like file sends
  • Send picker: enter stage a file · a add the current folder · backspace unstage · S send · esc back
  • Incoming prompt: y accept · n reject
  • Transfers: c clear finished
  • Messages: enter read the full message · y copy it to the clipboard · d delete it (incoming messages arrive automatically, with a footer notice)
  • Manage: space mark file/folder · a mark all · d delete marked (or the one under the cursor) · r refresh · / filter — deletion asks to confirm first
  • Settings: e edit (alias / receive dir / PIN) · a toggle auto-accept · i toggle icons · n toggle notifications
  • Sending to a PIN-protected peer prompts for the PIN and retries
  • q quit

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).