Skip to content

Conditions and Path Expressions

This page explains how to read values from JSON, XML, or step output and use them in if, when, repeat_until, and trigger filters.

Source of truth: engine/services/orchestrator/app/workflow_runnerv2.py (WhenCondition, TriggerFilter, context_extract_*, _resolve_input).

Mental model

flowchart LR
  T[Trigger body → initial] --> S[service_call / other steps → outputs]
  S --> E[context_extract_json / context_extract_xml]
  E --> C[run context: string keys]
  C --> I[if / when / until]
  T --> F[trigger_filters payload:$.path]
  1. Payloads (trigger body, service_call response, transform output) are strings passed along the step chain (initial, previous, outputs[step_id]).
  2. Extract steps copy a fragment into the run context as a string (context_key).
  3. if / when / until compare only context strings — they do not evaluate JSON Pointer, XPath, or $. paths directly.

The trigger JSON body is not automatically flattened into context keys. Use an extract step (or a trigger filter at workflow start) first.

if and when today

condition (and step-level when, repeat_until.until) use WhenCondition:

Field Required Description
context_key (alias variable) yes Key in the run context
equals exactly one of String equality
not_equals these three String inequality
one_of Value in list
- id: branch_on_status
  type: if
  condition:
    context_key: order_status
    equals: "shipped"
  then:
    - id: notify
      type: log
      message: "Order shipped"

Notes:

  • Comparisons are strict strings ("6"6).
  • There is no built-in initial.//alles[1] or initial:json:/alles/1 syntax in context_key today.

Resolving input: input_from and refs

Steps that read a document (context_extract_json, context_extract_xml, for_each, json_set, service_call.payload_from, …) resolve the source via _resolve_input:

Ref Resolves to
(omitted) initial on first step, else previous
initial, trigger, trigger.payload Trigger/request body string
previous Output of the immediately preceding step
<step_id> Output stored for that step id
context:<key> or var:<key> Value from run context

After a service_call, the HTTP response body is stored as:

  • outputs[<step_id>] — use input_from: <step_id> on a later step
  • previous — if the extract step runs directly after the call
  • context[<output_key>]only if output_key is set on the service_call step
- id: fetch_order
  type: service_call
  capability_name: orders.lookup
  path: /v1/orders/123
  payload_from: initial
  output_key: order_json    # optional: also copy response into context

- id: read_status
  type: context_extract_json
  input_from: fetch_order     # same as: previous (if no steps in between)
  json_path: /status
  context_key: order_status

- id: branch
  type: if
  condition:
    context_key: order_status
    equals: "CONFIRMED"
  then:
    - id: ok
      type: log
      message: "Order confirmed"

Alternative using output_key only (skip step-id ref on extract):

- id: fetch_order
  type: service_call
  ...
  output_key: order_json

- id: read_status
  type: context_extract_json
  input_from: context:order_json
  json_path: /status
  context_key: order_status

service_call does not parse JSON; the response must be valid JSON text for context_extract_json.

JSON: extract then branch

JSON Pointer (context_extract_json)

Use RFC 6901 JSON Pointer — always starts with /:

Intent Pointer Indexing
Field test /test
Second array element /alles/1 0-based (0 → first, 1 → second)
Whole array /alles For for_each with items_path: /alles

Example trigger: {"test": "1", "alles": ["4", "6"]}

- id: pick_second
  type: context_extract_json
  input_from: initial
  json_path: /alles/1
  context_key: second_alles

- id: is_six
  type: if
  condition:
    context_key: second_alles
    equals: "6"
  then:
    - id: found
      type: log
      message: "Second element is 6"

Not supported in extract paths: alles[1], $.alles[1], //alles.

Dollar path (trigger filters only)

At workflow start, invocation.trigger_filters can read the trigger body without an extract step:

invocation:
  type: http
  trigger_filters:
    - property: payload:$.alles.1
      equals: "6"

Syntax: payload: + $.segment.segment (dot-separated; numeric segments index arrays). No wildcards (*).

This does not apply to service_call output — only the initial trigger body when the run is accepted.

XML: extract then branch

Use context_extract_xml with XPath on XML text from initial, previous, or a step id:

- id: read_order_id
  type: context_extract_xml
  input_from: initial
  xpath: //order/id/text()
  context_key: order_id

- id: branch
  type: if
  condition:
    context_key: order_id
    equals: "42"
  then: []

XPath position predicates are 1-based (//items/item[2] = second item). This differs from JSON Pointer array indices (0-based).

Trigger filters with payload:$.… require parseable JSON; XML trigger bodies need an extract step (or transform to JSON first).

Arrays: “any element equals …”

There is no alles[*] = "6" operator in if today. Patterns:

for_each + if per item

- id: loop_alles
  type: for_each
  input_from: initial
  items_path: /alles
  as_key: item
  steps:
    - id: check
      type: if
      condition:
        context_key: item
        equals: "6"
      then:
        - id: found
          type: log
          message: "Found 6"

one_of after extracting a single value

When you already have one scalar in context:

condition:
  context_key: code
  one_of: ["6", "9"]

Using output from multiple steps

Pattern When to use
input_from: <step_id> Read a specific earlier step’s output string
input_from: previous Previous step only
input_from: context:<key> After context_set, output_key, or mirror_to_context
collect Merge several step outputs into one JSON object/array, then extract
- id: merge
  type: collect
  from_steps:
    - fetch_a
    - fetch_b
  merge_mode: object

- id: use_merged
  type: context_extract_json
  input_from: merge
  json_path: /fetch_a/status
  context_key: status_a

RAW / plain text

  • No context_extract_raw or substring step in the orchestrator v2 runner.
  • RAW body is available as the full string via initial / previous / step output.
  • Options: context_set with a static value, a service_call to a transform capability, or legacy transform steps where enabled.

invocation.payload_format: raw is mainly a dashboard/content-type hint, not a path language.

Bound documents (context_bind) — preferred for many fields

When you need multiple values from the same JSON/XML/YAML payload, bind it once and use path references instead of one extract step per field. See Bound documents.

- id: bind_request
  type: context_bind
  alias: request
  input_from: initial
  format: json

- id: log_header
  type: log
  message: "date={date}"
  values:
    date: request:json:/root/header/date

Planned extension (partial)

Direct path expressions on if / when without an intermediate context_set (e.g. condition.property: request:json:/status) are still a follow-up. Until then, bind + context_set or context_extract_* + context_key.

Quick reference

Goal Mechanism
IF on trigger JSON field context_bind + path refs, or context_extract_json + if
Many fields from one JSON body context_bind (see 11-bound-documents.md)
IF on service_call JSON field input_from: <service_step_id> + extract + if
Filter run at HTTP trigger trigger_filters with payload:$.path
IF on XML node context_extract_xml + if
IF on “any array member” for_each + nested if
Compare multiple allowed values one_of on WhenCondition