> ## Documentation Index
> Fetch the complete documentation index at: https://docs.b3os.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Expressions

Reference runtime data, workflow props, trigger payloads, node outputs, loop variables, and inputs inside action payloads.

Expressions let workflow nodes use data from triggers, props, inputs, prior nodes, loops, and chain context. B3OS resolves expressions recursively inside node payloads and preserves JSON types when the whole value is an expression.

## Common Context

| Expression                 | Meaning                                 |
| -------------------------- | --------------------------------------- |
| `{{$trigger}}`             | Full trigger payload                    |
| `{{$trigger.body}}`        | Inbound webhook or event body           |
| `{{$props.key}}`           | Workflow prop named `key`               |
| `{{$inputs.key}}`          | Workflow or block input named `key`     |
| `{{$nodes.nodeId.result}}` | Result of a prior node                  |
| `{{$nodes.nodeId.error}}`  | Sanitized error for a prior failed node |
| `{{$workflow.id}}`         | Current workflow ID                     |
| `{{$item}}`                | Current loop item                       |
| `{{$index}}`               | Current loop index                      |
| `{{$parent_item}}`         | Parent loop item inside nested loops    |
| `{{$for.nodeId.item}}`     | Item for a specific loop node           |

## Type Preservation

When the entire field is an expression, B3OS preserves the referenced value type:

```json
{
  "amount": "{{$nodes.quote.result.amount}}",
  "metadata": "{{$trigger.body.metadata}}",
  "enabled": "{{$props.enabled}}"
}
```

If `metadata` is an object and `enabled` is a boolean, they remain objects and booleans. If an expression is embedded inside a longer string, the result is a string.

```json
{
  "message": "Received {{$trigger.body.amount}} {{$trigger.body.asset}}"
}
```

## Trigger Data

Webhook and event triggers usually populate `body`, `headers`, and source-specific metadata:

```json
{
  "asset": "{{$trigger.body.asset}}",
  "requestId": "{{$trigger.headers.x-request-id}}",
  "source": "{{$trigger.source}}"
}
```

## Node Outputs

Name nodes intentionally and use stable IDs. A downstream node can reference any prior node result:

```json
{
  "channel": "alerts",
  "text": "Price is {{$nodes.fetchPrice.result.price}} for {{$props.asset}}"
}
```

## Loop Variables

Inside a loop body, B3OS exposes loop variables:

| Variable                    | Meaning                             |
| --------------------------- | ----------------------------------- |
| `{{$item}}`                 | Current item                        |
| `{{$index}}`                | Zero-based index                    |
| `{{$parent_item}}`          | Parent loop item in nested loops    |
| `{{$parent_index}}`         | Parent loop index                   |
| `{{$for.loopNodeId.item}}`  | Specific loop item by loop node ID  |
| `{{$for.loopNodeId.index}}` | Specific loop index by loop node ID |

**Use explicit loop paths in nested loops**

`{{$item}}` is convenient in a single loop. In nested loops, `{{$for.loopNodeId.item}}` is easier to read and safer to maintain.

## Conditions and Filters

Branch and filter-style payloads can evaluate values from context. Use early filtering to reduce provider calls and avoid unnecessary wallet operations.

```json
{
  "condition": "{{$trigger.body.amount}} > 100",
  "then": "large-payment",
  "else": "standard-payment"
}
```

For item-level filters, item fields can be referenced by the active item context:

```json
{
  "items": "{{$nodes.fetchBalances.result.items}}",
  "where": "{{$item.usdValue}} > 10"
}
```

## Secrets and Sensitive Values

Expressions can technically reference any data available to a run, but secrets should not be passed through visible payloads.

**Keep secrets in credential systems**

Put provider tokens in connectors, machine credentials in API keys or service accounts, and signing authority in
  wallets. Do not store secrets in props, workflow inputs, or arbitrary JSON payloads.

## Debugging Expressions

1. Test with a manual run and representative input.
2. Inspect the node input after expression resolution.
3. Inspect the prior node output shape.
4. Confirm the node ID in the expression matches the graph.
5. Check whether the value is an object, array, number, boolean, string, or null.
6. Use a `format`, `regex`, or `code-transform` node to normalize data before passing it to strict action schemas.