Skip to content

Write scripts

This page shows how to structure a Reflex script so it is easy to read, retry and debug.

A script is a plain Lua file. The libraries (Rest, Json, Xlsx, Sel, Dates and more) are global, so there is nothing to import. The same script runs as a server job, from the CLI, in FitNesse and under TestNG.

local response = Rest.get("https://api.example.com/status")
Assert.equals(200, response.status)
print(Json.decode(response.body).version)

For ready-made recipes see the examples. Testing a web UI? Read browser testing.

A run gets the whole project. Every file is unpacked into a clean workspace on the agent, and the workspace is removed after the run.

  • Address files with paths relative to the project root, such as files/report.xlsx.
  • Put shared code in other .lua files and load it with require().
  • Files your script writes come back as run results. That is how generated reports leave the agent.

Split anything longer than a few lines into steps. Define a global Steps table. Each step shows up separately in the run, with its own status and output.

local function fetch(url)
local response = Rest.get(url)
Assert.equals(200, response.status)
Data.set("orders", Json.decode(response.body))
end
Steps = {
{
name = "fetch",
description = "Download the open orders",
condition = "always",
func = fetch,
params = { "https://api.example.com/orders?status=open" },
retry = 2,
},
{
name = "report",
description = "Write the report",
condition = "previous",
func = function() print(Data.json()) end,
params = {},
retry = 0,
},
}

All six fields are required. A step that misses one is skipped without a warning.

FieldMeaning
nameShown in the run. Spaces become _. setup is reserved.
descriptionWhat the step does.
conditionalways, previous (only if the previous step succeeded) or never.
funcThe step body. It receives the values in params.
paramsArguments for func. Use {} for none.
retryHow often to retry the step when it fails.

End with an always step for cleanup, such as Sel.close().

To retry a single call inside a step, use Retry.run(attempts, delayMs, fn). To check results, use Assert.

Never put passwords or tokens in a script. Add them as project secrets and read them with secret("name"), which takes exactly one argument:

local sftp = Sftp.newSession("report-user", secret("sftp_password"), "sftp.example.com")

Secret values are masked in run output. Add and manage secrets in Projects, secrets and roles.

  • Out: Data.set("key", value) stores a value with the run.
  • In: a job can import the data of another job’s last run. Your script reads it from Values: Values.key, or Values.job["other-job"].key.
  • Job inputs: values set on the job also arrive in Values.

Set up the import on the job: see Schedule jobs and suites.

Agents also run Python, with the same libraries as Python objects. Results behave like dictionaries:

Terminal window
reflex exec --lang python "print(Rest.get('https://httpbin.org/get')['status'])"

Python runs in a sandbox with access to the run workspace only. Lua is the most used path, so check the library reference for the functions you need.

Open the failed run and read the console of the failing step. The debugging guide covers replays, live debugging and the healer.