How to Use Variables for Shared State in Flows#

python-icon Download Python Script

Python script/notebook for this guide.

Variable how-to script

Prerequisites

This guide assumes familiarity with Flows

When building Flows, you may need a way to preserve information as it moves from one step to another. WayFlow provides this through Variable, which serves as the flow’s state — a place where values can be stored, accessed, and updated throughout execution.

Why to use Variable?

  • Shared state: Holds data that multiple steps can share.

  • Intermediate results: Store partial results and reuse them later.

  • Simpler data flow: Avoid passing outputs between every step, persist them as state using Variable.

This guide will show you how to:

In this guide, you will see a simple example including defining a Variable that stores a list of user feedback, using VariableStep to insert new feedback into the list and read all collected feedback.

Define a Variable#

To define a variable, you need to define it with a name, type and optionally, a default value. The type of variable determines the kind of data it can hold and is defined using Property. In this case, our feedback_variable has the type of ListProperty and the item_type of StringProperty.

1from wayflowcore.variable import Variable
2from wayflowcore.property import ListProperty, StringProperty
3
4feedback_variable = Variable(
5    name="user_feedback",
6    type=ListProperty(item_type=StringProperty()),
7    description="list of user feedback",
8    default_value=[],
9)

API Reference: Variable | Property

Define Flow Steps#

We will define a simple flow including the following steps.

 1from wayflowcore.steps import StartStep, OutputMessageStep, VariableStep
 2from wayflowcore.property import StringProperty
 3from wayflowcore.variable import VariableWriteOperation
 4
 5FEEDBACK_1 = "feedback_1"
 6FEEDBACK_2 = "feedback_2"
 7
 8start_step = StartStep(
 9    name="start_step",
10    input_descriptors=[StringProperty(FEEDBACK_1), StringProperty(FEEDBACK_2)],
11)
12
13write_feedback_1 = VariableStep(
14    name="write_var_step_1",
15    write_variables=[feedback_variable],
16    write_operations=VariableWriteOperation.INSERT,
17)
18
19write_feedback_2 = VariableStep(
20    name="write_var_step_2",
21    write_variables=[feedback_variable],
22    write_operations=VariableWriteOperation.INSERT,
23)
24
25read_feedback = VariableStep(
26    name="read_var_step",
27    read_variables=[feedback_variable],
28)
29
30output_step = OutputMessageStep("Collected feedback: {{ feedback }}", name="output_step")

For simplicity, we pass initial feedback to the start_step, which then routes values to write_feedback_1 and write_feedback_2. In practice, those inputs could come from other steps (e.g. ToolExecutionStep).

When updating some variables, the VariableStep requires the write_variables that it writes to. It also accepts the following options of write operations:

  • VariableWriteOperation.OVERWRITE (or 'overwrite') works on any type of variable to replace its value with the incoming value.

  • VariableWriteOperation.MERGE (or 'merge') updates a Variable of type dict (resp. list),

  • VariableWriteOperation.INSERT (or 'insert') operation can be used to append a single element at the end of a list.

Here, we choose insert as we want to append new user feedback to the our list.

The VariableStep can also read one or more variables, via the read_variables parameter.

The VariableStep can perform both writes and reads of multiple variables at the same time. If you configure a step to both write and read a given variable, the value will be written first, and the updated variable will be used for the read operation.

In general, the input and output descriptors of the VariableStep correspond to the properties referenced by the variables being written and/or read in this step, respectively. For example, if the step is configured to overwrite a Variable(name="manager", type=DictProperty()), to extend a Variable(name="employees", type=ListProperty(item_type=DictProperty("employee")), and to read back the updated value of the employee list, the step would have the following descriptors:

  • An input descriptor DictProperty("manager"), to overwrite the full manager variable;

  • An input descriptor DictProperty("employee"), since the extend operation expects a single item of the employees list;

  • An output descriptor ListProperty("employees", item_type=DictProperty("employee"))

Define a Flow with Variable#

Now we connect everything into a flow: two write steps add feedback, and a read step collects it all for output.

 1from wayflowcore.controlconnection import ControlFlowEdge
 2from wayflowcore.dataconnection import DataFlowEdge
 3from wayflowcore.flow import Flow
 4
 5flow = Flow(
 6    begin_step=start_step,
 7    control_flow_edges=[
 8        ControlFlowEdge(start_step, write_feedback_1),
 9        ControlFlowEdge(write_feedback_1, write_feedback_2),
10        ControlFlowEdge(write_feedback_2, read_feedback),
11        ControlFlowEdge(read_feedback, output_step),
12        ControlFlowEdge(output_step, None),
13    ],
14    data_flow_edges=[
15        DataFlowEdge(start_step, FEEDBACK_1, write_feedback_1, feedback_variable.name),
16        DataFlowEdge(start_step, FEEDBACK_2, write_feedback_2, feedback_variable.name),
17        DataFlowEdge(read_feedback, feedback_variable.name, output_step, "feedback"),
18    ],
19    variables=[feedback_variable],
20)

Remember to include your defined variables in the Flow’s variables parameter.

Execute the Flow#

Finally, run the flow:

 1conv = flow.start_conversation(
 2    inputs={
 3        FEEDBACK_1: "Very good!",
 4        FEEDBACK_2: "Need to improve!",
 5    }
 6)
 7conv.execute()
 8
 9result = conv.get_last_message().content
10print(result)
11# >>> Collected feedback: ["Very good!", "Need to improve!"]

Agent Spec Exporting/Loading#

You can export the assistant configuration to its Agent Spec configuration using the AgentSpecExporter.

from wayflowcore.agentspec import AgentSpecExporter

serialized_assistant = AgentSpecExporter().to_yaml(flow)

Here is what the Agent Spec representation will look like ↓

Click here to see the AgentSpec assistant configuration.
component_type: ExtendedFlow
id: b41482ac-31b3-4117-805e-cb34931e9971
name: flow_3fc1343f__auto
description: ''
metadata:
  __metadata_info__: {}
inputs:
- type: string
  title: feedback_1
- type: string
  title: feedback_2
outputs:
- description: list of user feedback
  type: array
  items:
    type: string
  title: user_feedback
  default: []
- description: the message added to the messages list
  type: string
  title: output_message
start_node:
  $component_ref: 57f93e9d-9d58-4c7b-8d53-22f6d40b2a3b
nodes:
- $component_ref: 57f93e9d-9d58-4c7b-8d53-22f6d40b2a3b
- $component_ref: be27d2dc-0185-41b0-bbbc-31060306b34c
- $component_ref: 4991b600-4fe1-4e46-82f8-6d0764989291
- $component_ref: e8e2df93-abc9-492a-9c0b-92c4a68895b9
- $component_ref: bd2331f9-c336-446d-b6e8-5c4365e4327b
- $component_ref: 9834131e-83bf-4927-81bc-89965824271f
control_flow_connections:
- component_type: ControlFlowEdge
  id: c98164c9-eeaa-42da-9f42-c8e574b34c4a
  name: start_step_to_write_var_step_1_control_flow_edge
  description: null
  metadata:
    __metadata_info__: {}
  from_node:
    $component_ref: 57f93e9d-9d58-4c7b-8d53-22f6d40b2a3b
  from_branch: null
  to_node:
    $component_ref: be27d2dc-0185-41b0-bbbc-31060306b34c
- component_type: ControlFlowEdge
  id: 95b902ad-6e56-4587-9e92-d725c955f5b1
  name: write_var_step_1_to_write_var_step_2_control_flow_edge
  description: null
  metadata:
    __metadata_info__: {}
  from_node:
    $component_ref: be27d2dc-0185-41b0-bbbc-31060306b34c
  from_branch: null
  to_node:
    $component_ref: 4991b600-4fe1-4e46-82f8-6d0764989291
- component_type: ControlFlowEdge
  id: 57bafe45-a33c-44bc-a21a-51205da9a8d8
  name: write_var_step_2_to_read_var_step_control_flow_edge
  description: null
  metadata:
    __metadata_info__: {}
  from_node:
    $component_ref: 4991b600-4fe1-4e46-82f8-6d0764989291
  from_branch: null
  to_node:
    $component_ref: e8e2df93-abc9-492a-9c0b-92c4a68895b9
- component_type: ControlFlowEdge
  id: 621e214c-4048-409d-920d-7af0a09dd46a
  name: read_var_step_to_output_step_control_flow_edge
  description: null
  metadata:
    __metadata_info__: {}
  from_node:
    $component_ref: e8e2df93-abc9-492a-9c0b-92c4a68895b9
  from_branch: null
  to_node:
    $component_ref: bd2331f9-c336-446d-b6e8-5c4365e4327b
- component_type: ControlFlowEdge
  id: 4325173c-575c-41d1-9222-8f263267ec93
  name: output_step_to_None End node_control_flow_edge
  description: null
  metadata: {}
  from_node:
    $component_ref: bd2331f9-c336-446d-b6e8-5c4365e4327b
  from_branch: null
  to_node:
    $component_ref: 9834131e-83bf-4927-81bc-89965824271f
data_flow_connections:
- component_type: DataFlowEdge
  id: 29904c9b-8ff3-410c-a484-d95a9f4f9248
  name: start_step_feedback_1_to_write_var_step_1_user_feedback_data_flow_edge
  description: null
  metadata:
    __metadata_info__: {}
  source_node:
    $component_ref: 57f93e9d-9d58-4c7b-8d53-22f6d40b2a3b
  source_output: feedback_1
  destination_node:
    $component_ref: be27d2dc-0185-41b0-bbbc-31060306b34c
  destination_input: user_feedback
- component_type: DataFlowEdge
  id: 5440b896-e11b-48b3-ae83-4e0832f87bc6
  name: start_step_feedback_2_to_write_var_step_2_user_feedback_data_flow_edge
  description: null
  metadata:
    __metadata_info__: {}
  source_node:
    $component_ref: 57f93e9d-9d58-4c7b-8d53-22f6d40b2a3b
  source_output: feedback_2
  destination_node:
    $component_ref: 4991b600-4fe1-4e46-82f8-6d0764989291
  destination_input: user_feedback
- component_type: DataFlowEdge
  id: ff59cde4-e95d-4caf-b8b3-0e9097013bb2
  name: read_var_step_user_feedback_to_output_step_feedback_data_flow_edge
  description: null
  metadata:
    __metadata_info__: {}
  source_node:
    $component_ref: e8e2df93-abc9-492a-9c0b-92c4a68895b9
  source_output: user_feedback
  destination_node:
    $component_ref: bd2331f9-c336-446d-b6e8-5c4365e4327b
  destination_input: feedback
- component_type: DataFlowEdge
  id: f003fdad-8e7c-4d24-914f-1f30fa393f0d
  name: read_var_step_user_feedback_to_None End node_user_feedback_data_flow_edge
  description: null
  metadata: {}
  source_node:
    $component_ref: e8e2df93-abc9-492a-9c0b-92c4a68895b9
  source_output: user_feedback
  destination_node:
    $component_ref: 9834131e-83bf-4927-81bc-89965824271f
  destination_input: user_feedback
- component_type: DataFlowEdge
  id: 200b7819-9b5a-449e-9ce0-dbf1c78d8430
  name: output_step_output_message_to_None End node_output_message_data_flow_edge
  description: null
  metadata: {}
  source_node:
    $component_ref: bd2331f9-c336-446d-b6e8-5c4365e4327b
  source_output: output_message
  destination_node:
    $component_ref: 9834131e-83bf-4927-81bc-89965824271f
  destination_input: output_message
context_providers: []
state:
- description: list of user feedback
  type: array
  items:
    type: string
  title: user_feedback
  default: []
component_plugin_name: FlowPlugin
component_plugin_version: 26.1.0.dev4
$referenced_components:
  57f93e9d-9d58-4c7b-8d53-22f6d40b2a3b:
    component_type: StartNode
    id: 57f93e9d-9d58-4c7b-8d53-22f6d40b2a3b
    name: start_step
    description: ''
    metadata:
      __metadata_info__: {}
    inputs:
    - type: string
      title: feedback_1
    - type: string
      title: feedback_2
    outputs:
    - type: string
      title: feedback_1
    - type: string
      title: feedback_2
    branches:
    - next
  be27d2dc-0185-41b0-bbbc-31060306b34c:
    component_type: PluginVariableNode
    id: be27d2dc-0185-41b0-bbbc-31060306b34c
    name: write_var_step_1
    description: ''
    metadata:
      __metadata_info__: {}
    inputs:
    - description: list of user feedback (single element)
      type: string
      title: user_feedback
    outputs: []
    branches:
    - next
    input_mapping: {}
    output_mapping: {}
    write_variables:
    - description: list of user feedback
      type: array
      items:
        type: string
      title: user_feedback
      default: []
    read_variables: []
    write_operations:
      user_feedback: insert
    component_plugin_name: NodesPlugin
    component_plugin_version: 26.1.0.dev4
  4991b600-4fe1-4e46-82f8-6d0764989291:
    component_type: PluginVariableNode
    id: 4991b600-4fe1-4e46-82f8-6d0764989291
    name: write_var_step_2
    description: ''
    metadata:
      __metadata_info__: {}
    inputs:
    - description: list of user feedback (single element)
      type: string
      title: user_feedback
    outputs: []
    branches:
    - next
    input_mapping: {}
    output_mapping: {}
    write_variables:
    - description: list of user feedback
      type: array
      items:
        type: string
      title: user_feedback
      default: []
    read_variables: []
    write_operations:
      user_feedback: insert
    component_plugin_name: NodesPlugin
    component_plugin_version: 26.1.0.dev4
  e8e2df93-abc9-492a-9c0b-92c4a68895b9:
    component_type: PluginVariableNode
    id: e8e2df93-abc9-492a-9c0b-92c4a68895b9
    name: read_var_step
    description: ''
    metadata:
      __metadata_info__: {}
    inputs: []
    outputs:
    - description: list of user feedback
      type: array
      items:
        type: string
      title: user_feedback
      default: []
    branches:
    - next
    input_mapping: {}
    output_mapping: {}
    write_variables: []
    read_variables:
    - description: list of user feedback
      type: array
      items:
        type: string
      title: user_feedback
      default: []
    write_operations: {}
    component_plugin_name: NodesPlugin
    component_plugin_version: 26.1.0.dev4
  bd2331f9-c336-446d-b6e8-5c4365e4327b:
    component_type: PluginOutputMessageNode
    id: bd2331f9-c336-446d-b6e8-5c4365e4327b
    name: output_step
    description: ''
    metadata:
      __metadata_info__: {}
    inputs:
    - description: '"feedback" input variable for the template'
      type: string
      title: feedback
    outputs:
    - description: the message added to the messages list
      type: string
      title: output_message
    branches:
    - next
    message: 'Collected feedback: {{ feedback }}'
    input_mapping: {}
    output_mapping: {}
    message_type: AGENT
    rephrase: false
    llm_config: null
    expose_message_as_output: true
    component_plugin_name: NodesPlugin
    component_plugin_version: 26.1.0.dev4
  9834131e-83bf-4927-81bc-89965824271f:
    component_type: EndNode
    id: 9834131e-83bf-4927-81bc-89965824271f
    name: None End node
    description: End node representing all transitions to None in the WayFlow flow
    metadata: {}
    inputs:
    - description: list of user feedback
      type: array
      items:
        type: string
      title: user_feedback
      default: []
    - description: the message added to the messages list
      type: string
      title: output_message
    outputs:
    - description: list of user feedback
      type: array
      items:
        type: string
      title: user_feedback
      default: []
    - description: the message added to the messages list
      type: string
      title: output_message
    branches: []
    branch_name: next
agentspec_version: 25.4.2

You can then load the configuration back to an assistant using the AgentSpecLoader.

from wayflowcore.agentspec import AgentSpecLoader

assistant: Flow = AgentSpecLoader().load_yaml(serialized_assistant)

Note

This guide uses the following extension/plugin Agent Spec components:

  • PluginReadVariableNode

  • PluginWriteVariableNode

See the list of available Agent Spec extension/plugin components in the API Reference

Next steps#

Now that you have learned how to use Variables in Flows, you may proceed to FlowContextProvider to learn how to provide context for flow execution.

Full code#

Click on the card at the top of this page to download the full code for this guide or copy the code below.

  1# Copyright © 2025, 2026 Oracle and/or its affiliates.
  2#
  3# This software is under the Apache License 2.0
  4# %%[markdown]
  5# Code Example - How to Use Variables for Shared State in Flows
  6# -------------------------------------------------------------
  7
  8# How to use:
  9# Create a new Python virtual environment and install the latest WayFlow version.
 10# ```bash
 11# python -m venv venv-wayflowcore
 12# source venv-wayflowcore/bin/activate
 13# pip install --upgrade pip
 14# pip install "wayflowcore==26.2.0.dev0" 
 15# ```
 16
 17# You can now run the script
 18# 1. As a Python file:
 19# ```bash
 20# python howto_variable.py
 21# ```
 22# 2. As a Notebook (in VSCode):
 23# When viewing the file,
 24#  - press the keys Ctrl + Enter to run the selected cell
 25#  - or Shift + Enter to run the selected cell and move to the cell below# (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0) or Universal Permissive License
 26# (UPL) 1.0 (LICENSE-UPL or https://oss.oracle.com/licenses/upl), at your option.
 27
 28
 29
 30# %%[markdown]
 31## Define a Variable
 32
 33# %%
 34from wayflowcore.variable import Variable
 35from wayflowcore.property import ListProperty, StringProperty
 36
 37feedback_variable = Variable(
 38    name="user_feedback",
 39    type=ListProperty(item_type=StringProperty()),
 40    description="list of user feedback",
 41    default_value=[],
 42)
 43
 44
 45# %%[markdown]
 46## Define Flow Steps
 47
 48# %%
 49from wayflowcore.steps import StartStep, OutputMessageStep, VariableStep
 50from wayflowcore.property import StringProperty
 51from wayflowcore.variable import VariableWriteOperation
 52
 53FEEDBACK_1 = "feedback_1"
 54FEEDBACK_2 = "feedback_2"
 55
 56start_step = StartStep(
 57    name="start_step",
 58    input_descriptors=[StringProperty(FEEDBACK_1), StringProperty(FEEDBACK_2)],
 59)
 60
 61write_feedback_1 = VariableStep(
 62    name="write_var_step_1",
 63    write_variables=[feedback_variable],
 64    write_operations=VariableWriteOperation.INSERT,
 65)
 66
 67write_feedback_2 = VariableStep(
 68    name="write_var_step_2",
 69    write_variables=[feedback_variable],
 70    write_operations=VariableWriteOperation.INSERT,
 71)
 72
 73read_feedback = VariableStep(
 74    name="read_var_step",
 75    read_variables=[feedback_variable],
 76)
 77
 78output_step = OutputMessageStep("Collected feedback: {{ feedback }}", name="output_step")
 79
 80
 81# %%[markdown]
 82## Define a Flow with variable
 83
 84# %%
 85from wayflowcore.controlconnection import ControlFlowEdge
 86from wayflowcore.dataconnection import DataFlowEdge
 87from wayflowcore.flow import Flow
 88
 89flow = Flow(
 90    begin_step=start_step,
 91    control_flow_edges=[
 92        ControlFlowEdge(start_step, write_feedback_1),
 93        ControlFlowEdge(write_feedback_1, write_feedback_2),
 94        ControlFlowEdge(write_feedback_2, read_feedback),
 95        ControlFlowEdge(read_feedback, output_step),
 96        ControlFlowEdge(output_step, None),
 97    ],
 98    data_flow_edges=[
 99        DataFlowEdge(start_step, FEEDBACK_1, write_feedback_1, feedback_variable.name),
100        DataFlowEdge(start_step, FEEDBACK_2, write_feedback_2, feedback_variable.name),
101        DataFlowEdge(read_feedback, feedback_variable.name, output_step, "feedback"),
102    ],
103    variables=[feedback_variable],
104)
105
106
107# %%[markdown]
108## Execute flow
109
110# %%
111conv = flow.start_conversation(
112    inputs={
113        FEEDBACK_1: "Very good!",
114        FEEDBACK_2: "Need to improve!",
115    }
116)
117conv.execute()
118
119result = conv.get_last_message().content
120print(result)
121# >>> Collected feedback: ["Very good!", "Need to improve!"]
122
123
124# %%[markdown]
125## Export config to Agent Spec
126
127# %%
128from wayflowcore.agentspec import AgentSpecExporter
129
130serialized_assistant = AgentSpecExporter().to_yaml(flow)
131
132
133# %%[markdown]
134## Load Agent Spec config
135
136# %%
137from wayflowcore.agentspec import AgentSpecLoader
138
139assistant: Flow = AgentSpecLoader().load_yaml(serialized_assistant)