Hyprland IPC Micro-Library

Hyprland exposes two Unix sockets for IPC: .socket.sock for sending commands and .socket2.sock for receiving events. The event socket streams compositor events — workspace changes, window focus, monitor hotplug — as newline-delimited messages that any process can subscribe to. This micro-library wraps the event socket with a decorator-based API for Python scripts that need to react to compositor state.

Socket discovery

Hyprland generates a unique instance signature each session, so the socket paths aren't static. Both the signature and runtime directory come from environment variables:

self.signature = os.getenv("HYPRLAND_INSTANCE_SIGNATURE") self.runtime_dir = os.getenv("XDG_RUNTIME_DIR") self.event_sock_path = f"{self.runtime_dir}/hypr/{self.signature}/.socket2.sock" self.cmd_sock_path = f"{self.runtime_dir}/hypr/{self.signature}/.socket.sock"

Event handling

The @on() decorator doesn't transform the function — it just appends it to a list keyed by event name. Multiple handlers can subscribe to the same event this way:

def on(self, event_name: str) -> Callable[[EventHandler], EventHandler]: def decorator(func: EventHandler) -> EventHandler: self.handlers[event_name].append(func) return func return decorator

Events arrive as EVENT>>DATA lines. Each matching handler gets spawned as a concurrent task, so one slow handler doesn't block others:

raw = line.decode().strip() if ">>" in raw: event, data = raw.split(">>", 1) if event in self.handlers: for func in self.handlers[event]: asyncio.create_task(func(self, data))

Example

A wallpaper daemon might use this to repaint when monitors are added or removed:

hyprland = Hyprland() @hyprland.on("monitoraddedv2") async def on_monitor_added(ctx: Hyprland, data: str) -> None: # data contains monitor info from Hyprland await repaint_wallpaper() hyprland.run()
Library source and example usage
© 2025 William Wernert