Environment and Auth
How AX injects experiment environment variables and secrets, reads harness environment variables, and stores platform API credentials.
AX has two separate environment surfaces:
- Experiment environment variables are declared in experiment YAML and injected into variant containers — literal config, or secret values referenced from your organization's secret store.
- CLI and harness environment variables configure AX itself, such as model-provider credentials or platform API credentials.
Experiment environment variables
Declare env vars with environment_variables — a list of {name, value}, global to the experiment (and also available on a setup object):
schema_version: 2
id: github-example
name: "GitHub example"
environment_variables:
- { name: LOG_LEVEL, value: debug } # literal config — lives in the YAML
- { name: GITHUB_TOKEN, value: "ax://secrets/prod-gh" } # secret — referenced from the org store
agents: [claude]
prompts: ["…"]
tests:
- { name: noop, script: "true" }
limits: { max_time_seconds: 120 }A value is either a literal (non-secret config, written in the YAML) or a store reference ax://secrets/<slug> resolved from your organization's secret store (legacy axp://secrets/<slug> is also accepted). The ax:// and axp:// prefixes are reserved: a literal must not begin with either, and any ax://… or axp://… that isn't a valid secrets reference is rejected at validate time — so a typo can't silently become a literal.
environment_variables is injected by both ax experiment run --local and platform ax experiment run. Earlier releases rejected secret-bearing experiments on the platform; that restriction is gone. Unresolved references fail fast at preflight, before any container starts — see Resolution and precedence for which sources apply on each path.
The org secret store
Secret values live in a per-org store, encrypted at rest, and are referenced, never pasted into experiments. Manage them with the CLI:
ax secret set prod-gh # hidden prompt (never echoed), or stdin when piped
ax secret set prod-gh --description "Prod GitHub token"
ax secret list # slug + description + audit metadata — never values
ax secret list --json # bare metadata array on stdout; no values
ax secret view prod-gh # metadata + ax://secrets/prod-gh reference — never the value
ax secret view prod-gh --json # single metadata object including reference
ax secret delete prod-gh # confirm at TTY, or --yes (required off-TTY); missing = already gone
ax secret list --org org_... # one-off org override (set/view/delete accept --org too)Each secret is identified by a kebab-case slug (referenced as ax://secrets/<slug>), not an env-var name — the env var a value lands in is chosen per experiment by the name you bind it to. So one org can hold a prod and a staging token that both inject as GITHUB_TOKEN in different experiments.
Agents connected to the AX MCP server can manage the same store with secret_set, secret_list, and secret_delete. These tools use the current MCP org context, accept the same slugs and optional descriptions, and return only slug + audit metadata.
A stored value never comes back out of a read. ax secret list, ax secret view, secret_list, secret_set, and the UI return slugs and metadata only (view also shows the YAML reference). No command prints a secret value, so values stay out of logs, terminal scrollback, and screen-shares. Values are released only to inject into a run you are about to execute, and only to members of the org — a non-member who tries to resolve a secret is denied. (Org membership is the trust boundary in V0: any member can use any of the org's secrets in their experiments.)
Only names your experiment references are read from local sources. If .env or an --env-file contains unrelated variables, AX ignores them.
Resolution and precedence
-
Platform (
ax experiment run): dispatch resolves eachax://secrets/<slug>reference server-side from the org store and injects literals as-is. There is no.envin a platform sandbox — the YAML (and the store behind its refs) is the whole story. -
Local (
ax experiment run --local): eachax://secrets/<slug>reference resolves local-first by the environment-variablename(not the slug), then falls back to the active-org secret store by slug for names still missing. Local sources, from lowest to highest precedence:./.env, automatically discovered relative to the current working directory.- Each
--env-file PATH, in command-line order. Later files override earlier files. - Host environment variables.
--env NAME=VALUEor--env NAME.
Local sources always win over the store. A name missing from both local sources and the org store fails preflight. Local override values are always literal: a
.envvalue ofax://secrets/xis injected verbatim, never re-resolved as a reference.--resolve-variantsstays offline (no store call).
ax experiment run experiment.yaml --local \
--env-file local.env \
--env GITHUB_TOKEN \
--env LOG_LEVEL=traceFor --env NAME=VALUE, AX uses the value exactly as provided. For bare --env NAME, AX reads NAME from the host environment while parsing CLI flags; if the host variable is not set, parsing fails.
When ./.env supplies the final value for at least one referenced name, AX prints a notice:
axp: loaded secrets from /path/to/.envExplicit --env-file paths do not print that auto-load notice.
For each resolved ax://secrets/<slug> (or legacy axp://secrets/<slug>) experiment secret reference on a local run, AXP also prints a names-only provenance line on stderr — variant id, env-var name, and source (local sources or org secret store). Resolved secret values never appear in that line.
Valid names and reserved names
An environment_variables name must match:
^[A-Z_][A-Z0-9_]*$Use uppercase ASCII letters, digits, and underscores; the first character must be an uppercase letter or underscore. Lowercase, Unicode, hyphenated, and empty names are rejected, as are duplicate names within a list. (Store slugs are separate — they are kebab-case, e.g. prod-gh.)
These names are reserved by the harness and cannot be used:
ANTHROPIC_API_KEYANTHROPIC_BASE_URLOPENAI_API_KEYOPENAI_BASE_URLCURSOR_API_KEYMODELMAX_TURNSIS_SANDBOXTRACEPARENT- any name starting with
AXP_ - any name starting with
CLAUDE_CODE_ - any name starting with
CODEX_ - any name starting with
CURSOR_ - any name starting with
OTEL_
Removed: secrets
The older top-level (or setup) secrets: field is rejected by ax experiment validate and by platform submit — even an empty secrets: []. Use environment_variables with literal values or ax://secrets/<slug> references instead.
Forwarding secrets to MCP servers
Experiments that expose MCP servers to the agent can route an environment_variables entry into those servers as stdio env entries or HTTP/SSE headers, referenced by name (${NAME} placeholders for headers). Only names/placeholders appear in the YAML; the resolved value (literal or store-backed) is wired in at runtime. See MCP servers for the full schema and validation rules.
Resolved secret values are written verbatim into the ACP session/new JSON-RPC frame, which is recorded in agent-events.jsonl before any redaction. Any debug bundle generated for an experiment that forwards secrets to MCP servers will contain those values — treat such bundles as sensitive.
Model credentials
Model access has several surfaces. Organization BYOK (your own Anthropic/OpenAI upstreams stack-ranked with the 514.ax AI gateway) is configured under Integrations → LLM Providers, not in the secret store, a host .env, or experiment environment_variables. See Model Providers and the 514.ax AI Gateway.
ax experiment run (the platform path) and default ax experiment run --local supply model access for you — you do not set a model key. Sign in with ax auth login, or set AX_API_KEY if you are running in CI.
To use host provider keys on a local run instead, pass --local-model-keys. Then each selected agent needs a credential in your host environment:
agent: claudeusesANTHROPIC_API_KEY.agent: codexusesOPENAI_API_KEY.agent: cursorusesCURSOR_API_KEY.
export ANTHROPIC_API_KEY=...
ax experiment run experiment.yaml --local --local-model-keysexport OPENAI_API_KEY=...
ax experiment run codex-experiment.yaml --local --local-model-keysexport CURSOR_API_KEY=...
ax experiment run cursor-experiment.yaml --local --local-model-keysThese names are harness-managed and reserved, so do not put them in environment_variables. With --local-model-keys, AX reads them from the host, ./.env, --env-file, or --env, then injects only the selected agent's credential into the variant container.
ANTHROPIC_BASE_URL and OPENAI_BASE_URL are also reserved by AX. Do not put them in environment_variables.
AX-provided model access
ax experiment run always uses platform-supplied model access. Local runs default to the same managed path (ax experiment run --local / ax local run). It supports agent: claude, agent: codex, and agent: cursor variants.
ax experiment run experiment.yaml --localSign in first with ax auth login, or set AX_API_KEY if you are running in CI. If you are not signed in and do not pass --local-model-keys, the CLI fails before starting containers with guidance to log in or opt into host keys.
Use --api-base-url <URL> only when the AX team gives you a non-default platform URL, such as a preview environment:
ax experiment run experiment.yaml --local --api-base-url https://preview.example.com--api-base-url is only valid when using AX-provided model access.
agent: cursor variants use managed Cursor access through the model proxy (not organization BYOK), so they work under default managed local runs alongside claude and codex. For routing, allowlists, billing, and Integrations setup, see Model Providers and the 514.ax AI Gateway.
Platform credentials
AX stores platform API credentials at:
~/.fiveonefour/axp/credentials.tomlThe file stores the API key plus the email and active org returned by the platform WhoAmI RPC. AX writes the file with 0600 permissions and re-applies that mode when saving over an existing file.
AX_API_KEY overrides the saved API key when the CLI loads credentials:
AX_API_KEY=... ax auth statusThe environment override does not rewrite the saved API key in credentials.toml; it only affects that process. The saved active org is still used as the preferred org when the override key has access to it.
Platform URL
The CLI connects to the AX platform out of the box — you do not need to configure anything. If the AX team gives you a different platform URL, set AX_PLATFORM_URL:
AX_PLATFORM_URL=https://platform.example.com ax auth statusAX_PLATFORM_URL starts with AXP_, so it is reserved and cannot be declared as an experiment secret.
Auth commands
Log in with the AX MCP connector:
ax auth connect --code axpcli_...The cli_auth.start MCP tool creates the one-time code and returns the full command. The
code can only be used once and expires quickly.
Log in with the browser device flow:
ax auth loginThe CLI opens a browser for authorization, verifies the minted key with the platform WhoAmI RPC, selects an active organization, then saves credentials (API key plus active org) to ~/.fiveonefour/axp/credentials.toml. Login never finishes without an active org. If the CLI cannot open a browser, run ax auth login --no-browser to print the verification URL.
How the active org is chosen:
- One organization — selected automatically.
--org <org-id>— that org, when it is accessible to the key.- Multiple organizations, interactive terminal — an interactive picker.
- Multiple organizations, non-interactive — the first organization by name (deterministic). The CLI prints which org it chose and how to switch with
ax org list→ax org switch <org-id>.
Pass an API access token non-interactively with:
ax auth login --token ...Combine with --org when the key can access more than one org and you do not want the name-order default:
ax auth login --token ... --org org_...Show the identity resolved by the platform API:
ax auth statusUse JSON output for scripts:
ax auth status --jsonList organizations visible to the current API key and show which one is active:
ax org list
ax org list --jsonShow the active org (name, id, role, platform):
ax org view
ax org view --jsonSwitch the active CLI organization:
ax org switch org_...Platform commands such as ax run upload, ax send-debug, ax run download, ax experiment query, and ax run query use the active CLI org by default. For a one-off platform command without changing the saved active org, pass --org org_... to that command.
Legacy ax auth orgs / ax auth orgs --switch still work; prefer ax org list and ax org switch.
Invite teammates as non-admin members with ax org invite (org admin only; no
role flag). List, view, and switch stay under ax org list / view / switch
— see AX CLI → org for invite flags, errors, and domain
eligibility.
Log out locally:
ax auth logoutlogout removes ~/.fiveonefour/axp/credentials.toml. It does not revoke the API key on the platform.