Skip to main content

script

script

Runs a user-provided script as a graph node behind the same plugin contract as native plugins. The script receives the full Context (request, response, message) and returns a possibly modified copy; anything it writes into ctx.message is visible to downstream nodes. It can sit anywhere in the request or response pipeline. Only the Lua (Luau) runtime is currently supported. See the Lua scripting guide for the full Context table shape and examples.

Configuration

KeyTypeDefaultDescription
runtimestringluaScripting runtime. Any value other than lua is a config error.
sourcestringPath to a script file, read at policy-compile time.
inlinestringScript text embedded in the config. One of source or inline is required (source wins if both are set).
timeout_msinteger5000Script execution timeout. Currently stored but not enforced — see the warning below.
modules_pathstringsource's parent directory (none for inline)Directory the sandboxed require resolves modules from.
- id: enrich
type: script
config:
runtime: lua
source: scripts/enrich.lua
timeout_ms: 2000

The script must define a global execute(ctx) function that returns the (possibly modified) context table:

function execute(ctx)
ctx.request.headers["x-enriched"] = {"true"}
ctx.message.user_tier = "gold"
return ctx
end
warning

timeout_ms is parsed and stored but not yet enforced by the Lua VM. A script that loops forever will block the request indefinitely.

Note: the UI node editor's runtime select also lists python; choosing it fails at policy-compile time, since only lua is implemented.

Behavior

Scripts are loaded and validated once at policy-compile time, not per request: syntax errors, a failing top level, or a missing global execute function reject the policy immediately. At request time each execution runs in a fresh Lua VM, so scripts cannot leak state between requests.

require is sandboxed to modules_path: module names containing .., /, or \ are rejected, and modules resolve as <modules_path>/<name>.lua. Modules are re-evaluated on every require (no caching). With no modules_path (e.g. inline without an explicit setting), require is unavailable.

On success the context rebuilt from the script's return value flows through the success port. context.errors and the wire protocol are not exposed to scripts and are carried over unchanged. Any failure routes the original context through the error port with one of these codes appended to context.errors:

CodeMeaning
LUA_LOAD_ERRORThe script failed to load into the VM.
LUA_MARSHAL_ERRORThe Context could not be converted to a Lua table.
LUA_MISSING_EXECUTENo global execute function was found.
LUA_EXECUTION_ERRORThe script raised a runtime error.
LUA_UNMARSHAL_ERRORThe returned table could not be converted back to a Context.