Globals
Run
TaskHandle with:
handle:Cancel()— stop the coroutinehandle:IsRunning()— returnsboolean
handle:IsRunning() then returns false), and marks the script’s error state. Other coroutines and hooks keep running. Wrap fallible work in pcall to let a coroutine survive a recoverable error.
Sleep
ms milliseconds. Only valid inside a Run() block. Calling Sleep() outside a coroutine raises an error. Does not block anything else.
After
Run(function() Sleep(ms) fn() end). Returns a TaskHandle.
Async
fn in a coroutine when called. This lets you use Sleep() and other coroutine features inside callbacks that are normally synchronous (like Bind handlers).
When the wrapped function is called from the main thread, it spawns a Run() and returns false (swallow). When called from inside an existing coroutine, it calls fn directly to avoid double-wrapping.
require
returns something, usually a table). Modules
are cached: the file is evaluated once on first require, and later requires of
the same path return that same value.
Resolution for an extensionless name, in order: <name>.luau, <name>.lua,
<name>/init.luau, <name>/init.lua. Dots are path separators
(require("lib.math") → lib/math.luau); a leading ./ is stripped; an explicit
.lua / .luau suffix pins that exact file.
Sandboxed to the script directory: a name containing .., or any candidate that
resolves outside the directory, raises path traversal not allowed; an unresolved
name raises module '<name>' not found. There are no external packages,
registries, package.path, or aliases: local files only.
Only a directly-run script needs amin_sdkmodeline; arequire’d module is loaded through that script, not run directly, so it needs no header. See the scripting guide.
_REBIND
Hooks
Global functions your script defines. The runtime calls them when events occur.Lifecycle
OnTick fires on a fixed cadence set by the tick_rate modeline (default 1,000/s,
max 8,000/s) while the script is active. Its argument dtMs is the real time
elapsed since this script’s previous OnTick, in milliseconds. It is fractional
(at 8,000/s it’s ~0.125), and 0 on the very first call. Use it for frame-rate-
independent work, e.g. pos += velocity * dtMs. Run() coroutines, Timer
callbacks, and network I/O are serviced on every engine tick regardless of tick_rate.
OnStart runs once per load, before any other hook. For a targeted script that
is already focused at load time, OnFocus fires immediately on the same load; an
unfocused targeted script gets OnStart only, and its OnFocus/OnTick/timers
wait until the target gains focus.
Top-level code runs immediately when the script file is loaded, before OnStart is called. Use it for constants, module initialization, and guards that must run before anything else.
OnStart is the right place for anything that needs the script to be fully registered first, such as reading persisted UI values or starting timers.
Input
All input hooks canreturn false to block the event from reaching the PC, or return true to pass it through.
Exclusive capture: becauseOnDown/OnUpmay block any key, defining either one makes Rebind intercept every key system-wide and re-emit the ones your script passes through. Tools that only trust real device input (Keyboard Maestro, Karabiner, some games) will not see re-emitted keys while such a script runs. If you only care about specific keys, useBind. It intercepts only its declared triggers and leaves everything else untouched. A hook script that never blocks can also declarekey_block=falseto observe without intercepting.
Observers
Every input event is also delivered to a matching observer hook. Observers fire on all running scripts and their return value is ignored, so they cannot block an event. Use them to watch input without taking exclusive capture.Other (reserved, not yet dispatched)
These hooks are recognized but not dispatched in the current release. Defining them will not cause errors; they won’t fire.System
Read-only methods updated automatically every tick.System.Exec
cmd.exe /C on Windows, sh -c on macOS/Linux) and returns when it completes.
Returns: { exit: number, stdout: string, stderr: string }
Options:
timeout— max execution time in ms (default: 5000). The process is killed if it exceeds this.cwd— working directory for the command.
Run(): Called from inside Run() or OnTick, System.Exec runs the command on a background thread and yields the coroutine. The tick thread never blocks, and the call returns its result table on a later tick. Called outside Run() (OnDown/OnUp/OnMove, Bind callbacks, the top-level chunk), it falls back to synchronous blocking that stalls the tick thread until the command finishes and logs a one-time warning. This sync fallback is deprecated. Wrap System.Exec in Run().
System.Exec requires the exec permission. It is granted by default, but once the modeline declares any permission= line you must include permission=exec, or the call raises System.Exec() requires 'exec' permission at call time. (System.ExecDetached is gated by the same exec permission. See Permissions.)
System.ExecDetached
cmd as a detached, fire-and-forget process and returns immediately with its PID. Unlike System.Exec, it does not wait for the process or capture its output: stdio is discarded (null).
Returns: the spawned process PID as a number.
Options:
cwd— working directory for the process.
System.Exec vs System.ExecDetached:
System.Exec— capturesstdout/stderr/exit. Non-blocking insideRun()(yields the coroutine); synchronous blocking fallback elsewhere. Use when you need the output.System.ExecDetached— detached, returns instantly with a PID, no output captured. Use to launch apps or background processes.
HID
Sends keyboard and mouse output through the active transport.Keyboard
Important:HID.PressandHID.TypewriteruseSleep()internally and must be called inside aRun()coroutine or anAsync()handler: calling them outside a coroutine (e.g. directly inOnDownor aBindaction) raises an error.HID.Down,HID.Up, andHID.Combodo not sleep.HID.Typeneeds no coroutine, but hardware typing emits per-character reports and can occupy the calling hook while it does so.
Combos
Combo, Down, Up, and Press all support + for modifier combos:
HID.Combo presses keys left-to-right and immediately releases them right-to-left, in one synchronous call. Use it to fire a shortcut from a Bind action or OnDown. HID.Press does the same but holds for a duration (coroutine only). HID.Down presses left-to-right; HID.Up releases right-to-left.
Modifier aliases: in addition to the canonical LCtrl/LShift/LAlt/LWin names, combos accept the shorthands Ctrl, Shift, Alt, Win/Meta/Cmd, and (macOS-friendly) Opt/Option. So "cmd+opt+i" and "LWin+LAlt+I" are equivalent.
The + key itself is spelled Equal (unshifted) or KpPlus (numpad), so there is no ambiguity.
Mouse
Mouse mode
Relative mode (default): single-pass movement, designed to be fast; may drift. Best for fast cursor movement.
Absolute mode: iterative correction with position validation, slower, designed for sub-5px accuracy. Best for desktop automation.
Input
Reads the current physical state of input devices.Input.IsDown / Input.GetDuration accept the same names as the rest of the SDK, including mouse buttons (Mouse1 through Mouse5); an unknown or never-pressed code returns false / 0 rather than erroring.
UI
Defines a settings panel rendered in the Rebind UI.Schema
cfg.key, write with cfg.key = value.
Widgets
Widget options
A
Slider with no min/max defaults to a range of 0 to 100. tooltip, group, tab, and showIf apply to every widget, including UI.Color.
Other
Persistence
Values are saved automatically on every change and restored at startup. Persistence is keyed to the script’s file path: no configuration required.Macro
Record and play back input sequences.Playback
Speed:
1.0 = normal, 0.5 = half speed, 2.0 = double speed. Default: 1.0.
Mode: "parallel" (default), "replace".
Handle methods:
handle:Stop()handle:Pause()handle:Resume()handle:IsPlaying()— returnsbooleanhandle:GetProgress()— returns0.0to1.0handle:Wait()— blocks the current coroutine until playback ends. Must be called insideRun()
Hardware streaming
Macros containing
"type" actions always play host-side. Macro.Play() automatically falls back to host-side execution when any Type action is present.
Recording
Record options:
{ ignore_mouse = false, ignore_keyboard = false, precision = "normal" } (keys are snake_case, and camelCase is silently ignored)
Format
Actions in a macro table:Timer
Handle methods:
handle:Cancel(), handle:Pause(), handle:Resume()
Math
Random
Transforms
All transform functions return a new table (original is unchanged).
Interpolate vs Resample:
Resamplechanges all delays uniformly (normalizing recorded macros)Interpolateadds intermediate steps between existing points (smoothing patterns)
JSON
Hash
Common cryptographic and checksum hashing. All inputs are treated as raw bytes.Hash.HMAC accepts algo of "sha256", "sha512", or "sha1". Any other value raises an error.
Codec
Base64 and hex encoding/decoding. These are encodings, not encryption. They provide no confidentiality.Log
Globals:
print(...) and log(...) are both aliases for Log.Info. They accept multiple arguments, joined by tabs, identical to standard Lua print behaviour.
File
All paths are relative to your script’s directory. Path traversal (..) is rejected.
File.IsDir and File.IsFile never throw: they return false for missing or out-of-sandbox paths. File.Move uses a rename and may fail across filesystems.
Net
Client
Client calls yield. Wrap them inRun()/Async(). Every HTTP client method below blocks on a background thread and yields the coroutine, so calling one directly inOnDown, top-level code, or any synchronous hook raisesNet.X() must be called inside Run(). The snippets below assume they run inside aRun()block or anAsync()handler. (The WebSocket callsNet.WSListen/Net.WSConnectare exempt: their I/O runs on dedicated threads.)
Response:
{ status: number, body: string, headers: table }
Options: { timeout = milliseconds } — optional trailing table for convenience methods.
Net.Request options: { method: string, url: string, body?: string, headers?: table, timeout?: number }
User-Agent) can be set on any request via the headers table.
HTTP server
request, returns { status, body, headers? }.
Request fields: req.method (e.g. "GET", "POST"), req.path (e.g. "/click"), req.body (string), req.headers (table).
Server handle: server:Stop()
Net.Listen binds 127.0.0.1 (localhost only). It is not reachable from
other machines. For a LAN-facing endpoint use Net.WSListen, which binds 0.0.0.0.
Under burst load only the newest queued request per server is dispatched to your
handler each tick; older queued requests receive an automatic 200 OK, so keep
handlers fast and idempotent.
For a worked “HTTP request in, hardware out” example, see Automation in the cookbook.
WebSocket server
Client handle (passed to handlers):
client.id, client:Send(text), client:SendBinary(bytes), client:Close().
Server handle: server:Broadcast(text), server:BroadcastBinary(bytes), server:ClientCount(), server:Stop().
Binary frames arrive as Lua strings (read bytes with string.byte / string.unpack); the is_binary flag distinguishes them from text. The maximum message/frame size is 64 MiB per connection. A larger frame drops the connection. WebSocket handlers run on dedicated threads, so they are exempt from the Run() requirement the HTTP client methods have.
The server binds 0.0.0.0:<port>. Events are dispatched to Lua handlers on the
script’s tick loop. Up to 32 events are processed per tick per server; excess
messages backlog into the next tick. There is no built-in rate limiting.
Scripts exposed to untrusted networks should implement their own.
For latency and throughput caveats, see Remote control.
Example:
WebSocket client
ws://host:port/path or wss://host:port/path. TLS uses the
standard web root certificates.
Handlers table: all optional.
Connection handle:
conn:Send(text), conn:SendBinary(bytes), conn:Close().
Example:
Screen
Pixel color sampling from the screen. Works on Windows and macOS. On Linux the namespace is a callable stub (GetPixelColor returns black, no error); see Platforms.
GetPixelColor reads the non-blocking buffer when available and otherwise falls
back to a live platform read. SearchForColor has no live fallback, so it can
return nil while the first buffered frame is being captured as well as when no
pixel matches. Screen.Capture always captures live.
On macOS, capture handles Retina displays automatically. GetPixelColor/SearchForColor coordinates are in logical (non-retina) pixels; Screen.Capture returns native (physical) pixels and reports the scale via the returned dimensions vs the display’s logical size.
Screen.SearchForColor
region:{x1, y1, x2, y2}table of screen coordinatescolor: hex string"rrggbb", case-insensitive (matchesGetPixelColoroutput)tolerance: optional, 0.0 to 1.0 (default 0.0 = exact match). Per-channel percentage of 255.- Returns
{x, y}of first match (top-left to bottom-right scan), ornilif not found
Screen.List
Returns one entry per connected monitor. Use#Screen.List() for the monitor count.
Each entry:
Screen.Capture
Captures a display live and returns a lossless PNG plus the geometry needed to map image pixels back to screen coordinates. This is the primitive behind screenshot-driven automation (see the remote-control protocol’sscreen.capture).
opts (all optional):
display: 1-based index fromScreen.List(). Defaults to the display under the cursor.region:{x, y, w, h}in that display’s local coordinates. Defaults to the full display; clamped to the display’s bounds.max_edge: optional. Downscale the returned PNG so its longer side is at most this many pixels, preserving aspect ratio. Omit for native resolution. Use it to keep base64 frames small in screenshot-heavy loops, for example a remote-control server passingmax_edge = 1280so a 4K capture doesn’t overrun the script’s memory limit.
Window
Window manipulation functions. Handles are integer values obtained fromWindow.Find() or Window.List(). Passing nil for a handle targets the active (foreground) window.
Platform support: full on Windows, partial on macOS, stub on Linux. Per-call macOS behavior is in Platforms.
macOS Accessibility:Window.Moveand the other Accessibility-backed functions require Rebind to hold the macOS Accessibility grant (the same permission software-mode input capture already needs), so if your scripts run, these work. On macOSWindow.Movetargets the frontmost focused window (the handle is advisory), matching a “resize the front window” workflow.
Query
Activation
Movement / sizing
State control
Window.Close asks the window to close gracefully (it may prompt to save). Window.Kill force-terminates the process that owns the window. There is no prompt and unsaved work is lost. Window.Kill can take down sibling windows in the same process.
Window.SetAlwaysOnTop and Window.SetTransparency are best-effort: some fullscreen/DirectX apps repaint over them.
Waiting
Examples
App
Application-level control: the counterpart toWindow (which acts on individual
windows). App acts on whole applications: launch, focus, hide, quit, and query
running apps. Apps are addressed by name, matched case-insensitively against the
application’s display name.
Platform support: macOS only for now. Front, IsFront, IsRunning, and
Activate are permission-free; Hide, Quit, and IsHidden drive an AppleEvent
and prompt for macOS Automation permission on first use.
AppvsWindow: useAppwhen you mean the whole application (“activate Terminal”, “is Slack running”), andWindowwhen you mean a specific window (find/move/resize by handle or title). For app-conditional remaps, prefer aprocess=-scoped script (Rebind activates/deactivates it as you switch apps) over pollingApp.Front()on every keypress.
Audio
Audio.Play
File paths are relative to the script directory (same sandboxing rules as
File).
SoundHandle
The object returned byAudio.Play:
Always call
Audio.StopAll() in OnStop and OnBlur to clean up playing sounds.
Clipboard
Read and write the system clipboard. Works on Windows and macOS; a stub on Linux, see Platforms.Process
Query and manage system processes.Dialog
Native OS dialogs for messages, confirmations, and file selection. All functions must be called insideRun(): they yield the coroutine while the dialog is open. Input processing, timers, and other coroutines continue running uninterrupted.
Linux/BSD: requires Zenity, KDialog, or YAD to be installed.
Message and confirm
Options:
{ title?: string, level?: string }
level controls the icon: "info" (default), "warning" (alias "warn"), or "error". Matching is case-insensitive, and any unrecognized value falls back to "info".
File dialogs
Options:
{ title?: string, location?: string, filters?: { { name: string, extensions: { string } } } }
location— initial directory the dialog opens in.filters— restrict the file types shown. Each entry has a displaynameand a list ofextensions(without leading dot).
Regex
Pattern matching using Rustregex syntax. It is backtracking-free and does not
support lookaround or backreferences.
Use [[ ]] long strings for patterns to avoid Luau escape interpretation: [[\d+]] instead of "\\d+".
Match result
Regex.Find and Regex.FindAll return tables with:
Replacement syntax
Replacements use$1, $2, etc. for capture group references:
Examples
string.find, string.match, string.gmatch) which use different syntax (%d instead of \d). The Regex namespace uses standard regex syntax and supports features Lua patterns lack: alternation (|), non-greedy quantifiers, lookahead, and more.
Config
Read and write TOML configuration files. TOML is a superset of INI for common use cases: simplekey = value files work as-is, with support for typed values (booleans, numbers, strings), arrays, and nested tables.
File paths are relative to the script directory (same sandboxing rules as
File).
File.ReadJSON / File.WriteJSON functions in the File namespace.
Env
Environment variables and known user folders.Variables
Env.Set mutates the Rebind process-wide environment: the change is visible to Env.Get in every other running script and to any later System.Exec / System.ExecDetached, and persists until Rebind exits. It is not scoped to your script. Prefer File / Config for per-script state.
Known folders
Each returns an absolute path, ornil if the location cannot be determined. Env.Temp is the exception: it always returns a string.
These paths point outside the
File sandbox. Use them for informational purposes (such as a Dialog.OpenFile start location), not for sandboxed File.* operations.
Pipe
Shared memory IPC for communicating with external processes (Python, Node.js, etc). Windows only. Returns an error on macOS and Linux (POSIX shared memory support planned).Opening
Local\Rebind_<name>, the tag an external process opens (so Pipe.Open("vision")
maps Local\Rebind_vision). The name must be 1 to 64 characters of ASCII letters,
digits, -, or _. The size option (default 65536) is rounded up to the
next power of two, then clamped between 1024 and 16 MiB, so pipe.size (and
pipe.capacity = size/2 − 12) may exceed what you requested.
Methods
Properties
Wire protocol
The region is split into two fixed channels so both sides can read and write without locking: the script writes to channel A (offset0) and reads from
channel B (offset size / 2). An external peer does the inverse: it writes to
channel B and reads from channel A.
Each channel is a 12-byte header followed by the payload:
A writer lays down the payload, then the length, then the sequence number last
(a release barrier); a reader compares the sequence to the one it last saw and only
reads when it changed. Each channel is a single slot, last-writer-wins. It is not a
queue, so an unread message is overwritten by the next write. Pace writes to the
reader’s poll interval. Working Python, Rust, and Node peers are included in
the SDK’s examples.
Registry
Read and write the Windows registry. Windows only. Every function raises an error on macOS and Linux.keyPath begins with a hive: HKLM / HKEY_LOCAL_MACHINE, HKCU, HKCR, HKU, or HKCC.
Registry.Write accepts a type of REG_SZ, REG_DWORD, REG_QWORD, REG_EXPAND_SZ, REG_MULTI_SZ, or REG_BINARY.
Script
Globals:
exit(reason?) and die(reason?) are aliases for Script.Exit.
Bind
Declarative key binding as an alternative to writingOnDown/OnUp handlers.
Blocking
Bind blocks by default. This is the opposite of OnDown/OnUp.
Most binds remap or trigger actions where blocking the original key is what you want. To pass the key through, you must explicitly
return true.
When using Async() with Bind, the wrapper always returns false (block) immediately when it spawns the coroutine. Any return value inside the coroutine body has no effect on propagation — the decision was already made.
Handle
Handle methods:handle:unbind(), handle:disable(), handle:enable(), handle.enabled (read-only).
Routing
Keys claimed byBind do not reach OnDown/OnUp. If a bind’s when guard returns false, the key falls through to the next bind or to OnDown/OnUp.
Selective interception
Bind triggers are declared data, so Rebind intercepts only those keys at the OS level. Every other key stays outside the bind’s interception path, and device-level tools (Keyboard Maestro, Karabiner) keep working alongside your script. This is the key advantage over anOnDown handler that
inspects key itself: defining OnDown forces system-wide interception (see
Input hooks).
The trigger string is captured when Bind() runs. Bind(cfg.hotkey, …) reads
the saved value of a UI.Keybind field at load, but rebinding it later in
the config panel takes effect on the next script restart, not live.
Modeline
A modeline at the top of a script sets its configuration. A directly-run script must declaremin_sdk: in its modeline, or in its package’s rebind.toml
(any script under a package root inherits [package].min_sdk; see
Package format). Rebind refuses to run a plaintext script with
no declared Rebind version. Every other key is optional and falls back to its
default. (require’d modules are loaded through their parent script and are not
gated.) Inside a package, rebind.toml overrides the modeline; see
Package format.
Three comment forms are accepted. The multi-line block is the recommended
header. One rebind: line per setting reads cleanly as a script grows, and it is
the exact form Rebind suggests on failure:
" or ' to include spaces and =: name="My Script". Inside a quoted value, escape its quote and backslashes as \" and \\. A string-valued key alone on its own line (as in the block form) takes the rest of the line, so rebind: name=My Script needs no quotes. Repeatable keys may appear on separate lines or together on one line. Unknown keys are ignored. Scripts using regex or exclusion targeting must declare min_sdk=3.4.1 or newer so an older Rebind build refuses them instead of ignoring their scope.
Positive window and process rules combine with OR. With no positive rules, the script is active for every focused window. Any matching exclusion deactivates it, even when a positive rule also matches. Exclusion-only configs therefore mean “active everywhere except here.”
Regular expressions use Rust
regex syntax. Lookaround and backreferences are not supported. Invalid or empty expressions stop the script from loading instead of widening its scope.
The former id key is deprecated and ignored. UI state now persists automatically by file path.
Permissions
A script that declares nopermission= line holds every permission. The moment
any permission= line is present, the script switches to allow-list mode:
only the listed permissions are granted, so permission=net alone also denies
exec, and vice-versa.
To declare that a script needs nothing, give the key an empty value or none:
permission= and permissions= each accept one
value or a comma-separated list, and every line adds to the set, so
permissions=net,exec and two singular lines are the same thing. An empty value or
none resets to the empty set, so a later “needs nothing” wins over an earlier
grant. In a package, permissions = [] in rebind.toml means the same.
Omitting the key entirely is the only state that grants everything. There is no
difference between permission= and permissions=none: both deny.
Only exec and net actually gate anything; any other permission= value grants
nothing real but still flips the script into allow-list mode. A denied call fails
as a runtime error when it runs (e.g. Net.Get() requires 'net' permission),
not as a load-time refusal, so a gated call inside a branch only fails when reached.
Nothing else is gated.
File, Registry, Process, Clipboard, Env,
Input, HID, and Macro have no permission check: they work the same whether
or not the modeline declares permissions. File paths are still confined to the
script directory, but that is path resolution, not a permission.
Declare the minimum permissions a script needs.
Key reference
Key names are case-insensitive."F1" and "f1" are identical.
Use these strings with HID.Down, HID.Up, HID.Press, Bind, and in OnDown/OnUp hooks.
Transport key support
Named keys are USB HID usages, not characters. The operating system’s active keyboard layout decides which glyph a usage produces. Text handling differs by transport:- Software mode gives
HID.Typetext to the operating-system output backend. Unicode and layout behavior therefore follows that backend. - Rebind Link output converts each character to a USB HID usage. On Windows it consults the active keyboard layout when a matching HID usage exists. On macOS and Linux it uses a US-layout map for letters, digits, common punctuation, newline, and tab.
- Unsupported hardware-mode characters may not type. macOS software mode can fall back to Unicode text for characters without a keycode mapping, but that is not a portable hardware guarantee.
Clipboard.Set plus the platform paste
shortcut where Clipboard is supported. Test layout-sensitive scripts on every
target layout and transport.
Letters
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
Numbers
0 1 2 3 4 5 6 7 8 9
Function keys
F1 through F24. F13-F24 are HID output only (they work with HID.Press but will not appear in OnDown/OnUp hooks).
Mouse buttons
Modifiers
Editing and control
Navigation
System
Punctuation
These names refer to the physical key, regardless of shift state.Numpad
Media keys (HID output only)
These can be sent viaHID.Press but will not appear in input hooks.