Skip to content

Plugins

Reach has a plugin system that lets you extend the app with custom Lua scripts. Plugins run in a sandboxed environment and can interact with SSH connections, store data, and hook into app events.

This feature is currently in beta.

Each plugin is a Lua script (Luau dialect) that runs inside a sandboxed VM. Plugins can:

  • Execute commands on active SSH connections
  • Store and retrieve persistent data
  • Register hooks that run on specific events (e.g., on connect, on disconnect)
  • Provide UI elements that appear in the plugin panel

The sandbox restricts file system access and network calls to prevent plugins from doing anything unexpected. Plugins can only interact with Reach through the provided host API.

Go to Settings > Plugins to manage your plugins. From there you can:

  • Install a plugin from a .lua file
  • Enable / Disable installed plugins
  • Remove plugins you no longer need
  • View plugin details including name, version, and description

A plugin is a single .lua file with a metadata header and one or more hook functions.

-- Plugin metadata
PLUGIN = {
name = "My Plugin",
version = "1.0.0",
description = "A simple example plugin",
author = "Your Name"
}
-- Called when the plugin is loaded
function on_load()
log("Plugin loaded!")
end
-- Called when an SSH connection is established
function on_connect(connection_id, host)
log("Connected to " .. host)
end
-- Called when an SSH connection is closed
function on_disconnect(connection_id, host)
log("Disconnected from " .. host)
end

Plugins have access to the following host API functions:

FunctionDescription
log(message)Print a message to the plugin log
ssh_exec(connection_id, command)Execute a command on an SSH connection and return the output
storage_get(key)Retrieve a value from persistent plugin storage
storage_set(key, value)Store a value persistently (survives app restarts)
storage_delete(key)Remove a value from storage
HookArgumentsWhen it runs
on_load()Plugin is loaded or enabled
on_unload()Plugin is disabled or removed
on_connect(id, host)connection ID, hostnameSSH connection established
on_disconnect(id, host)connection ID, hostnameSSH connection closed

Plugin storage is persistent and scoped to each plugin. Data is stored encrypted in the vault alongside your other secrets. Use storage_get and storage_set to read and write key-value pairs.

-- Save a counter
local count = storage_get("run_count") or 0
count = count + 1
storage_set("run_count", count)
log("This plugin has run " .. count .. " times")

Here’s a complete example plugin that collects basic info from a server whenever you connect and logs it. You can use this as a starting point for your own plugins.

PLUGIN = {
name = "Server Info",
version = "1.0.0",
description = "Logs basic system info when you connect to a server",
author = "Reach"
}
function on_load()
log("Server Info plugin ready")
end
function on_connect(connection_id, host)
log("Collecting info from " .. host .. "...")
-- Get hostname
local hostname = ssh_exec(connection_id, "hostname")
log("Hostname: " .. hostname)
-- Get OS info
local os_info = ssh_exec(connection_id, "cat /etc/os-release 2>/dev/null | grep PRETTY_NAME | cut -d'\"' -f2")
if os_info and os_info ~= "" then
log("OS: " .. os_info)
end
-- Get uptime
local uptime = ssh_exec(connection_id, "uptime -p 2>/dev/null || uptime")
log("Uptime: " .. uptime)
-- Get memory usage
local mem = ssh_exec(connection_id, "free -h 2>/dev/null | grep Mem | awk '{print $3 \"/\" $2}'")
if mem and mem ~= "" then
log("Memory: " .. mem)
end
-- Track how many times we've connected to this host
local key = "connect_count_" .. host
local count = storage_get(key) or 0
count = count + 1
storage_set(key, count)
log("You've connected to " .. host .. " " .. count .. " time(s)")
end
function on_disconnect(connection_id, host)
log("Disconnected from " .. host)
end

Save this as server-info.lua and install it from Settings > Plugins. Next time you connect to a server, check the plugin log to see the output.

Plugins run in a sandboxed Luau VM with no access to:

  • The local file system
  • Network sockets
  • OS-level operations
  • Other plugins’ storage

The only way a plugin can interact with the outside world is through the host API. This means a misbehaving plugin can’t read your files, make network requests, or interfere with other plugins.

  • Plugins cannot create custom UI beyond the built-in elements
  • No async/await — SSH commands block until they return
  • Plugin storage values must be strings or numbers
  • The plugin API is in beta and may change in future versions