DSL Reference
Complete reference for reArray's task automation language: structure, selectors, actions, conditions, and flow control.
reArray tasks are written in a domain-specific language (DSL) executed by agents against real browser sessions. This page is the canonical syntax reference.
Required structure
- Exactly one
flow { ... }block per script - Platforms are preconfigured on the agent — do not declare platforms in DSL
- Use configured platform handlers directly:
in login { ... }
Variable namespaces
| Prefix | Source |
|---|---|
$params.* | Execution inputs (UI form or API) |
$settings.* | Agent settings |
$store.* | Read-only run-wide bag populated via store |
$secrets.* | Platform vault credentials (only inside in handler { }) |
$context.* | Read-only execution metadata |
$name | Block/loop-scoped local variable |
Locals ($name)
- Declare and assign with
$x = <expr>. First assignment creates the binding; later assignments update it in the current scope. - Locals are scoped to the current block (
in,if,for,whilebody). - Example:
$i = $i + 1,$fullName = "Hello {$params.name}".
Store bag (store)
- Write persistent values with
store <key> <expr>. - Read with
$store.<key>. $storeitself is read-only except throughstorestatements.
flow {
in portal {
store orderId extract { css "#order-id" }
store receipt { orderId: $store.orderId, runAt: $context.startTime }
}
}
Execution context ($context)
| Field | Value |
|---|---|
$context.startTime | Task start timestamp (ISO 8601, agent timezone). Frozen for the run. |
$context.timezone | Agent IANA timezone (e.g. America/Sao_Paulo). |
$context.executionId | Current execution id. |
$context.agentId | Agent id running the task. |
String interpolation
Inside any string literal, {expr} embeds a value. Escape literal braces as \{ and \}.
fill { css "#search" } "Query: {$params.term}"
fill { css "#from" } "From: {now(days = -30, unit = "date")}"
Expressions
Operators (precedence low → high)
| Level | Operators |
|---|---|
| Boolean OR | or |
| Boolean AND | and |
| Unary NOT | not |
| Comparison | == != < <= > >= |
| Additive | + - |
| Multiplicative | * / % |
| Unary minus | - |
Comparisons are numeric-aware when both sides coerce to numbers; otherwise strings/objects use deep equality.
if $params.mode == "fast" and visible { css "#ready" } { ... }
if $total > 100 or $store.force { ... }
Values
- Literals:
"text",123,true,false,null - Arrays:
[1, 2, $params.id] - Objects:
{ key: "value", count: $store.n } - Variables:
$params.foo,$store.bar,$myLocal now(...)— live date/time (see below)infer "prompt" with ($page)— LLM-inferred valueextract { selector } [attribute "href"] [timeout N] [default value]extract_all { selector } [attribute "href"] [timeout N] [default value]
Current time (now(...))
Evaluated on every reference (unlike frozen $context.startTime).
now() // full object now(unit = "date") // YYYY-MM-DD now(days = -30, unit = "date") // 30 days ago now(hours = 2, unit = "time") // HH:mm:ss now(unit = "date", tz = "America/New_York")
Deltas: years, months, weeks, days, hours, minutes, seconds (integers, may be negative).
Output units: iso, date, time, datetime, year, month, day, hour, minute, second, weekday, weekdayName, epochMs, epochSec.
flow {
in reports {
$t = now()
fill { css "#year" } $t.year
fill { css "#from" } now(days = -30, unit = "date")
fill { css "#to" } now(unit = "date")
}
}
Selectors
| Form | Example |
|---|---|
| CSS | { css "#submit" } |
| XPath | { xpath "//button[@type='submit']" } |
| Text | { text "Continue" } |
| Role | { role "button" } |
| Role + name | { role "button" "Continue" } |
| Fallback chain | { css "#submit" xpath "//button[@type='submit']" } |
| Frame scope | { frame "f0" css "#card-number" } |
| Interpolated CSS | { css "[data-invoice-id='{$params.invoiceId}']" } |
| Interpolated text | { text "Invoice {$params.invoiceId}" } |
css and text selectors may embed {expr} holes that resolve at run time; xpath and role may not. Keep the literal parts of the selector and interpolate only the value that varies — a selector made entirely of holes (css "{$params.sel}") is rejected. Put holes inside quotes ([data-id='{$params.id}']); an unquoted hole (#row-{$params.id}) accepts only bare identifier values.
To pick one row of a table by a value in one of its cells, interpolate into a :has() filter:
click { css "#invoices tr:has(td:text-is('{$params.invoiceId}')) button.open" }
Actions
click {selector} [timeout N]
fill {selector} expr [typing] [timeout N]
select {selector} expr [using ai] [timeout N]
wait expr [timeout N]
assert expr
upload {selector} expr [timeout N]
download {selector} [timeout N]
solve_captcha
fill {sel} "4242"— instant fill (default): fast, firesinput/change, skips key events.fill {sel} "4242" typing— clears the field then types character-by-character with real key events. Use for input masks, autocomplete pickers, or per-keystroke validation. Slower (~20ms per character). Must not contain newlines or tabs.select {sel} "US"— literal option value.select {sel} $params.country using ai— LLM maps input to the best<option>.
Implicit waits: click, fill, select, download, and screenshot {sel} poll until the target is visible (same as wait visible {sel}) before acting. upload and extract poll until the element exists (hidden inputs are OK). Default timeout is 10 seconds; add timeout N (milliseconds) to override. You usually do not need a separate wait visible before fill or click.
Use store <key> extract { ... } or $x = extract { ... } to capture DOM values. extract waits for a non-empty value by default; add timeout N and default value to control wait behavior and fallbacks.
Conditions (DOM + expressions)
DOM conditions are expressions:
visible {selector}
exists {selector}
element_contains [case_sensitive expr] {selector} expr
decide "question?" with ($page)
not (expr)
element_containsis substring match; case-insensitive by default.case_sensitive trueprefix enables case-sensitive matching.
Flow control
if expr { ... } else { ... }
for $item in expr { ... }
while expr [max N] { ... }
break
terminate
terminate(expr)
$x = expr
store key expr
in platformHandler { ... }
terminateends the run;terminate({ result: $store.data })sets the final payload (parentheses required when passing a value).while max Nlimits iterations (integer 1–100).breakonly works insidewhile.
LLM helpers (decide / infer)
if decide "Is the user logged in?" with ($page) { ... } else { ... }
$label = infer "primary CTA label" with ($page)
withis required; use parentheses:with ($page),with ($page, $store),with (fragment { css ".panel" }, $params).- Never include
$secretsinwith.
See AI Helpers for usage guidance.
Platform blocks
Wrap site-specific steps in in handler { ... }:
flow {
in login_portal {
fill { css "#email" } $secrets.username
click { css "#submit" }
}
in crm {
store accountName extract { css ".account-name" }
}
}
$secrets.* is only valid inside the matching platform block.
Minimal valid template
flow {
in portal {
if visible { css "#dashboard" } {
// already signed in
} else {
if visible { css "#login-form" } {
fill { css "#username" } $secrets.username
fill { css "#password" } $secrets.password
click { css "button[type='submit']" }
}
wait visible { css "#dashboard" } timeout 30000
}
store welcome extract { css "#welcome-message" }
}
}
Common mistakes
| Mistake | Fix |
|---|---|
Missing flow block | Wrap all statements in flow { ... } |
| Local assignment | Use $x = expr |
| Persist extracted value | Use store key extract { ... } or $x = extract { ... } |
$secrets outside in | Move secrets usage inside in handler { } |
Missing with on decide/infer | Both require with (...) |
break outside while | Only valid inside while loops |
Invalid while max | Must be integer 1–100 |
Bare terminate value | Use terminate(value) with parentheses |
Session-aware authentication
See Credentials for the recommended login pattern that handles both fresh and persisted sessions.