Step Configuration
Each step in a workflow is defined with the following properties:| Property | Purpose | Example |
|---|---|---|
id | Unique step identifier | "COLLECT_NAME" |
goal | Brief description (shown to the agent) | "Collect the user's name" |
instructions | Agent guidance (string or array) | "Ask for the user's full name." |
inputs | Parameters to collect (JSON Schema) | [{name: "user_name", type: "string"}] |
on | Lifecycle hooks for actions | {enter: [...], submit: [...]} |
next | Transition routing | ["NEXT_STEP"] or [{if: "...", id: "..."}] |
tools | Tool visibility control | {allow: [...], call: true} |
id
A unique string identifier for the step. Used in:- Transition routing (
nextentries) - Manual navigation (
go_to_step) - Debugging and logging
COLLECT_EMAIL, VERIFY_DOB).
goal
A brief description of what this step accomplishes. This text becomes the submit tool’s description, helping the agent understand the purpose of the current step.instructions
Guidance for the agent on how to execute this step. Can be a string or array of strings:inputs
Defines the parameters the agent should collect before advancing. See Inputs Schema for full details.next
Controls workflow routing after successful submission. See Step Transitions for full details.tools
Controls which tools the agent can access during this step. See Tool Configuration for full details.Lifecycle Hooks
Lifecycle hooks execute actions at specific points during step execution. Define them in theon property:
Event Summary
| Event | When Triggered | Allowed Actions | Primary Use Cases |
|---|---|---|---|
on.enter | Entering a step (before input collection) | get, set, inc, say, call | Step welcome messages, pre-populate inputs |
on.presubmit | After agent submits, before validation | get, set, inc, save | Default missing values, data transformation |
on.submit | After validation passes | set, inc, say, save, call | Persist data, trigger side effects |
on.enter
Executes when the workflow enters this step, before the agent begins input collection. Common uses:- Display step-specific greetings or progress indicators
- Pre-populate inputs from existing data
- Initialize step-local counters
on.presubmit
Executes after the agent calls the submit tool, but before input validation runs. Restriction: Nosay or call actions (data mutation only). This prevents confusing UX where the agent says “Saved!” but validation then fails.
Common uses:
- Default missing optional fields
- Transform input values before validation
on.submit
Executes after validation passes, before evaluating transitions. Common uses:- Persist inputs to global variables
- Update counters
- Confirm submission to user
- Trigger external tool calls
Actions Reference
Actions are the operations executed during lifecycle events. All actions support an optionalif condition.
Action Summary
| Action | Description | Key Parameters | Available In |
|---|---|---|---|
say | Queue a verbatim message | text, role | on.enter, on.submit |
set | Set a variable value | name, value or value_from | all events |
inc | Increment a counter | name, by | all events |
get | Pre-populate inputs from variables | inputs, overwrite | on.enter, on.presubmit |
save | Persist inputs to global variables | name, inputs | on.presubmit, on.submit |
call | Queue a tool call | name, arguments | on.enter, on.submit |
say
Queues text that the agent must include verbatim in its response.| Parameter | Type | Default | Description |
|---|---|---|---|
text | string | required | Verbatim text to include |
role | string | "assistant" | Message role |
if | string | - | Optional condition |
say text is approximately 95%. The agent may occasionally add minor variations.
set
Sets a variable to a static value or computed expression.| Parameter | Type | Description |
|---|---|---|
name | string | Target variable path (e.g., local.x, user_name) |
value | any | Static value to set |
value_from | Expression | Dynamic value from expression (mutually exclusive with value) |
if | string | Optional condition |
inc
Increments a numeric variable. Creates the variable with value 0 if it doesn’t exist.| Parameter | Type | Default | Description |
|---|---|---|---|
name | string | required | Variable to increment |
by | number | 1 | Amount to increment by |
if | string | - | Optional condition |
get
Copies values from existing variables into step inputs. Useful for pre-filling forms with known data.| Parameter | Type | Default | Description |
|---|---|---|---|
inputs | list[string] | all inputs | Which inputs to populate |
overwrite | boolean | false | If true, overwrite existing input values |
if | string | - | Optional condition |
save
Saves step inputs to global variables for use in later steps or after workflow completion.| Parameter | Type | Default | Description |
|---|---|---|---|
inputs | list[string] | all inputs | Which inputs to save |
name | string | input name | Target variable name (for single input) |
if | string | - | Optional condition |
call
Queues a tool call to be executed. The call is injected into the conversation.| Parameter | Type | Description |
|---|---|---|
name | string | Tool name to call |
arguments | object | Template-rendered arguments |
if | string | Optional condition |
call action queues the tool call; it doesn’t execute immediately. The call is processed in the next middleware pass.
Conditional Actions
All actions support an optionalif field for conditional execution:
if condition is evaluated as a JMESPath expression by default. See Expressions for syntax details.
Expressions
Expressions are used in conditions (if fields), computed values (value_from), and step transitions (next[].if).
JMESPath (Default)
JMESPath is the default expression language. When you write a string condition, it’s evaluated as JMESPath. Common Patterns:| Issue | Wrong | Correct |
|---|---|---|
| Boolean literals need backticks | flag == true | flag == \true“ |
| Number literals need backticks | count > 3 | count >= \3“ |
| String quotes | name == morning | name == 'morning' |
CEL (Common Expression Language)
CEL is useful when you need features JMESPath doesn’t support: arithmetic, string concatenation, or ternary operators. Syntax:inputs.address.city). Use JMESPath for nested structures.
When to Use Which
| Use Case | Recommended | Why |
|---|---|---|
| Simple condition checks | JMESPath | Default, no syntax overhead |
| String comparisons | JMESPath | Cleaner syntax |
| Nested property access | JMESPath | CEL doesn’t support it |
| Arithmetic | CEL | JMESPath can’t compute |
| String building | CEL | JMESPath can’t concatenate |
| Ternary logic | CEL | Clean conditional values |
Inputs Schema
Each step can defineinputs—parameters that the agent should collect before advancing.
Input Parameters
Theinputs array defines parameters that become the submit tool’s function schema:
Available Fields
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Parameter name |
type | string | No | JSON Schema type: string, number, integer, boolean, object, array. Defaults to string |
description | string | No | Human-readable description shown to agent |
required | boolean | No | Whether parameter must be collected. Defaults to true |
enum | list[str] | No | Allowed values (agent constrained to these options) |
format | string | No | Format hint: date, time, date-time, email, uri, etc. |
pattern | string | No | Regex pattern for validation |
Accumulation Behavior
Inputs accumulate across multiple submissions until all required fields are collected:- New values overwrite: If the agent provides a new value for an existing input, it replaces the old value
- Missing values retained: Inputs not included in a call keep their previous values
- Empty string = missing: For string types,
""and whitespace-only strings are treated as empty
Reset on Transition
Important: Input variables (inputs.*) are cleared when transitioning to a new step. To preserve values across steps, use the save or set actions:
Templates
Template substitution lets you inject dynamic values into text fields using variable placeholders.Supported Syntax
| Syntax | Behavior | Example |
|---|---|---|
{{var}} | Replace with value, or empty string if missing | {{user_name}} → "Alice" or "" |
${var} | Replace with value, or empty string if missing | ${user_name} → "Alice" or "" |
${var=default} | Replace with value, or default if missing | ${name=Guest} → "Alice" or "Guest" |
{{var}} (handlebars style) for most cases.
Where Templates Are Expanded
| Field | Template Expansion | Notes |
|---|---|---|
instructions[] | Yes | Step instructions are rendered with current context |
say action text | Yes | Message text is rendered before queuing |
set action value | Yes (if string) | Static string values are rendered |
call action arguments | Yes (recursive) | All string values in arguments are rendered |
goal | No | Used as-is |
if conditions | No | Use expression evaluation instead |
value_from | No | Use expression evaluation (JMESPath/CEL) |
Available Variables
| Scope | Access Pattern | Example |
|---|---|---|
| Global variables | {{variable_name}} | {{user_name}} |
| Task-local state | {{local.key}} | {{local.retry_count}} |
| Step inputs | {{inputs.field}} | {{inputs.provided_dob}} |
| Nested values | {{scope.path.to.value}} | {{inputs.address.city}} |
Examples
In instructions:Step Transitions
Thenext field controls workflow routing after a step is successfully submitted.
Transition Basics
Evaluation Order
Transitions are evaluated in order. The first matching entry wins:- Iterate through
nextarray from first to last - For each entry: if it has an
ifcondition, evaluate it - If condition is true (or no condition), transition to that step
- If no entries match, the workflow cannot proceed (error state)
if as the last item:
Terminal Steps
A step is terminal if:- It has no
nextfield, OR - It has
"next": [](empty array)
- The workflow is marked as completed
- The submit tool is removed from the agent’s available tools
- The workflow state is preserved for reference
Loop-Back Transitions
Steps can transition back to themselves or earlier steps for retry patterns:Tool Configuration
Thetools field on a step controls which tools the agent can access and whether to force specific tool behavior.
Configuration Options
| Field | Type | Default | Description |
|---|---|---|---|
tools.allow | list[string] | null (all) | Whitelist of allowed tool names |
tools.call | boolean | false | Force immediate tool call |
tools.allow_go_to_step | boolean | false | Expose manual step navigation |
tools.allow
Restricts which tools the agent can see during this step. The submit tool is always available regardless of this setting.- Prevent agent from calling irrelevant tools during sensitive steps
- Progressive disclosure: unlock tools as workflow progresses
- Security: restrict access to sensitive operations
tools.call
Whentrue, forces the agent to make a tool call before responding to the user. Typically used with on.enter call actions.
- Sets
tool_choice: requiredin the agent request - Combined with queued
callactions, ensures specific tools are called - Useful for fetching data before proceeding
tools.allow_go_to_step
Whentrue, adds a go_to_step parameter to the submit tool schema, allowing the agent to manually jump to a specific step.
- The agent chooses the step by name
- Invalid step IDs return a validation error
- Bypasses normal
nextevaluation when used
Variables
Step Workflows use multiple variable scopes for different purposes.Variable Scopes
| Scope | Prefix | Lifetime | Use Case |
|---|---|---|---|
| Global | (none) or vars.* | Conversation | Shared data, final outputs |
| Task-local | local.* | Workflow | Counters, flags, intermediate state |
| Step inputs | inputs.* | Current step | Collected input parameters |
Global Variables
Global variables persist for the entire conversation and are accessible to all tools and workflows.- Data needed after the workflow completes
- Sharing data between concurrent workflows
- Final outputs that other systems will use
Task-Local Variables
Task-local variables (local.*) are scoped to a single workflow instance.
- Retry counters within the workflow
- Flags and intermediate state
- Data that shouldn’t persist after workflow completion
Step Inputs
Step inputs (inputs.*) contain the current step’s collected parameters.
Key behaviors:
- Cleared when transitioning to the next step
- Accumulated across multiple submissions
- Read-only in expressions; use
setto modify
| Context | Available Inputs |
|---|---|
on.enter | Empty (step just started) |
on.presubmit | Values from current submit call |
on.submit | Validated values (all required present) |
if conditions | Current accumulated values |
| Templates | Current accumulated values |
When to Use Which Scope
| Scenario | Scope | Why |
|---|---|---|
| Data needed after workflow completes | Global | Persists beyond workflow |
| Retry counter within workflow | local.* | Workflow-specific state |
| Sharing between concurrent workflows | Global | Task-local is isolated |
| Sensitive intermediate data | local.* | More contained scope |

