Your devices, connected. Share files, notifications and more between nearby devices, directly over the local network, with no account, cloud or server.
| Path | What it is |
|---|---|
crates/linksy-core |
Device identity, discovery (mDNS), pairing, QUIC transport, file transfer. No UI. |
crates/linksyd |
The always-on background service. Knows which devices are nearby, receives files, shows desktop notifications. |
crates/linksy-ipc |
The local socket protocol between the service and its front ends. |
crates/linksy-cli |
linksy, the command-line front end. |
crates/linksy-gtk |
linksy-app, the GTK4/libadwaita app for Linux. |
crates/linksy-screen |
Screen capture and H.264 encoding (GStreamer, ScreenCast portal), started only while sharing. |
brand/ |
Logo and brand assets. |
data/ |
Desktop entry, icons, systemd user unit. |
docs/protocol.md |
Handoff for the Android app: product, feature status and the exact wire protocol. |
Front ends come and go; the service does the work. With no window open, Linksy is one small process (about 6 MB on disk, 7 MB of memory, no CPU when idle).
- Identity. Each device makes a self-signed certificate on first run. Its SHA-256 fingerprint is the device id. There is no central authority.
- Presence. Devices advertise
_linksy._udp.local.over mDNS and re-check every 45 s that the devices they see are still there. That's all that happens while idle. - Connect on demand. Sending something dials the device at every address known for it (announced ones and the last one that worked) in parallel. A connection with nothing going on closes after a minute. "Stay connected" in Preferences keeps links open instead, for the lowest latency on mains power.
- Pairing. Both screens show a 6-digit code derived from the encrypted session, and both users confirm it. A device in the middle would see a different code.
- Transport. QUIC (TLS 1.3, mutual authentication). Each transfer or message gets its own stream on the connection, so a large file never blocks a notification.
- Transfers. Files are streamed from disk with a BLAKE3 check per file. Interrupted transfers resume, and a file only appears once its checksum matches.
- Consent. Pairing always asks both users. Incoming files ask first, in the app or through a desktop notification with Accept/Decline buttons, unless "Accept From Paired Devices" is on.
Download the latest Linux release from
LinkSy-mg/linksy-releases
(linux-v… tags), in the format that suits your system:
flatpak install --user linksy-0.5.5.flatpak # any distribution
sudo apt install ./linksy_0.5.5_amd64.deb # Ubuntu 24.04+, Debian 13+ (the Qt app: Ubuntu 25.04+)
sudo dnf install ./linksy-0.5.5-1.x86_64.rpm # Fedora 41+
sudo zypper install --allow-unsigned-rpm ./linksy-0.5.5-1.suse.x86_64.rpm # openSUSE Tumbleweed
tar xzf linksy-0.5.5-linux-x86_64.tar.gz && linksy-0.5.5-linux-x86_64/install.sh # into ~/.localThe .deb, .rpm and tarball need x86_64 with glibc 2.39+, GTK 4.14+ and libadwaita 1.5+. The background service starts with your session; the Flatpak sets that up the first time it opens.
To cut a release: add the version's section to CHANGELOG.md and the metainfo's
<releases>, bump version in Cargo.toml, commit, and run scripts/publish-release.sh. It
tags vX.Y.Z and pushes it; GitHub (the Packages workflow) builds every package and the
Flatpak, installs the packages on every supported distribution, and when all of that passes
publishes the release here and, as linux-vX.Y.Z (not marked latest, which belongs to the
Android APKs), on linksy-releases. Flathub builds from the tag with
packaging/flatpak/mg.diary.linksy.Linksy.yml. scripts/package-linux.sh and
scripts/package-flatpak.sh still build everything locally, to try a package.
Rust stable (edition 2024). The service, CLI and core build anywhere:
cargo build --release # linksyd + linksy
cargo test # unit + end-to-end testsThe GTK app and the screen helper need GTK ≥ 4.14, libadwaita ≥ 1.5 and GStreamer ≥ 1.22 headers:
sudo dnf install gtk4-devel libadwaita-devel gstreamer1-devel gstreamer1-plugins-base-devel # Fedora
sudo apt install libgtk-4-dev libadwaita-1-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev
sudo zypper install gtk4-devel libadwaita-devel gstreamer-devel gstreamer-plugins-base-devel # openSUSE
cargo build --release -p linksy-app -p linksy-screenAt run time, screen mirroring uses GStreamer plugins: pipewiresrc (pipewire-gstreamer),
an H.264 encoder (VA-API, x264 or OpenH264), an H.264 decoder (libav, VA-API or OpenH264)
and gtk4paintablesink (gstreamer1-plugin-gtk4).
Without root, a toolbox works: toolbox create linksy-dev, then
toolbox run -c linksy-dev sudo dnf install -y gtk4-devel libadwaita-devel gcc, then
build with toolbox run -c linksy-dev cargo build -p linksy-app.
linksy-qt is a second window on the same service, in Qt 6 and Kirigami, for Plasma. It
needs Qt 6 (base and declarative), Kirigami, Kirigami Addons and KDE's desktop style, and
the lld linker:
sudo dnf install qt6-qtbase-devel qt6-qtdeclarative-devel kf6-kirigami kf6-kirigami-addons kf6-qqc2-desktop-style lld
QMAKE=qmake6 cargo build -p linksy-qtWithout root, packaging/qt/Containerfile is that environment in a container (its header
says how), and scripts/qt-shot.sh renders the app in it against two test services.
scripts/install-local.sh # installs to ~/.local and enables the user service
linksy-app # the app
linksy devices # or the CLI
linksy pair "Other Laptop"
linksy send "Other Laptop" ~/Pictures/photo.jpg
linksy clip "Other Laptop" "some text"
linksy settings auto-accept onOr run without installing: cargo run -p linksyd in one terminal, then
cargo run -p linksy -- devices.
Firewall: allow UDP 47200 (Linksy) and UDP 5353 (mDNS). On Fedora and openSUSE (firewalld):
sudo firewall-cmd --permanent --add-port=47200/udp, sudo firewall-cmd --permanent --add-service=mdns,
then sudo firewall-cmd --reload.
On openSUSE, reading the firewall's zone needs the administrator's password (polkit), so
Finish Setup doesn't look: it shows the firewall as to set up until Linksy has opened it once.
- Discovery, presence, pairing (code or by address), persistent identities
- Connect on demand with idle close; optional stay-connected
- File and folder transfer with progress, integrity check, resume
- Device-to-device notifications
- Background service, desktop notifications, CLI
- GTK4/libadwaita app: device pages with an activity timeline, Add Device hub, Preferences
- Activity history kept by the service (
linksy history) - Clipboard sharing (text, images and single files up to 10 MB, on demand: app ⋯ menu or
linksy clip; received content is copied via wl-copy/xclip/xsel) - Automatic clipboard sync, computer to phone, where the desktop allows watching the clipboard (KDE, wlroots; not GNOME)
- "Send with Linksy" in Files (right-click → Scripts), "Open With Linksy" for files and folders
- Away from home: paired devices reach each other over the internet (iroh, Linksy's relay), for a week after they last met on the same network; screens, files, camera and microphone stay local unless allowed per device
- Locate a phone (
linksy locate), asked once, never tracked - Terminal from the phone (
linksy terminal): a shell here behind a code set on this computer, allowed per phone - Finish Setup: everything a feature needs (packages, camera device, USB, firewall, autostart) in one go
- QR-code pairing
- Android app (Flutter, separate repository; see
docs/protocol.md) - Tray icon (GNOME has none by default)
- Screen mirroring between computers (View Screen; the sharer always approves)
- Remote control of a mirrored screen (Take Control; asked for separately)
- Sidecar: another device as a second display (virtual monitor, driven from that device)
- Another device's camera as a webcam ("Linksy Camera" in PipeWire apps), with its camera controls on the computer; the Android side is in
docs/protocol.md - Another device's microphone as a microphone ("Linksy Microphone",
linksy mic) - Phones over a USB cable (Android Open Accessory, no developer options): lower latency, no network needed
scripts/ui-scene.sh <dir>starts two local services ("This Laptop" and "Studio Desktop") and pairs them. Point the app or CLI at one withLINKSY_SOCKET=<dir>/a.sock.scripts/ui-shot.sh <socket> <out.png> [delay-ms] [light|dark] [files…]renders the app on a headless Wayland compositor (weston, inside the toolbox) and saves a screenshot. Nothing appears on screen.
Screenshots are in docs/screenshots/.
Linksy is open source under the GNU Affero General Public License v3.0 or later. The open-source
libraries it builds in are credited, with their licenses, in
THIRD-PARTY-NOTICES; regenerate it with
scripts/third-party-notices.py > THIRD-PARTY-NOTICES after Cargo.lock changes.
