Attributes

Attributes connect Steps and control how input values are selected.

Values Shared by Steps

An Attribute is a named value in Flow state. A Step consumes Attributes as inputs and contributes new values as outputs. Matching names create the dependency between a producer and every consumer that needs its value.

  • Inputs are the values a Step consumes.
  • Outputs are the values it contributes to the Flow.

Attribute Roles

Each Attribute has a role that defines how it’s used:

Required Input

The Step cannot execute until this value is available. Required inputs must come from the Flow’s initial state or from upstream Steps: earlier Steps that produce values used by it.

Optional Input

The Step can execute without this value. Optional inputs can have a default value and a deadline (milliseconds) after which the Step proceeds with whatever is available.

Constant

A fixed value built into the Step definition, sent as input on every execution. Useful for configuration that belongs to the Step rather than the Flow:

{
  "region": {
    "role": "const",
    "type": "string",
    "const": { "value": "\"us-east-1\"" }
  }
}

Metadata

A value drawn from execution metadata at invocation time. The key selects a field such as flow_id, step_id, receipt_token, or webhook_url. Argyll resolves it separately for each Work Item and sends it as a Step-local input:

{
  "callback_url": {
    "role": "meta",
    "meta": { "key": "webhook_url" }
  }
}

Output

The Step produces this Attribute value. Outputs become available to downstream Steps: later Steps that declare them as inputs.

Attribute Types

Attributes can be any JSON type:

  • Strings
  • Numbers
  • Objects
  • Arrays
  • Booleans
  • Null

Invocation Mapping

The name used in Flow state is the Attribute’s outer name: the key in the Step’s attributes object. A mapping.name gives that Attribute a different inner name in the HTTP request or response.

This Step consumes the Flow Attribute customer_id but sends it to the endpoint as customerId:

{
  "customer_id": {
    "role": "required",
    "type": "string",
    "required": {
      "mapping": { "name": "customerId" }
    }
  }
}

Input mapping changes the name and optional value transformation before invocation. Output mapping reads the endpoint’s inner name or transforms its response, then stores the result under the outer Attribute name for downstream Steps. A mapping.script supplies a Lua or JPath transformation when renaming alone is not enough.

Collection Policies

When multiple Steps can produce the same Attribute, the Collection Policy on an input controls when the Step is satisfied and what value it receives. Set it inside the input’s role-specific configuration:

{
  "price": {
    "role": "required",
    "type": "number",
    "required": { "collect": "last" }
  }
}
PolicySatisfied whenValue received
firstFirst value arrivesThat value (remaining providers removed because they are no longer needed)
lastAll providers finishThe last value produced
someAll providers finishArray of all values that arrived
allAll providers finish, all succeededArray of all values
noneAll providers finish with no valueNothing (gating on absence)

The default policy is first.

graph TD A["Step A → price: 10"] B["Step B → price: 12"] C["Step C (price, collect: last)"] A -->|price| C B -->|price| C C -->|"waits for both,
receives 12"| Done["Executes"] style Done fill:#e8f5e9

none behaves differently from the other policies: it satisfies the input when upstream Steps produce nothing. Use it to run a Step only after confirming that a value is absent; for example, proceed only if no fraud signal was raised.

Collection Deadline

Optional inputs can declare a deadline (milliseconds). The deadline starts when the Step’s required inputs are satisfied. When it expires, the Step takes the best available value according to its collect policy, or falls back to the declared default. Later upstream values still flow to other consumers, but this Step won’t restart to use them.

{
  "profile": {
    "role": "optional",
    "type": "object",
    "optional": {
      "collect": "last",
      "deadline": 2000,
      "default": "{}"
    }
  }
}

If all upstream providers complete before the deadline without satisfying the input, the Step resolves immediately rather than waiting for the deadline to expire. There is nothing left to wait for.