IPC

September 2, 2026 · View on GitHub

Umbriel listens on a single UNIX socket. The same connection answers one-shot queries and, on request, becomes an event stream. UMBRIEL_SOCKET holds the path; without it, clients derive $XDG_RUNTIME_DIR/umbriel-$WAYLAND_DISPLAY.sock.

Every request is one JSON object on one line. Every reply is one JSON object on one line: {"ok": …} or {"err": "…"}. The umbriel subcommands in Actions and umbriel --help are thin clients over this socket, so anything they do is available to a script.

printf '{"cmd":"workspaces"}\n' | socat -t 5 STDIO "$UMBRIEL_SOCKET"

Queries

RequestCLIReply
{"cmd":"windows"}umbriel windows --jsonwindow list with ids, app ids, titles, geometry, workspace ids
{"cmd":"workspaces"}umbriel workspaces --jsonworkspace list with names, indices, outputs, active/focused flags, layout modes
{"cmd":"submap"}umbriel submap --jsonactive keybind submap, or null
{"cmd":"layers"}umbriel layers --jsonlayer-shell surfaces
{"cmd":"msg","arg":"<action>"}umbriel msg <action>runs an action

A connection with no subscription closes once its replies are written, and a connection that sends nothing is dropped after a second.

Event stream

{"cmd":"subscribe","events":["workspaces","windows"]}

The connection stays open. Umbriel first writes the current state of every subscribed family, one line each, then a line whenever that family changes. Each line is {"event":"<family>","data":…}.

FamilyFires on
themecolor or corner-radius changes from a config reload; see payload
overviewthe overview opening or closing
keyboard_layoutlayout switches; skipped in the initial state when no keyboard exists
windowswindow open, close, focus, title, app id, geometry, workspace, floating state
workspaceslayout mode, activation, names, indices, and workspace or output membership
submapthe active keybind submap changing; null is the default context

Subscribing to an unknown family answers {"err":"unknown subscription event: <name>"} and closes, so a typo fails immediately rather than waiting on a stream that never opens.

Each family is a full snapshot, not a delta: the payload is the same structure the matching query returns. A client replaces its state with the newest line and never reassembles it from increments, so a stream cannot desync. Window and workspace updates are coalesced per event-loop iteration, and a payload identical to the last one sent for that family is dropped, so a resize that ends where it started wakes nobody.

Events are the only way to follow a workspace's layout mode: the ext-workspace-v1 protocol publishes workspace lists, names, and activation to any Wayland client, but it has no concept of a layout, and Umbriel selects scrolling, dwindle, or master per workspace.

Theme payload

The theme payload mirrors the color configuration. Every color is an #RRGGBBAA string, and corner_radius is an integer count of logical pixels. The example is wrapped for readability; the stream writes it as one line.

{"event":"theme","data":{
  "background":"#141419FF",
  "text_primary":"#E8E8EAFF",
  "text_muted":"#8A8A92FF",
  "accent_primary":"#7AA3FFFF",
  "accent_secondary":"#F5C96BFF",
  "warning":"#F5C96BFF",
  "error":"#FF6B6BFF",
  "insert_hint":"#7FC8FF80",
  "backdrop":"#000000FF",
  "shadow":"#0000007F",
  "border":{
    "focused":"#7AA3FFFF",
    "unfocused":"#292933FF",
    "scratchpad_focused":"#E5C07BFF",
    "scratchpad_unfocused":"#5C4A2AFF",
    "outer":"#1A1A1FFF"
  },
  "overview":{
    "background_tint":"#10101430",
    "workspace_background":"#00000044",
    "badge":"#7AA3FFFF"
  },
  "corner_radius":10
}}

The flat keys, the border object, and the overview object carry [colors], [colors.border], and [colors.overview] as written in the configuration, and corner_radius carries appearance.corner_radius. See Appearance for what each color paints.

From the command line

umbriel subscribe workspaces
umbriel subscribe workspaces,windows
umbriel subscribe submap

One JSON line per event on stdout, flushed as it arrives, until the compositor exits or the reader closes the pipe. This is the same stream as the socket request, so a bar, a status script, or a plugin can consume it without a socket library:

umbriel subscribe workspaces | while read -r line; do
  jq -r '.data[] | select(.focused) | "\(.output) \(.name) \(.layout)"' <<< "$line"
done

Inspection commands

umbriel outputs, umbriel color, umbriel tearing, umbriel layers, and umbriel keyboard-layouts print human-readable state; each takes --json for the machine-readable form. umbriel validate checks a config file without a running compositor.