desktop automation AI
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Yuxuan Shui 305913d79e
6 days ago
.circleci ci: add a valgrind suppression file 1 year ago
desktop Add a .desktop file and a start script 1 year ago
docs Fix memory leaks, change API, etc. 1 year ago
examples update example 1 year ago
include randr: make view config object fields writable 1 week ago
plugins randr: make view config object fields writable 1 week ago
scripts switch to mesonbuild 1 year ago
tests os: New module 9 months ago
.clang-format core: Make __destroy a bit more formalized 1 year ago
.codecov.yml Update CI 1 year ago
.editorconfig Check in .editorconfig 1 week ago
.gitignore Add test cases for X 1 year ago
LICENSE.txt Changes: 1 year ago Update README 6 days ago
TODO Update TODO 1 year ago
callable.c Namespacing the type names 4 months ago switch to mesonbuild 1 year ago
di_internal.h ci: add a valgrind suppression file 1 year ago
event.c Give the add_member_* functions more reasonable names 1 year ago
event.h core: API re-design 1 year ago
helper.c Fix memory leak of error messages 4 months ago
list.h core: New listener ref_counting model 1 year ago
log.c core, log: fix memory leak 1 year ago
log.h move headers around 1 year ago
main.c Compiler things 1 week ago Compiler things 1 week ago
meson_options.txt Add option to compile with sanitizer 7 months ago
object.c Namespacing the type names 4 months ago
os.c os: New module 9 months ago
os.h os: New module 9 months ago
spawn.c Give the add_member_* functions more reasonable names 1 year ago
spawn.h core: API re-design 1 year ago
string_buf.c string_buf: Fix string_buf_clear 1 year ago
uthash.h xorg: cache atoms 1 year ago
valgrind.supp ci: add a valgrind suppression file 1 year ago

Table of Contents


Codecov CircleCI Gitter

deai is a tool to automate your Linux desktop. It has similar goals as hammerspoon. But it aims to be more extensible and support for more language.


Desktop Environments (DE) are great, as long as your way of using your computer is the same as the designer of the DE. Otherwise you will have a hard time bending the DE to your will, and the end result might still be unsatisfying. That’s why a lot of people choose to carefully hand pick all the tools they use, and build their own “Desktop Environments”.

However, with Desktop Environments come great integration. The various tools come with the DE are usually designed to work together. So you can do things like dimming the screen when you unplug, applying settings when you plug in a new device, etc. Building a customized “DE” means sacrificing that integration. Sure, one can try to glue things together by writing a bunch of shell scripts, but that will not be officially supported, and a headache to maintain.

So I decided to make deai. deai tried to expose common desktop events and interfaces to scripting languages, so users can write scripts to react to those events. This way the users will be able to implement a lot of the “DE features” with a scripting language they like. And unlike using shell scripts, the users don’t need to trust a gazillion different command line tools anymore, which will leads to easier maintenance.


The documentation is WIP. Currently I want to spend more time on implementing the features, but I understand documentation is very important. I just don’t have enough time.

I hope the few examples given here are self explanatory enough, if not, you can always find ways to ask me in Contact


deai is designed to be really extensible. Except those features that depends on libev, all other features are implemented in plugins, and exposed in deai as modules. If you don’t need certain feature, you can simply remove the plugin. This also means you don’t need approval to add new features to deai. You can do it completely independently, and ship it as a plugin.

In order to interface with scripting languages nicely, deai uses a dynamic type system that mimics the “object” concept found in languages like JavaScript, Lua, or Python. This does make developing for deai in C slightly harder, but it also means I only need to develop a feature once, and have it seamleesly shared between all supported languages.

Current features

Right now the only supported scripting language is Lua, so the examples will be give in Lua.

  • Launch programs
-- "di" is how you access deai functionality in lua
-- "di.spawn" refers to the "spawn" module
-- "run" is the method that executes program
p ={"ls", "-lh"})
p.on("stdout_line", function(_, line)
    print("output: ", line)
p.on("exit", function()
    -- This cause deai to exit

  • Set timer
di.event.timer(10).on("elapsed", function()
    print("Time flies!")
  • Set environment variables
di.env["PATH"] = "/usr"
  • Watch file changes
watcher ={"."})
watcher.on("open", function(_, dir, filepath)
    print(dir, filepath)
watcher.on("modify"), -- similar
  • Connect to Xorg
-- Connect to Xorg is the first step to get X events
xc = di.xorg.connect()

-- You can also use .connect_to(DISPLAY)
  • Set xrdb
-- Assume you have connected to X
xc.xrdb = "Xft.dpi:\t192\n"
  • X Key bindings{"ctrl"}, "a", false -- false meaning don't replay the key
).on("pressed", function()
    -- do something
  • Get notified for new input devices
xc.xinput.on("new-device", function(_, dev)
    print(dev.type, dev.use,,
    -- do something about the device
  • Change input device properties
-- Assume you get a dev from an "new-device" event
if dev.type == "touchpad" then
    -- For property names, see libinput(4)
    dev.props["libinput Tapping Enabled"] = {1}

if == "<<<Some touchscreen device name here>>>" then
    -- Map your touchscreen to an output, if you use multiple
    -- monitors, you will understand the problem.
    M = compute_transformation_matrix(touchscreen_output)
    dev.props["Coordinate Transformation Matrix"] = M
  • Get notified when resolution change, or when new monitor is connected, etc.
-- Note: RandR support is not quite done
xc.randr.on("view-change", function(_, v)
    -- A "view" is a rectangular section of the X screen
    -- Each output (or monitor) is connected to one view
    for _, o in pairs(v.outputs) do
        -- But each view might be used by multiple outputs
  • Adjust backlight
for _, o in pairs(xc.randr.outputs) do
    -- Backlight must be set with an integer, math.floor is required here
    o.backlight = math.floor(o.max_backlight/2)

Planned features

I use the issue tracker to track the progress of these feature, so if you are interested, you can find more info there.

  • dbus support: Lots of the interfaces are now exposed via dbus, such as UDisks to manage removable storage, UPower for power management. So obviously dbus support is a must have.

  • Audio: Support adjust volumes, etc., via ALSA or Pulseaudio

  • Network: Support for network events and react to them. For example, automatically connect to VPN after switching to an open WiFi.

  • Power management: Reacts to power supply condition changes, etc.

  • UI components: Allows you to create tray icons, menus, etc. So you can interact with deai using a GUI.

  • More languages: Support everyone’s favourite scripting languages!

  • And more… If you want something, just open an issue.

Build and Run

Build Dependencies

  • libev
  • dbus-libs
  • xorg
    • xcb
    • xcb-randr
    • xcb-xinput
    • xcb-xkb
    • libxkbcommon
    • xcb-util-keysyms
  • lua

In the future, you will be able to build only the plugins you want.


/path/to/deai module.method arguments...

A more detailed explanation of how the command line arguments works can be found in the wiki


  • IRC: #deai at
  • Email: yshuiv7 at gmail dot com