Variables
Note: This is an alpha feature and is not currently compatible with agent mediators or agent participants
Experimenter setup
Deliberate Lab offers variable support within experiments. Variable configs can be defined in the experiment builder; for the currently available config type (“random permutation”), experimenters can specify:
- A schema defining the variable structure (primitives, objects, or arrays)
- Whether values are assigned at the cohort level (every participant in the cohort sees the same value) or participant level
- A set of variable names to be populated
- A set of values to choose from (as JSON strings)
Support for other config types, such as populating variables based on a weight distribution of values or manually assigning values when creating a cohort, to be added eventually.

The variables use Mustache templating and are supported in the following locations:
- Stage descriptions (primary text, info text)
- Info stages (info lines)
- Multi asset allocation stages (stock name and description)
Variable Schemas
Variables use JSON Schema (via TypeBox) to define their structure. This provides runtime validation and type safety.
Primitive Types
// String variable
schema: VariableType.STRING
// Number variable
schema: VariableType.NUMBER
// Boolean variable
schema: VariableType.BOOLEAN
Object Types
For structured data with named fields:
schema: VariableType.object({
name: VariableType.STRING,
age: VariableType.NUMBER,
active: VariableType.BOOLEAN,
})
Template usage: ,
Array Types
Arrays of primitives:
// Array of strings
schema: VariableType.array(VariableType.STRING)
// Array of numbers
schema: VariableType.array(VariableType.NUMBER)
Template usage: ,
Arrays of objects:
schema: VariableType.array(
VariableType.object({
title: VariableType.STRING,
text: VariableType.STRING,
})
)
Template usage: ,
Nested Structures
Schemas can be nested arbitrarily:
schema: VariableType.object({
policy: VariableType.STRING,
arguments_pro: VariableType.array(
VariableType.object({
title: VariableType.STRING,
text: VariableType.STRING,
})
),
arguments_con: VariableType.array(
VariableType.object({
title: VariableType.STRING,
text: VariableType.STRING,
})
),
})
Runtime Validation
All schemas are validated at runtime when:
- Creating or updating variable configs via the API
- Assigning values to variables
- Resolving templates
Invalid schemas or values will be rejected with detailed error messages.
Implementation
Schema Definition (utils/src/variables.ts)
Variables use TypeBox to create JSON Schema objects:
export namespace VariableType {
export const STRING = Type.String();
export const NUMBER = Type.Number();
export const BOOLEAN = Type.Boolean();
export const object = (properties: Record<string, TSchema>) =>
Type.Object(properties);
export const array = (items: TSchema) =>
Type.Array(items);
}
Each VariableItem contains:
name: Variable identifierdescription: Human-readable descriptionschema: TypeBox schema (TSchema) defining the structure
Schema Validation (utils/src/variables.validation.ts)
Runtime validation uses recursive TypeBox schemas to validate incoming JSON Schema objects from API requests:
const JSONSchemaData: any = Type.Recursive((Self) =>
Type.Union([
Type.Object({type: Type.Literal('string')}, {additionalProperties: true}),
Type.Object({type: Type.Literal('number')}, {additionalProperties: true}),
Type.Object({type: Type.Literal('boolean')}, {additionalProperties: true}),
Type.Object({
type: Type.Literal('object'),
properties: Type.Optional(Type.Record(Type.String(), Self)),
}, {additionalProperties: true}),
Type.Object({
type: Type.Literal('array'),
items: Type.Optional(Self),
}, {additionalProperties: true}),
])
);
This ensures malformed schemas are rejected before being stored.
Value Assignments
When experiments, cohorts, and participants are created (in functions/),
the variable configs (from the experiment config) are used to assign relevant
values to a variableMap.
For instance, when setting up a cohort, the variable configs are passed into
variable utility functions (utils/src/variables.utils.ts) that extract
variable items (as each variable config may contain multiple variables)
that are to be assigned at the cohort level. Values are then generated via
the specified means (e.g., random permutation) and a variableMap matching
variable names to values is updated for the cohort config.
Values are type-coerced based on the schema:
string: Used directlynumber/integer: Parsed from stringboolean: Converted from ‘true’/’false’ stringsobject/array: Parsed from JSON strings
(Note that cohort and participant variable value assignment can be verified in the experiment dashboard via the displayed JSON configs.)
Template Resolution (utils/src/variables.template.ts)
When stages are rendered in the participant view (and for the reveal stage),
the stage config is passed through a StageHandler function that
runs specified fields through template resolution.
Template validation:
- Extracts all variable references from Mustache templates
- Validates each reference against the schema
- For nested paths (e.g., ``):
- Navigates through object
properties - Navigates through array
itemsschemas - Skips numeric array indices
- Validates field existence at each level
- Navigates through object
Template rendering:
- Type-coerces values based on schema type
- Uses Mustache.js for template rendering
- Supports nested object/array access with dot notation
In the base class StageHandler, the stage’s description (primary text, info
text) fields are resolved (extended classes are encouraged to extend this
functionality).
NOTE: Not all stages have been migrated to the stage manager/handler setup.