Miracast daemon and CLI for Linux — like Windows
Win + K, but for your Wayland desktop.
Mirai is a lightweight, headless Miracast controller for Linux. It exposes a plain JSON-over-Unix-socket API that any shell, widget, or status bar (such as Quickshell or Hyprland panels) can talk to.
- Source mode — cast your Linux desktop to a Miracast sink (TV, dongle,
another PC…) just like Windows does with
Win + K. - Sink mode — make your Linux machine appear as a Miracast receiver, so you can mirror an Android / iOS / Windows device to it.
- Display selection — pick the monitor or window to share.
- Window / fullscreen — render the received stream the way you want.
- Wayland & PipeWire native — works on Hyprland, Sway, KDE Plasma and any XDG Desktop Portal compatible compositor.
Mirai does not ship a full GUI. It is meant to be embedded: bind a key in Hyprland, build a Quickshell widget, or drive it from scripts.
- Overview
- How it works
- Install
- Usage
- Quickshell / Hyprland integration
- Configuration
- Troubleshooting
- Inspirations & references
- License
| Feature | Status | Notes |
|---|---|---|
| Discover Miracast sinks | ✅ | MICE over mDNS/Avahi + NetworkManager P2P |
| Connect and cast screen | ✅ | Uses gnome-network-displays-stream (XDG Portal / PipeWire) |
| Receive Miracast stream | ✅ | Uses MiracleCast (miracle-wifid + miracle-sinkctl) |
| Render in window | ✅ | GStreamer / mpv |
| Render fullscreen | ✅ | mirai sink-mode fullscreen |
| Select monitor to share | ✅ | Through the XDG Desktop Portal dialog |
| Hyprland / Wayland / PipeWire | ✅ | Detects compositor and picks the right sink |
| Quickshell widget example | ✅ | See quickshell/Mirai.qml |
┌─────────────┐ JSON / Unix socket ┌──────────────┐
│ Hyprland │◄────────────────────────────►│ │
│ Quickshell │ │ mirai │
│ CLI │ │ daemon │
└─────────────┘ └──────┬───────┘
│ │
│ sink.py │ source.py
│ ┌──────────────────────┐ │ ┌─────────────────────┐
└───►│ miracle-wifid │ └──►│ NetworkManager │
│ miracle-sinkctl │ │ Avahi discovery │
│ + GStreamer player │ │ gnome-network- │
└──────────────────────┘ │ displays-stream │
└─────────────────────┘
The daemon is a single Python process. Clients send one-line JSON messages over a Unix socket and receive JSON replies. Events (sink found, connected, disconnected, etc.) are pushed to all connected clients.
curl -fsSL https://raw.githubusercontent.com/Leriart/Mirai/main/install.sh | shThe installer detects your distribution and installs dependencies when a known
package manager is available. Supported: Arch / Manjaro, Debian / Ubuntu,
Fedora, openSUSE, Alpine, Void, NixOS (via nix run), and generic fallback.
If you prefer a different prefix:
curl -fsSL https://raw.githubusercontent.com/Leriart/Mirai/main/install.sh | PREFIX=/usr/local shgit clone https://github.com/Leriart/Mirai.git
cd Mirai
sudo make install
# or
sudo ./install.sh- Python >= 3.10
dbus-python(usuallypython-dbusin distro packages)wpa_supplicantwith P2P supportmiraclecast(miracle-wifid,miracle-sinkctl)gstreamer(gst-launch-1.0,gst-inspect-1.0)gnome-network-displays(for source / casting mode only)NetworkManagerandavahi(recommended for discovery)mpv(optional alternative player)
Add the flake input:
{
inputs.mirai.url = "github:Leriart/Mirai";
outputs = { self, nixpkgs, mirai, ... }: {
nixosConfigurations.myhost = nixpkgs.lib.nixosSystem {
modules = [
mirai.nixosModules.default
{
services.mirai.enable = true;
services.mirai.user = "myuser";
}
];
};
};
}Or run it imperatively:
nix run github:Leriart/MiraiSink mode needs root privileges to manage Wi-Fi P2P.
# Foreground (useful for debugging)
sudo mirai daemon --foreground
# Background
sudo systemctl enable --now miraimirai status # show daemon state, displays and sinks
mirai displays # list connected monitors
mirai logs # tail the daemon log
# Sink: receive a Miracast stream on this machine
mirai sink-start
mirai sink-mode window # or fullscreen
mirai sink-stop
# Source: cast this machine to a Miracast sink
mirai source-scan # discover sinks
mirai source-list # show discovered sinks
mirai source-connect <id> --display HDMI-A-1
mirai source-disconnect
# Stop everything and quit
mirai stop
mirai quitConnect to /tmp/mirai.sock (or $MIRAI_SOCK) and send newline-delimited
JSON. Example with socat:
printf '{"cmd":"status"}\n' | socat - UNIX-CONNECT:/tmp/mirai.sockSupported commands:
| Command | Arguments | Description |
|---|---|---|
status |
— | Full state |
displays |
— | List monitors |
sink_start |
{link?: int} |
Start Miracast sink |
sink_stop |
— | Stop sink |
sink_mode |
{mode: "window" | "fullscreen"} |
Set render mode |
source_scan |
{timeout?: int} |
Scan for sinks |
source_connect |
{sink_id, display?} |
Connect to sink |
source_connect_uri |
{uri, display?} |
Connect by URI |
source_disconnect |
— | Disconnect source |
stop_all |
— | Stop all sessions |
quit |
— | Stop daemon |
Events pushed by the daemon:
{"type": "source", "event": "sink_found", "data": {...}}
{"type": "sink", "event": "connected", "data": {...}}A ready-to-use widget is in quickshell/Mirai.qml. To install it:
mkdir -p ~/.config/quickshell/mirai
ln -s /usr/share/mirai/quickshell/Mirai.qml ~/.config/quickshell/mirai/shell.qml
quickshell -c miraiExample Hyprland key bindings:
bind = SUPER, K, exec, mirai source-scan
bind = SUPER SHIFT, K, exec, ~/.config/hypr/scripts/mirai-toggle.shA small helper script is included in scripts/mirai-toggle.sh.
Configuration is mostly done through environment variables:
| Variable | Default | Description |
|---|---|---|
MIRAI_SOCK |
/tmp/mirai.sock |
Unix socket path |
MIRAI_LOG |
/tmp/mirai.log |
Daemon log path |
MIRAI_SINK_NAME |
Mirai Display |
Name shown to Miracast sources |
MIRAI_SOURCE_NAME |
Mirai |
Name advertised when casting |
MIRAI_SINK_PLAYER |
auto |
Player backend: gst, mpv, auto |
GNOME_NETWORK_DISPLAYS_STREAM |
/usr/lib/gnome-network-displays-stream |
Path to GNOME source helper |
MiracleCast needs root to create a P2P group owner. Run the daemon with
sudo, pkexec, or the provided systemd service.
- Make sure the TV/dongle is in Miracast / screen-mirroring mode.
- Verify Avahi is running:
systemctl status avahi-daemon. - On some hardware, MICE is supported but P2P discovery is not; Mirai lists both separately.
Use mirai sink-mode fullscreen, or set a geometry manually:
mirai sink-mode window # default; drag/resize the window with your compositorEnsure your GStreamer setup includes AAC decoders:
gst-inspect-1.0 avdec_aacFor source mode, Mirai relies on gnome-network-displays-stream, which uses
xdg-desktop-portal. Make sure you have the portal implementation for your
compositor installed, e.g.:
- Hyprland:
xdg-desktop-portal-hyprland - Sway:
xdg-desktop-portal-wlr - KDE:
xdg-desktop-portal-kde - GNOME:
xdg-desktop-portal-gnome
Mirai stands on the shoulders of several open-source projects and public specifications:
- MiracleCast — the original
Linux implementation of Wi-Fi Display (Miracast) by David Herrmann, now
maintained by Alberto Fanjul. Mirai wraps
miracle-wifidandmiracle-sinkctlfor its sink mode. - GNOME Network Displays
— provides the source streaming backend (
gnome-network-displays-stream) used by Mirai to cast the desktop through PipeWire and the XDG Desktop Portal. - Wi-Fi Display Technical Specification v1.1 / v2.1 — the Miracast / Wi-Fi Display standard from the Wi-Fi Alliance.
- Quickshell — the Qt/QML shell framework that inspired Mirai's socket-based, UI-agnostic design.
- The Windows
Win + Kwireless display flow is the user-experience goal: discover, connect, and stream from a single shortcut.
Copyright (C) 2026 Leriart
Mirai is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. See LICENSE.