iRightMenu Pro Lua API Reference
Complete reference for the Lua plugin API.
Engine version: 1.3.0 Last updated: April 2026
Source of truth:
engineVersionin the client’sLuaAPIRegistry.swift(computed as the max of allsince:field values).
Module index
| Module | What it does | Docs |
|---|---|---|
app.api |
API Availability | api.md |
app.plugin |
Plugin Info | plugin-info.md |
app.log |
Logging | log.md |
app.context |
Finder context | context.md |
app.dialog |
Dialogs and forms | dialog.md |
app.progress |
Progress dialogs | progress.md |
app.notification |
System notifications | notification.md |
app.settings |
Plugin settings | settings.md |
app.file |
File operations | file.md |
app.path |
Path utilities | path.md |
app.shell |
Shell commands | shell.md |
app.finder |
Finder operations | finder.md |
app.clipboard |
Clipboard | clipboard.md |
app.system |
System information | system.md |
app.json |
JSON | json.md |
app.plist |
Plist | plist.md |
app.http |
HTTP requests | http.md |
app.archive |
Archives | archive.md |
app.image |
Image processing | image.md |
app.crypto |
Crypto and encoding | crypto.md |
app.string |
String utilities | string.md |
app.date |
Date and time | date.md |
app.regex |
Regular expressions | regex.md |
app.process |
Process management | process.md |
app.application |
macOS applications | application.md |
app.database |
SQLite database | database.md |
app.i18n |
Localization | i18n.md |
app.applescript |
AppleScript | applescript.md |
app.thread |
Concurrency and coroutines | thread.md |
app.uti |
Uniform type identifiers | uti.md |
app.url |
URL parsing and building | url.md |
app.xattr |
Extended attributes and tags | xattr.md |
app.trash |
Trash | trash.md |
app.metadata |
Spotlight metadata | metadata.md |
app.csv |
CSV parsing and generation | csv.md |
app.xml |
XML parsing and generation | xml.md |
app.pdf |
PDF operations | pdf.md |
app.network |
Network information | network.md |
app.power |
Power and battery | power.md |
app.screen |
Screen and appearance | screen.md |
app.audio |
Audio control | audio.md |
app.bluetooth |
Bluetooth Devices | bluetooth.md |
app.window |
Window Management | window.md |
app.location |
Location Services | location.md |
app.ocr |
Text recognition (OCR) | ocr.md |
app.qrcode |
QR codes | qrcode.md |
app.wakelock |
Sleep prevention | wakelock.md |
app.watcher |
File watching | watcher.md |
app.share |
macOS Share | share.md |
app.shortcuts |
Shortcuts | shortcuts.md |
app.timer |
Timers | timer.md |
app.color |
Color utilities | color.md |
app.keychain |
Secure credential storage | keychain.md |
app.defaults |
UserDefaults preferences | defaults.md |
app.websocket |
WebSocket client | websocket.md |
app.keyboard |
Keyboard simulation | keyboard.md |
app.mouse |
Mouse simulation | mouse.md |
app.chooser |
Quick chooser | chooser.md |
app.webview |
WebView windows | webview.md |
app.dock |
Dock badge and bounce | dock.md |
app.hotkey |
Global hotkeys | hotkey.md |
app.statusbar |
Status bar items | statusbar.md |
Quick reference
Cheat sheet
-- Logging
app.log.info("message")
app.log.error("error")
-- Context
local files = app.context.selectedFiles()
local dir = app.context.currentDirectory()
local dataDir = app.context.dataDirectory() -- plugin's own writable dir (survives updates, removed on uninstall)
-- Dialogs
app.dialog.alert({title = "Title", message = "Body text"})
local ok = app.dialog.alert({title = "Confirm", message = "Are you sure?", buttons = {"OK", "Cancel"}}) == 1
local __form = app.dialog.form({
title = "Enter a value",
fields = {{type = "text", lock = "value", label = "Input", default = "default"}}
})
local input = __form and __form.value
-- Progress
local p = app.progress.create({title = "Working", message = "Please wait..."})
p:update(50, "Halfway")
p:close()
-- Notifications
app.notification.show("Done", "Processed 10 files")
-- Settings (stored under app.context.dataDirectory(), not the plugin install dir)
local val = app.settings.get("key", "default")
app.settings.set("key", "value")
-- Files
local content = app.file.read("/path/to/file")
app.file.write("/path/to/file", "content")
app.file.copy(src, dst)
app.file.move(src, dst)
app.file.delete(path)
-- Paths
app.path.basename("/a/b/c.txt") -- "c.txt"
app.path.dirname("/a/b/c.txt") -- "/a/b"
app.path.join("/a", "b", "c") -- "/a/b/c"
app.path.exists(path) -- true/false
-- Shell
local result = app.shell.execute("ls -la")
-- result.code, result.stdout, result.stderr
app.shell.quote("my file") -- "'my file'" (safe for shell)
-- JSON
local t = app.json.parse('{"a":1}')
local s = app.json.stringify({a = 1})
-- UTI / URL
local uti = app.uti.fromExtension("pdf") -- "com.adobe.pdf"
local url = app.url.parse("https://example.com/path?q=1")
-- Extended attributes / tags
local tags = app.xattr.getTags(path)
app.xattr.addTag(path, "Important")
app.trash.moveToTrash(path)
-- Data formats
local rows = app.csv.parseFile("data.csv", {header = true})
local doc = app.xml.parseFile("config.xml")
local info = app.pdf.info("document.pdf")
-- Network / system
local ip = app.network.localIP()
local bat = app.power.battery()
local isDark = app.screen.isDarkMode()
app.audio.setVolume(0.5)
-- OCR / QR codes
local text = app.ocr.recognize("image.png")
app.qrcode.generate("hello", {path = "/tmp/qr.png"})
-- Sleep prevention / file watching
local lock = app.wakelock.preventSleep({duration = 3600})
local w = app.watcher.watch("/path", function(e) end)
-- Share / Shortcuts
app.share.show({"/path/to/file.pdf"})
app.shortcuts.run("My Shortcut", {input = "hello"})
-- Timers
app.timer.after(3, function() print("done") end)
local t = app.timer.start(10, function() print("tick") end)
-- Colors
local c = app.color.parse("#FF6600")
local hex = app.color.lighten("#336699", 20)
local ratio = app.color.contrast("#000", "#FFF")
-- Keychain
app.keychain.set("api_key", "sk-xxx")
local token = app.keychain.get("api_key")
app.keychain.has("api_key") -- true/false
-- UserDefaults
local val = app.defaults.read("com.apple.finder", "AppleShowAllFiles")
app.defaults.write("com.apple.finder", "AppleShowAllFiles", true)
-- WebSocket
local ws = app.websocket.connect("wss://echo.websocket.org", {
onMessage = function(lock, data) print(data) end
})
ws:send("hello")
-- Keyboard / mouse
app.keyboard.hotkey({"cmd"}, "c")
app.mouse.click(100, 200)
local pos = app.mouse.position()
-- Chooser
local item = app.chooser.show({{text = "A"}, {text = "B"}})
-- WebView
local wv = app.webview.open({html = "<h1>Hello</h1>"})
wv:eval("document.title")
-- Bluetooth
local devices = app.bluetooth.connectedDevices()
app.bluetooth.watch("deviceDisconnected", function(e) end)
-- Window Management
local windows = app.window.list({app = "Safari"})
app.window.move({app = "Safari"}, 0, 0)
app.window.maximize({app = "Safari"})
-- Location
local loc = app.location.current()
local addr = app.location.reverseGeocode(loc.latitude, loc.longitude)
-- Event Watching (various modules)
app.application.watch("terminate", function(e) end)
app.system.watch("sleep", function() end)
app.power.watch("powerSourceChanged", function(e) end)
app.network.watch("networkChanged", function(e) end)
app.screen.watch("darkModeChanged", function(e) end)
Return value convention
Every API follows the same result, error two-value pattern:
local result, err = app.xxx.yyy(...)
if not result then
-- err is a reason string (permission denied / missing argument / timeout / ...)
app.log.error("Failed: " .. (err or "unknown"))
end
Rules:
- Success: returns the value (string / number / bool / table); the second value is nil
- Failure: returns
nil, "reason"orfalse, "reason" - User cancelled: a cancelled dialog returns
nilwith no error — cancelling is not a failure
Where the error boundary sits — the distinction is “did the call work”, not “did you like the answer”:
- Shell: a non-zero exit code is still a successful call (
result = {code, stdout, stderr}); only a timeout returns an error - HTTP: a 4xx/5xx response is still a successful call (
result = {status, body}); only a network or DNS failure returns an error - Dialog: cancelling returns nil normally; it is not an error