Predicates

Skip Steps based on Flow state with a Lua, Ale, or JSONPath predicate. Includes match predicates for filtering individual upstream values and the dependency pruning that follows a skipped Step.

Skip Conditions

A Step can include a Predicate. If it evaluates to false when the Step’s inputs are ready, the Step is skipped and no service call is made:

{
  "id": "send-premium-discount",
  "type": "sync",
  "predicate": {
    "language": "lua",
    "script": "return customer_tier == \"premium\""
  }
}

A skipped Step produces no outputs. Downstream Steps that depend on those outputs will fail if they have no other way to get them.

Predicate Languages

JSONPath (jpath)

JSONPath expressions. The Predicate is true when the query matches at least one value.

$.customer.tier == "premium"
$.amount > 100
$.status != "cancelled"

Lua

Use Lua for conditions involving multiple Attributes or more complex logic:

return amount > 1000 and status == "approved"

Ale

Argyll’s native scripting language. Purely functional, safe for Predicates:

(and (> amount 1000) (eq status "approved"))

Errors vs Skips

A Predicate that evaluates to false skips the Step. A Predicate that throws a runtime error fails the Step. Predicates should be simple boolean expressions over known Attributes. If a Predicate can error, it’s a sign the logic belongs elsewhere.

Dependency Pruning

When a Step is skipped, upstream work that existed solely to serve that Step is pruned. This avoids executing unnecessary work.

Interaction with For Each

When a Step has both a Predicate and for_each, the Predicate is evaluated before initial Work Item scheduling and again before each pending or retried Work Item starts. If the Predicate is false, that work does not run.

Routing

Use Predicates to route work conditionally. Different Steps with different Predicates handle different paths:

graph TD Init["Process Payment
payment_method: ?"] Check1{"payment_method
== credit_card?"} Check2{"payment_method
== bank_transfer?"} CC["charge-card"] Bank["initiate-transfer"] Confirm["confirm-payment"] Init --> Check1 Init --> Check2 Check1 -->|true| CC Check2 -->|true| Bank CC --> Confirm Bank --> Confirm style CC fill:#c8e6c9 style Bank fill:#c8e6c9

Match Predicates on Required Inputs

A required input can declare a match script that filters upstream values before collection. Each candidate value is evaluated individually, and only values that pass are collected. If no values pass once all providers finish, the Step is skipped without demanding its other required inputs.

{
  "attributes": {
    "payment_result": {
      "role": "required",
      "required": {
        "match": {
          "language": "jpath",
          "script": "$.status == \"approved\""
        }
      }
    }
  }
}

The match script receives one candidate at a time. For Ale and Lua the candidate is available as value; for JSONPath it is evaluated as the document.