hen 0.20.2

Run protocol-aware API request collections from the command line or through MCP.
Documentation
---
sidebar_position: 1
title: Variables and Environments
description: Declare scalar inputs, prompt placeholders, arrays, and named environment overrides.
---

## Variables

```hen
$ variable_name = value
$ variable_name = $(command)
$ variable_name = secret.env("NAME")
$ variable_name = secret.file("./path/to/value.txt")
$ variable_name = [[ prompt_name ]]
$ variable_name = [[ prompt_name = default_value ]]
$ variable_name = [foo, bar]
```

- Scalars are the default building block for reusable values.
- `$(...)` runs a shell command at preparation time.
- Prompt placeholders can declare defaults.
- Arrays expand a request once per value.

Prompt defaults are plain text up to the closing `]]`, so URL-shaped values such as
`[[ ws_origin = wss://example.com ]]` are valid.

## Array Expansion

```hen
$ USER = [alice,bob]

---

Fetch profile

GET https://api.example.com/users/{{ USER }}

^ & status == 200
```

Hen turns that single request block into mapped requests, one per array value. In this example, the
planner creates `Fetch profile [USER=alice]` and `Fetch profile [USER=bob]`.

When a request references two array variables, Hen creates mapped requests for the Cartesian
product of those values.

Arrays are intentionally constrained:

- values must stay simple scalars
- no nested arrays
- no whitespace inside array items
- up to two array variables per request and 128 total combinations

Generated requests are suffixed with the chosen values, such as `[USER=foo]`.

If a mapped request fails, Hen aborts the remaining iterations. Exports from each iteration are
suffixed with the same selected-value label.

Mapped requests may depend on the matching expanded iteration of another mapped request when they
share compatible iteration bindings. Unmapped requests still cannot depend on a mapped request, and
ambiguous mapped matches still fail. If multiple downstream requests need the same unmapped setup,
move that setup into an unmapped helper request.

## Named Environments

```hen
$ API_ORIGIN = https://api.example.com
$ CLIENT_ID = [[ client_id ]]

env local
  $ API_ORIGIN = http://localhost:3000
  $ CLIENT_ID = hen-local

env staging
  $ API_ORIGIN = https://staging.example.com
```

- Environment blocks are valid only in the collection preamble.
- Environment overrides may only target previously declared scalar variables.
- Environment values must stay scalar.
- Arrays, shell substitutions, and nested environment syntax are rejected inside environment blocks.

## Selection Order

Resolution order is:

1. Collection preamble scalar assignments
2. Selected named environment
3. Explicit CLI `--input key=value` values
4. Prompt defaults declared with `[[ name = default ]]`
5. Runtime captures and callback exports

## Run-Time Selection

Use:

```bash
hen run ./collection.hen 0 --env local --input client_id=demo --non-interactive
```

If no environment is selected, Hen uses the collection defaults.

For secret-backed values, continue to [Secrets and redaction](./secrets-and-redaction.md).