Expected Parrot · A practical research tutorial

Social Simulation

From an explicit interaction design to inspectable Concordia code, recorded runs, transcripts, and outcomes—with the social process itself as the object of study.

01 Orientation

Many experiments ask isolated people to answer the same question. Social simulation asks something different: what happens when agents act, react, reveal information, bargain, coordinate, or disagree inside a shared situation?

OneHeart is the study-definition and code-generation layer for that work. It stores the design as durable project state, validates it, and generates an inspectable pilot runner. Concordia supplies the simulation machinery; Expected Parrot EDSL supplies model access and post-run measurement.

Use OneHeart

When two or more agents interact, their roles and information matter, and treatments or outcomes must be tracked across runs.

Use a survey workflow

When each respondent independently reacts to a vignette or question and the interaction itself is not the research object.

Canonical state

The study specification under .oneheart/ is the durable record of intended design.

Derived artifacts

Generated runners, logs, transcripts, HTML chats, and outcome tables are inspectable products of that design.

The central contract. Define with the CLI, generate code, inspect the exact prompts, run explicitly, then record the outputs. OneHeart does not silently launch an expensive simulation.
Specify
Validate
Generate
Run
Record

02 The study model

A study becomes runnable when four pieces agree with one another.

PieceQuestion it answersTypical contents
Interaction frameWhat world and protocol do agents share?Premise, turn order, maximum turns, game master
AgentsWho acts, what do they know, and what do they want?Role, goal, public bio, private context, stable attributes
TreatmentsWhat changes exogenously between conditions?Scope, target, levels, visibility, behavioral instructions
MeasurementsWhat evidence will answer the research question?Outcome type, evaluator, extraction prompt
Interaction frameAgentsTreatmentsMeasurements GeneratedConcordia pilot Transcript + logTyped outcomes
The study definition controls generation. The run produces both a social trace and measurements extracted from that trace.

03 Design before code

Begin with a causal contrast small enough to inspect. A good first pilot usually has two to four agents, one treatment, one primary outcome, and a short interaction.

Pilot discipline. A plausible transcript is not evidence that a manipulation worked. Include a manipulation check, inspect the opening turns, and replicate conditions before interpreting an effect.

A worked question

This tutorial uses a hiring interview: does an opening compliment increase the interviewer’s hiring rating? The candidate receives either a compliment or neutral-opening instruction; the interviewer and the rest of the setting remain fixed.

Design choicePilot decisionReason
Protocolordered_dialogue, 8 turnsClear alternation and a bounded first run
PrefabconversationalProduces spoken dialogue rather than third-person narrative
Treatmentcompliment / no complimentOne legible causal contrast
Primary outcome1–7 hiring ratingSpecific and answerable from the completed interview
Manipulation checkcompliment noticed?Separates a null effect from a failed manipulation

04 Create the project and interaction

oneheart init compliment_interview --title "Compliment Interview Pilot"
cd compliment_interview

oneheart study create compliment_effect \
  --title "Opening compliment effect" \
  --description "Candidate opens a job interview with or without a compliment."

oneheart study set-interaction compliment_effect \
  --premise "A final-round interview for a B2B marketing manager role." \
  --protocol ordered_dialogue \
  --max-turns 8 \
  --game-master dialogic

The premise describes common ground. It should contain what remains constant across conditions, not treatment-specific language. OneHeart supports ordered, random, and game-master-selected dialogue protocols.

ProtocolBest useConcordia acting order
ordered_dialogueControlled alternation and inexpensive pilotsfixed
random_dialogueSpeaker order is legitimately variablerandom
gm_choice_dialogueThe game master should choose the natural next speakergame_master_choice

05 Give agents goals and information

A name is not a social actor. Each focal agent needs a role, a goal, and enough context to behave distinctly. Keep public facts separate from information that only one agent should know.

oneheart agent add compliment_effect candidate \
  --name "Alex Rivera" --role candidate \
  --goal "Demonstrate fit and earn a strong hiring recommendation." \
  --prefab conversational \
  --public-bio "Five years of B2B SaaS marketing experience." \
  --private-context "Especially strong in demand generation and product marketing."

oneheart agent add compliment_effect interviewer \
  --name "Jordan Ellis" --role interviewer \
  --goal "Assess fundamentals, results, and communication fairly." \
  --prefab conversational

Use conversational for dialogue, basic when reflection and associative memory matter outside dialogue, and minimal for cheaper sweeps where richness is secondary.

oneheart agent attribute-set compliment_effect interviewer \
  evaluation_style=evidence-focused
Information hygiene. Stable attributes describe the agent. Treatments describe what the experiment changes. Do not hide a treatment inside a biography if you want OneHeart to track it as an experimental condition.

06 Make treatments behavioral

Treatment level names are labels, not instructions. A model does not reliably infer the intended behavior from opening_compliment=compliment. Define the factor, then attach an explicit stage direction to every level.

oneheart treatment add compliment_effect opening_compliment \
  --scope agent --target candidate --type binary \
  --levels compliment,no_compliment --private

oneheart treatment level-set compliment_effect opening_compliment compliment \
  --instruction "Open with one sincere, specific compliment about the company or interviewer's work before answering. Do not compliment again."

oneheart treatment level-set compliment_effect opening_compliment no_compliment \
  --instruction "Open with a brief neutral professional greeting. Do not compliment the interviewer at any point."
Resolved private treatmentExperimental treatment (private) — opening_compliment=compliment: Open with one sincere, specific compliment about the company or interviewer's work before answering. Do not compliment again.

Agent-scoped instructions enter the target agent’s resolved prompt. Study- or environment-scoped instructions enter the resolved premise. Visibility should reflect the design: a private instruction is not automatically shared with the other participants.

07 Define observable measurements

Measurements are extraction questions asked after the simulation. Make each prompt answerable from the transcript or simulation context, name the evaluator, and choose a response type that matches the construct.

oneheart measurement add compliment_effect hiring_rating \
  --kind outcome --response-type numeric --agent interviewer \
  --prompt "On a 1–7 scale, how strongly would you recommend hiring the candidate?"

oneheart measurement add compliment_effect would_hire \
  --kind outcome --response-type boolean --agent interviewer \
  --prompt "Would you hire the candidate? Answer yes or no."

oneheart measurement add compliment_effect noticed_compliment \
  --kind process --response-type boolean --agent interviewer \
  --prompt "Did the candidate compliment you during the interview? Answer yes or no."
Weak promptStronger prompt
“How did it go?”“Did the parties reach an agreement? Answer yes or no.”
“Was the candidate good?”“On a 1–7 scale, how strongly would you recommend hiring the candidate?”
“Measure warmth.”“Rate the interviewer’s warmth during the exchange from 1 (cold) to 7 (very warm).”

08 Validate design and environment

Structural validation and runtime validation answer different questions. Run both before generation.

oneheart status
oneheart validate compliment_effect
oneheart doctor
oneheart validate compliment_effect --check-env
CheckWhat it catchesTypical response
statusCurrent project phase, counts, and next actionsContinue from the returned checklist
validateMissing frame, agents, treatments, measurements, or prefab mismatchRepair the study definition
doctorPython, Concordia, and EDSL availabilityActivate or install the intended runtime
--check-envStudy readiness and runtime readiness togetherGenerate only after both pass

Generated runners expect the Expected Parrot Concordia fork with EDSL support. If Concordia exists only as a checkout, the runner accepts --concordia-src /path/to/concordia.

09 Generate, then inspect

oneheart codegen pilot compliment_effect
.oneheart/ ├── studies/ canonical study definitions └── generated/<generation>/ immutable provenance snapshot oneheart_jobs/compliment_effect/ ├── concordia_config.json resolved machine-readable design ├── prompts.md exact prompts for this condition ├── run_pilot.py inspectable runner ├── manifest.json generation metadata └── README.md execution notes

Read prompts.md before spending model calls. Confirm that the resolved premise is correct, every agent receives the intended context, every treatment has a level-specific instruction, and every measurement is unambiguous.

The prompt gate is deliberate. The runner refuses to start until the prompts are explicitly confirmed. Regeneration removes durable acknowledgement so changed prompts must be reviewed again.

10 Execute the pilot explicitly

python oneheart_jobs/compliment_effect/run_pilot.py --confirm-prompts

For repeat runs of the same generation, create the acknowledgement file once and run without the flag:

touch oneheart_jobs/compliment_effect/prompts.acknowledged
python oneheart_jobs/compliment_effect/run_pilot.py

The runner performs a model preflight, builds Concordia entities and the game master, runs the simulation, writes logs and transcripts, and uses EDSL to extract the configured measurements.

Runner optionPurpose
--model / --service-nameOverride the EDSL model or provider
--disable-remote-inferenceCall the underlying provider rather than Expected Parrot remote inference
--disable-language-modelExercise structure cheaply with Concordia’s no-LM backend; measurements are not substantive
--concordia-srcUse a local Concordia checkout
--output-dirChoose a different artifact directory

11 Record provenance and export evidence

A generated directory is working code; a run record connects what was generated to what actually ran. Preserve the generation ID returned by codegen and record seed and model metadata.

oneheart run record compliment_effect \
  --type pilot \
  --generated <generation_id> \
  --outputs oneheart_jobs/compliment_effect/outputs/pilot_summary.json \
  --seed 42 \
  --model gpt-5.4

oneheart export outcomes --output .oneheart/exports/outcomes.csv

oneheart export chat-html \
  oneheart_jobs/compliment_effect/outputs/simulation_log.json \
  --output writeup/compliment-chat.html

Keep both forms of evidence: the transcript shows whether the social process was credible, while the outcome table supports comparisons across recorded runs.

12 From one pilot to a comparison

A treatment is a design object, but a generated pilot resolves one condition. Generate and run each arm deliberately, keeping the agents, setting, measurements, model policy, and analysis constant.

# For a two-level treatment, "first" selects the first declared level;
# "midpoint" selects the second. Separate output directories avoid overwrites.
oneheart codegen pilot compliment_effect --selector first \
  --output-dir oneheart_jobs/compliment_arm
oneheart codegen pilot compliment_effect --selector midpoint \
  --output-dir oneheart_jobs/no_compliment_arm
  1. Generate the compliment condition and inspect its resolved prompt.
  2. Generate the neutral condition and verify that only the intended instruction changes.
  3. Run multiple seeds within each arm; one run per arm cannot estimate variation.
  4. Record every run and export a single outcome table.
  5. Inspect manipulation checks and transcript excerpts before estimating treatment differences.
Fixed studysame frame + agentsCompliment armseeds 1 … nNeutral armseeds 1 … nEvidence tableeffects + uncertainty
Replication within arms is what turns two anecdotes into an estimate of simulation variability.

13 Interpret without overclaiming

Simulation results characterize a configured model world. They do not automatically estimate how real people would behave. Interpretation should separate implementation validity, within-simulation evidence, and external validity.

QuestionEvidenceFailure to watch for
Did the treatment land?Resolved prompts, opening turns, manipulation checkThe level existed only as an inert label
Was the interaction credible?Transcript and structured logNarration, role leakage, repetitive or implausible dialogue
Was the outcome measured well?Typed output and extraction promptAmbiguous scale or unsupported inference
Is the effect stable?Replicates, seeds, agent/model variantsReading causality from one trajectory
Does it generalize?Human validation or empirical benchmarksTreating model behavior as population truth
A useful null result. If the manipulation check passes but outcomes match across arms, the run observed no difference. It still does not establish equivalence—especially with one run, one candidate, one interviewer, or a ceiling-bound outcome.

14 Command reference and recovery

CommandPurpose
oneheart statusRead project phase, counts, checklist, and next steps
oneheart doctorCheck Python, Concordia, and EDSL
oneheart docs list|show|searchRead bundled offline guidance
oneheart study …Create, configure, inspect, list, or select a study
oneheart agent …Add agents and stable attributes
oneheart treatment …Add experimental factors and per-level instructions
oneheart measurement addDefine typed post-run extraction questions
oneheart validateCheck study readiness, optionally including environment
oneheart codegen pilotWrite provenance and an inspectable runnable copy
oneheart run recordConnect completed outputs to generation metadata
oneheart export …Write outcome tables and chat artifacts
# The recovery loop for humans and coding agents:
oneheart status
oneheart docs show workflow
oneheart docs show study-design
oneheart docs show codegen

Prefer CLI mutations to hand-editing files under .oneheart/studies/. If a generated runner needs study-specific refinement, edit the working copy under oneheart_jobs/; leave the immutable provenance snapshot intact.