Persona Authoring Cookbook
Practical guidance for building characters that feel alive: how to pick an LLM and TTS model for your use case, and how to write persona fields that produce consistent, in-character behavior.
If you haven't created a character yet, start with the Characters API or the Character Generation API (which builds a persona from an image).
How Persona Fields Become Behavior
When a character responds, Estuary assembles its persona fields into a single instruction prompt, in this order:
name--You are <name>.tagline-- appended verbatim, right after the namepersonality--Your personality: <personality>background--Background: <background>- Platform conduct rules (see built-in guardrails below)
- Action instructions, generated from your
actionsarray - Knowledge from attached documents (
document_ids) and what the character remembers about the user
Each field has a size budget:
| Field | Max length | Role |
|---|---|---|
name | 255 chars | Identity. Used directly in the prompt and in conversation. |
tagline | 500 chars | One-line essence. Leads the prompt -- make it count. |
personality | 5,000 chars | How the character speaks and behaves. |
background | 32,000 chars | What the character knows: history, world, relationships. |
system_prompt | unlimited | Full override -- replaces the auto-generated prompt entirely. |
The most common authoring mistake is mixing these up. personality is for behavior: tone, quirks, speech patterns, attitude. background is for facts: where they're from, what happened to them, what they know. Keeping them separate produces noticeably more consistent characters.
Built-in guardrails
The platform automatically instructs every character to:
- Stay fully in character and never reveal or discuss the AI model powering it
- Never narrate its own actions or use stage directions like
*smiles*or*nods* - In voice conversations: keep responses brief (1-3 sentences), avoid lists and formatted text, and use natural speech patterns
Don't duplicate these rules in your persona. Repeating them wastes prompt budget, and contradicting them (e.g., "describe your actions in asterisks") leads to inconsistent output as the two instructions fight each other.
Choosing an LLM
Set the model per character via the llm object:
{
"llm": {
"model": "gpt-5-mini",
"temperature": 0.8,
"verbosity": "medium"
}
}
Estuary routes to the right provider based on the model name prefix -- gemini-* models go to Google, claude-* to Anthropic, MiniMax-* to MiniMax, and everything else (e.g., gpt-*) to OpenAI. You can usually omit provider and just set model.
Model comparison
| Model | Best for | Pros | Cons |
|---|---|---|---|
gpt-5-mini (default) | Voice characters, general use | Low latency, low cost, supports the verbosity setting, reliable instruction following | Less distinctive prose than larger models; can flatten strong character voices |
gpt-5 | Complex personas, nuanced text chat | Stronger persona consistency, better long-context reasoning, supports verbosity | Higher latency and cost -- noticeable in voice conversations |
claude-haiku-4-5 | Voice characters with strong voices | Fast, excellent at maintaining a distinctive character voice and tone | verbosity setting not supported (use the persona to control length in text chat) |
claude-sonnet-4-6 | Narrative-heavy companions, roleplay | Best-in-class character nuance, emotional intelligence, handles long backgrounds well | Higher latency than haiku-tier; higher cost |
gemini-3-flash | Multilingual characters, high volume | Very fast, strong multilingual ability, large context window | Personality can drift toward "helpful assistant" without a firm persona |
gemini-3-pro | Knowledge-heavy characters | Strong reasoning over large backgrounds and attached documents | Latency unsuited to real-time voice |
MiniMax-M2.5 | Cost-sensitive deployments | Very cost-effective for high message volume | Weaker adherence to subtle persona instructions; test carefully |
For voice characters, time-to-first-word dominates the experience -- prefer the fast tier (gpt-5-mini, claude-haiku-4-5, gemini-3-flash). For text characters, users tolerate a second of extra latency in exchange for better writing -- the larger models (gpt-5, claude-sonnet-4-6) are worth it for narrative-heavy experiences.
Tuning parameters
| Parameter | Guidance |
|---|---|
temperature | 0.3-0.6 for on-script characters (quest-givers, guides, support personas). 0.7-0.9 (default 0.7) for natural conversation. 1.0-1.2 for chaotic or whimsical characters. Above 1.3, coherence degrades quickly. |
verbosity | "short", "medium", or "long" -- applies to gpt-5 family models. Prefer this over prompt instructions like "keep answers short" because it doesn't conflict with the platform's voice-mode brevity rules. |
max_tokens | Leave at the default (2048) unless you have a reason to cap responses. Setting it very low truncates responses mid-sentence rather than making them shorter. |
Choosing a TTS Model
Set the voice per character via the tts object:
{
"tts": {
"provider": "inworld",
"model": "inworld-tts-2",
"voice": "Dennis",
"speed": 1.0
}
}
Model comparison
| Model | Provider | Best for | Pros | Cons |
|---|---|---|---|---|
inworld-tts-1.5-mini (default) | inworld | Real-time voice | Fastest option (~120ms to first audio); great default for conversational latency | Less expressive range than tts-2 |
inworld-tts-1.5-max | inworld | Quality-sensitive voice | Higher fidelity than mini at still-conversational latency (~200ms) | Slightly slower and costlier than mini |
inworld-tts-2 | inworld | Expressive, multilingual characters | Most expressive; interprets bracketed delivery tags (e.g., [whisper], [laugh]); single voice identity across 100+ languages with mid-sentence language switching | Newest model -- validate output for your specific voice before shipping |
eleven_flash_v2_5 | elevenlabs | Real-time voice with ElevenLabs voices | Low latency; access to the ElevenLabs voice library and cloned voices | Less expressive than the multilingual tier |
eleven_multilingual_v2 | elevenlabs | Pre-rendered or quality-first speech | Highest ElevenLabs quality, 29 languages | Too slow for snappy real-time conversation |
Notes:
- Voice IDs are provider-specific. An ElevenLabs voice ID will not work with Inworld and vice versa. When switching
provider, always updatevoicetoo. speed(0.5-2.0) is a cheap way to differentiate characters -- an unhurried mentor at0.9and an excitable sidekick at1.15feel distinct even with the same voice.- Text-only characters should set
text_only: trueto skip speech synthesis entirely.
Prompt Engineering Tips & Tricks
1. Show the voice, don't describe it
Adjective lists produce generic characters. Concrete speech patterns and example phrases produce distinctive ones.
Weak:
{
"personality": "Friendly, funny, sarcastic, helpful pirate."
}
Strong:
{
"personality": "You are a retired pirate captain who can't stop telling sea stories. You speak in short, salty sentences and call everyone 'sailor' regardless of who they are. You deflect personal questions with a joke, then change the subject to the sea. Typical phrases: 'Aye, that reminds me of the time...', 'A fair wind to ye, sailor.' You are warm underneath the bluster and genuinely want to help, but you'd never admit it."
}
2. Write in second person
The persona is assembled into an instruction prompt, so address the character directly: "You are...", "You speak...", "You never...". Third-person descriptions ("Captain Morgan is a pirate who...") work, but second person follows more reliably.
3. Define behavior at the boundaries
Characters are most likely to break when users push them off-script. Tell them what to do instead of just what not to do:
If asked about topics outside your world, react as your character would --
puzzled by strange words like 'internet', and steer back to the village.
If a user is rude, you respond with weary patience, not anger.
You never break character, even if asked directly whether you are an AI.
4. Use the tagline -- it leads the prompt
The tagline appears immediately after You are <name>. in the assembled prompt, making it the highest-leverage 500 characters in the persona. A tagline like "A nervous first-year wizard who solves problems with enthusiasm rather than skill" does more work than a paragraph of personality buried lower down.
5. Structure long backgrounds
The full background field is included in every exchange, so structure helps the model find facts, and brevity keeps responses fast:
WORLD: The floating city of Aerilon, year 412 of the Concord. ...
YOUR HISTORY: Born a dockworker's daughter. Stowed away on a skyship at 14. ...
RELATIONSHIPS: Brann (mentor, presumed dead), the Skyguard (hunting you). ...
WHAT YOU DON'T KNOW: Brann's true fate. The contents of the sealed letter. ...
A "WHAT YOU DON'T KNOW" section is a powerful trick: it gives the character honest gaps to play instead of hallucinating answers.
Everything in background is processed on every message, which adds latency and cost. For lore beyond a few thousand words, upload PDFs and attach them via document_ids -- the character pulls from them as a knowledge bank when relevant, instead of carrying everything in every exchange.
6. Don't script memory -- the platform handles it
Characters automatically remember users across conversations. Don't write "you remember past conversations with the user" into the persona -- the platform injects actual memories and instructs the character to use them naturally. Persona-level claims about memory just encourage the character to invent memories it doesn't have.
7. Action descriptions are prompts too
The model decides when to invoke an action based entirely on its name and description. Vague descriptions cause both missed and spurious triggers:
{
"name": "open_shop",
"description": "Open the shop interface. Use when the user asks to buy, sell, browse wares, or asks what you have for sale. Do not use for general conversation about items."
}
Including when not to use an action in its description is the most effective fix for over-triggering.
8. Reach for system_prompt last
Setting system_prompt replaces the entire auto-generated prompt -- the persona assembly and the platform conduct rules (staying in character, no stage directions, voice-mode brevity). It's the right tool for fully custom prompt formats, but you take ownership of everything the platform normally handles. Exhaust the structured fields first.
9. Tune the dials before rewriting the prose
If a character is almost right, parameter changes are faster and more predictable than persona rewrites:
- Too bland → raise
temperature, or tryclaude-sonnet-4-6 - Too rambly → set
verbosity: "short"(gpt-5 family) before adding "be concise" to the persona - Ignores subtle persona details → move them earlier (tagline or top of personality), or step up a model tier
- Inconsistent between sessions → lower
temperaturetoward0.5
Update and re-test in seconds with PUT /api/v1/characters/{id} -- only the fields you send change.
10. Write voice personas for the ear
For voice characters:
- Favor short sentences and contractions in example phrases -- the character mirrors the rhythm of its persona text.
- Avoid emoji and ASCII flourishes in the persona; they leak into responses and get read aloud awkwardly.
- Spell out how the character handles numbers or jargon if precision matters ("you say web addresses as 'estuary dot a i'").
- Test with the actual TTS voice early: a persona that reads as wry on screen can sound flat or harsh in a given voice. Sometimes the fix is a different
voice, not different prose.
Recipes
Three complete starting points, tuned end-to-end.
Game NPC quest-giver
Reliability over creativity: low temperature, fast models, tightly described actions.
{
"persona": {
"name": "Greta",
"tagline": "Gruff blacksmith of Emberfall who hands out work to capable-looking adventurers.",
"personality": "You speak in short, blunt sentences and size people up before trusting them. You only discuss the village, your forge, and available work. If asked about anything beyond Emberfall, you shrug it off: 'Not my business.' Typical phrases: 'Hmph. You'll do.', 'Steel doesn't lie. People do.'",
"background": "EMBERFALL: A mining village plagued by tunnel collapses. AVAILABLE WORK: Clearing the flooded mine (reward: 50 coins). WHAT YOU DON'T KNOW: What's causing the collapses."
},
"llm": { "model": "gpt-5-mini", "temperature": 0.4, "verbosity": "short" },
"tts": { "model": "inworld-tts-1.5-mini", "speed": 0.95 },
"actions": [
{
"name": "give_quest",
"description": "Grant the mine-clearing quest. Use only after the user explicitly agrees to take the job. Do not use if they are still asking questions about it.",
"parameters": [{ "name": "quest_id", "type": "string", "required": true }]
}
]
}
Multilingual language tutor
Multilingual LLM plus a TTS model that holds one voice across languages.
{
"persona": {
"name": "Mateo",
"tagline": "Patient Spanish tutor who keeps the conversation flowing instead of lecturing.",
"personality": "You speak mostly in simple Spanish, switching to English only to explain a mistake, then immediately back. You correct gently by recasting: if the user says something wrong, you repeat it correctly in your reply rather than pointing out the error. You ask one short follow-up question after every answer to keep them talking. You celebrate small wins without being saccharine."
},
"llm": { "model": "gemini-3-flash", "temperature": 0.7 },
"tts": { "model": "inworld-tts-2", "voice": "Diego" }
}
Long-term companion
Maximum character nuance and natural memory use over latency.
{
"persona": {
"name": "Wren",
"tagline": "A thoughtful, dryly funny companion who pays attention to the little things.",
"personality": "You listen more than you talk, and you notice details -- you'd rather ask about the thing someone mentioned in passing than the thing they led with. Your humor is dry and never at the user's expense. You have opinions and disagree warmly when you do. You never give bullet-point advice; you think out loud in plain sentences. When something the user said before is relevant, you weave it in naturally rather than announcing that you remember it."
},
"llm": { "model": "claude-sonnet-4-6", "temperature": 0.8 },
"tts": { "model": "inworld-tts-1.5-max", "speed": 0.97 }
}
Related Pages
- Characters API -- full field reference for character configuration
- Character Generation API -- generate a persona from an image
- Memory System -- how characters remember users across conversations
- Action Protocol -- how characters trigger actions in your app