An Omarchy Quattro bar-widget plugin for
kcd, a KDE Connect protocol
daemon written in Go. Surfaces your phone in the bar and in a
dashboard panel: device status, battery, now-playing card with
transport controls, and single-press quick actions.
| Catppuccin | Flexoki | Vantablack |
|---|---|---|
![]() |
![]() |
![]() |
- Omarchy Quattro (
omarchy-shell) kcddaemon >= 1.22.0 with a paired phonesshfs, only for the Files quick action
The Files toggle needs a daemon that publishes SFTP mount state
(sftp.mounted / sftp.unmounted, in 1.22.0). On an older daemon the
mount still works, but the tile stays on "Files" instead of flipping to
"Unmount"; tapping it again re-opens the folder rather than failing.
This plugin is a frontend, you need to install the daemon first.
Install from the AUR using your preferred helper:
yay -S kcd-binThen enable the socket so the daemon starts on demand at login (the service unit stays installed for activation, but disabled):
systemctl --user enable --now kcd.socketCold client commands (including this panel's probes) summon the daemon on first use, so there is normally nothing to start by hand.
For other configurations and protocol details, see the
official kcd repo.
omarchy plugin add https://github.com/bethropolis/omarchy-kcd-plugin.git --enable-
Bar shows battery level (dimmed when offline). Left-click toggles the panel, middle-click refreshes.
-
Panel header: phone, link icon (tooltip shows the phone's reported network type when available), battery, last-seen.
-
Media card: album art, title/artist, prev / play-pause / next, wave seeker with smooth playhead.
-
Quick actions, all live (they dim when the phone is unreachable): Ring, Screenshot, Clipboard, then Share and Files below. Files is a toggle: it mounts the phone's storage over SFTP (
sshfs) and opens it in your file manager, then turns into Unmount while the mount is live. Mount state comes from the daemon (sftp.mounted/sftp.unmountedevents), so the tile is never guessing; mounting is idempotent, so tapping twice just re-opens the folder. It needssshfsand a phone that granted storage permission, and reports failures as a desktop notification. Share picks one file with the native chooser (omarchy-file-select) and sends it viakcd share, reporting back as a desktop notification. Screenshot captures the focused monitor withgrim(after the panel hides itself) and sends the PNG the same way. Captures stage as temporary/tmpfiles (never the cache dir) becausekcd sharereturns on invitation while the daemon opens the file seconds later; the staged file is deleted onshare.complete(stale ones pruned after an hour, the rest vanish on reboot), and the notification only claims success then. -
No paired phone? Start pairing runs
kcd pair -y(auto-accepts the first request, then stops). Daemon down? Start daemon primes the socket, then the next probe wakes the daemon on its own. -
To unpair, press and hold the phone name in the panel header: the dashboard has no tile or menu for it. A confirm dialog appears (Cancel is preselected) before anything is sent, so a mis-hold costs you nothing. Unpairing revokes trust on the desktop, so the phone must accept the pairing again before it works.
-
Footer gear opens
kcd.tomlin Neovim. Footer right shows the livekcd <version>; click it to openbethropolis/kcdon GitHub. -
Scriptable through the shell like any widget (toggle the panel from a keybind, close it on lock):
The panel is event-driven end to end. It boots from one kcd watch --json
snapshot (devices with battery, media, signal and SFTP mount state) and then
stays live on watch events; the only CLI call left is kcd --version, used to
detect whether the binary is installed at all. No timers poll: an unhealthy
plugin spawns nothing, and steady-state idle CPU is 0% by construction.
Position is drift-free math from the daemon's anchor stamp (pos +
posAnchorMs), re-evaluated only while the panel is open and playing.
Long-running work (the watch stream, pairing listen mode) lives in managed
Process blocks in KcdIo.qml; one-shot sends go through
Quickshell.execDetached, and the flows that need failure handling (share,
screenshot, SFTP) go through the shell scripts so errors become
notifications rather than silence.
Pure parsing lives in Kcd.js (Qt-free, testable under bun):
bun test tests/| File | Purpose |
|---|---|
manifest.json |
Plugin contract (bar-widget → BarWidget.qml) |
BarWidget.qml |
Bar button, mirrors panel state |
Panel.qml |
Dashboard panel, owns all kcd IO |
QuickTile.qml |
Quick-action tile component (+ accent primary style) |
KcdMissing.qml / KcdUnpaired.qml |
Empty-state panels |
Kcd.js |
Device/track/event parsing + CLI argv builders |
kcd-share.sh |
Share flow: native pick → kcd share → notification |
kcd-sftp.sh |
Files flow: kcd sftp mount / unmount → classified failure notification |
kcd-screenshot-share.sh |
Screenshot flow: grim → /tmp stage → kcd share → delete on share.complete |
tests/kcd.test.js |
Bun suite for the Kcd.js helpers (bun test tests/) |
This repo bundles the official kcd client docs under docs/
(CLIENT_GUIDE.md, IPC_PROTOCOL.md), so anyone can extend the panel
with features skipped here. The pattern for a new quick action:
- Add an argv builder in
Kcd.jsnext totileCommand(pure function, covered bybun test tests/). - Add a
QuickTileinQuickActionsRow.qmlwith a FontAwesome-range glyph (the panel font lacks the Material block). - Wire the signal through
Panel.qmlinto aKcdIo.qmlspawn function, followingshareScreenshot().
Long-running work (watch streams, pairing listen mode) belongs in
managed Process blocks in KcdIo.qml. One-shot sends go through
Quickshell.execDetached like the tile commands.
omarchy plugin remove io.github.bethropolis.kcdThis deletes the plugin folder; the shell drops the bar widget
automatically. The kcd daemon and its pairing stay installed, remove
those separately if you no longer need them.
MIT. See LICENSE.


