Every way to talk to LunaDash.
LunaDash exposes one owner-only Unix control socket, a versioned Settings API and Plugin SDK 2's synchronous C ABI; the shell reaches it through SlintLu. This page documents the contracts implemented by the current source tree.
This is a local session API, not HTTP. LunaDash listens on a Unix socket that only your user can open. The website documents the API; it cannot control a running desktop.
Wire protocol and ludashctl
Processes launched by LunaDash inherit LUNADASH_CONTROL. The client still accepts the historical LUDASH_CONTROL, then searches the runtime directory for one unambiguous *-control socket. Prefer LUNADASH_CONTROL in new code.
lunadashctl status
lunadashctl workspace 1
lunadashctl appearance '{"gap":16,"animations":true}'
lunadashctl quit confirmThe CLI sends one compact UTF-8 JSON object followed by a newline. method and value are strings, so structured payloads are JSON encoded inside value. The compositor accepts at most 65,536 request bytes, applies a three-second server timeout and returns one compact JSON object plus a newline.
{"method":"appearance","value":"{\"gap\":16}"}
Invalid JSON returns {"error":"Invalid request"}. An unsupported method/value returns {"error":"Invalid command or value"}. lunadashctl waits up to 1.5 seconds per socket read and refuses responses larger than 1 MiB.
import json, os, socket
path = os.environ.get("LUNADASH_CONTROL") or os.environ.get("LUDASH_CONTROL")
if not path:
raise RuntimeError("LUNADASH_CONTROL is not set")
request = {"method": "appearance", "value": json.dumps({"gap": 16})}
with socket.socket(socket.AF_UNIX) as client:
client.settimeout(3)
client.connect(path)
client.sendall(json.dumps(request).encode() + b"\n")
data = b""
while b"\n" not in data:
chunk = client.recv(65536)
if not chunk or len(data) + len(chunk) > 1024 * 1024:
raise RuntimeError("Invalid LunaDash response")
data += chunk
response = json.loads(data.split(b"\n", 1)[0])
if "error" in response:
raise RuntimeError(response["error"])
print(json.dumps(response, indent=2))Status is the discovery API
Use status to discover client ids, display modes, connection names, plugin ids, available power/session actions and layout actions instead of hard-coding host-specific values.
| Field | Type | Purpose |
|---|---|---|
| clients | array | Window ids, metadata, geometry, workspace, focus/mapping and minimize/maximize/fullscreen state. |
| workspace / tiling / windowLayout | number / objects | Current workspace, layout snapshot, template id, overlap policy, settings schema/values and actions. |
| appearance | object | Effective desktop preferences. |
| extensions | object | Installed plugins, the target registry, the extensions document and path, and per-plugin errors. |
| settingsApi | object | Settings API version and editable target descriptors; same payload as settings-describe. |
| audio / network / power | objects | Service availability, devices/profiles, busy state and errors. |
| display / brightness / ddcBrightness | objects | Output modes/scale/pending confirmation, backlight state and DDC/CI monitors. |
| input / shortcuts | objects | Keyboard/backend/protocol state and effective shortcut map. |
| screenCapture | object | zwlr_screencopy protocol/version, last path, busy phase and error. |
| xwayland | object | XWayland compatibility and utility-surface state. |
| system / update / sessionActions / settingsTools | objects | System state, updater, logind actions and validated settings helpers. |
| language / translations | string / object | Locale and shell translation dictionary. |
| settingsSerial / pickerSerial / launcherSerial / shellActionSerial | numbers | Serials SlintLu watches to open shell surfaces when a shortcut asks (settings, Super+W, launcher, control center). |
| graphicsApi / shaderReady / graphicsFailed | string / booleans | Renderer-health summary for the active wlroots path. |
| workspaceCount | number | The number of workspaces: the occupied ones plus one empty workspace after them. |
| tilingMode | string | fill or scroll: the tiling mode in use. |
| wallpaperPoster | string | A file:// still frame of a video wallpaper; empty for images. |
| wallpaperLive | boolean | Whether mpvpaper is playing the video wallpaper below the shell. |
Each ordinary status.clients[] entry includes a positive session-local id, title, app id, icon, desktop id, X11 flag, workspace, geometry, focus/minimize/maximize/fullscreen/mapped flags and buffer/content sizes. Do not persist these ids across compositor restarts.
Every control method
The tables are aligned with WaylandCompositor::control() on the dev branch. Examples use the CLI form; direct socket clients send the same method/value pair.
State and settings
| Method | Value | Behavior | Example |
|---|---|---|---|
| status | Empty | Return the complete compositor snapshot: windows, workspaces, appearance, displays, input, audio, network, power, plugins, modules, capture state and Settings API descriptors. | lunadashctl status |
| settings-describe | Empty | Return Settings API v1 and every editable target. Each descriptor contains id, schema, values and a SHA-256 revision token. | lunadashctl settings-describe |
| settings-update | JSON {"target":"...","revision":"...","changes":{...}} | Patch one Settings API target. The revision must still match; unknown fields, stale revisions, read-only changes and schema-invalid values are rejected. The request is capped at 24 KiB. | lunadashctl settings-update '{"target":"builtin:window-animation","revision":"<revision>","changes":{"duration":260}}' |
| appearance | Partial desktop-preferences JSON | Validate and atomically apply a desktop preference patch; invalid or unknown fields reject the update. | lunadashctl appearance '{"gap":16,"animations":true}' |
| reset-preferences | Empty | Remove the desktop preference group, then reapply keyboard configuration and layout. Plugin/module/default-app documents are separate. | lunadashctl reset-preferences |
| open-settings | Empty or a built-in page id | Open Settings at general, appearance, windows, shortcuts, display, input, input-method, sound, network, bluetooth, power, applications, privacy, system, devices, about, modules, plugins or dashboard. | lunadashctl open-settings plugins |
Windows and workspaces
| Method | Value | Behavior | Example |
|---|---|---|---|
| workspace | Zero-based workspace index | Switch to a workspace. Workspaces are dynamic: the occupied ones plus one empty workspace after them (status.workspaceCount). | lunadashctl workspace 1 |
| focus | Positive client id | Switch to the client's workspace, restore it if minimized, focus it in the layout and give the surface keyboard focus. | lunadashctl focus 12 |
| activate-window | Positive client id | Activate a task/window through the compositor task activation path. | lunadashctl activate-window 12 |
| minimize | Positive client id | Minimize the client, update XWayland state when applicable, update the layout and synchronize focus. | lunadashctl minimize 12 |
| close | Positive client id | Request a normal application close; this is not a process kill. | lunadashctl close 12 |
| group-window | JSON {"window":ID,"target":ID} | Ask the active layout to group one window with another. The layout must support group-with. | lunadashctl group-window '{"window":12,"target":7}' |
| expel-window | Positive client id | Ask the active layout to expel a window from its current group. | lunadashctl expel-window 12 |
| window-layout-settings | JSON matching status.windowLayout.schema | Patch the active layout template settings and rearrange immediately. | lunadashctl window-layout-settings '{"gap":12}' |
| window-layout-action | JSON {"action":"<id>","payload":{...}} | Invoke an action advertised by status.windowLayout.actions. Only action and payload are accepted; required work-area data is injected by the compositor. | lunadashctl window-layout-action '{"action":"expel","payload":{"window":12}}' |
| switch-window | Positive client id | Select a particular item in the active compositor window switcher. | lunadashctl switch-window 12 |
| switch-step | previous or next | Step the switcher backward for previous, otherwise forward. | lunadashctl switch-step next |
| switch-accept | Empty | Accept the current window-switch selection. | lunadashctl switch-accept |
| switch-cancel | Empty | Cancel the current window-switch operation. | lunadashctl switch-cancel |
| launcher-visible | true or false | Synchronize launcher visibility with the compositor; primarily used by the LunaDash shell. | lunadashctl launcher-visible true |
| tiling-mode | toggle, fill or scroll | Switch tiling between Fill (the split tree fills the screen) and Normal (niri-like scrollable columns). Same as Super+Shift+Space; stored as the tilingMode preference. | lunadashctl tiling-mode toggle |
| switch-begin | windows or workspaces | Open the window switcher (every window in the taskbar) or the workspace switcher without a keyboard shortcut; switch-step, switch-window and switch-accept/switch-cancel drive it. | lunadashctl switch-begin windows |
Input and shortcuts
| Method | Value | Behavior | Example |
|---|---|---|---|
| shortcut-capture | true or false | Enable/disable shortcut-capture mode while Settings records a key combination. | lunadashctl shortcut-capture true |
| shortcuts | Partial JSON mapping known action ids to shortcut strings | Update bindings. Values are Disabled or a Meta/Alt key combination; duplicates and Alt+Tab / Alt+Shift+Tab are rejected. | lunadashctl shortcuts '{"launchTerminal":"Meta+Return","closeWindow":"Meta+Q"}' |
| reset-shortcuts | Empty | Restore the built-in shortcut map, including workspace1..10 and moveToWorkspace1..10. | lunadashctl reset-shortcuts |
| send-key | copy, paste, cut or selectAll | Inject the corresponding Ctrl chord into the currently focused wlroots keyboard surface. | lunadashctl send-key copy |
Applications and URLs
| Method | Value | Behavior | Example |
|---|---|---|---|
| default-apps | JSON object of command arrays | Save default terminal/files/browser command arrays. Empty terminal/files commands can use LunaDash fallbacks. | lunadashctl default-apps '{"browser":["google-chrome-stable"]}' |
| launch-default | terminal, files or browser | Launch the configured default. Terminal/files can fall back to LunaDash built-ins; browser requires an available browser command. | lunadashctl launch-default browser |
| launch-command | Non-empty JSON command array | Launch a program directly without a shell. Every argument is a string up to 1024 characters. | lunadashctl launch-command '["foot","-e","htop"]' |
| launch-with-x11 | JSON command array; CLI also accepts -- program args | Launch through the external-command path with authenticated X11 compatibility prepared. | lunadashctl launch-with-x11 -- xterm -e htop |
| launch-x11 | Command-line string parsed by QProcess::splitCommand | Launch directly through XWayland. This parses arguments; it does not evaluate shell operators. | lunadashctl launch-x11 'xterm -e htop' |
| launch-application | JSON exactly {"desktopId":"...","command":[...]} | Launch a desktop-app command after capability resolution. desktopId <=256 chars; command has 1–64 non-empty strings, each <=1024 chars. | lunadashctl launch-application '{"desktopId":"org.example.App","command":["example-app"]}' |
| open-url | URL string | Resolve the configured browser command and open the URL. | lunadashctl open-url https://github.com/LuYishan-4/LunaDash |
| system-tool | Id from status.settingsTools | Open one validated system-settings helper; discover ids through status rather than guessing executables. | lunadashctl system-tool '<tool-id>' |
Plugins
| Method | Value | Behavior | Example |
|---|---|---|---|
| extension-save | Complete extensions schemaVersion 1 JSON | Validate and atomically save built-in/plugin configuration, refresh PluginManager and rearrange. Maximum size: 24 KiB. | lunadashctl extension-save '{"schemaVersion":1,"builtins":{},"plugins":{}}' |
| extension-install | Plugin id from status.extensions.remote | Start an install from the reviewed Store catalogue. The immediate response is pending; progress/error lives in extensions.remote. | lunadashctl extension-install org.example.plugin |
| extension-remove | User-installed plugin id | Disable and remove only a plugin under the canonical user LunaDash plugin root. System plugins cannot be removed here. | lunadashctl extension-remove org.example.plugin |
| extension-error | JSON {"id":"package@target","error":"message"} | Report a plugin runtime failure; messages are capped at 1024 chars. Send an empty error to clear quarantine and retry/refresh. | lunadashctl extension-error '{"id":"org.example.panel@panel","error":""}' |
Audio, network and power
| Method | Value | Behavior | Example |
|---|---|---|---|
| audio | JSON with exactly device plus id, volume or mute | device is output/input. Select output with id, set integer volume 0..100, or set mute boolean. Requires wpctl/WirePlumber and no pending audio change. | lunadashctl audio '{"device":"output","volume":50}' |
| network | JSON with "action" and action-specific fields | Structured NetworkManager/Bluetooth operations; accepted actions are documented below. Read status.network for current names/devices first. | lunadashctl network '{"action":"wifi-connect","ssid":"My WiFi","password":"secret"}' |
| power-profile | Profile from status.power.profiles | Switch with powerprofilesctl to an advertised profile such as power-saver, balanced or performance. | lunadashctl power-profile balanced |
| session-action | suspend, reboot or poweroff | Call systemd-logind only when status.sessionActions reports the action available. | lunadashctl session-action suspend |
Displays
| Method | Value | Behavior | Example |
|---|---|---|---|
| brightness | Integer 1..100 | Set the active backlight through brightnessctl; status.brightness must report an available device. | lunadashctl brightness 75 |
| ddc-brightness | JSON {"id":"<device-id>","percent":0..100} | Set and verify external-monitor VCP 0x10 brightness through ddcutil. | lunadashctl ddc-brightness '{"id":"i2c-6:DELL U2720Q","percent":60}' |
| ddc-refresh | Empty | Rescan DDC/CI displays and query current brightness. | lunadashctl ddc-refresh |
| display-configure | JSON containing mode and/or scale | Test+commit a primary-display change. mode must be advertised; scale is 1.0..3.0. Success starts a 15-second confirmation timer. | lunadashctl display-configure '{"scale":1.25}' |
| display-confirm | Empty | Persist the pending display width/height/refresh/scale before the 15-second revert timer expires. | lunadashctl display-confirm |
| display-revert | Empty | Immediately restore the display state saved before the pending change. | lunadashctl display-revert |
| desktop-size | Nested output size | Resize a supported windowed nested session; physical/fullscreen sessions reject unsupported resizing. | lunadashctl desktop-size 1440x900 |
Capture and wallpaper
| Method | Value | Behavior | Example |
|---|---|---|---|
| capture | Absolute new output path | Start an asynchronous screenshot save. Relative paths and existing files are rejected; response includes path/pending/phase. | lunadashctl capture /tmp/lunadash-shot.png |
| screenshot | Empty | Start the normal LunaDash screenshot flow; read status.screenCapture for completion/error. | lunadashctl screenshot |
| wallpaper | 0 or 1 | Select a built-in shader wallpaper palette and set wallpaperMode to shader. | lunadashctl wallpaper 1 |
| choose-wallpaper | Empty | Open Settings → Appearance and signal the image picker. | lunadashctl choose-wallpaper |
| wallpaper-image | Absolute local path or file URL | Validate and select an image wallpaper. | lunadashctl wallpaper-image /home/user/Pictures/wallpaper.png |
| wallpaper-default | Empty | Clear the custom image wallpaper and restore the default image state. | lunadashctl wallpaper-default |
| wallpaper-favorite | add:<path> or remove:<path> | Mark a library wallpaper as a favourite or remove the mark. | lunadashctl wallpaper-favorite add:/home/me/Pictures/Wallpapers/sky.png |
| wallpaper-refresh | Empty | Rescan the wallpaper library folder without opening the shell's picker. | lunadashctl wallpaper-refresh |
Language, setup and maintenance
| Method | Value | Behavior | Example |
|---|---|---|---|
| language | Supported locale id | Save a supported LunaDash UI locale. | lunadashctl language zh_TW |
| configure-network | Empty | Open nm-connection-editor, otherwise run nmtui in a supported terminal. | lunadashctl configure-network |
| check-update | Empty | Ask the update checker to refresh; read status.update for the result. | lunadashctl check-update |
| setup | Empty | Mark first-run setup incomplete and reopen the welcome flow. | lunadashctl setup |
| finish-setup | Empty | Record first-run setup completion. | lunadashctl finish-setup |
| quit | Literal "confirm" | Request normal LunaDash session shutdown. Empty is rejected. | lunadashctl quit confirm |
Network action payloads
network accepts structured operations, never arbitrary nmcli text. Actions are bluetooth-scan, network-reset, connection-reconnect, wifi-scan, wifi-connect, connection-up/down/delete, device-connect/disconnect, networking-enable, wifi-enable, connection-autoconnect, connection-ipv4-auto/manual, connection-ipv6-auto/disabled and connection-route-metric.
lunadashctl network '{"action":"wifi-scan"}'
lunadashctl network '{"action":"wifi-connect","ssid":"Lab WiFi","password":"..."}'
lunadashctl network '{"action":"networking-enable","enabled":true}'
lunadashctl network '{"action":"connection-ipv4-manual","name":"Lab","address":"192.0.2.20/24","gateway":"192.0.2.1","dns":"1.1.1.1"}'Shortcut ids
Known actions are focusLeft/Right/Up/Down, groupLeft/Right, reorderLeft/Right, expelWindow, centerColumn, widenColumn, narrowColumn, maximizeWindow, toggleFullscreen, toggleTilingMode, closeWindow, minimizeWindow, launchTerminal, launchFiles, launchLauncher, launchOrbit, chooseWallpaper, randomWallpaper, toggleEyeCare, toggleScratchpad, openControlCenter, openClipboard, openPowerMenu, screenshot, plus workspace1..10 and moveToWorkspace1..10. Values are Meta/Alt/Ctrl/Shift combinations such as Meta+Shift+Space, or Disabled.
Settings API version 1
settings-describe returns descriptors with id, name, type, category, normalized schema, current values and a SHA-256 revision. The revision hashes schema plus values for optimistic concurrency.
builtin:<extension-target>
plugin:<package-id>:<extension-target>
module:<module-id>:<section>
layout:<active-window-template># Read descriptors
lunadashctl settings-describe
# Send the selected target's exact revision with a partial change
lunadashctl settings-update '{"target":"plugin:org.example.motion:window-animation","revision":"<64-hex-sha256>","changes":{"duration":280}}'If another editor changed the target, the patch fails with Settings changed. Reload before applying this edit.. Schemas can describe boolean, string, integer, number and bounded enum-array fields. Plugin schemas intentionally allow only toggle, select, number and slider controls.
Native Plugin SDK 2 ABI
Native effects do not receive wlroots pointers. Hooks run synchronously on the compositor thread over UTF-8 JSON; do not block, retain host pointers, run nested event loops or create lifetime-escaping callbacks/background work.
#include <stddef.h>
#include <stdint.h>
#define LUDASH_PLUGIN_API_VERSION 2u
typedef struct ludash_plugin_api {
uint32_t struct_size;
uint32_t api_version;
const char *metadata_json;
int (*process)(const char *request, char *response, size_t capacity);
} ludash_plugin_api;
int ludash_plugin_process(const char *request, char *response, size_t capacity);
const ludash_plugin_api *ludash_plugin_entry_v2(void);
int ludash_plugin_write_json(const char *json, char *response, size_t capacity);The SDK generates ludash_plugin_entry_v2, embeds the built manifest and produces the receipt. The loader checks struct size, API version 2, process pointer and equality between embedded and installed metadata.
{
"target":"window-animation",
"mode":"replace",
"context":{},
"builtin":{"duration":220,"enterOffset":12,"focusOpacity":0.82,"exitScale":0.9,"easing":"outCubic"},
"current":{},
"settings":{"duration":280}
}builtin is always available. Replacement hooks get empty current; augment hooks receive the previous valid result. Return a complete JSON object and its byte length excluding NUL, or a negative value. The response buffer is 262,145 bytes. Invalid/oversized output quarantines the instance and preserves the built-in/previous result.
The native targets are window-animation, shell-animation, window-rules and window-layout; see Compositor plugins.
Trust boundary: native effects run inside the compositor without a sandbox.