Experiment YAML

Lookup reference for the AX experiment YAML schema: fields, object shapes, shorthand forms, constraints, and validation rules.

Experiment YAML is the file format passed to ax experiment run and ax experiment run --local.

The current parser accepts schema_version: 2 and rejects unknown fields at every level. For the canonical machine-readable schema, use experiment.v2.schema.yaml.

Schema URL

Use the version-pinned schema URL for editor validation:

# yaml-language-server: $schema=https://docs.514.ax/schema/experiment.v2.schema.yaml

Published schema URLs:

URLUse
https://docs.514.ax/schema/experiment.schema.yamlLatest supported schema
https://docs.514.ax/schema/experiment.v2.schema.yamlVersion-pinned v2 schema
https://docs.514.ax/schema/experiment.v1.schema.yamlLegacy v1 schema. v1 experiments no longer run; this remains available so older files that pin it still validate in-editor while migrating to v2.

ax experiment schema prints the latest supported schema to stdout.

Field index

ObjectFields
Top-level experimentschema_version, id, name, description, agents, models, prompts, agent_mode, environments, products, extensions, environment_variables, files, tests, limits
Agentname
Modelname, lab, effort, context_window_size, thinking, fast
Promptid, prompt, description, tags
Environmentname, setup, description, tags, commit
Productname, type, setup, version, commit, description, tags
Setupname, script, description, tags, files, environment_variables, mcp_servers, setup_checks
Extensionid, description, tags, agents, models, prompts, agent_mode, environments, products, extensions
Environment variablename, value
File entryname, source, sha256, dest
Testname, script
Setup checkname, script
MCP servername, type, command, args, url, env, headers
MCP stdio env entryname, from
MCP HTTP and SSE headername, value
Limitsmax_turns, max_time_seconds, max_cost_usd

Minimal example

# yaml-language-server: $schema=https://docs.514.ax/schema/experiment.v2.schema.yaml
schema_version: 2
id: cli-install
name: "CLI install"

agents: [claude]
models: [claude-sonnet-4-6]

prompts:
  - id: install
    prompt: |
      Install the CLI and write its version to /workspace/version.txt.

products:
  - name: cli
    type: CLI
    setup: npm pack

tests:
  - name: version-file-exists
    script: test -f /workspace/version.txt

limits:
  max_turns: 25
  max_time_seconds: 300
  max_cost_usd: 0.50

Top-level experiment

An experiment defines what you want to learn about agents using a product surface. It names the agents, prompts, products, environments, and tests AX uses to compute and run variants.

FieldRequiredType / shapeNotes
schema_versionYesIntegerMust be 2.
idYesKebab-case stringStable experiment id. Should match the YAML file name without .yaml.
nameYesStringHuman-readable experiment name.
descriptionNoStringOptional context used when analyzing outcomes.
agentsNoAgent axisOptional at the top level only if an extension supplies agents. Every resolved variant must have an agent.
modelsNoModel axisOptional. Cross-multiplied with agents; incompatible pairs are pruned. Absent ⇒ each agent runs its provider-default model.
promptsNoPrompt axisOptional at the top level only if an extension supplies prompts. Every resolved variant must have a non-empty prompt.
agent_modeNoAgent-mode axisOptional. build (default) or plan. Accepts a single value or list. plan runs the agent read-only (no mutations). Defaults to build.
environmentsNoEnvironment axisOptional.
productsNoProduct axisOptional.
extensionsNoExtension listOptional. If present, only extension-derived variants are created.
environment_variablesNoEnvironment variable list{name, value} entries injected into every variant. Values can be literals or ax://secrets/<slug> references resolved from your org secret store.
filesNoFile entry listHost files staged into every variant before setup runs.
testsYesTests listMust contain at least one test.
limitsYesLimits objectRun caps.

Top-level environment_variables and files apply to every variant. MCP servers and setup checks are setup-owned fields.

Variant axes

Variant axes are the experiment inputs AX combines into runnable variants. This lets you define the dimensions you care about once, then compare results by agent, prompt, environment, and product.

variants = agents × models × prompts × agent_mode × environments × products

Only agents and prompts must be specified: every resolved variant carries an agent and a prompt (each can also be supplied by an extension). The rest are optional. Omit models and each agent runs its provider-default model; omit agent_mode, environments, or products and that axis is left out of the cross product and of the variant coordinate.

Agents

agents defines which coding agents run the experiment. The model an agent runs comes from the models axis, not the agent.

Accepted shapes:

# String form: one agent.
agents: claude

# List of strings: multiple agents. Valid names: claude, codex, cursor.
agents:
  - claude
  - codex
  - cursor

# Object form is also accepted, but only carries the name.
agents:
  - name: claude

The nested agents[].model key was removed. Put the model on the top-level models axis instead. Authoring agents: [{ name: claude, model: … }] fails ax experiment validate with a migration message.

Agent object

FieldRequiredType / valuesNotes
nameYesclaude, codex, or cursorCoding agent to run. The model comes from the models axis.

Models

models defines which models run, as an independent axis cross-multiplied with agents. Listing agents: [claude] with models: [opus, sonnet] produces both variants without duplicating the agent.

Accepted shapes:

# String form: one model.
models: claude-opus-4-8

# List of strings: multiple models.
models:
  - claude-opus-4-8
  - claude-sonnet-4-6

# Object form: a model with controls.
models:
  - name: gpt-5.3-codex
    effort: high

models is optional. If omitted, each agent runs its provider-default model.

Pruning incompatible pairs

The agents × models cross product keeps only the compatible pairs. A model the catalog knows for a different agent's provider — for example claude × an openai model — is pruned (dropped), not an error, so one agents + models pair of lists expresses every valid combination:

agents: [claude, codex]
models: [claude-opus-4-8, gpt-5.3-codex]
# 2 × 2 = 4 pairs → pruned to the 2 valid ones:
#   ✓ claude + claude-opus-4-8     ✓ codex + gpt-5.3-codex
#   ✗ claude + gpt-5.3-codex       ✗ codex + claude-opus-4-8   (dropped)

Pruning is visible — dropped pairs show up as a smaller resolved matrix in ax experiment variants. If a listed agent or model is compatible with nothing else listed (every pair it appears in is pruned), ax experiment validate hard-errors, since that entry is almost certainly a typo.

Model id format

Prefer the lab-official models.dev id with no owner prefix, such as claude-opus-4-8, gpt-5.3-codex, or composer-2.5. AX infers the runtime provider from the selected agent and stores a canonical provider/lab/model id behind the scenes.

If a bare id is ambiguous, validation asks for lab; use the model object form, for example { name: claude-opus-4-8, lab: anthropic }. Most model ids do not need this.

Older owner/provider-prefixed and gateway-style ids, such as anthropic/claude-opus-4-8 or anthropic/claude-opus-4.8, are accepted for compatibility and normalize to the same canonical id.

Model object

A model object configures one model and its controls. Optional controls are passed through when the selected agent supports them. To compare two control settings of the same model, list two models entries.

FieldRequiredType / valuesNotes
nameYesStringLab-official models.dev id, such as claude-opus-4-8 or gpt-5.
labNoStringOptional disambiguator, such as anthropic or openai, used only when validation reports an ambiguous bare id.
effortNolow, medium, high, x-high, maxReasoning effort control, validated against the (agent, model) catalog. Delivered where each harness honors it: an ACP session/set_config_option for Claude / Codex, baked into the model id for Cursor.
context_window_sizeNoStringContext window size, such as 1M or 200k (a token count also works). Supported for Claude (200k or 1M) and Codex (any size up to the model's limit). Not supported for Cursor — the Cursor CLI cannot select a context window, so ax experiment validate (and therefore ax experiment run / ax experiment run --local) rejects any Cursor variant that sets it. Validation also rejects sizes over the selected model's limit.
thinkingNoBooleanEnables thinking mode when supported.
fastNoBooleanEnables fast mode when supported.
agents: [claude, codex]
models:
  - name: claude-opus-4-8
    effort: high
    context_window_size: 1M
    thinking: true
  - gpt-5

Prompts

prompts defines the tasks agents try to complete. Each resolved variant receives one final prompt.

Accepted shapes:

# String form: one prompt.
prompts: "Build the report."

# List of strings: multiple prompts.
prompts:
  - "Build the report."
  - "Build the report and explain your steps."

# Object form: list of named prompts.
prompts:
  - id: detailed
    prompt: "Build the report and explain your steps."

Prompt object

A prompt object gives a task stable metadata, so Results can filter and group by the prompt that produced each run.

FieldRequiredType / valuesNotes
idYesKebab-case stringStable prompt id. Recorded for filtering in Results.
promptYesStringTask text given to the agent.
descriptionNoStringHuman-readable notes.
tagsNoString listFree-form labels.

Bare prompt strings get positional ids: p0, p1, and so on.

Agent mode

agent_mode is a top-level model variable. Accepts a single value or list of build / plan. It is cross-multiplied with the other axes just like agents and models to define the variants tested.

  • build (default) runs the agent normally: it executes tools, can read and write, and mutates the workspace.
  • plan puts the agent in its native read-only / planning mode. This plans, and mutates nothing in the sandbox. The abstract plan value resolves to that agent's planning mode (claude / cursor resolve to plan, codex to read-only). If the selected mode isn't available the variant fails loudly rather than silently running in build.
# Sweep both modes over one agent/model/prompt → 2 variants.
agents: [claude]
models: [claude-opus-4-8]
agent_mode: [build, plan]

agent_mode is optional; defaulting to build mode. When you declare the axis, the mode is emitted into the variant id. This applies to plan and build options. So a [build, plan] sweep produces …::build::my-prompt and …::plan::my-prompt. When the axis is absent nothing is emitted, so experiments that don't use agent_mode keep their original ids (for example claude::anthropic-claude-opus-4-8::my-prompt). Note that authoring agent_mode: build explicitly therefore yields a different id than omitting the axis.

A plan variant produces no file changes. Every test in the flat tests list runs for every variant regardless of mode; the harness does not scope tests by agent_mode. A build-oriented workspace check will fail the plan variant unless you guard it (e.g. [ ! -f out.json ] || <verify out.json>). For a [build, plan] sweep, score the plan variant with trace-based checks over $AX_TRACE_PATH. See examples/experiments/plan-mode-comparison.yaml.

Environments

environments defines the sandbox conditions around the agent, such as installed tools, fixtures, or external integrations. Use environments when you want to compare how agents perform under different surrounding conditions.

Accepted shapes:

# String form: one setup script with a generated environment name.
environments: "pip install -r requirements.txt"

# Object form: one named environment.
environments:
  name: workspace
  setup: "pip install -r requirements.txt"

# List form: multiple named environments.
environments:
  - name: workspace
    setup: "pip install -r requirements.txt"

Environment object

An environment object names one sandbox setup condition. Its setup prepares the sandbox before the agent receives the prompt.

FieldRequiredType / valuesNotes
nameYesKebab-case stringEnvironment coordinate. Recorded for filtering in Results.
setupYesSetupPrepares the sandbox before the agent runs.
descriptionNoStringHuman-readable notes.
tagsNoString listFree-form labels.
commitNoStringSource commit of the environment under test.

Bare environment strings are shorthand for an environment whose setup is that string.

Products

products defines the agent-facing surface under test. A product can be a CLI, API, MCP server, SDK, docs surface, or other tool the agent uses to complete the prompt.

Accepted shapes:

# String form: one setup script with a generated product name.
products: "npm install -g my-cli"

# Object form: one named product.
products:
  name: my-cli
  type: CLI
  version: "1.2.0"
  setup: "npm install -g my-cli"

# List form: multiple named products.
products:
  - name: my-cli
    type: CLI
    version: "1.2.0"
    setup: "npm install -g my-cli"

Product object

A product object names what you want to compare. Product metadata is recorded so Results can filter and group by product and product version.

FieldRequiredType / valuesNotes
nameYesKebab-case stringProduct coordinate. Recorded for filtering in Results.
typeNoProduct typeDefaults to Other.
setupYesSetupPrepares the product before the agent runs.
versionNoStringProduct version. Quote numeric versions, such as "25.3".
commitNoStringSource commit of the product under test.
descriptionNoStringHuman-readable notes.
tagsNoString listFree-form labels.

Product type

Allowed values: CLI, MCP, API, Skill, SDK, Schema, Docs, Marketing, Agents.md, Other.

Setup

setup prepares the sandbox for an environment or product. Use setup scripts to install tools, create fixtures, start services, or expose resources the agent needs.

Each variant has its own isolated /workspace. A setup script cannot rely on files or side effects created by another variant.

Accepted shapes:

# String form: one setup script.
setup: "npm install"

# List of strings: multiple setup scripts, run in order.
setup:
  - "npm install"
  - "npm test -- --help"

# Object form: one named setup with optional scoped resources.
setup:
  name: install-cli
  script: "npm install"

# List of objects: multiple named setups, run in order.
setup:
  - name: install-cli
    script: "npm install"
  - name: smoke-cli
    script: "npm test -- --help"

# Mixed list: strings and setup objects can be combined.
setup:
  - "npm install"
  - name: smoke-cli
    script: "npm test -- --help"

Setup object

A setup object is the named form of setup. Use it when setup needs its own files, environment variables, MCP servers, or setup checks.

FieldRequiredType / valuesNotes
nameYesKebab-case stringRequired for object form.
scriptYesStringBash run before setup checks and before the agent. Secret values are not injected here.
descriptionNoStringHuman-readable notes.
tagsNoString listFree-form labels.
filesNoFile entry listHost files staged before this setup's script runs (scoped to variants that resolve this setup).
environment_variablesNoEnvironment variable listRuntime env vars scoped to variants that use this setup.
mcp_serversNoMCP server listMCP servers exposed to the agent.
setup_checksNoSetup check listChecks run after setup and before the agent.

When both a product and environment contribute setup, product setup runs before environment setup.

Setup checks

setup_checks verify that setup produced a usable sandbox before the agent starts. A failed setup check stops that variant before any agent work happens. Setup checks receive resolved environment_variables, AX_VARIANT_ID, and AX_RUN_CONTEXT_PATH; they do not receive trace or agent-log paths because the agent has not run yet.

setup_checks:
  - name: cli-on-path
    script: my-cli --version

Setup check object

FieldRequiredType / valuesNotes
nameYesKebab-case stringAppears in setup-checks/<name>.json.
scriptYesStringBash check streamed over stdin and hidden from the agent. A non-zero exit aborts the variant before the agent runs.

MCP servers

mcp_servers exposes MCP servers to the agent for variants that use this setup. Use this field when the product surface or environment includes an MCP tool.

mcp_servers:
  - name: fixture-sentinel
    type: stdio
    command: /workspace/fixture-mcp.py
    args: []
  - name: ax
    type: http
    url: http://localhost:3001/mcp

MCP server object

An MCP server object defines one server and its transport. The required connection fields depend on type.

FieldRequiredType / valuesNotes
nameYesStringMust be unique within the setup's mcp_servers.
typeYesstdio, http, or sseTransport.
commandFor stdioStringExecutable path or command inside the sandbox.
argsNoString listStdio command arguments.
urlFor http / sseStringMCP endpoint URL.
envNoMCP stdio env entriesOnly valid for stdio.
headersNoMCP header entriesOnly valid for http / sse.

Transport-specific rules:

  • stdio uses command, optional args, and optional env.
  • http and sse use url and optional headers.
  • Mixing stdio-only and endpoint-only fields is rejected.

MCP stdio env entry

env forwards declared environment values to a stdio MCP process. Each entry is either a bare name or an object:

env:
  - GITHUB_TOKEN
  - name: GH_AUTH
    from: GITHUB_TOKEN
  # Managed model access for an LLM-backed MCP server (no raw provider key):
  - name: ANTHROPIC_API_KEY
    from: AXP_MODEL_PROXY_TOKEN
  - name: ANTHROPIC_BASE_URL
    from: AXP_MODEL_PROXY_URL
FieldRequiredType / valuesNotes
nameYesStringEnv var name as seen by the MCP server process.
fromYesEnv name or virtual refDeclared environment_variables name, or a managed-proxy virtual ref (AXP_MODEL_PROXY_TOKEN / AXP_MODEL_PROXY_URL).

AXP_MODEL_PROXY_TOKEN and AXP_MODEL_PROXY_URL are virtual references to the run's workload token and Anthropic-style proxy base URL. They resolve only when the run has managed model access (ax experiment run, or default ax experiment run --local / ax local run; not with --local-model-keys); without it they are dropped with a warning. They are not org secret-store slugs and are not organization BYOK configuration — see Model Providers and the 514.ax AI Gateway.

MCP HTTP and SSE header object

headers attaches HTTP headers to an http or sse MCP server. Use placeholders when a header needs a declared secret value.

headers:
  - name: Authorization
    value: "Bearer ${SUPABASE_SERVICE_ROLE_KEY}"
FieldRequiredType / valuesNotes
nameYesStringHTTP header name. Header names must be unique per server, case-insensitively.
valueYesStringMay contain ${SECRET_NAME} placeholders. Bare $NAME is literal.

MCP env entries and header placeholders reference environment variable names visible to the variant. Values can come from literal environment_variables, ax://secrets/<slug> references, or (stdio env only) the managed-proxy virtual refs AXP_MODEL_PROXY_TOKEN / AXP_MODEL_PROXY_URL.

Rules enforced at ax experiment validate time:

  • Every stdio env[*].from and every ${NAME} placeholder in a header value must reference a name visible to the variant, or (stdio env only) a managed-proxy virtual ref.
  • Bare $NAME is treated as a literal; only ${NAME} is a placeholder.
  • HTTP header names are unique per server, case-insensitively.
  • command / args / env are only valid for type: stdio; url / headers are only valid for type: http / sse.

Resolved secret values are written into the agent session frame and can appear in run artifacts. Treat artifacts as sensitive whenever an experiment forwards secrets to MCP servers.

Extensions

extensions refine the variant set when the base axes do not express the combinations you need. Use extensions to narrow an axis, swap products or environments for a subtree, or append prompt guidance to a slice of variants.

If an experiment declares any extensions, AX creates only extension-derived variants.

Extension object

An extension object is one node in the refinement tree. Nested extensions are recursively cross-multiplied with their parents.

FieldRequiredType / valuesNotes
idYesKebab-case stringMust be unique among sibling extensions.
descriptionNoStringHuman-readable notes.
tagsNoString listAdded to resolved variant tags.
agentsNoAgent listReplaces inherited agents for this extension subtree.
modelsNoModel axisReplaces inherited models for this extension subtree.
agent_modeNoAgent-mode axisReplaces inherited agent modes for this extension subtree.
promptsNoPrompt listAppended to inherited prompt text. Does not replace the prompt axis.
environmentsNoEnvironment listReplaces inherited environments for this extension subtree.
productsNoProduct listReplaces inherited products for this extension subtree.
extensionsNoExtension listNested extensions.
prompts:
  - id: analyze
    prompt: "Read /workspace/task.md and write /workspace/report.json."

extensions:
  - id: with-cli
    products:
      - name: cli
        type: CLI
        setup: "curl -fsSL https://clickhouse.com/ | sh"
    prompts: ["Use the ClickHouse CLI for the analysis."]
  - id: without-cli
    products:
      - name: no-cli
        setup: "true"
    prompts: ["Do not use the ClickHouse CLI; use another local method."]

Environment variables

environment_variables injects environment variables into variants at runtime. Use it for non-secret runtime configuration and supported secret references.

environment_variables:
  - name: LOG_LEVEL
    value: debug
  - name: GITHUB_TOKEN
    value: ax://secrets/prod-gh
  - name: DATABASE_URL
    value: ax://secrets/staging-db

Environment variable object

FieldRequiredType / valuesNotes
nameYesEnv-var nameMust match ^[A-Z_][A-Z0-9_]*$. Harness-reserved names and prefixes are rejected.
valueYesStringLiteral value or ax://secrets/<slug> reference (legacy axp://secrets/<slug> is also accepted). Other values beginning with ax:// or axp:// are rejected.

Store secret values once with ax secret set <slug>, then reference them with ax://secrets/<slug>. Both platform and local ax experiment run invocations resolve these references before injecting env vars into the sandbox.

A referenced slug that does not exist in your org fails at preflight.

Reserved names:

  • ANTHROPIC_API_KEY
  • ANTHROPIC_BASE_URL
  • OPENAI_API_KEY
  • OPENAI_BASE_URL
  • CURSOR_API_KEY
  • MODEL
  • MAX_TURNS
  • IS_SANDBOX
  • TRACEPARENT
  • any name beginning with AX_, AXP_, CLAUDE_CODE_, CODEX_, CURSOR_, or OTEL_

Files

Top-level files stages host files into every variant's /workspace before setup runs. The same shape is accepted on setup objects; setup-scoped entries stage only for variants that resolve that setup.

files:
  - name: my-cli
    source: ../build/mycli
    dest: tools/mycli
  - source: https://example.com/fixtures/data.bin
    sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
    dest: fixtures/data.bin

File entry object

FieldRequiredType / valuesNotes
nameSometimesKebab-case stringRequired when source is omitted. Used as the --file NAME=SOURCE handle.
sourceSometimesHost path or http(s) URLRequired when name is omitted. Relative paths resolve against the YAML file's directory.
sha256No64-char hex stringValid for file sources and URL downloads. Invalid for directory sources.
destYesWorkspace-relative pathAbsolute paths, .., .axp-bridge, and :: are rejected.

Notes:

  • Directory sources copy their contents under dest/.
  • File sources land as a single file at dest.
  • URL sources must be publicly fetchable and land as a single file at dest; unpack archives in setup if needed.
  • Sandboxes are Linux containers; macOS binaries staged from a laptop will not run there.
  • Directory walks honor .axpignore, not .gitignore.
  • --file NAME=SOURCE binds or overrides the source of a named entry.
  • --file SOURCE::DEST stages an ad-hoc entry into every variant.
  • Missing or unbound sources abort real runs at preflight. --resolve-variants renders MISSING / UNBOUND annotations without failing.
  • Staging failures roll the variant up as status=error / exit_reason=staging_failed; the rest of the run keeps going.
  • Platform and local runs both stage top-level files.
  • Treat experiment YAML like a script you run: sources are read with your permissions and may point anywhere on the host.

Tests

tests defines how AX scores each run. It is one flat list of bash checks. Test scripts receive resolved environment_variables, AX_VARIANT_ID, and path env vars for staged run artifacts, so any test can inspect final /workspace state, run commands, read $AX_TRACE_PATH, or branch on $AX_RUN_CONTEXT_PATH.

tests:
  - name: report-exists
    description: Confirms the agent produced the required report artifact.
    script: test -f /workspace/report.json
  - name: under-thirty-tool-calls
    script: |
      [ "$(jq -s '[.[] | select(.kind == "tool_call")] | length' "$AX_TRACE_PATH")" -lt 30 ]

Test runtime environment

Tests run inside the variant sandbox with /workspace as the working tree. The agent does not see the test scripts or these test-only path variables.

Env varAvailable toValue
AX_RUN_CONTEXT_PATHSetup checks and tests/tmp/axp/run-context.json, a JSON object with run_id, run_request_id, repeat_idx, variant_id, variant_tag, agent, model, canonical_model_id, effort, context_window_size, thinking, fast, prompt_id, prompt, environment_id, product_id, product_version, tags, and resolved_extend_id. Absent axes/controls are JSON null.
AX_TRACE_PATHTests only/tmp/axp/agent-events.jsonl, staged when the agent event stream exists. ACP runs and non-native cursor runs produce one; --flag native runs do not (no ACP session), so the variable is never set for them and trace-based tests fail native variants.
AX_AGENT_LOG_PATHTests only/tmp/axp/agent.log, staged when the agent log exists.
AX_VARIANT_IDSetup checks and testsThe derived variant id. Kept for backward compatibility; the same value is also in run context JSON.

Example:

jq -e '.run_id != null and .agent == "claude"' "$AX_RUN_CONTEXT_PATH"

Test object

FieldRequiredType / valuesNotes
nameYesKebab-case stringMust be unique.
descriptionNoNon-empty stringExplains the test's intent to analysis models. Updating or removing it with ax experiment push keeps the same semantic version and existing runs; ax experiment pull and the mutable description column in ax experiment query return the latest pushed value. Test outcome fields and version-change reports remain unchanged.
scriptYesStringBash script. Streamed over stdin and not shown to the agent.

Limits

limits sets the run caps for each variant execution.

Limits object

FieldRequiredType / valuesNotes
max_turnsYesInteger greater than 0Agent turn cap.
max_time_secondsYesInteger greater than 0Wall-clock timeout in seconds.
max_cost_usdYesNumber greater than 0Enforced when the agent reports cumulative cost during the run; if no cost is reported, AX cannot stop on cost.

The cost that max_cost_usd caps is the agent's own reported model spend — the running token cost the agent computes as it works. It excludes 514-managed sandbox and other harness infrastructure spend, and it applies the same way whether the run uses your own provider key or 514-managed model access. Because it's the agent's live estimate rather than a reconciled bill, treat the cap as an approximate guardrail.

Secrets removed

The top-level (and setup) secrets: field is rejected by ax experiment validate and platform submit, including an empty secrets: []. Use environment_variables with literals or ax://secrets/<slug> references. MCP secret-forwarding fields reference declared environment_variables names, not store slugs.

Validation rules

An experiment is invalid if:

  • the YAML contains a field not defined by the schema
  • schema_version is not 2
  • any required field is missing
  • an id that must be kebab-case is not kebab-case
  • a model id contains ::
  • a declared axis is empty
  • duplicate ids or names appear where uniqueness is required
  • the resolved variant set is empty
  • a resolved variant has an empty prompt
  • two resolved variants collide on variant_id
  • no tests are defined
  • test names are duplicated
  • an env var name is invalid or reserved
  • a file entry has an invalid name, source, sha256, or dest
  • an MCP server mixes transport-specific fields
  • an MCP server references an env var name not visible to the variant
  • any secrets: key is present (removed; use environment_variables)
  • any limit is not greater than zero

YAML syntax boundaries

The experiment data model is JSON-compatible even though the authoring file is YAML.

  • YAML comments are allowed.
  • YAML anchors and aliases are allowed when the resolved value is JSON-compatible.
  • Custom YAML tags are unsupported.
  • Non-string mapping keys are unsupported.