{"id":49953045,"url":"https://github.com/bethropolis/kcd","last_synced_at":"2026-05-23T16:01:30.594Z","repository":{"id":352977004,"uuid":"1204071105","full_name":"bethropolis/kcd","owner":"bethropolis","description":"A lightweight, fully headless KDE Connect daemon written in Go. Perfect for minimal window managers (Sway/Hyprland), and terminal automation.","archived":false,"fork":false,"pushed_at":"2026-05-17T00:28:21.000Z","size":363,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-17T20:58:22.925Z","etag":null,"topics":["hyprland","kde-connect","sway","systemd","waybar"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bethropolis.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-04-07T16:59:35.000Z","updated_at":"2026-05-17T00:28:26.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/bethropolis/kcd","commit_stats":null,"previous_names":["bethropolis/kcd"],"tags_count":9,"template":false,"template_full_name":null,"purl":"pkg:github/bethropolis/kcd","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bethropolis%2Fkcd","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bethropolis%2Fkcd/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bethropolis%2Fkcd/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bethropolis%2Fkcd/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bethropolis","download_url":"https://codeload.github.com/bethropolis/kcd/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bethropolis%2Fkcd/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33402174,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-23T04:15:53.637Z","status":"ssl_error","status_checked_at":"2026-05-23T04:15:53.242Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["hyprland","kde-connect","sway","systemd","waybar"],"created_at":"2026-05-17T20:39:25.778Z","updated_at":"2026-05-23T16:01:30.588Z","avatar_url":"https://github.com/bethropolis.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# kcd - Headless KDE Connect Daemon\n\n[![Go Version](https://img.shields.io/badge/Go-1.25%2B-00ADD8?style=for-the-badge\u0026logo=go\u0026logoColor=white)](https://golang.org)\n[![Protocol](https://img.shields.io/badge/KDE%20Connect-v8-4CAF50?style=for-the-badge\u0026logoColor=white)](https://valent.andyholmes.ca/documentation/protocol.html)\n[![License](https://img.shields.io/badge/License-MIT-F7DF1E?style=for-the-badge\u0026logoColor=black)](LICENSE)\n[![Release](https://img.shields.io/github/v/release/bethropolis/kcd?style=for-the-badge\u0026logo=github\u0026color=181717\u0026logoColor=white)](https://github.com/bethropolis/kcd/releases/latest)\n[![Build](https://img.shields.io/github/actions/workflow/status/bethropolis/kcd/ci.yml?style=for-the-badge\u0026logo=githubactions\u0026logoColor=white\u0026label=build)](https://github.com/bethropolis/kcd/actions/workflows/ci.yml)\n[![GHCR](https://img.shields.io/badge/container-ghcr.io-2496ED?style=for-the-badge\u0026logo=docker\u0026logoColor=white)](https://github.com/bethropolis/kcd/pkgs/container/kcd)\n[![Platforms](https://img.shields.io/badge/Platform-Linux-6e40c9?style=for-the-badge\u0026logoColor=white)](https://github.com/bethropolis/kcd)\n\n`kcd` is a lightweight, headless implementation of the [KDE Connect protocol v8](https://kdeconnect.kde.org/) written in Go. It lets Linux servers, containers, and minimal desktop environments participate in the KDE Connect ecosystem without a GUI, a full KDE installation, or heavy D-Bus dependencies.\n\n## Features\n\n| Plugin / Feature | What it does |\n|---|---|\n| **Battery** | Monitor remote device charge and charging state |\n| **Clipboard** | Bi-directional sync (Wayland via `wl-copy`, X11 via `xclip`) |\n| **Notifications** | Forward phone notifications to the desktop via `notify-send`\u003cbr\u003e\u003e Desktop notification icons require `libnotify ≥ 0.8.0` (Ubuntu 22.04+, Fedora 36+). Older versions receive text-only notifications. |\n| **Share** | Receive files and URLs from the phone; send local files to it |\n| **RunCommand** | Execute pre-configured local shell commands triggered from your phone |\n| **MPRIS** | Control desktop media players via D-Bus **and** control phone music (play/pause/next/prev/volume/seek) from the desktop CLI |\n| **Mousepad** | Use the phone as a wireless trackpad and keyboard |\n| **Find My Phone** | Ring the phone to locate it |\n| **Telephony** | Get call and SMS notifications on the desktop |\n| **SMS** | Send SMS messages via the phone |\n| **SFTP** | Browse the phone's filesystem |\n| **Lock / Unlock** | Lock and unlock the desktop session |\n| **Ping** | Simple connectivity check |\n| **Connectivity** | Phone signal strength and network type reporting |\n| **System Volume** | Control desktop audio volume from the phone |\n| **Send Notification** | Push a notification from the PC to the phone |\n| **Auto-reconnect** | Paired devices reconnect automatically after dropping |\n\nDiscovery is dual-mode: **UDP broadcast** (port 1716) and **mDNS/Zeroconf** (`_kdeconnect._udp`), so `kcd` works on both simple home networks and restricted environments (corporate Wi-Fi, Docker, university networks) where broadcast packets are dropped.\n\n\u003e [!NOTE]\n\u003e Broadcast is off by default. It only runs during `kcd pair` (listen mode) and stops immediately after. The UDP/mDNS **listener** stays always-on, so paired devices reconnect automatically via remembered IPs at 0.0% idle CPU.\n\n---\n\n## Installation\n\n\n### From source (Recommended)\n```bash\ngit clone https://github.com/bethropolis/kcd.git\ncd kcd\n./scripts/install.sh\n```\n\n\n### Arch Linux\n\nInstall from the AUR using your preferred helper:\n\n```bash\nyay -S kcd-bin\n```\n\n### Container\n\nMulti-arch images on GHCR: [`docs/CONTAINER.md`](docs/CONTAINER.md)\n\n### Binary releases\n\nDownload the latest pre-built binary from [GitHub Releases](https://github.com/bethropolis/kcd/releases).\n\n\n---\n\n## Firewall\n\nKDE Connect needs three port ranges open:\n\n| Port | Protocol | Direction | Purpose |\n|---|---|---|---|\n| 1716 | UDP | bidirectional | Device discovery broadcast |\n| 1716 | TCP | bidirectional | Encrypted control channel |\n| 1739–1764 | TCP | inbound | File transfer side-channels |\n\n\u003e **Installed via .deb, .rpm, or AUR?** The firewall rules are already in place\n\u003e — nothing to do on your end. These steps are only needed for manual installs.\n\n### UFW (Ubuntu / Debian)\n```bash\nsudo cp packaging/ufw-kcd /etc/ufw/applications.d/kcd\nsudo ufw allow kcd\n```\n\n### firewalld (Fedora / RHEL)\n```bash\nsudo cp packaging/firewalld-kcd.xml /etc/firewalld/services/kcd.xml\nsudo firewall-cmd --permanent --add-service=kcd\nsudo firewall-cmd --reload\n```\n\n### Manual\n```bash\nsudo ufw allow 1716/udp\nsudo ufw allow 1716/tcp\nsudo ufw allow 1739:1764/tcp\n```\n\n---\n\n## Quick Start\n\n### 1. Start the daemon\n\nIf you installed via the script, `.deb`, `.rpm`, or AUR, the systemd user service\nis already set up — enable and start it:\n\n```bash\nsystemctl --user enable --now kcd\n```\n\nCheck that it's running:\n\n```bash\nsystemctl --user status kcd\n```\n\nTo run in the foreground instead (for testing):\n\n```bash\nkcd daemon\n```\n\n\n### 2. Discover your phone\n\nOpen the KDE Connect app on your Android device and make sure it is on the same network. Then:\n\n```bash\nkcd devices\n```\n\n```\nDEVICE ID                            NAME              TYPE       STATE      CONNECTED\n---------------------------------------------------------------------------------------------------\na1b2c3d4_e5f6_7890_abcd_ef1234567890 Pixel 8 Pro       phone      Unpaired   true\n```\n\n### 3. Pair\n\nTwo ways to pair:\n\n**A. Send pair request to a discovered device:**\n```bash\nkcd pair a1b2c3d4_e5f6_7890_abcd_ef1234567890\n```\n\nyou can accept the pair request on your phone\n\n\n**B. Listen mode — accept any incoming request (headless/server):**\n```bash\nkcd pair\n```\n\nBroadcast starts automatically so the phone can find the PC. Accept on the phone, the CLI confirms and exits. Broadcast stops immediately. Press Ctrl+C to cancel.\n\n\n### 4. Use it\n\n```bash\n# Check daemon health and dependencies\nkcd doctor\n\n# Show daemon uptime, version, connected devices, and plugins\nkcd status\n\n# Push your clipboard to the first connected phone\nkcd clipboard\n\n# Send a file\nkcd share \u003cdevice-id\u003e ~/Pictures/photo.jpg\n\n# Ring the phone\nkcd findmyphone \u003cdevice-id\u003e\n\n# Watch live events\nkcd watch\n\n# Watch device connect/disconnect live\nkcd devices --watch\n\n# List MPRIS players on the phone and control playback\nkcd mpris list\nkcd mpris play\nkcd mpris pause\nkcd mpris next\nkcd mpris previous\n```\n\n---\n\n## Configuration\n\nThe daemon reads `$XDG_CONFIG_HOME/kcd/kcd.toml` (typically `~/.config/kcd/kcd.toml`). All settings are optional — sensible defaults are applied automatically.\n\n```toml\ndevice_name = \"my-desktop\"\ndevice_type = \"desktop\"        # desktop | laptop | phone | tablet | tv\ntcp_port    = 1716\nlog_level   = \"info\"           # debug | info | warn | error | quiet\n\n# Directory where received files are saved.\ndownload_dir = \"~/Downloads/kcd\"\n\n# Reload [commands] and log_level without restarting: kill -HUP $(pidof kcd)\n\n[plugins]\n# battery      = true\n# clipboard    = true\n# ... (see example config for full list)\n\n# ─── Detailed Plugin Configuration ────────────────────────────────────────────\n# Each plugin has its own section for fine-tuning behavior.\n\n[battery]\n# notify_low   = true\n# notify_full  = true\n# low_urgency  = \"critical\"\n\n[notification_plugin]\n# fetch_icons  = true\n# expire_ms    = -1\n\n[share]\n# auto_open    = false\n# open_command = \"xdg-open\"\n\n[sftp]\n# auto_open    = true\n# mount_dir    = \"/home/user/mnt\"\n\n[commands]\nuptime   = \"uptime\"\nlock     = \"loginctl lock-session\"\n\n[notifications]\n# \"*\" = \"show\"\n\n# See packaging/kcd.example.toml for the full annotated reference of all settings.\n```\n\nSee [`packaging/kcd.example.toml`](packaging/kcd.example.toml) for the full annotated reference.\n\n---\n\n## Desktop Integrations\n\n### Nautilus / GNOME Files\n\nMost of the installation methods, add the [kcd nautilus plugin](packaging/nautilus-kcd.py) which allows you to right-click any file in Nautilus to send it directly to a paired device.\n\n### Waybar (phone battery widget)\n\nAdd to `~/.config/waybar/config`:\n```json\n\"custom/phone-battery\": {\n    \"exec\": \"kcd watch --events=battery.update | jq -r 'select(.type==\\\"battery.update\\\") | \\\"\\\\(.payload.charge)%\\\" + (if .payload.charging then \\\" \\\" else \\\"\\\" end)'\",\n    \"restart-interval\": 0,\n    \"format\": \"󰏚 {}\",\n    \"return-type\": \"\"\n}\n```\n\nA ready-made config snippet, python script and stylesheet are in [`kcd-waybar-integration/`](kcd-waybar-integration/).\n\n### Tiling WM shortcuts (Sway / Hyprland)\n\n```bash\n# Push clipboard to the first connected phone\nbindsym Super+c exec kcd clipboard\n\n# Ring the phone\nbindsym Super+Shift+f exec kcd findmyphone\n\n# Control phone music playback\nbindsym Super+Shift+period exec kcd mpris next\nbindsym Super+Shift+comma exec kcd mpris previous\nbindsym Super+Shift+m exec kcd mpris toggle\n```\n\n### Custom event scripts\n\n```bash\nkcd watch --json | while read -r event; do\n    type=$(echo \"$event\" | jq -r '.type')\n    case \"$type\" in\n        battery.update)\n            charge=$(echo \"$event\" | jq -r '.payload.charge')\n            notify-send \"Phone battery\" \"${charge}%\"\n            ;;\n        telephony.ringing)\n            echo \"$event\" | jq -r '.payload | \"Call from \\(.contactName // .phoneNumber)\"'\n            ;;\n    esac\ndone\n```\n\n---\n\n## Events\n\n`kcd watch --json` streams NDJSON events. All events include `type`, `timestamp` (RFC3339), and `deviceId` fields.\n\n| Event type | Payload fields | Description |\n|---|---|---|\n| `device.added` | `name`, `type` | New device seen for the first time |\n| `device.removed` | — | Device unpaired and removed |\n| `device.connected` | `name`, `type` | TCP connection established |\n| `device.disconnected` | — | Connection dropped |\n| `pair.requested` | — | Phone sent a pairing request |\n| `pair.accepted` | — | Pairing completed on both sides |\n| `pair.rejected` | — | Pairing denied or cancelled |\n| `battery.update` | `charge`, `charging` | Battery reading received |\n| `battery.threshold` | `charge`, `charging`, `event` | Low (event=1) or full (event=2) |\n| `notification` | `appName`, `title`, `text`, `requestReplyId` | Phone notification forwarded |\n| `notification.canceled` | `id` | Phone dismissed a notification |\n| `share.progress` | `file`, `current`, `total` | File transfer in progress (~2/sec) |\n| `share.complete` | `file`, `path` | File transfer finished |\n| `share.text` | `text` | Plain text received |\n| `share.url` | `url` | URL received |\n| `ping.received` | — | Ping arrived |\n| `telephony.ringing` | `contactName`, `phoneNumber` | Incoming call |\n| `telephony.missed` | `contactName`, `phoneNumber` | Missed call |\n| `telephony.canceled` | — | Call ended |\n| `connectivity.update` | `signal`, `networkType` | Signal strength report |\n| `mpris.update` | `player`, `title`, `artist`, `album`, `isPlaying`, `pos`, `length`, `volume` | Phone now playing state changed |\n| `volume.update` | `name`, `volume`, `muted` | Desktop volume changed from phone |\n| `sftp.mount` | `uri`, `ip`, `port`, `user`, `password`, `path` | SFTP credentials received |\n\n---\n\n## Security\n\n- **TLS everywhere** — all traffic is encrypted. Plaintext is only used for the initial identity exchange before the TLS upgrade.\n- **Certificate fingerprinting** — trust is established by comparing the SHA-256 fingerprint of each peer's self-signed certificate during pairing. No CA required.\n- **Path sanitisation** — filenames received via the Share plugin are strictly sanitised to prevent path traversal attacks.\n- **Memory-safe transfers** — large file transfers stream directly to disk to prevent OOM conditions.\n\n---\n\n## Performance\n\n`kcd` is optimised for extremely low resource usage. Broadcast is off by default (only enabled during `kcd pair` listen mode for discovery), so the daemon sits at **0.0% idle CPU** in normal operation. Paired phones reconnect automatically via the last known IP without any broadcast chatter.\n\n---\n\n## Manual Connection\n\nOn networks that block broadcast packets (corporate Wi-Fi, Docker bridges, university networks):\n\n```bash\n# Enter the PC's IP in the KDE Connect app: ⋮ → Add device by IP\n# Then on the PC:\nkcd connect 192.168.1.100\n```\n\n---\n\n## Further Reading\n\n| Document | Description |\n|---|---|\n| [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) | System architecture, plugin system, event bus, IPC protocol |\n| [`docs/CLI.md`](docs/CLI.md) | Full CLI reference and sub-commands |\n| [`docs/CONTAINER.md`](docs/CONTAINER.md) | Running kcd in Docker / Podman |\n| [`packaging/kcd.example.toml`](packaging/kcd.example.toml) | Annotated configuration reference |\n\n---\n\n## License\n\n[MIT](./LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbethropolis%2Fkcd","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbethropolis%2Fkcd","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbethropolis%2Fkcd/lists"}