burrow & IPC#
burrow is carrot's companion CLI. It talks to a JSON socket that any script or status bar can use directly; everything burrow can do, nc can do too.
The socket#
$XDG_RUNTIME_DIR/carrot.$WAYLAND_DISPLAY.sock, for example /run/user/1000/carrot.wayland-1.sock. The protocol is one JSON value per line in both directions. Replies are wrapped: {"ok": ...} on success, {"error":"..."} on failure. If WAYLAND_DISPLAY is unset, burrow finds any carrot.*.sock in the runtime dir.
$ echo '"workspaces"' | nc -U "$XDG_RUNTIME_DIR/carrot.$WAYLAND_DISPLAY.sock"
{"ok":[{"index":1,"windows":2,"active":true,"output":"eDP-1","layout":"dwindle"}]}
Actions#
Actions are the same vocabulary as keybinds, as JSON. A bare string for argument-less actions, an object for the rest (workspace numbers are 0-based on the wire, 1-based everywhere humans type them):
"toggle-fullscreen"
"center-column"
"toggle-full-width"
{"focus-workspace":2}
{"focus-dir":"left"}
{"adjust-split-ratio":0.1}
{"set-layout":"toggle"}
{"spawn":["foot"]}
{"spawn-sh":"a | b"}
Dispatch always replies {"ok":true}. With burrow:
burrow workspace 3 # absolute (1-based)
burrow workspace +1 # relative
burrow send-to-workspace 2
burrow toggle-floating
burrow focus-left
burrow split-ratio -0.1
burrow spawn foot
burrow quit
Note the two short forms: the CLI says workspace and split-ratio where the bind actions say focus-workspace and adjust-split-ratio.
The scrolling and pointer verbs (set-layout, consume-or-expel-left/-right, move-column-left/-right, cycle-column-width, cycle-column-width-back, toggle-full-width, center-column, pointer-move, pointer-resize) and the binds query are accepted on the socket in the JSON forms above; the burrow CLI has not grown subcommands for them yet, so send them through nc for now.
Queries#
| Verb | Returns |
|---|---|
monitors | each output: name, x, y, width, height, scale, workspace, focused |
workspaces | each workspace: index (1-based), windows, active, output, layout (dwindle or scrolling) |
windows | windows on the active workspace: title, app-id, geometry, floating, fullscreen, focused |
clients | every window everywhere, adding id, pid, workspace, output, xwayland, mapped |
burrow prints these human-readable by default; burrow --json <verb> keeps the wire JSON for scripts.
Control verbs#
| Verb | Does |
|---|---|
reload | re-read the config; a parse error keeps the running config and reports every error; cold keys (outputs, debug, startup spawns) print a needs-restart notice |
binds | list the active binds with their chords, actions, and title labels, for shell-drawn hotkey overlays (raw socket only; no CLI subcommand yet) |
dpms-off / dpms-on | blank or wake every output (any input also wakes) |
dump-shadow | write the focused window's CPU pixel shadow to /tmp/carrot-shadow-<id>.ppm, a forensic tool for telling client bugs from render bugs |
subscribe | turn the connection into a live event stream |
The event stream#
burrow subscribe prints ndjson forever: first a snapshot ({"workspaces":[...]} then {"windows":[...]}), then one event per line as things happen. It exists so status bars never have to poll.
| Event | Fires when |
|---|---|
{"workspace":N} | the active workspace changes |
{"window-opened":{"title":...,"app-id":...}} | a window maps |
{"window-closed":{"title":...}} | a window unmaps |
{"window-focused":{"title":...,"app-id":...}} | keyboard focus moves |
{"fullscreen":bool} | fullscreen toggles |
{"event":"config-loaded","failed":bool,"errors":[...],"cold-keys-pending":[...]} | a config load or reload finishes, success or not |
Exit codes#
0 success, 1 runtime errors (no socket, an {"error"} reply), 2 usage errors.