functionExpressions and JSONata Scopes

Expressions let a workflow compute values from the trigger input, runtime context, previous task output, and loop state. Hexabot uses JSONataarrow-up-right for these expressions.

Any string that starts with = is evaluated as a JSONata expression. A string that does not start with = is treated as a literal value.

defs:
  send_literal:
    kind: task
    action: send_text_message
    inputs:
      text: "Hello"

  send_dynamic:
    kind: task
    action: send_text_message
    inputs:
      text: "='You said: ' & $input.text"

In this example, send_literal.inputs.text is the literal string Hello, while send_dynamic.inputs.text is evaluated before the task runs.

For the JSONata language itself, use the official JSONata documentationarrow-up-right. This page focuses on how JSONata is used inside Hexabot workflows.

Where Expressions Are Used

Expressions are commonly used in:

Location
Example
Purpose

Task inputs

text: "='Hello ' & $input.name"

Build dynamic action inputs.

Conditional branches

condition: "=$input.text = 'help'"

Decide which branch runs.

Loop inputs

in: "=$input.items"

Choose the array a for_each loop iterates over.

Loop conditions

while: "=$not($exists($output.reply.text))"

Continue or stop a while loop.

Loop accumulators

merge: "=$append($accumulator, [$output.send_message])"

Collect values across iterations.

Final outputs

result: "=$output.lookup_customer"

Shape the workflow result.

The editor's expression fields switch into JSONata mode when the value starts with =. In JSONata mode, the field highlights syntax problems and can suggest known workflow scopes such as $input, $output, and $context.

Literal Values vs Expressions

The leading = is the important difference.

YAML value
Meaning

"Hello"

Literal string.

"=$input.text"

Expression that returns the workflow input text.

"='Hello ' & $input.name"

Expression that concatenates text with an input value.

5

Literal number.

true

Literal boolean.

{ limit: 5 }

Literal object.

Quote expression strings in YAML when they contain punctuation, braces, regular expressions, or comparison operators. This avoids YAML parsing surprises and makes expressions easier to review.

Available Scopes

Hexabot evaluates expressions with a set of workflow scopes.

Scope
Available where
What it contains

$input

Most workflow expressions

The validated input payload for the run.

$context

Most workflow expressions

Runtime metadata and state injected by Hexabot.

$output.<task_id>

After a task has run

Raw output returned by a task action.

$iteration

Inside loop steps and loop expressions

Current loop item and zero-based index.

$accumulator

Inside loops that use accumulate

Current accumulator value before the merge expression returns the next value.

Scopes are read-only from the expression's point of view. To change external state, use an action designed to write that state.

$input

$input is the workflow trigger payload.

For conversational workflows, it includes message data such as text and message. For manual workflows, it follows the input schema defined by the workflow author. For scheduled workflows, it includes schedule metadata.

Examples:

Useful patterns:

Need
Expression

Read incoming text

"=$input.text"

Normalize text

"=$lowercase($trim($input.text))"

Check for a keyword

"=$contains($lowercase($input.text), 'help')"

Count input items

"=$count($input.items)"

Filter open items

"=$input.items[status = 'open']"

$context

$context contains runtime metadata and state supplied by Hexabot. The editor can suggest common fields such as:

Field
Meaning

$context.initiatorId

Identifier for the subscriber, user, schedule, or caller that started the run.

$context.workflowId

Current workflow ID.

$context.runId

Current workflow run ID.

$context.memory

Loaded workflow memory values, keyed by memory slug when memory is mounted.

The exact context can vary by workflow type and runtime integration.

Examples:

Use $context for metadata and read-only state. Use task outputs when you need results produced during the current run.

$output.<task_id>

Each task result is stored under $output.<task_id>.

Only read outputs from tasks that have already run on the current path. This is especially important with conditionals and wait_any parallel blocks.

Safe output checks:

Useful patterns:

Need
Expression

Check whether a task ran

"=$exists($output.lookup_customer)"

Read a nested result

"=$output.lookup_customer.body.status"

Fallback value

"=$exists($output.lookup_customer.body.status) ? $output.lookup_customer.body.status : 'unknown'"

Build a final output

"={'status': $output.lookup_customer.body.status, 'run_id': $context.runId}"

$iteration

$iteration is available inside loop bodies and loop-related expressions.

Field
Meaning

$iteration.item

Current item in a for_each loop.

$iteration.index

Zero-based iteration index.

Example:

Use $iteration only inside the loop. Outside the loop, it is not available.

$accumulator

$accumulator is available when a loop defines accumulate. It holds the current accumulated value. The merge expression returns the next accumulated value.

Common accumulator shapes:

Goal
Initial value
Merge expression

Count iterations

0

"=$accumulator + 1"

Collect task results

[]

"=$append($accumulator, [$output.process_item])"

Collect current items

[]

"=$append($accumulator, [$iteration.item])"

Keep latest value

null

"=$output.process_item"

If you want to expose the accumulator as a workflow output, give the loop a name and read $output.<loop_name>.<accumulator_name>.

Practical JSONata Examples

Text Formatting

Boolean Conditions

Regular Expression Matching

This example checks whether a reply contains exactly eight digits:

The same pattern can be used in a while loop to keep asking until a valid value is received:

Arrays

Objects

For larger objects, use YAML block style to keep the expression readable:

Authoring Tips

  • Start dynamic values with =.

  • Keep literal text as normal strings without =.

  • Prefer clear task IDs because they become $output.<task_id> paths.

  • Use $exists(...) before reading optional task output.

  • Use the graph editor for branch and loop structure, then review expressions in YAML.

  • Quote expressions in YAML unless the expression is very simple.

  • Keep complex expressions small. If an expression becomes hard to review, move the work into a task.

Troubleshooting

Problem
Likely cause
Fix

Value is sent literally, such as $input.text

Missing leading =.

Use "=$input.text".

Editor reports invalid JSONata

Syntax error after the leading =.

Check quotes, parentheses, and function calls.

Output path is empty

The task has not run on this path, or the task ID is wrong.

Check flow, branch logic, and task ID spelling.

Expression works in one branch but fails in another

A referenced output is branch-specific.

Guard with $exists(...) or move the dependent step into the same branch.

Loop expression cannot read $iteration

The expression is outside the loop.

Use $iteration only inside loop steps, until, or accumulator expressions.

Last updated

Was this helpful?