# Scripting the Airdress CLI

The CLI is built to be driven: one flag for machine-readable output, exit
codes that mean one thing each, and no prompt a script cannot answer.

## `--output json`

Every command takes `--output json` (or `-o json`). The result is JSON on
stdout; a failure is exactly one JSON object on stderr, with a stable `code`
to decide on (see [exit codes](/cli/exit-codes/#failure-output)). Under
`--output json` the `→ acting on …` status line is silent, and the resolved
airdress travels inside the result.

```sh
airdress airdress list --output json | jq -r '.airdresses[].name'
airdress fn deploy ./hello --yes --output json
airdress current --output json          # for a prompt: active profile, airdress, source
```

`airdress airdress list --output json` answers one object: the `profile`,
its `active_airdress`, and the `airdresses` array.

## Confirmations: `-y`

Every command that changes something it cannot undo asks first, and every
one of them takes `-y` / `--yes`. Without a terminal, or under
`--output json`, it never asks: it exits `7` with `confirmation_required`
and a hint naming `--yes`. A script therefore either passes `--yes` on
purpose or fails loudly; it never hangs on a prompt.

```sh
airdress device revoke "$ENROLLMENT_ID" --dry-run   # see what would go
airdress device revoke "$ENROLLMENT_ID" --yes       # then do it
```

## Timeouts: `--timeout`

The connect timeout is 10 seconds. Each request has 30 seconds unless you
say otherwise:

```sh
airdress --timeout 120 fn logs hello --since 1h
AIRDRESS_TIMEOUT=120 airdress fn logs hello --since 1h
```

A request that does not answer in time exits `5` with `timeout`.

## Precedence: flag, then environment, then default

Wherever a setting can come from more than one place, the command line wins
over the environment, and the environment wins over the default (or the
profile). `--timeout 60` beats `AIRDRESS_TIMEOUT=10`, which beats 30.
`-A office` beats `AIRDRESS_NAME=home`, which beats the `.airdress` marker
and the profile's pinned airdress (the full order is in
[Get started](/cli/getting-started/#which-airdress-a-command-acts-on)).

## A token for something else

```sh
TOKEN=$(airdress auth token)                    # for the hub's API
OP_TOKEN=$(airdress auth token --airdress home) # one that only that airdress accepts
```

`auth token` prints a fresh bearer token and nothing else, refreshing first
when the cached one is stale. The output is a credential: do not log it, and
treat anything that captured it as a reason to sign out and in again.
Scripts should call this command rather than read the profile file.

## Environment variables

| Variable | Effect |
| --- | --- |
| `AIRDRESS_NAME` | The airdress to act on, below `--airdress` |
| `AIRDRESS_QUIET` | `1`, `true`, `yes` or `on`: no `→ acting on …` line |
| `AIRDRESS_TIMEOUT` | Per-request timeout in seconds (default 30; `--timeout` wins) |
| `AIRDRESS_LOG` / `RUST_LOG` | Diagnostic traces, instead of `-v` / `-vv` |
| `AIRDRESS_OPERATOR_URL` | Talk to this airdress directly, skipping the hub lookup |
| `AIRDRESS_MACHINE_KEY`, `AIRDRESS_MACHINE_ENROLLMENT` | Act as an approved machine ([deploying from CI](/functions/#deploying-from-ci)) |
| `AIRDRESS_FUNCTION_SIGNING_KEY` | The function source-signing seed, as hex |
| `AIRDRESS_PLUGIN_INDEX_KEYS` | Pinned registry keys for `plugins verify` |
| `AIRDRESS_BOOTSTRAP_TOKEN` | For `device bootstrap`, instead of a flag |
| `AIRDRESS_CA_FILE` | Trust a private CA in addition to the system roots |
| `AIRDRESS_INSECURE` | Skip certificate validation. Development only; warns every time |

Boolean variables take `1`, `true`, `yes` or `on`, case-insensitive, so a
typo does not quietly turn validation off.

## In CI

For deploying functions from a pipeline, the CLI authenticates as an
approved **machine** rather than as you; see
[Functions: deploying from CI](/functions/#deploying-from-ci). The public
GitHub Action
[`airdress-co/deploy-functions`](https://github.com/airdress-co/deploy-functions)
wraps that mode.