Fork brand variants
Take a canonical brand persona, fork it into formal / casual / locale-specific variants without losing the through-line. Walk through Refine, lineage, distinctiveness.
Brand teams typically maintain multiple voice variants — a serious B2B tone, a playful social tone, an EN and a DE version. Hand-curated that's six prompts to keep in sync. Forking turns it into a single canonical persona with a tracked tree of variants.
1. Build the canonical persona
Start with the most authoritative voice — the one others will fork from. Treat its Soul + Self as the "brand DNA"; downstream variants should preserve those layers.
const brand = await client.personas.createPersona({
intent:
'Brand voice for Moonborn — Character Consistency Engine. Scholarly, character-centric, technically precise. Editorial restraint. Lead with concrete detail, avoid sales fluff.',
workspaceId: 'ws_...',
});Audit and provocation tests run automatically; aim for ≥ 4.0/5 on the audit before forking. If lower, refine before adding variants.
2. Fork a formal variant
POST /v1/personas/{id}/fork copies the persona and writes the
parent edge. Pair it with a refine argument to apply an axis
transform in the same call:
const formal = await client.personas.fork({
id: brand.id,
refine: {
mode: 'refine',
layer: 'mask',
axis: 'more-authoritative',
amount: 0.4,
},
note: 'Sales materials variant',
});The fork keeps Soul + Self locked (the brand DNA) and rewrites only the Mask. Audit re-runs against the new Mask; distinctiveness compares the formal variant against the canonical (custom baseline) to catch drift toward a generic corporate voice.
3. Fork a casual variant
const casual = await client.personas.fork({
id: brand.id,
refine: {
mode: 'refine',
layer: 'mask',
axis: 'warmer',
amount: 0.45,
},
note: 'Social media + community variant',
});4. Fork a Turkish locale variant
For multi-locale, refine the Surface (language + cultural details) while keeping Soul / Self / Mask locked:
const tr = await client.personas.fork({
id: brand.id,
refine: {
mode: 'lock',
lockLayers: ['soul', 'self', 'mask'],
edits: {
'surface.language': 'tr',
'surface.location': 'İstanbul, Türkiye',
},
},
note: 'TR locale variant',
});5. Audit the variant set
const lineage = await client.personas.getLineage({ id: brand.id });
console.log(lineage.children.map((c) => c.id));
// Are the variants drifting toward each other?
const compare = await client.consistency.compareWithOrgPersonas({
personaId: formal.id,
threshold: 0.30,
});
console.log(compare.closest);The compareWithOrgPersonas query returns the closest persona by
voice fingerprint distance. If your "formal" and "casual" variants
score < 0.15 against each other, they collapsed during refine — the
axis amount was too small, or the canonical Mask already encoded too
much variability. Re-fork with a larger amount or refine Soul instead
(a Cascade mode edit).
6. Deploy
Each variant exposes its own persona ID. Wire each ID into the appropriate channel:
formal.id→ your sales email automation.casual.id→ your social inbox.tr.id→ your Turkish-locale support agent.
Through the OpenAI-compatible endpoint, the variant ID is the model
field:
import OpenAI from 'openai';
const oai = new OpenAI({
apiKey: process.env.MOONBORN_API_KEY,
baseURL: 'https://api.moonborn.co/v1/openai',
});
const reply = await oai.chat.completions.create({
model: `persona://${formal.id}`,
messages: [{ role: 'user', content: 'Tell me about Moonborn.' }],
});Next
- The narrative: Brand voice variants use case.
- Lineage governance: Voice variant lineage governance guide.
- Personas API → Fork.