Message format

Every message is one JSON object. A request names a command in t; include an id when you want a correlated reply (reads), omit it for fire-and-forget (HID writes).
On connect, the server sends a hello frame with the protocol version, whether auth is required, and (on remote.luau) which danger gates are enabled — so a client can verify compatibility and capability with no round-trip.

Command surface

The full surface below is served by remote.luau (protocol 1.2). The minimal remote_access.lua (protocol 1.1) serves only the HID / Screen / System / Input / Clipboard / Window rows plus hello, ping, auth, lua.exec, subscribe, unsubscribe. Send { "t": "commands", "id": 1 } to introspect exactly what a given server exposes. * gated off by default (see Authentication). sandboxed to the script directory and gated behind ALLOW_FILE. system.window reads the active (foreground) window; the window.* commands list, find, activate, move, and wait on windows. hid.move_smooth glides the cursor to a point over a duration server-side (one call instead of streaming hid.move frames); screen.capture_window captures a single window by handle or title without computing a region. screen.capture (protocol 1.1.0+) returns a display as a base64 PNG at native resolution plus its geometry and the cursor position, and screen.displays enumerates monitors with signed virtual-desktop origins — together the basis for screenshot-driven, computer-use-style automation. Async commands (net.*, dialog.*, window.wait*, hid.press, hid.typewriter, hid.move_smooth) run in a coroutine on the server and reply when the underlying call completes — always include an id for them. Screen, Window, and Registry commands depend on platform support — Screen and Window are limited or absent on Linux, Clipboard is Windows/macOS, and Registry is Windows-only. See Platforms & limits.

Authentication

Auth is off by default (fine on localhost; risky on a LAN, since the server binds 0.0.0.0). To require a token:
  • remote.luau — set the Auth token field in the script’s settings panel. It is compared over SHA-256 (so timing can’t leak its length or prefix) and is redacted from ui.get/ui.get_all so an authenticated client can’t read it back.
  • remote_access.lua — set AUTH_TOKEN at the top of the script before installing.
Either way the client then sends { "t": "auth", "token": "..." } first; every non-handshake command is refused with unauthenticated until it does. Dangerous surfaces are gated off by default in remote.luau and must be enabled by editing the file constants (they are deliberately not wire-flippable): ALLOW_EXEC (shell exec, process kill), ALLOW_FILE (filesystem, TOML files), ALLOW_REGISTRY (registry writes), and ALLOW_LUA_EXEC (arbitrary Lua via lua.exec). A gated command returns disabled when its flag is off. Leave these off unless you trust every client that can reach the port.

Performance

Measured on localhost (Windows host, release build): Round-trips are sub-millisecond over localhost and a wired LAN — the transport won’t be your bottleneck.