Attributes

Attributes are how Steps share data. Covers the five roles (required, optional, const, meta, output), the five collection policies (first, last, some, all, none), and Collection Deadlines for optional inputs.

What are Attributes?

Attributes are named values that Steps use to communicate. Each Step declares:

  • Inputs: What Attributes it needs
  • Outputs: What Attributes it produces

Argyll automatically connects Steps by matching Attribute names. No explicit wiring required.

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 Step outputs.

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 baked 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 step/flow execution metadata at invocation time. Similar to const in that it is local to the Step and not wired through the Flow graph, but instead of a fixed value it injects a named metadata field (such as flow_id, step_id, receipt_token, or webhook_url). Values are resolved per work item, so each execution gets the correct metadata for that specific invocation:

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

Output

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

Attribute Types

Attributes can be any JSON type:

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

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 in required.collect or optional.collect.

PolicySatisfied whenValue received
firstFirst value arrivesThat value (remaining providers pruned)
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 is the odd one out: it satisfies the input when upstream produces nothing. Use it to gate a Step on the confirmed absence of a value, for example, only proceed 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.

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.