Skip to content

YAML configuration

Experiments are described in a single YAML file, which aigora reads to set up the market, agents, and their instructions. This page documents the complete configuration schema, including required fields, defaults, and validation rules. This page is necessarily long, but you don't need to read it all at once. Use it as a reference when you want to understand a specific field or feature, and follow the first experiment tutorial to see how the fields work together in practice.

Field Required Default Description
variables No Not declared; interpolation disabled Named inputs to reuse within the YAML file or override for a run.
experiment Yes — The experiment's identity, timing, assets, markets, and agent groups.

A full example configuration

The following example is a complete YAML configuration for a simple market with one buyer and one seller. Use it as a template for your own experiments, and see the first experiment tutorial for a walkthrough of its features.

variables:
    model: gpt-5.4-mini
    reasoning_effort: none
    seed: 42
    buyer_value: 100
    seller_cost: 40

experiment:
    name: first_experiment
    seed: ${variables.seed}
    output_dir: results
    protocol:
    period_duration_seconds: 30
    assets:
    - id: asset
        name: Good
    markets:
    - id: asset
        price_min: '0'
        price_max: '150'
    agents:
    - id: buyer
        lm:
        provider: openai
        model: ${variables.model}
        temperature: null
        reasoning_effort: ${variables.reasoning_effort}
        max_tokens: 4096
        prompt:
        instructions:
            content: |
            You are a buyer. You can buy one unit in this round.
            Your private value is ${variables.buyer_value}.
            Your earnings are your private value minus the purchase price.
            If you do not trade, your earnings are zero.
            Maximise your earnings. Do not buy above your value. Do not sell.
        context_providers:
            - type: snapshot_period_timing
            - type: snapshot_order_book
            - type: snapshot_own_orders
            - type: snapshot_own_holdings
            - type: snapshot_last_action_outcome
        initial_holdings:
        cash: '150'
        units: {asset: 0}
        trading_constraints:
        allowed_sides: [bid]
        max_units: {asset: 1}
        max_order_quantity: 1
        max_outstanding_orders: 1
    - id: seller
        lm:
        provider: openai
        model: ${variables.model}
        temperature: null
        reasoning_effort: ${variables.reasoning_effort}
        max_tokens: 4096
        prompt:
        instructions:
            content: |
            You are a seller. You can sell one unit in this round.
            Your private cost is ${variables.seller_cost}.
            Your earnings are the sale price minus your private cost.
            If you do not trade, your earnings are zero.
            Maximise your earnings. Do not sell below your cost. Do not buy.
        context_providers:
            - type: snapshot_period_timing
            - type: snapshot_order_book
            - type: snapshot_own_orders
            - type: snapshot_own_holdings
            - type: snapshot_last_action_outcome
        initial_holdings:
        cash: '0'
        units: {asset: 1}
        trading_constraints:
        allowed_sides: [ask]
        max_order_quantity: 1
        max_outstanding_orders: 1

variables

Variables are optional named inputs that can be reused in the YAML file, to avoid repeating the same value in multiple places, or to allow the caller to dynamically override them for a run. The syntax is defined by OmegaConf, which aigora uses to load and validate the YAML file.

Declaring a variable

Declare variables at the top level, alongside experiment. Reference a declared input with ${variables.name} wherever its value is needed in the YAML document. Names must be strings; values can be strings, numbers, booleans, null, lists, or mappings.

variables:
  reasoning_effort: none
  seed: 42
  buyer_values: ["100", "80", "60"]
  buyer_endowment:
    cash: "150"
    units: { asset: 0 }

Use variables to avoid repetition

In the example above, ${variables.model} is used for both agents' model names, and ${variables.buyer_value} is inserted into the buyer's instructions. If you want to change the model or the buyer's value, you can do it in one place instead of editing multiple fields.

Validate before making model requests

Use aigora.load_config("experiment.yaml", variables={"seed": 7}) to resolve inputs and validate the configuration without starting a market.

Setting a variable at runtime

Use ??? instead of a value when the caller must supply an input:

variables:
  seed: ???

Loading this document fails unless you supply variables={"seed": 7} or another valid seed. Every ??? must be resolved, even if that variable is not referenced elsewhere in the document.

Use variables to dynamically define inputs

You can pass a mapping to aigora.run to define a variable at runtime. For example, you can run the same experiment with different seeds or reasoning effort levels without changing the YAML file.

import aigora

run_dir = await aigora.run(
    "experiment.yaml",
    variables={"reasoning_effort": "medium", "seed": 7},
)

See Parameter sweeps for an example of running multiple combinations of variables in a loop.

Keep literal text

When interpolation is enabled, escape a literal ${ with a backslash inside a single-quoted YAML string:

content: 'Keep this expression literal: \${variables.seed}'

The resolved text contains ${variables.seed} without the backslash. Text loaded from a prompt file is always literal; only values inside the YAML document are interpolated.

experiment

Field Required Default Description
name Yes — Nonblank experiment label written to the output records.
description No "" Researcher metadata describing the experiment.
seed No 42 Integer seed for local random state.
output_dir Yes — Parent directory for unique run folders, relative to the YAML file.
protocol Yes — Shared trading periods, timing, and lifecycle hooks.
assets Yes — Nonempty list of assets that agents can hold.
markets Yes — Nonempty list of markets for declared assets.
agents Yes — Nonempty list of complete agent-group configurations.

name

A nonblank string identifying the experiment in its output records. It is a label, not an asset or agent ID, so the identifier pattern described below does not apply.

description

Free-form researcher metadata, empty by default. It is saved with the configuration and is not automatically added to agent prompts.

seed

An integer controlling local random state, including the shared random-number generator available to hooks. Hosted model output and asynchronous action order need not repeat exactly when the same seed is used.

output_dir

A nonblank path to the parent directory where aigora creates a unique folder for each run. Relative paths are resolved from the directory containing the YAML file; absolute paths are also accepted. See Output files for the folder contents.

protocol

Field Required Default Description
periods No 1 Number of trading rounds; an integer of at least 1.
period_duration_seconds Yes — Positive, finite duration of each trading round, in seconds.
action_interval_seconds No 0.0 Nonnegative, finite delay after each agent decision, in seconds.
period_interval_seconds No 0.0 Nonnegative, finite delay between rounds, in seconds.
hooks No {period_start: [], period_end: []} Ordered callbacks at the start and end of each period.

A period is a timed trading round. The protocol applies to all agents and markets in the experiment.

periods

The number of rounds to run, defaulting to one. It must be an integer of at least 1.

period_duration_seconds

The wall-clock trading duration of each period, in seconds. It must be positive and finite; preparation, hooks, and between-period compaction do not consume this trading budget.

action_interval_seconds

The delay after each agent decision before it may decide again, while trading time remains. It defaults to zero and must be nonnegative and finite.

period_interval_seconds

The delay between trading periods, outside the trading clock. It defaults to zero and must be nonnegative and finite.

hooks

Field Required Default Description
period_start No [] Hooks before each period's opening snapshots and trading clock.
period_end No [] Hooks after successful trading, before closing snapshots and order cleanup.

Both kinds of hook receive live agents and a shared, seeded random-number generator through context.rng. Each list runs in the configured order. If a hook fails, the experiment stops; earlier changes remain in place and partially applied hooks are not retried. See the Python API for hook interfaces and examples.

period_start
Field in each list item Required Default Description
type Yes — Dotted Python class path for a hook with on_period_start(context).
params No {} Keyword arguments passed to the hook constructor.

Start hooks run before every period, including the first. Use them to reset endowments or update information before agents see the opening state.

type

A nonblank, importable class path, such as examples.tutorials.multiple_rounds.hooks.ResetEndowments. The class must implement on_period_start(context).

params

A mapping of constructor keyword arguments, empty by default. The selected hook defines the accepted keys and their requirements; aigora does not impose a common parameter schema.

period_end
Field in each list item Required Default Description
type Yes — Dotted Python class path for a hook with on_period_end(context).
params No {} Keyword arguments passed to the hook constructor.

End hooks run after every successfully completed period, including the last, before closing snapshots and order cleanup. Use them for settlement such as paying dividends on held assets.

type

A nonblank, importable class path whose class implements on_period_end(context). The hook API example shows how to implement a dividend payment.

params

A mapping of constructor keyword arguments, empty by default. Its accepted keys, required values, and defaults depend on the selected hook.

assets

Field in each list item Required Default Description
id Yes — Unique identifier for an asset that agents can hold.
name Yes — Nonblank display name used by built-in context providers.
description No "" Researcher metadata describing the asset.

An asset is something an agent can hold; a market is where that asset can be traded. Declare at least one asset. An asset without a matching market can appear in holdings but cannot be traded through orders.

id

A unique asset key matching [a-z][a-z0-9_]*, such as asset or bond_1. Use the same ID in markets, holdings, and position bounds.

name

The nonblank display label used by built-in context providers when presenting the asset to agents. It need not match the identifier.

description

Free-form researcher metadata, empty by default. It does not enter agent prompts automatically.

markets

Field in each list item Required Default Description
id Yes — ID of the declared asset traded in this market.
description No "" Researcher metadata describing the market.
price_min Yes — Finite decimal lower bound on accepted order prices.
price_max Yes — Finite decimal upper bound, strictly greater than price_min.
short_selling_allowed No false Allow sales that create negative holdings, subject to agent position bounds.

Declare at least one market, with at most one market per asset. The built-in continuous double auction matches crossing orders at the price of the order already resting in the book. For example, an ask at 70 followed by a bid at 80 trades at 70. Orders at the same price have priority in arrival order.

id

The ID of a declared asset, matching [a-z][a-z0-9_]* and unique among markets. Agents use this ID to identify the market in their actions.

description

Free-form researcher metadata, empty by default. It is saved with the configuration and does not enter prompts automatically.

price_min

The lowest accepted order price, inclusive. It must be finite and strictly less than price_max. Prices use decimal arithmetic; quote decimal amounts in YAML, such as '0.10', to preserve the value you enter.

price_max

The highest accepted order price, inclusive. It must be finite and strictly greater than price_min.

short_selling_allowed

Whether agents may submit asks that would leave them with negative holdings in this asset. It defaults to false; setting it to true still leaves each agent's configured position bounds in force.

agents

Field in each list item Required Default Description
id Yes — Unique agent-group identifier, used as the prefix of runtime agent IDs.
n No 1 Number of independent agents created from this entry.
lm Yes — Model provider and request settings.
prompt Yes — Participant instructions, observations, and optional conversation controls.
initial_holdings Yes — Initial cash and asset positions for each agent.
response No {include_reason: true} Whether actions must include a reason.
error_handling No {request_timeout_seconds: null, max_retries: 3, failure_policy: abort} Request timeouts, retries, and terminal decision-failure behaviour.
trading_constraints No {allowed_sides: [bid, ask], min_units: {}, max_units: {}, min_order_quantity: 1, max_order_quantity: null, max_outstanding_orders: null} Limits applied when admitting orders.

Each list item defines a group of participants with the same configuration. Every participant gets its own conversation and provider instances, including when YAML anchors share authoring inputs.

id

A unique group identifier matching [a-z][a-z0-9_]*. An entry with id: buyer and n: 3 creates buyer_1, buyer_2, and buyer_3; even a group with n: 1 gets the _1 suffix.

n

The number of agents created from this group, defaulting to one. It must be an integer of at least 1.

lm

Field Required Default Description
provider Yes — Model service: openai, anthropic, or google.
model Yes — Nonblank model identifier for the selected provider.
temperature Yes — Finite number, or explicit null to omit the parameter from requests.
reasoning_effort Yes — none, low, medium, high, xhigh, or explicit null to omit the parameter.
max_tokens Yes — Positive integer limiting model output tokens.
extra_params No {} Additional supported provider parameters.

These settings belong to each agent group, so different groups may use different providers or models. YAML validation can succeed even when the selected provider later rejects a combination of model settings.

provider

Choose openai, anthropic, or google. Credentials come from OPENAI_API_KEY, ANTHROPIC_API_KEY, or GEMINI_API_KEY, respectively, in the process running the experiment. See Installation for setup; API keys do not belong in YAML.

model

A nonblank model identifier for the selected service. The example uses gpt-5.4-mini, matching the tutorials; choose a model that supports your requested settings.

temperature

A finite number, or null to leave temperature out of the provider request. This field is required even when its value is null; aigora does not supply a temperature default. The acceptable numeric range and whether temperature is supported depend on the selected model.

reasoning_effort

One of none, low, medium, high, xhigh, or null. The field must be present, and the selected model must support the requested level.

none and null differ

reasoning_effort: none explicitly requests that effort level. reasoning_effort: null omits the parameter so the provider's default can apply.

max_tokens

A positive integer setting the model's output-token limit. It is required and has no aigora default.

extra_params

A mapping of additional parameters supported by the provider, empty by default. Its keys are provider-specific; it cannot replace the model settings, messages, conversation controls, retries, or timeouts that aigora manages.

prompt

Field Required Default Description
instructions Yes — Prompt source defining the participant's objective and treatment instructions.
system No null Prompt source replacing the generated execution contract in full.
context_providers Yes — Nonempty, ordered list of observations supplied before each decision.
between_period_compaction No null Prompt source for summarising active history between successful periods.

For each decision, aigora sends the active conversation history and a fresh provider update, together with the system message. Once a response is parsed successfully, the exchange enters the conversation even if the market later rejects the action. A failed decision leaves the history unchanged.

instructions
Field Required Default Description
content If file is not set null Nonblank participant instructions written directly in YAML.
file If content is not set null Nonblank path to a UTF-8 file containing the participant instructions.

Choose exactly one non-null source; neither an empty mapping nor two populated sources is valid. These instructions enter the agent's conversation history.

content

Inline, nonblank instructions describing the participant's objective and treatment. Use a YAML block scalar (content: |) for multiple lines; variable references are resolved when variables is declared.

file

A nonblank path, resolved relative to the YAML file, such as prompts/buyer.txt. The file must contain nonblank UTF-8 text; its contents are not interpolated.

system
Field, when a source is supplied Required Default Description
content If file is not set null Nonblank replacement system message written in YAML.
file If content is not set null Nonblank path to a UTF-8 replacement system message.

Omit system, or set it to null, to use aigora's generated action-format and trading instructions. Supplying a source replaces that entire message; choose exactly one non-null content or file. The system message is kept separately from conversation history, and the parser and trading constraints still enforce the same rules.

content

Inline, nonblank text replacing the system message in full. Variable references are resolved when interpolation is enabled.

file

A nonblank path to nonblank UTF-8 system text, resolved relative to the YAML file. The file's contents remain literal, including any ${...} expressions.

context_providers
Field in each list item Required Default Description
type Yes — Built-in provider name or dotted Python class path.
params No {} Keyword arguments passed to the provider constructor.

Supply at least one provider. Providers run in list order to build each agent's observation before a decision. See Built-in context providers for names, supported parameters, and examples of their text.

type

A nonblank built-in name, such as snapshot_order_book, or an importable class path implementing get_context(context). See Customise what agents 'see' for a custom provider.

params

A mapping of constructor keyword arguments, empty by default. The selected provider defines its accepted keys and defaults; see its entry in the provider reference. You can use variables to supply whole lists or mappings here.

between_period_compaction
Field, when a source is supplied Required Default Description
content If file is not set null Nonblank inline instructions for summarising the active history.
file If content is not set null Nonblank path to a UTF-8 file containing summary instructions.

Omit this field, or set it to null, to disable compaction. Otherwise, choose exactly one non-null source to request a summary after each successfully completed period except the last. The summary replaces active history for the next period, while the complete audit trace remains on disk. Compaction uses the agent's model, retry settings, and timeout; if it fails, the run stops even when the decision failure policy is do_nothing.

content

Inline, nonblank instructions telling the model what to preserve in its summary. Variable references are resolved when interpolation is enabled.

file

A nonblank path to nonblank UTF-8 summary instructions, resolved relative to the YAML file. The loaded text remains literal.

initial_holdings

Field Required Default Description
cash Yes — Finite decimal amount of settled cash at the start.
units Yes — Mapping of asset IDs to integer positions; {} is valid.

These are the initial accounts of every participant created from this agent group. Trading constraints govern subsequent order admission; they do not adjust these initial balances or rebalance accounts changed by hooks.

cash

A finite decimal cash amount; zero is valid and there is no default. Quote decimal amounts such as '150.00' to preserve their exact value in YAML.

units

A required mapping from declared asset IDs to integer quantities, such as {asset: 1}. An empty mapping is valid, and omitted assets have zero units. Integer positions may be negative; market and agent constraints determine which subsequent orders are admitted.

response

Field Required Default Description
include_reason No true Require a string reason in each action; false forbids it.

Agents return one JSON action per decision: place_bid, place_ask, cancel_order, or do_nothing.

include_reason

When true, every action must contain a string reason. When false, the parser forbids that field rather than merely making it optional.

error_handling

Field Required Default Description
request_timeout_seconds No null Positive, finite per-request timeout; null sets no aigora request timeout.
max_retries No 3 Nonnegative integer counting additional attempts after the initial request.
failure_policy No abort Stop the run on a terminal decision failure, or record a failed no-op with do_nothing.

These settings apply to model decisions and are also used for compaction requests, except that a terminal compaction failure always stops the run.

request_timeout_seconds

A positive, finite timeout for each individual model request attempt, or null for no aigora request timeout. The end of a trading period also cancels outstanding decision requests.

max_retries

The number of additional attempts after the first; the default of 3 permits up to four attempts. Temporary provider failures, truncated output, or invalid action responses may trigger retries. Nonretryable failures, such as authentication or configuration errors, stop the attempts earlier. A parsed order rejected by the market does not trigger a model retry.

failure_policy

Choose abort to stop the run when a decision fails, or do_nothing to record a failed no-op and continue. With do_nothing, the failed exchange does not advance the agent's conversation or observation baseline. This differs from a market rejection, such as an order rejected for insufficient cash, which is recorded as a trading outcome. See Output files for recorded actions and failures.

trading_constraints

Field Required Default Description
allowed_sides No [bid, ask] Nonempty set of permitted order sides.
min_units No {} Mapping of asset IDs to integer lower position bounds.
max_units No {} Mapping of asset IDs to nonnegative integer upper position bounds.
min_order_quantity No 1 Positive integer minimum quantity for a submitted order.
max_order_quantity No null Positive integer maximum submitted quantity; null adds no maximum.
max_outstanding_orders No null Positive integer cap on open orders across markets; null adds no cap.

These rules control order admission. Open bids reserve cash and room under position limits; open asks reserve room to sell. Until a trade settles, a pending sale cannot fund a purchase, and a pending purchase cannot supply units for a sale.

allowed_sides

A nonempty YAML list containing bid, ask, or both, interpreted as a set. Use [bid] for buyers and [ask] for sellers when the experimental design assigns fixed roles.

min_units

A mapping from declared asset IDs to integer lower position bounds; negative bounds are allowed. An omitted asset has no additional agent-specific lower bound, but short selling still requires the market's permission. A bound cannot exceed the corresponding max_units value.

max_units

A mapping from declared asset IDs to nonnegative integer upper position bounds. An omitted asset has no upper position bound; each supplied maximum must be at least the corresponding minimum.

min_order_quantity

The minimum submitted order quantity, defaulting to 1. It must be a positive integer and cannot exceed a configured max_order_quantity. The limit is checked on submission, so a partial fill may leave a smaller remaining quantity.

max_order_quantity

A positive integer limiting each submitted order, or null for no upper quantity limit. When set, it must be at least min_order_quantity.

max_outstanding_orders

A positive integer limiting an agent's total open orders across all markets, or null for no cap. Other admission checks, including cash and position limits, still apply.

Reuse and validation

You can use YAML anchors to share configuration between agent groups.

YAML merges are shallow

Replacing a nested block such as prompt replaces the whole block, including inherited instructions and providers. Explicitly merge its contents too if you want to retain those settings while changing one field.

Asset, market, and agent-group IDs must match [a-z][a-z0-9_]* and be unique within their respective lists. Aigora rejects unknown schema fields, duplicate explicit keys, references to undeclared assets, nonfinite numbers, and invalid ranges. Counts, quantities, and positions must be integers; booleans are not accepted as integers. The open mappings documented above accept the keys defined by their author, provider, or hook.

Aigora validates the configuration, loads prompt files, and constructs providers and hooks before reserving a run directory. It saves resolved inputs and defaults in the run metadata. Secret-like parameters are redacted there, so you may need replacement values before rerunning a saved configuration.