1 Automation
Vincent S. edited this page 2026-06-28 01:08:01 +02:00

Automation

The automation engine (automation/) runs on its own dedicated std::thread (not the tokio runtime), driven by an mpsc channel of EngineMessages.

Each enabled [[automation.scripts]] entry is a Lua script (mlua, lua54) given an alfred global.

The alfred Lua global

API Purpose
on / once register event handlers (per-event, or one-shot)
defer schedule deferred work
vars script-local variables
audio table audio control helpers
state persistent key/value backed by SQLite (store.rs)
hyprland table Hyprland control (hypr.rs)

state survives restarts (SQLite-backed). Use it for anything that must persist across daemon reloads.

Hyprland integration

automation/hypr.rs runs a second thread with a Hyprland EventListener that translates WM events into AutomationEvents your scripts can handle via on(...).

Note the two different Hyprland mechanisms in the codebase:

  • serve/server.rs control uses the hyprctl subprocess,
  • automation/hypr.rs uses the native hyprland crate.

Reloading

curl -X POST --unix-socket "$XDG_RUNTIME_DIR/alfred.sock" http://localhost/automation/reload

or the equivalent client path. Scripts are re-read from the on-disk config.

Threading rule

Blocking work (subprocess calls, sqlite, sysfs) belongs on the automation thread or in spawn_blocking — never inline in an async module collect(). The automation engine is intentionally off the tokio runtime so long-running Lua can't stall async tasks.