Environments¶
The environment file configures how AAT connects to your API at runtime — base URL, authentication, headers, LLM settings, and multi-host routing.
Overview¶
AAT separates what to test (graph, plans, templates) from where to test (environment). The environment file holds connection details for a specific target: API endpoints, credentials, static headers, and runtime settings. Switching between development, staging, and production is a matter of selecting a different environment via --env or the project manifest.
AAT supports two environment file formats:
- Single-environment (legacy) — one environment per file, selected by pointing
--env-config(or the manifest'senvironment:) at the file - Multi-environment — multiple environments in one file, selected with
--env
Single-Environment Format¶
The simplest format is a YAML document with a top-level environment name and apiBaseUrl:
environment: dev
apiBaseUrl: https://api.dev.example.com
auth:
type: none
A more typical configuration includes authentication and headers:
environment: staging
apiBaseUrl: https://api.staging.example.com
auth:
type: apikey
headerName: X-API-Key
credentials:
key:
source: env
var: STAGING_API_KEY
headers:
Accept: application/json
X-Client-Version: "2.1"
Multi-Environment Format¶
When your project targets multiple environments (dev, staging, production, etc.), use the multi-environment format to define them all in one file. This eliminates duplication of shared config like headers, LLM settings, and runtime defaults.
shared:
headers:
Accept: application/json
llm:
endpoint: https://api.openai.com/v1
apiKey:
source: env
var: OPENAI_API_KEY
model: gpt-4
settings:
oasValidation: auto
environments:
dev:
apiBaseUrl: https://api.dev.example.com
auth:
type: none
staging:
apiBaseUrl: https://api.staging.example.com
auth:
type: apikey
headerName: X-API-Key
credentials:
key:
source: env
var: STAGING_API_KEY
prod:
apiBaseUrl: https://api.example.com
auth:
type: oauth2
tokenUrl: https://auth.example.com/oauth/token
credentials:
username:
source: env
var: PROD_USERNAME
password:
source: env
var: PROD_PASSWORD
clientId:
source: env
var: PROD_CLIENT_ID
clientSecret:
source: env
var: PROD_CLIENT_SECRET
Select an environment with --env:
aat run plan checkout.yaml --env staging
AAT detects the format automatically: if the YAML has an environments key, it's multi-environment; if it has apiBaseUrl at the top level, it's single-environment.
Shared Config¶
The shared section provides defaults that merge into every environment. Per-environment fields override shared fields:
headers,values,vars— map merge (environment keys win, shared keys preserved)auth,llm— full replace (if the environment specifies auth, it replaces shared auth entirely)settings— field-level merge (environment can override individual settings fields)
Inheritance with extends¶
Environments can inherit from other environments using extends. This eliminates duplication when multiple environments share the same structure:
environments:
_direct:
auth:
type: none
overrides:
- match: "search*"
baseUrl: https://search-${env_tag}.internal.example.com
- match: "price*"
baseUrl: https://price-${env_tag}.internal.example.com
dev:
extends: _direct
vars:
env_tag: dev
staging:
extends: _direct
vars:
env_tag: staging
auth:
type: bearer
credentials:
token:
source: env
var: STAGING_TOKEN
When extending, the child environment's fields are merged on top of the resolved parent using the same rules as shared config. Child overrides are appended after the parent's, so a child entry wins over an inherited entry of the same kind for the same node (the last registered match wins).
Inheritance chains are supported (a extends b extends c). Circular inheritance is detected and rejected.
Abstract Environments¶
Environment names starting with _ (underscore) are abstract — they serve as templates for inheritance but cannot be selected directly with --env. This is useful for defining override patterns that are shared across similar environments.
Variable Substitution¶
The vars map enables parameterized environments. ${var_name} placeholders in every string of the environment are replaced from the merged vars after inheritance and shared config resolution — base URLs, headers, auth fields and credentials, override entries (including their auth, values, and expectFailure descriptions), LLM settings, and settings. Map keys, such as header names, are not substituted, and the vars map itself is not:
environments:
_base:
overrides:
- match: "api*"
baseUrl: https://${service}.${region}.example.com
us-east:
extends: _base
vars:
service: api
region: us-east-1
Unresolved ${...} placeholders after substitution are a validation error.
Setting vars from the command line¶
--var KEY=VALUE (repeatable) sets a var for one invocation and wins over the vars the file declares or inherits. It is accepted by aat run plan, aat run batch, aat prompt, aat validate, aat env list, and aat mcp serve, and applies to multi-environment files only. Use it to point a project at a different host without editing the file — for example the shop example against a sandbox in Docker or on other ports:
aat run plan smoke --var apiHost=localhost:9765 --var payHost=localhost:9766
A key that the file never declares or references with ${key} is an error, so a typo does not silently change nothing.
File Splitting with include¶
The include directive lets you split a multi-environment file into parts — for example, keeping secrets separate from committable structure:
# env.yaml (committed to git)
include:
- env.secrets.yaml
shared:
headers:
Accept: application/json
environments:
dev:
apiBaseUrl: https://api.dev.example.com
prod:
apiBaseUrl: https://api.example.com
# env.secrets.yaml (gitignored)
environments:
dev:
auth:
type: none
prod:
auth:
type: oauth2
tokenUrl: https://auth.example.com/oauth/token
credentials:
username:
source: env
var: PROD_USERNAME
password:
source: env
var: PROD_PASSWORD
clientId:
source: env
var: PROD_CLIENT_ID
clientSecret:
source: env
var: PROD_CLIENT_SECRET
Include files use the same format (shared + environments sections) and are merged into the base file. Paths are resolved relative to the base file's directory. Multiple includes are processed in order. Recursive includes (an include file with its own include) are not allowed.
Environment Name Resolution¶
When using a multi-environment file, the environment name is resolved from:
--envflag (highest priority)AAT_ENV_NAMEenvironment variableenvironment:in an overlay file — an explicit--overlayfile first, then an auto-discovered.aat-overrides.yaml(see Selecting the Environment)defaultEnvironmentin the project manifest, for the environment file the manifest names (not for one given with--env-config)- Error listing available environments
A single-environment file has no names to choose from. --env is an error for it, and the other sources are ignored, so AAT_ENV_NAME or a manifest's defaultEnvironment does not stop --env-config from loading one.
Listing Environments¶
Use aat env list to see available environments:
$ aat env list
dev https://api.dev.example.com
prod https://api.example.com
staging https://api.staging.example.com
Authentication¶
AAT supports four authentication types. Tokens are cached by an internal AuthProvider to avoid redundant auth calls — OAuth2 tokens are refreshed 30 seconds before expiry, while API key and bearer tokens are cached indefinitely.
OAuth2¶
Resource Owner Password Credentials (ROPC) flow. AAT exchanges credentials for a token at the specified tokenUrl:
auth:
type: oauth2
tokenUrl: https://auth.example.com/oauth/token
credentials:
username:
source: env
var: API_USERNAME
password:
source: env
var: API_PASSWORD
clientId:
source: env
var: API_CLIENT_ID
clientSecret:
source: env
var: API_CLIENT_SECRET
Required credentials: username, password, clientId, clientSecret. All four must be present for OAuth2.
Custom Grant Type¶
By default AAT sends grant_type=password. Some OAuth2 providers (e.g., Auth0) require a different grant type and additional parameters. Use grantType and extraParams to customize the token request:
auth:
type: oauth2
tokenUrl: https://auth.example.com/oauth/token
grantType: "http://auth0.com/oauth/grant-type/password-realm"
extraParams:
realm: my-realm
credentials:
username:
source: env
var: API_USERNAME
password:
source: env
var: API_PASSWORD
clientId:
source: env
var: API_CLIENT_ID
clientSecret:
source: env
var: API_CLIENT_SECRET
| Field | Default | Description |
|---|---|---|
grantType |
password |
OAuth2 grant_type form parameter |
extraParams |
(empty) | Additional key-value pairs appended to the token request form |
Client Credentials¶
grantType: client_credentials works, but AAT still requires username and password for every oauth2 configuration and sends them in the token request. Give them empty literal values, which the shop sandbox's token endpoint (like most) ignores for this grant:
auth:
type: oauth2
tokenUrl: https://auth.example.com/oauth/token
grantType: client_credentials
credentials:
clientId:
source: env
var: API_CLIENT_ID
clientSecret:
source: env
var: API_CLIENT_SECRET
username: {source: literal, value: ""} # required by AAT, unused by this grant
password: {source: literal, value: ""}
API Key¶
A static key sent as a custom header. The headerName field controls which header carries the key:
auth:
type: apikey
headerName: X-API-Key
credentials:
key:
source: env
var: INVENTORY_API_KEY
Required: credentials.key and headerName.
Bearer Token¶
A pre-obtained token sent as Authorization: Bearer <token>:
auth:
type: bearer
credentials:
token:
source: env
var: ANALYTICS_TOKEN
Required: credentials.token.
No Auth¶
For public APIs or when authentication is handled externally:
auth:
type: none
An empty or missing type field is treated as none.
Custom Headers¶
Static headers added to every request. These form the base layer — every other header source can override them:
headers:
Accept: application/json
X-Client-Id: aat-test-runner
X-Request-Source: automated-testing
Header merge order. A later value replaces an earlier one with the same name, whatever the case of the name:
- Environment headers — this
headerssection - Plan headers — the plan's top-level
headers(see Plans) - Template headers — per-template
request.headers(see Templates) - Auth credential —
Authorization: Bearer …, or the API key header, from the effective auth .aat-overrides.yamlheaders — its top-levelheaders--overlayheaders — the overlay file's top-levelheaders
A plan or template header therefore cannot replace the credential, and an overlay header replaces everything before it.
A node matched by an override that routes it (one that sets baseUrl, auth, headers, or pathRewrite, or a --override flag) takes the same environment, plan, and template headers. If the override declares its own auth, the inherited credential is dropped. Then come the override's headers, the credential of its effective auth, and the overlay headers, in that order. A template header cannot replace the override's headers either.
Values¶
The values map holds per-environment data such as a region's postal code. Plan values, graph input defaults, and layers read it with a {{env.KEY}} expression, which checks the OS environment variable KEY first and then this map:
values:
postalCode: "78701"
# graph.yaml — a node input
- name: postalCode
type: string
default: "{{env.postalCode}}"
Values do not fill template placeholders directly: a template's {{postalCode}} resolves only from the step's inputs, so route an environment value through an input as above. See Value Resolution: Environment Variables.
Secrets¶
Credentials and API keys are stored as SecretRef values. Each ref specifies a source and a resolution method:
Environment Variable (Recommended)¶
credentials:
key:
source: env
var: MY_API_KEY
AAT resolves the value from the OS environment variable at runtime. If the variable is not set, authentication fails with a clear error message.
Literal Value¶
credentials:
key:
source: literal
value: sk-test-1234567890
The value is stored directly in the YAML file. Use this only for local development — never commit literal secrets to version control.
Redaction¶
Run archives redact request and response headers by name: Authorization, Proxy-Authorization, X-API-Key, X-Auth-Token, Cookie, and Set-Cookie values become [REDACTED]. AAT also collects the resolved values of every secret credential that can apply to a run — the environment's and its host overrides' auth, the plan's auth, overlay auth, and the LLM API key; not the oauth2 username or clientId — and redacts them from every string in the archive, bodies and URLs included. A secret shorter than eight characters is redacted only where a whole value equals it. Tokens an API issues at run time are not known secrets outside credential headers, so review an archive before sharing it. See Archives: What Is Redacted, and What Is Not.
LLM Configuration¶
The llm section configures the language model used by aat prompt for plan generation:
llm:
endpoint: https://api.openai.com/v1/chat/completions
apiKey:
source: env
var: OPENAI_API_KEY
model: gpt-5.2
| Field | Description |
|---|---|
endpoint |
LLM API endpoint URL |
apiKey |
Secret reference for the API key |
model |
Model identifier to use |
provider |
"openai" or "anthropic" — auto-detected from the endpoint URL when omitted |
Provider auto-detection uses the endpoint hostname: URLs containing anthropic use the Anthropic protocol; all others default to OpenAI-compatible.
Runtime Settings¶
Execution-time defaults for the engine:
settings:
oasValidation: auto
minRequestInterval: 250ms
| Field | Default | Description |
|---|---|---|
oasValidation |
auto |
OpenAPI validation mode: auto, strict, or off |
minRequestInterval |
(none) | Least time between the starts of two requests, such as 250ms or 1s; see Request Pacing |
Retries are not an environment setting: set them per step with retry: (see Plans: Retry) or per run with --retries (see Running Tests: Retries).
Request Pacing¶
An API with a rate limit rejects requests that arrive too fast, often with 429 Too Many Requests. minRequestInterval spaces the starts of requests at least that far apart, so a run stays under the limit instead of recovering from it:
shared:
settings:
minRequestInterval: 250ms # at most four requests a second
- One interval per command. Everything one command sends shares it: every plan of
aat run batch, including plans running side by side with--parallel, and every retry, verification step, and cleanup step.--parallel 4with250msstill sends at most four requests a second. - Every way of running a plan honors it:
aat run plan,aat run batch,aat prompt, and the MCP server'sexecute_plan. The MCP server paces across calls for as long as it runs. - Waits count toward durations. A step's duration includes the time it waited for its turn, as it includes retry waits.
- OAuth2 token requests are not paced.
- The value is a duration with a unit (
ms,s,m): - A bare number such as
250is rejected when the file loads. - Empty or
0sturns pacing off. - Like any string in the file, it can come from a var:
minRequestInterval: ${pace}with--var pace=1s.
OAS Validation Mode¶
When the graph references an OpenAPI spec, each step's request body, when it is JSON or form-encoded, and its response body are checked against it at runtime. oasValidation sets the per-environment default:
| Value | Behavior |
|---|---|
auto |
Validate whenever specs are present; violations are reported as warnings (default). A spec that fails to load is a warning |
strict |
Like auto, but a violation in the request or response fails the step (cleanup still runs); expectFailure steps are exempt. A spec that fails to load stops the run with exit code 2 |
off |
Skip loading specs and validating entirely |
The --oas-validate flag on aat run plan, aat run batch, and aat prompt overrides the environment setting for a single invocation (CLI flag > settings.oasValidation > auto). Any other value is rejected, in the environment file when it loads and on the command line, so a typo such as stirct cannot quietly mean auto. Turning it off in a busy environment saves the spec-loading time; keeping it on surfaces contract drift as OAS: N warning(s) markers and an issues count in the archive. See Running Tests: OAS Validation and API Graphs: OAS Validation.
Multi-Host Routing¶
When your API spans multiple services, use overrides to route specific nodes to different base URLs:
apiBaseUrl: https://api.example.com
overrides:
- match: "payment*"
baseUrl: https://payments.example.com
- match: "inventory*"
baseUrl: https://inventory.example.com
auth:
type: apikey
headerName: X-Inventory-Key
credentials:
key:
source: env
var: INVENTORY_KEY
- match: "notifications*"
baseUrl: https://notify.internal.example.com
auth:
type: none
headers:
X-Internal-Caller: aat
Each override matches node names using glob patterns. When a node matches:
baseUrl— replaces the top-levelapiBaseUrl. If omitted, inherits the top-level base URL.auth— replaces the top-level auth for that node. The top-level credential (theAuthorizationheader, or the top-level API key header) is dropped first, so it is never sent to the override's host. If omitted, inherits the top-level auth.headers— merged over the run's headers (environment, plan, and overlay headers); override-specific headers win on conflict, and the credential is set again after them (see Custom Headers).
An entry that sets none of baseUrl, auth, headers, or pathRewrite — only values: or expectFailure: — does not change routing: the node keeps the route that a broader glob or the top-level configuration gives it. An overlay can therefore turn paymentCharge into a negative test without pulling it off a payment* route.
Overrides are matched against the node name with two rules: an exact name always beats a glob pattern, and within each kind (exact or glob) the last registered entry wins. Entries register in this order — env.yaml overrides:, then .aat-overrides.yaml, then the --overlay file, then --override flags — so a later source overrides an earlier one for the same node, whether both are globs or both are exact names. See Local Development: Priority Chain.
Path Rewriting¶
Overrides can rewrite URL paths when the target service uses a different path structure:
overrides:
- match: "catalog*"
baseUrl: https://catalog.example.com
pathRewrite:
strip: /api/v2
prefix: /v1
With this config, a template path of /api/v2/products/{{productId}} becomes /v1/products/{{productId}} when routed to the catalog service.
| Field | Description |
|---|---|
strip |
Prefix to remove from the template path |
prefix |
Prefix to add after stripping |
Both fields are optional — you can strip without adding, add without stripping, or do both.
Runtime Overrides¶
Two mechanisms let you adjust routing without editing the environment file:
--override flag — routes a specific node to a different URL:
aat run plan checkout.yaml --override createPayment=https://sandbox.payments.example.com
This flag is repeatable for multiple overrides. Each one behaves exactly like an entry - match: NODE with baseUrl: URL: the request keeps the environment headers, the plan headers, overlay headers, and the credential of the effective auth.
--overlay flag — merges a sparse overlay file on top of the base environment:
aat run plan checkout.yaml --overlay local-routing.yaml
.aat-overrides.yaml dotfile — auto-discovered by walking up from your working directory. Same format as an overlay file, but requires no flags. Ideal for local development where you always want traffic routed to your local service. Use --no-auto-overrides to disable.
See the Overlay Files section below.
Overlay Files¶
An overlay file is a sparse YAML document that merges with the base environment. It can contain per-node overrides (same format as the environment overrides: section) and optional transaction-level auth and headers that apply to every API call in the run.
Per-Node Overrides¶
The overrides: section works the same as in an environment file — each entry matches node names by glob and can override baseUrl, auth, headers, pathRewrite, input values, and expectFailure for matched nodes only:
# local-routing.yaml
overrides:
- match: "payment*"
baseUrl: https://localhost:8081
auth:
type: none
When both the base environment and an overlay define overrides that match the same node, the overlay's entry registers later and takes precedence: exact names beat globs, and among entries of the same kind the last registered wins. Registration order is env.yaml overrides: → .aat-overrides.yaml → --overlay → --override.
Input-Value and Expected-Failure Overrides¶
An override can also inject specific input values and declare that a matched step is expected to fail. This is the primitive for authoring depth/error tests without editing a plan — run the existing happy-path plan, but an overlay forces the targeted node to receive a malformed value and pass only when it fails with the declared status:
overrides:
- match: createBooking
values:
passengerAge: -1
lastName: ""
expectFailure:
status: [400, 422]
description: "invalid payload"
Semantics:
values:merge into the resolved inputs map at step execution time, overwriting plan-supplied values. Precedence: overlay values > plan step values > graph defaults. They are used exactly as written:{{...}}expressions such as{{today}}are not evaluated, and the input's graph type is not applied. The archive records each one as the input's resolution, with the sourceoverride_value, so the decision trail shows the value that was sent.expectFailure:applies to matched steps only when the plan step doesn't already declare its ownexpectFailure. Status codes must all be>= 400.- Match precedence: exact matches win over glob matches on key conflicts, and later registrations overwrite earlier ones (
env.yaml→.aat-overrides.yaml→--overlay→--override). ForexpectFailure, the last exact match wins; if no exact match, the last glob match wins.
Both fields can be combined with baseUrl, auth, headers, and pathRewrite in a single override entry.
Transaction-Level Auth¶
A top-level auth field in an overlay replaces the environment's auth for the entire run — all nodes, not just those matching an override pattern. This is useful when the target environment requires different credentials than the base environment:
# overlay with transaction-level auth
auth:
type: oauth2
tokenUrl: https://auth.staging.example.com/token
credentials:
username:
source: env
var: STAGING_USERNAME
password:
source: env
var: STAGING_PASSWORD
clientId:
source: env
var: STAGING_CLIENT_ID
clientSecret:
source: env
var: STAGING_CLIENT_SECRET
overrides:
- match: "payment*"
baseUrl: https://localhost:8081
In this example, all nodes authenticate with the staging OAuth2 credentials, but payment nodes are routed to localhost. The auth configuration supports the same types and fields as an environment's auth section (oauth2, apikey, bearer, none).
Auth priority (lowest to highest):
env.yamlauth:— base environment credentials.aat-overrides.yamlauth:— auto-discovered overlay--overlayfileauth:— explicit overlay- Plan-level
auth:— per-plan override
Transaction-Level Headers¶
A top-level headers map in an overlay is merged into every request. These headers take precedence over environment-level headers, plan headers, and the auth credential (template headers still come after them; see Custom Headers), making them useful for injecting access-group tokens, correlation IDs, or other cross-cutting headers:
# overlay with transaction-level headers
headers:
X-Access-Group: my-access-group-id
X-Correlation-Id: local-dev-session
overrides:
- match: placeOnQueue
baseUrl: http://localhost:8080
Selecting the Environment¶
A top-level environment: field in an overlay selects which named environment the run should target. This is primarily useful for local development: if your overlay routes traffic to a locally-running service, and that local service talks to a different backend than the project default, the overlay can name the backend so you don't have to pass --env every time:
# .aat-overrides.yaml — local-dev overlay
environment: dev # backend the local service talks to
overrides:
- match: "*"
baseUrl: http://localhost:8080
Environment-name priority (highest to lowest):
--envCLI flagAAT_ENV_NAMEenvironment variable--overlayfileenvironment:— explicit overlay.aat-overrides.yamlenvironment:— auto-discovered overlaydefaultEnvironmentfrom the project manifest, when the run uses the environment file the manifest names
Explicit CLI choices always win, so the overlay's environment: behaves as a smart default — it kicks in when no env is specified, and is silently deferred when one is. Combine with --no-auto-overrides to skip auto-discovery entirely.
Combining Auth, Headers, and Overrides¶
All three sections can appear in a single overlay file:
auth:
type: oauth2
tokenUrl: https://auth.example.com/token
grantType: "http://auth0.com/oauth/grant-type/password-realm"
extraParams:
realm: my-realm
credentials:
username:
source: env
var: MY_USERNAME
password:
source: env
var: MY_PASSWORD
clientId:
source: env
var: MY_CLIENT_ID
clientSecret:
source: env
var: MY_CLIENT_SECRET
headers:
X-Access-Group: my-access-group-id
overrides:
- match: myService
baseUrl: http://localhost:3000
pathRewrite:
strip: /api/v2
prefix: /v1
Overlays are useful for:
- Routing specific services to local instances during development
- Switching a subset of nodes to a sandbox environment
- Replacing auth credentials for an entire test run
- Injecting transaction-level headers across all API calls
Validation¶
aat validate checks environment files for structural correctness. A key that no field accepts, such as a misspelled apiBaseURL, is an error naming the file, the line, and the likely intended key.
Single-environment files:
environmentname is requiredapiBaseUrlis required- Auth type must be one of:
oauth2,apikey,bearer,none - OAuth2 requires
tokenUrland all four credential fields - API key requires
credentials.keyandheaderName - Bearer requires
credentials.token - Override entries must have a
matchpattern settings.oasValidationmust beauto,strict, oroffsettings.minRequestIntervalmust be a duration with a unit, such as250ms
Multi-environment files — all the above, plus:
- All
extendstargets must exist - No circular inheritance chains
- All
${var}references must resolve after merging - Abstract environments (underscore prefix) cannot be the
defaultEnvironment - Each non-abstract environment must produce a valid configuration after resolution
apiBaseUrlis not required (environments may route entirely through overrides)
See Validation for the full reference covering all validation subcommands.
Schema Reference¶
Single-Environment Format¶
# env.yaml — single-environment annotated example
environment: staging # required — environment name
apiBaseUrl: https://api.staging.example.com # required — default base URL
auth: # authentication configuration
type: oauth2 # oauth2 | apikey | bearer | none
tokenUrl: https://auth.example.com/token # token endpoint (oauth2 only)
headerName: X-API-Key # custom header name (apikey only)
grantType: password # oauth2 grant_type (default: "password")
extraParams: # extra form params for oauth2 token request
realm: my-realm # example: Auth0 realm
credentials: # named credential fields
username: # oauth2: username, password, clientId, clientSecret
source: env # source: env (recommended) or literal
var: API_USERNAME # env var name (when source=env)
password:
source: env
var: API_PASSWORD
clientId:
source: env
var: API_CLIENT_ID
clientSecret:
source: env
var: API_CLIENT_SECRET
key: # apikey: key
source: env
var: API_KEY
token: # bearer: token
source: env
var: BEARER_TOKEN
headers: # optional — static headers on every request
Accept: application/json
X-Client-Id: aat
llm: # LLM configuration (for aat prompt)
endpoint: https://api.openai.com/v1/chat/completions
apiKey:
source: env
var: OPENAI_API_KEY
model: gpt-4o
provider: openai # optional — auto-detected from endpoint
settings: # optional — runtime defaults
oasValidation: auto # auto, strict, or off (default: auto)
minRequestInterval: 250ms # least time between request starts (default: none)
notes: "Staging environment for QA" # optional — freeform notes
overrides: # optional — per-node routing overrides
- match: "payment*" # glob pattern matching node names
baseUrl: https://payments.example.com # override base URL (optional)
auth: # override auth (optional, inherits top-level)
type: apikey
headerName: X-Payment-Key
credentials:
key:
source: env
var: PAYMENT_KEY
headers: # additional headers (merged with env headers)
X-Payment-Version: "3"
pathRewrite: # optional URL path rewriting
strip: /api/v2 # prefix to remove
prefix: /v1 # prefix to add
values: # optional — input value overrides for matched steps
amount: 0 # each key is an input name on the matched node
currency: "XYZ"
expectFailure: # optional — flip matched steps to negative-test mode
status: [400, 422] # all entries must be >= 400
description: "invalid payment"
values: # optional — key-value pairs for {{env.KEY}}
region: us-east
Multi-Environment Format¶
# env.yaml — multi-environment annotated example
include: # optional — additional files to merge
- env.secrets.yaml # resolved relative to this file
shared: # optional — defaults merged into every environment
headers:
Accept: application/json
llm:
endpoint: https://api.openai.com/v1
apiKey:
source: env
var: OPENAI_API_KEY
model: gpt-4
settings:
oasValidation: auto
minRequestInterval: 250ms
values:
region: us-east
environments:
dev: # selectable with --env dev
apiBaseUrl: https://api.dev.example.com
auth:
type: none
_base-direct: # abstract (underscore) — not directly selectable
auth:
type: none
overrides:
- match: "search*"
baseUrl: https://search-${env_tag}.internal.example.com
staging:
extends: _base-direct # inherits overrides and auth from _base-direct
vars: # ${env_tag} replaced in inherited strings
env_tag: staging
prod:
apiBaseUrl: https://api.example.com
auth:
type: oauth2
tokenUrl: https://auth.example.com/oauth/token
credentials:
username:
source: env
var: PROD_USERNAME
password:
source: env
var: PROD_PASSWORD
clientId:
source: env
var: PROD_CLIENT_ID
clientSecret:
source: env
var: PROD_CLIENT_SECRET
Source: config/environment.go, config/multi_env.go, config/auth.go, config/auth_provider.go, config/load.go.