MaveraMavera Docs
Conversations
Checking…
Use or share this pageSend the page itself, print it, or open its complete context in your AI workspace.

Focus groups

Moderated panels with code-computed group dynamics.

3 min readDocs build Updated Jul 26, 2026

Endpoint: POST /api/v1/tools/focus_group. Required: audienceId + topic.

The full input schema

FieldTypeWhat it does
audienceId (required)stringThe audience the panel is drawn from.
topic (required)stringThe framing the moderator opens with.
stimulusstringThe concrete thing they react to — a concept, price, claim, or described creative. Strongly recommended.
panelSizeintegerHow many distinct personas sit on the panel (5–8 is the sweet spot).
roundsintegerPasses through the panel. 2+ lets personas react to each other (real dynamics emerge).
moderatorGuidestring[]Ordered questions the moderator works through across rounds.
seedintegerReproducible panel draw + responses — fix it to compare two stimuli against the same room.
freshPanelbooleanPerturbs the draw by topic so each group recruits different people (like a real multi-group study). Default false = same seed ⇒ same panel (comparable A/B cells).
modelPanelbooleanDefault true. One frontier call casts the whole panel's identities together under a distinctness contract (no shared backstories, beats, or verbal fingerprints). Measured +7.5 realism points vs template panels. Set false for the fully deterministic template path.
gradeRealismbooleanA JUDGE-tier model grades the transcript for synthetic tells after the run; the grade rides the response as realism and feeds the quality ledger.
promptVersion"v1""v2"
modelTierstringOverride the model tier (defaults to the conversation tier).
POST /api/v1/tools/focus_group
{
  "audienceId": "aud_f1_1",
  "topic": "A $29/mo all-in-one finance app for solo founders",
  "stimulus": "Bookkeeping, invoicing, and cash-flow forecasting in one place for $29/mo. No setup fees.",
  "panelSize": 5,
  "rounds": 2,
  "moderatorGuide": [
    "First reaction — would this fit your world?",
    "What's the single biggest thing that would stop you from buying?",
    "What would make it a no-brainer?"
  ],
  "seed": 42
}

What comes back

Response
{ "ok": true, "data": {
  "panel": [
    { "personaId": "aud_f1_1@v1#42#0", "name": "Maya R. — a bootstrapped founder juggling three tools",
      "archetype": "Price & cost", "disposition": "enthusiast", "speechStyle": "terse",
      "attributes": { "company_size": "smb", "market_status": "in-market" }, "realizedBy": "model" }
  ],
  "transcript": [
    { "round": 1, "personaId": "aud_f1_1@v1#42#0", "name": "Maya R. — a bootstrapped founder juggling three tools",
      "content": "At $29 this is a no-brainer for me...", "abstained": false, "respondingTo": null },
    { "round": 2, "personaId": "aud_f1_1@v1#42#1", "name": "Devon K. — an ops lead who's been burned by tool sprawl",
      "content": "I'd worry it won't keep up once we're 20 people.", "abstained": false, "respondingTo": null }
  ],
  "dynamics": {
    "convergence": [ { "theme": "Price & cost", "share": 0.8 } ],
    "polarizing":  [ { "theme": "Proof & credibility", "forCount": 2, "againstCount": 3 } ],
    "shifts":      [ { "personaId": "aud_f1_1@v1#42#1", "fromStance": "Proof & credibility", "toStance": "Price & cost" } ],
    "quietParticipants": [ "aud_f1_1@v1#42#3" ]
  },
  "diversity": {
    "crossSpeakerLexicalOverlap": 0.002, "turnLengthVariation": 0.33,
    "openerDiversity": 1, "sharedIdiomCount": 0, "lengthRangeRatio": 2.63
  },
  "honesty": { "synthetic": true, "groundingStrength": "category-modeled" },
  "realism": null
} }
FieldMeaning & how to use it
panel[].realizedBy"model" = identities cast by the frontier model (default); "code" = deterministic template path.
dynamics.convergenceThemes the panel agreed on (share across participants). Your strongest, most defensible findings.
dynamics.polarizingThemes that split the room. These are your richest follow-ups — feed them to the Insight Miner / branch them.
dynamics.shiftsPersonas whose dominant theme changed between rounds — shows what argument moved them.
dynamics.quietParticipantsPersonas who abstained or said least. Worth a targeted 1:1 chat — silence can hide the real objection.
diversityCode-computed panel-diversity telemetry, free on every run. See the quality loop.
realismPresent when gradeRealism: true: the judge's score, verdict, and evidence-quoted tells.

All of dynamics and diversity is code-computed from the transcript text — shares, splits, overlaps, and shift detection are counted/scored, not asserted by the model.

From group to insight

# 1. run the group → take data.transcript
# 2. reshape to [{speaker, text}] and mine it for the splits
POST /api/v1/tools/mine_insights { "turns":[...transcript...], "useLlm":true, "llmMode":"identify" }
# 3. take a divergence's branchPrompt and explore it live
POST /api/v1/insights/branch { "audienceId":"aud_f1_1", "branchPrompt":"<from step 2>", "depth":2 }

See Mining insights and Branching & flip-tests for the full loop.

Designing a group that produces signal

  • Always give a concrete stimulus. "React to this $29 offer with features X, Y, Z" yields far sharper output than an abstract topic alone. Personas need something specific to push against.
  • Use 2+ rounds. Round 1 is first impressions; the real dynamics — agreement forming, dissent hardening, minds changing — happen in round 2+.
  • panelSize 5–8. Enough diversity to surface splits, few enough that individual voices stay distinct.
  • Write a tight moderatorGuide. 3–5 escalating questions (reaction → objection → what-would-fix-it) beats one open prompt.
  • Fix the seed when comparing stimuli (e.g. $29 vs $49) so the only variable is the stimulus, not the panel.

Focus group vs the other modalities

A focus group is the right tool when you want group reaction + dynamics. If you want depth on one person use chat or deep_interview; for a head-to-head argument use persona_debate; for emotional/unspoken drivers use projective_session. See all modalities.

On this page