
# Flow Control Actions

Flow-control actions change the **shape** of a workflow rather than its data: they branch, iterate, halt, and compose other automations as sub-workflows.

## Condition Groups

`path` branches and the `filter/continue` gate evaluate **condition groups** — one or more comparisons combined with `and`/`or`.

| Element      | Description                                               |
| ------------ | --------------------------------------------------------- |
| `logic`      | `and` (all must match, default) or `or` (any must match). |
| `conditions` | Array of `{ field, operator, value? }` (minimum 1).       |

**Comparison operators:** `equals`, `notEquals`, `contains`, `notContains`, `startsWith`, `endsWith`, `greaterThan`, `greaterThanOrEqual`, `lessThan`, `lessThanOrEqual`, `isEmpty`, `isNotEmpty`, `isNull`, `isNotNull`, `matches`.

```yaml
condition:
  logic: and
  conditions:
    - { field: '{{trigger.data.status}}', operator: equals, value: paid }
    - { field: '{{trigger.data.amount}}', operator: greaterThan, value: 100 }
```

## Path — Branching

The `path/branch` operator routes execution into named branches. Each branch has its own `condition` and nested `actions`.

| Prop    | Description                                                                           |
| ------- | ------------------------------------------------------------------------------------- |
| `paths` | Array of branches: `{ name, condition?, actions[] }`.                                 |
| `mode`  | `first-match` (run the first matching branch) or `all-matching` (run all that match). |

```yaml
- name: route
  type: path
  operator: branch
  props:
    mode: first-match
    paths:
      - name: vip
        condition:
          conditions: [{ field: '{{trigger.data.tier}}', operator: equals, value: vip }]
        actions:
          - {
              name: vipEmail,
              type: email,
              operator: send,
              props: { to: '{{trigger.data.email}}', subject: 'VIP welcome', body: 'Thanks!' },
            }
      - name: standard
        actions:
          - {
              name: stdEmail,
              type: email,
              operator: send,
              props: { to: '{{trigger.data.email}}', subject: 'Welcome', body: 'Hi!' },
            }
```

## Loop — Iteration

The `loop/each` operator iterates over an array, running its nested `actions` per item.

| Prop                  | Description                                         |
| --------------------- | --------------------------------------------------- |
| `items`               | Template resolving to the array to iterate.         |
| `actions`             | Nested actions executed for each item.              |
| `maxIterations`       | Cap on the number of iterations.                    |
| `continueOnItemError` | When `true`, a failing item doesn't abort the loop. |

```yaml
- name: notifyEach
  type: loop
  operator: each
  props:
    items: '{{fetchSubscribers.result}}'
    maxIterations: 500
    continueOnItemError: true
    actions:
      - name: send
        type: email
        operator: send
        props: { to: '{{item.email}}', subject: 'Update', body: 'Hi {{item.name}}' }
```

## Flow — Stop

The `flow/stop` operator immediately halts the run with an optional status and output.

| Prop      | Description                              |
| --------- | ---------------------------------------- |
| `message` | Reason the run stopped (templatable).    |
| `status`  | `success` or `error` (default `error`).  |
| `output`  | Key-value output returned to the caller. |

```yaml
- name: bail
  type: flow
  operator: stop
  props: { status: success, message: 'Nothing to do', output: { processed: 0 } }
```

## Automation — Call & Return (Sub-Workflows)

The `automation` family composes workflows. `call` invokes another automation (one with an `automation-call` trigger); `return` sends output back to the caller.

| Operator | Props                                                  | Description                                                                                                                                   |
| -------- | ------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------- |
| `call`   | `name`, `inputData?`, `waitForCompletion?`, `timeout?` | Invoke a sub-automation by `name`; optionally wait for it and time out.                                                                       |
| `return` | `output`                                               | Return key-value output to the calling automation (only with `automation-call` trigger). Accessible as `steps.{name}.result.*` in the parent. |

```yaml
# Parent: invoke a reusable sub-workflow and wait
- name: enrich
  type: automation
  operator: call
  props:
    name: enrich-lead
    inputData: { email: '{{trigger.data.email}}' }
    waitForCompletion: true
    timeout: 30000

# Sub-workflow (trigger: { type: automation-call }): return result
- name: done
  type: automation
  operator: return
  props: { output: { score: '{{computeScore.result}}' } }
```

:::callout
**Sub-workflow vs failure handling.** `automation/call` invokes a target that declares an `automation-call` trigger. To react to a workflow that _fails_, use the [`automation-failure` trigger](/en/docs/automation-triggers) instead.
:::

## Related Pages

- [Actions Overview](/en/docs/automation-actions-overview) — base props and the family map.
- [Triggers](/en/docs/automation-triggers) — `automation-call` and `automation-failure` triggers.
- [Data & State Actions](/en/docs/automation-data-actions) — `filter/continue` conditional gating.
- [Approval & Delay](/en/docs/automation-approval-delay) — pausing a run for humans or time.
