Files, messages, photos, a deck of buttons, clipboard, screens, webcam, microphone and terminal between your Android phone and your Linux computer. Over Wi-Fi or a USB cable, with no account, no cloud and no server.
Install · What it does · Screenshots · How it works · Build · Contributing
Note
This repository is the Linux side: the background service, the GTK app (GNOME and most desktops) and the Qt app (KDE Plasma). The phone needs Linksy for Android, from linksy-releases.
On the computer, one line finds your system and desktop, asks which app you want, and installs it with one password:
curl -fsSL https://linksy.diary.mg/install.sh | shOr by hand, from linksy-releases (linux-v… releases; its README has the commands for each distribution):
| System | What to get |
|---|---|
| Ubuntu 24.04+, Mint 22+, Debian 13+ | .deb: linksy-common plus linksy (GTK) or linksy-qt (Plasma) |
| Fedora 41+, openSUSE Tumbleweed | .rpm: the same two packages |
| Arch | the AUR's linksy or linksy-qt |
| Anything else, or older | the Flatpak, or the tarball without root |
On the phone, install the latest .apk from linksy-releases, open Linksy on both, and pair: both screens show the same code.
Tip
Only download Linksy from these repositories, linksy.diary.mg or the AUR. A copy from anywhere else could be modified.
Requirements and the Flatpak
The .deb, .rpm and tarball need x86_64 with glibc 2.39+, GTK 4.14+ and libadwaita 1.5+; the
Qt app, Qt 6.8+ and KDE Frameworks 6.13+. The background service starts with your session.
The Flatpak does everything the packages do: it has host access (org.freedesktop.Flatpak),
so Finish Setup turns on starting at login, the webcam driver and the USB cable there too,
and the terminal for phones is the computer's own shell.
The command line is linksy (linksy --help). The packages put it in /usr/bin, the tarball
and scripts/install-local.sh in ~/.local/bin (which needs to be in your PATH). The Flatpak
keeps it inside: flatpak run --command=linksy mg.diary.linksy.Linksy devices, or an alias
for that in your shell. A build from source has it at target/release/linksy until installed.
docs/dependencies.md lists everything Linksy relies on, with the packages for each distribution, for installing it by hand.
Firewall: allow UDP 47200 (Linksy) and UDP 5353 (mDNS). Finish Setup does it for you; by hand
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.
- A page for each phone. Use As, Inbox, Gallery, Files, Transfers, History and Settings, in tabs, with how it's connected and its battery at the top.
- Messages. The phone's chats, texts and mail in one Inbox, made from its notifications: WhatsApp, Telegram, Signal, the SMS app, Gmail and others. Answer from the computer where the app allows it; codes that arrive are copied for you. Nothing is kept on disk.
- Photos and files. The phone's photos and videos by album, saved to Pictures in a click, and a file manager for the folder it shares: copy both ways, rename, delete.
- Deck. The phone as a deck of buttons for the computer: media, volume, microphone, sound output, lock, Do Not Disturb, Wi-Fi, Bluetooth, power modes, restart, and your own commands. Build it on the computer, on a phone drawn true to size, in five looks (the editor is in the GTK app for now).
- Share. Files and folders both ways, resumable and checked; the clipboard (text, images, small files), automatically where the desktop allows; notifications. "Send with Linksy" in Files, Dolphin and Thunar.
- Use the phone as a second display for the computer, a webcam ("Linksy Camera" in every app, with the phone's camera controls) or a microphone ("Linksy Microphone").
- Screens. Watch another device's screen and take control of it, each asked for separately. A phone on the USB cable can be controlled from the computer with no developer options.
- Terminal. The computer's shell on the phone, behind a code set on the computer, allowed per phone.
- Find your phone. Ring it, loud even on silent, or locate it on a map: asked once, never tracked.
- Away from home. Paired devices still reach each other over the internet for a week after they last met on the same network. Screens, files, camera and microphone stay local unless allowed per device.
- Every desktop. GNOME, KDE Plasma, Hyprland, Sway, niri, X11 desktops and more (docs/desktop-support.md), a tray icon, Update Now.
With no window open, Linksy is one small process (about 20 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.
Front ends come and go; the service does the work. docs/protocol.md is the exact wire
protocol, and the handoff for the Android app.
You only need this to change the code. To use Linksy, see Install.
Rust stable (edition 2024). The service, CLI and core build anywhere:
cargo build --release # linksyd + linksy
cargo test # unit + end-to-end testsTo leave away from home out entirely (no relay code, nothing past the local network and
the cable), build the service with cargo build --release -p linksyd --no-default-features.
The 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.
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/.
| 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-qt |
linksy-qt, the Qt 6/Kirigami app for KDE Plasma. |
crates/linksy-screen |
Screens, cameras and microphones, started only while sharing: capture and H.264 encoding (GStreamer: the ScreenCast portal, or the X display on X11), and input (the RemoteDesktop portal, XTest on X11, the virtual pointer and keyboard on Hyprland and Sway). |
crates/linksy-setup |
Finish Setup: what each feature needs, and adding it with one password. Shared by both apps. |
crates/linksy-host |
Programs and files on the computer, from the Flatpak too, and pkexec with Linksy's own password prompt. |
crates/linksy-upgrade |
Update Now and linksy upgrade. |
crates/linksy-i18n, linksy-news, linksy-logs |
Translations, What's New, and logs.txt for bug reports. |
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. |
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.
What's next is in ROADMAP.md.
Done so far
- 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; with nautilus-python, else → Scripts), Dolphin and Thunar (Send To), "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, from the service (GNOME shows it with the AppIndicator extension)
- Qt 6 app for KDE Plasma
- Every desktop: X11 (screens and control without a portal), Hyprland and Sway (control through the compositor's virtual pointer and keyboard), niri, and Linksy's own password prompt where no polkit agent runs (docs/desktop-support.md)
- A Flatpak that does everything the packages do
- Update Now and
linksy upgrade: the new version checked against the release's checksums and installed with one password - 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
Bug reports, translations and pull requests are welcome: see CONTRIBUTING.md. If Linksy helps you, a star or telling a friend helps it reach more people.
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.







