One Character, Many Worlds: Reusing AI Personas Across Contexts
You’ve built an AI character. It has a personality, an emotional state, memories. It feels real.
Now you want that same character in a different context. A coffee shop scene. A therapy simulation. A classroom. Maybe a game where the same NPC appears across multiple levels.
With most AI frameworks, you’d copy-paste the character config, hope the prompts stay consistent, and end up with N slightly-different versions of the same character. None of them remember each other.
We just shipped a better way.
The problem with character duplication
Let’s say you have Luna — a warm, empathetic barista character. She’s great in your cafe chatbot. Now you want her in a group scene with other characters.
The naive approach: recreate Luna’s config in the new context. But now you have two Lunas. They don’t share emotional state. If a user makes Luna happy in the cafe, group-scene Luna doesn’t know. You’re maintaining two copies of the same personality definition, and they drift over time.
This is the “character duplication problem” — and it’s worse than it sounds. Because the whole point of having an emotional state is continuity. A character that forgets how they felt is just a chatbot with extra steps.
One persona, many worlds
The molroo SDK now supports three ways to add a persona to a world (our term for a context where characters interact):
1. Inline mode — define everything on the fly:
import { Molroo } from '@molroo-io/sdk';
const molroo = new Molroo({ apiKey: 'mk_live_...' });
const world2 = await molroo.createWorld({ name: 'Cafe' });
await world2.addPersona({
configId: 'luna',
displayName: 'Luna',
config: {
identity: { name: 'Luna', role: 'barista' },
personality: { O: 0.7, C: 0.6, E: 0.8, A: 0.9, N: 0.3, H: 0.8 },
},
});
This is fine for prototyping. But it creates a new persona every time.
2. Reference mode — point to an existing persona by ID:
await world2.addPersona({
personaId: 'prs_abc123', // Luna's persona ID
});
Now both worlds share the same Luna. Same emotional state, same personality, same history.
3. Instance mode — the cleanest DX:
import { Molroo } from '@molroo-io/sdk';
const molroo = new Molroo({ apiKey: 'mk_live_...' });
// Create Luna once
const luna = await molroo.createPersona(
{
identity: { name: 'Luna', role: 'barista', speakingStyle: 'warm' },
personality: { O: 0.7, C: 0.6, E: 0.8, A: 0.9, N: 0.3, H: 0.8 },
},
{ llm },
);
// Chat with her directly
const chat = await luna.chat('Hey Luna, how are you?');
// Now drop her into any world
const cafe = await molroo.createWorld({ name: 'Cafe' });
const classroom = await molroo.createWorld({ name: 'Classroom' });
await cafe.addPersona(luna); // same Luna
await classroom.addPersona(luna); // still the same Luna
That’s it. world.addPersona(luna) — pass the instance directly. The SDK extracts the persona ID under the hood. Luna is the same character in both worlds.
Why this matters for developers
Shared emotional state. If Luna gets upset in the cafe, she’s upset in the classroom too. Her emotional state is real — it lives in the persona, not in the world.
Single source of truth. One personality definition. One set of traits. Update Luna’s speaking style once, it applies everywhere.
Mix persona and world. You can use luna.chat() for 1:1 conversations and world.persona('luna').react() for multi-character scenes — same persona, different interaction modes.
Here’s what multi-character interaction looks like:
// Get persona handles within the world
const lunaHandle = cafe.persona(luna.id, { llm });
const minaHandle = cafe.persona(mina.id, { llm });
// Set up how they relate to each other
await cafe.setRelationship({
from: luna.id,
to: mina.id,
type: 'coworker',
attributes: { trust: 0.8, familiarity: 0.9 },
});
// Luna reacts to a customer
const { text, state } = await lunaHandle.react({
message: 'Two lattes please!',
from: 'customer-1',
});
console.log(text);
// "Coming right up! Mina, can you grab the oat milk?"
console.log(state.emotion.discrete);
// { primary: 'cheerful', intensity: 0.72 }
Characters that know each other, react emotionally, and maintain that emotional history across every interaction.
The practical pattern
Here’s the pattern we recommend for production apps:
import { Molroo } from '@molroo-io/sdk';
const molroo = new Molroo({ apiKey: 'mk_live_...' });
// 1. Create personas at app startup or user signup
const characters = await Promise.all([
molroo.createPersona(lunaDefinition, { llm }),
molroo.createPersona(minaDefinition, { llm }),
molroo.createPersona(jaeDefinition, { llm }),
]);
// 2. Store persona IDs (they're stable)
// characters.map(c => c.id) → save to your DB
// 3. Create worlds per context/session
const world = await molroo.createWorld({ name: 'Session 42' });
for (const char of characters) {
await world.addPersona(char);
}
// 4. Interact through the world
const handle = world.persona(characters[0].id, { llm });
const result = await handle.react({ message: 'Hello everyone!', from: 'user' });
Personas are long-lived. Worlds are ephemeral (or long-lived — your call). This separation means you can spin up new contexts without recreating characters.
Try it
Install the SDK:
npm install @molroo-io/sdk
Get an API key from the dashboard, pick an LLM provider, and start building characters that actually persist across contexts.
The full World SDK docs are at molroo.io/docs/world/sdk.
molroo is an emotion engine for AI characters. We compute what characters feel, so they can stop pretending. Learn more at molroo.io.