Deliberation Lab Syntax Reference
This page is intended as a concise, precise description of the syntax used in designing Deliberation Lab studies. It can be given to an AI coding agent to support implementation of treatment designs that are compatible with DL requirements. It also forms a short cheat-sheet for humans, with the bulk of the description in other parts of the documentation.
1) Top-Level Treatment File Shape
- Root object fields:
templates(optional): array of template definitions (see §3).introSequences(required): array of intro sequence objects (see §8).treatments(required): array of treatment objects (see §9).
Everything is validated after templates are expanded; unfilled ${field} placeholders or template blocks are errors.
2) Common Primitives and Placeholders
- Names: 1–64 chars; letters, numbers, spaces,
_,-; may include${field}placeholders. Regex:^(?:[a-zA-Z0-9 _-]|\$\{[a-zA-Z0-9_]+\})+$. - Descriptions: freeform strings.
- Files/URLs:
fileis a string path (no existence check in schema).urlmust be a valid URL. - Durations/Times:
durationpositive int seconds;displayTimenonnegative int seconds;hideTimepositive int seconds. - Positions: zero-based nonnegative integers unless otherwise noted.
- Visibility:
showToPositions/hideFromPositionsare nonempty int arrays; used to gate rendering per position. - Field placeholders: Strings like
${key}may appear anywhere; replaced during template expansion with providedfields/broadcastvalues.
3) Templates and Template Contexts
- Template definition (
templates[]): templateName: required name.contentType: optional but recommended enum; one ofintroSequence,introSequences,elements,element,stage,stages,treatment,treatments,reference,condition,player,introExitStep,exitSteps,other(validated exceptotherwhich always errors for safety).templateDesc: optional string.templateContent: payload matching thecontentTypeschema (see sections below).- Template context (can appear anywhere a value is allowed):
yaml template: <templateName> fields: { key: value, ... } # optional; substitutes ${key} broadcast: { d0: [...], d1: [...] } # optional cartesian broadcast fields: key/value map; values can themselves contain templates/placeholders.broadcast: axes namedd0,d1, … each is either an array of field maps, another template context, or a single placeholder key. Expansion flattens the cartesian product, injectingd#indices as strings.- Expansion rules (see
fillTemplates):- Recursively expand nested templates in
fields/broadcast. - Substitute
${key}(string and object contexts). - Apply broadcast cartesian product; each combination produces a copy of
templateContent. - Repeat until no
templateblocks remain; error if any${...}remain.
- Recursively expand nested templates in
4) References (used by displays/conditions)
Reference string forms (split on .):
survey.<name>.<path...>(path required)submitButton.<name>.<path...>(path required)qualtrics.<name>.<path...>(path required)discussion.<name>(name required)participantInfo.<name>(name required)prompt.<name>(name required)urlParams.<path...>(path required)connectionInfo.<path...>(path required)browserInfo.<path...>(path required)
Invalid types or missing name/path emit validation errors.
5) Conditions
- Shape:
{ reference, comparator, value?, position? } position(optional):shared,player,all,any,percentAgreement, or nonnegative int. (Use only where stage logic supports position-aware checks.)- Comparators and value types:
exists/doesNotExist: no value.equals/doesNotEqual: string | number | boolean |${field}.isAbove/isBelow/isAtLeast/isAtMost: number |${field}.hasLengthAtLeast/hasLengthAtMost: nonnegative int |${field}.includes/doesNotInclude: string |${field}.matches/doesNotMatch: string (treated as regex) |${field}. Regex validity not enforced beyond string type.isOneOf/isNotOneOf: nonempty array of string/number |${field}.- Conditions arrays must be nonempty when provided.
6) Players (group composition entries)
- Fields:
desc?,position(int),title?(max 25 chars),conditions?(array). - In treatments, positions must be unique, contiguous 0..playerCount-1.
7) Elements (the building blocks of stages)
Base fields (all element types):
type: discriminator (see below).name?,desc?,file?,displayTime?,hideTime?,showToPositions?,hideFromPositions?,conditions?(array),tags?(string array).
Element types (all strict objects):
audio:type: audio,filerequired.image:type: image,filerequired.display:type: display,referencerequired (see §4),positionselector (shared|player|all|any| int; defaultplayer).prompt:type: prompt,filerequired,shared?(true for shared prompt data; disallowed in intro/exit).qualtrics:type: qualtrics,urlrequired (survey link),urlParams?array of param objects — each withkey(required), and eithervalue(literal string/number/boolean) orreference(reference string) plus optionalposition;valueandreferenceare mutually exclusive. Runtime: env varsQUALTRICS_API_TOKENandQUALTRICS_DATACENTERare required at validation time; Deliberation Lab appendsdeliberationIdandsampleIdto the URL automatically.separator:type: separator,style?enumthin | thick | regular.sharedNotepad:type: sharedNotepad.submitButton:type: submitButton,buttonText?(<=50 chars).survey:type: survey,surveyNamerequired (must exist in@watts-lab/surveysat runtime).talkMeter:type: talkMeter.timer:type: timer,startTime?,endTime?,warnTimeRemaining?(all > 0). (Runtime expectation: start < end; warn < end-start.)video:type: video,urlrequired.
Prompt shorthand: a bare string in an elements array is coerced to { type: "prompt", file: "<string>" }.
Position limits: When used inside a treatment, any numeric position in showToPositions/hideFromPositions must be < playerCount.
8) Discussions and Video Layout
discussionobject (stage-level optional):chatType:text|audio|video.showNickname(bool),showTitle(bool),showSelfView?(bool, default true),showReportMissing?(bool, default true),showAudioMute?(bool, default true),showVideoMute?(bool, default true).reactionEmojisAvailable?(string array),reactToSelf?(bool),numReactionsPerMessage?(nonnegative int) — only allowed whenchatType=text.layout?: video layout map keyed by seat index (stringified nonnegative int) → layout definition. Only allowed whenchatType=video.- Layout definition:
grid{ rows: int>0, cols: int>0, options? { gap?, background? } };feedsnonempty array;defaults?feed defaults. - Feed:
source(participantwithposition,self, or custom{ type: <string not participant/self>, position? }),media? { audio?, video?, screen? },displayRegion { rows: int or {first,last}, cols: int or {first,last} }within grid bounds,zOrder?,render?(auto|tile|audioOnlyBadge|hidden|<string>),label?,options?(record).
- Layout definition:
rooms?(video only): nonempty array of{ includePositions: nonempty int[] }. After applying discussion-levelshowToPositions/hideFromPositions, every visible position must appear in exactly oneincludePositions.showToPositions?/hideFromPositions?: optional discussion-level visibility filters (respectplayerCount).
9) Stages
- Stage object:
name(required),desc?discussion?(see §8)duration(positive int or${field})elements(nonempty array of elements)- Validation:
- Must have
elements. - Per-treatment checks enforce position bounds for element visibility and discussion visibility/rooms.
10) Intro/Exit Steps and Intro Sequences
- Intro/Exit step object:
name,desc?,elements(nonempty). - Constraints in intro/exit:
prompt.sharednot allowed.position,showToPositions,hideFromPositionsnot allowed on elements.- Intro sequence:
{ name, desc?, introSteps: [intro/exit steps] }. introSequences: nonempty array of intro sequence objects.exitSequence(on treatment): array of exit steps (same shape as intro;sharedstill disallowed).
11) Treatments
- Fields:
name(required),desc?playerCount(number; must cover all positions starting at 0)groupComposition?: array of players (§6). If present, positions must be unique and exactly0..playerCount-1.gameStages: nonempty array of stages (§9).exitSequence?: array of exit steps (§10).- Additional per-treatment checks:
- Any numeric positions in elements’
showToPositions/hideFromPositionsand discussions’ visibility lists must be< playerCount. - In
discussion.rooms, after applying discussion-level visibility filters, every visible position must appear in oneincludePositions; no out-of-range indices.
12) Treatments Array
treatments: nonempty array of treatment objects. Can include templates; all template contexts are expanded before validation.
13) Template Content Matching (for template authors)
templateContentcan be any of: introSequence, introSequences, elements, element, stage, stages, treatment, treatments, reference, condition, player, introExitStep, exitSteps. Best-match heuristic picks the schema with fewest unmatched keys ifcontentTypeomitted; errors reference the closest match.
14) Runtime Semantics and Interop Notes
- Template expansion happens before validation is applied to the final structures used at runtime (
getTreatments+fillTemplates). Unresolved${...}cause errors. - Qualtrics elements require
QUALTRICS_API_TOKENandQUALTRICS_DATACENTERenv vars; validation will throw if missing. At runtime, Deliberation Lab appendsdeliberationIdandsampleIdas URL params; anyurlParamsentries are also appended (withreferencevalues resolved from player/game state); submitted Qualtrics responses are fetched (if API keys) and stored underqualtrics_<step>in science data. - Survey elements rely on
@watts-lab/surveys; ensuresurveyNameis valid there. - Discussion/video layouts control Daily call composition;
roomssplit participants across subrooms;layoutdefines on-screen tiling for video stages. - Visibility/conditions are evaluated in the client to gate rendering of prompts, displays, etc.; make sure referenced data exists in earlier steps or URL/browser/connection info.
- Durations drive timers and stage limits;
displayTime/hideTimegate element visibility relative to stage elapsed. - Position semantics: integers refer to treatment positions (0-based).
shared/all/any/player/percentAgreementare special selectors understood by client logic for displays/conditions.
This reference mirrors the enforced schema; deviations will fail validation during batch initialization. Use it as a definitive contract for generating treatment manifests from natural-language specs.
15) Batch Config Validation (preFlight/validateBatchConfig.ts)
Separate from the treatment file, the batch config (admin UI / YAML) must satisfy:
batchName: string.cdn: enumtest | prod | local.treatmentFile: string ending in.yaml.introSequence: string or literal"none"(use"none"to skip intro).treatments: nonempty array of treatment names (strings).payoffs: nonempty array of positive numbers matchingtreatmentslength, or literal"equal".knockdowns: one of- single number in (0,1];
- nonempty array of numbers in (0,1] with length ==
treatments.length; - nonempty matrix of numbers in (0,1]; rows =
treatments.length, each row length =treatments.length; - literal
"none". exitCodes: object{ complete, error, lobbyTimeout, failedEquipmentCheck }(strings) or literal"none".launchDate: ISO-ish string that parses to a future Date, or literal"immediate".customIdInstructions: either a.mdstring,"none", or a nonempty map of URL-safe keys (alphanumeric/underscore/hyphen) to.mdstrings.platformConsent: enumUS | EU | UK | custom.consentAddendum:.mdstring or"none".debrief:.mdstring or"none". Custom debrief content shown on the final page.dispatchWait: positive number (seconds).videoStorage:{ bucket: string, region: <AWS region enum> }or"none".preregRepos: array of{ owner, repo, branch, directory }(can be empty to skip).dataRepos: array of{ owner, repo, branch, directory }(required; nonempty).centralPrereg: boolean.checkAudio: boolean.checkVideo: boolean (cannot be true whilecheckAudiois false).
Super-refine rules:
- If
payoffs !== "equal", payoffs length must equaltreatmentslength. - If
checkVideois true,checkAudiomust also be true. knockdownsshapes must matchtreatmentslength (vector or matrix as described above).
If validation fails, an aggregated error message is thrown and batch creation fails.
16) Prompt/Markdown Validation (preFlight/validatePromptFile.ts + getTreatments.js)
Prompt files (referenced by prompt elements) are validated server-side when treatments are loaded:
- File structure: three sections separated by
---lines: metadata YAML, prompt body, responses block. - Metadata schema:
name: string; must match the file path (from repo root).type: enumopenResponse | multipleChoice | noResponse | listSorter | slider.notes?: string.rows?: int >= 1 (only foropenResponse; error otherwise).shuffleOptions?: boolean (disallowed fornoResponse).select?: enumsingle | multiple | undefined(only formultipleChoice).minLength?/maxLength?: ints (openResponse-only; minLength <= maxLength).- Slider-only:
min(required),max(required),interval(required),labelPts?(array of numbers). Must satisfymin < maxandmin + interval <= max.labelPts, if present, must have the same length as the number of response items (checked separately invalidateSliderLabels). - Non-slider elements must not specify
min,max,interval, orlabelPts. - Prompt body: must be nonempty.
- Responses block:
- Omitted only when
type === "noResponse". - Every response line must start with
-(multiple choice) or>(open response) to be parsed. - Empty file or invalid type/name/prompt/responses throws an error; batch load fails.
Additional runtime checks during treatment load (getTreatments.js):
- Prompt files are fetched from the configured CDN; fetch/parse failures are fatal.
- Qualtrics elements: require
QUALTRICS_API_TOKENandQUALTRICS_DATACENTERenv vars; metadata fetch is attempted and failure is fatal. - Time guards:
displayTime,hideTime,startTime, andendTimemust not exceed the parent stageduration; violations throw errors. - Stage checks: every stage must have
nameandduration; treatments must havegameStages; a warning is logged (not fatal) if neitherexitSurveysnorexitSequenceis present.
Use these rules in addition to the treatment schema to ensure prompt assets and batch configs are valid before running studies.