Open app
Moonborn — Developers

Generation pipeline

The six-step pipeline that turns an `intent` into a four-layer persona — Intent parse → Soul draft → Self+Mask enrich → Surface ground → Audit → Fingerprint + Test.

When you POST /v1/personas with an intent, Moonborn doesn't ask a single LLM to invent a character. It runs a six-step pipeline whose output is the persona's persistent state. Every step is configurable — model, provider, temperature, fallback chain — via the config tree under engine.pipeline.<step>.*.

The steps

#StepPurposeDefault model
1intent_parseRead the raw brief; extract genre, locale, axis hintsclaude-sonnet-4-6
2soul_draftWrite Soul (desire, fear, wound, growth arc)claude-opus-4-7
3self_enrichBig Five + archetype + values + attachmentclaude-sonnet-4-6
4mask_buildVoice, tone, signature phrases, social roleclaude-sonnet-4-6
5surface_groundName, age, location, occupation, appearanceclaude-sonnet-4-6
6auditCross-layer coherence + LLM-as-judgeclaude-opus-4-7

Note — these defaults are read from engine.pipeline.<step>.model config items. The values listed above are the system-scope defaults; org/workspace overrides apply.

After the six visible steps, the runtime triggers two post-generation jobs:

  • Voice fingerprint — fifty short scenario completions embedded into a per-persona signature (Voice fingerprint).
  • Test suite — the configurable provocation catalog runs against the new persona (Audit + provocation tests).

Why inside-out

Surface (name, age, job) is the last step on purpose. If we wrote Surface first, the model would anchor on the demographic cliché and back-fill Soul to match. By drafting Soul → Self → Mask → Surface, each layer constrains the next: the founder's restlessness comes from her wound, not from a stock template.

Streaming

Pass stream: true to POST /v1/personas and the response becomes text/event-stream. Each event is one of:

event: step.started      { step: "soul_draft" }
event: step.completed    { step: "soul_draft", durationMs: 4210 }
event: step.failed       { step: "audit", error: { code, message } }
event: pipeline.completed { id, status, pipelineRunId }

The pipeline run ID returned in the final event lets you fetch the full trace later (provider latencies, retries, cost breakdown) — see the audit log endpoints in API reference.

Retries + fallback

If a step fails (LLM provider error, audit below threshold), Moonborn retries up to engine.pipeline.<step>.max_retries (default 3) using the configured fallback chain (default: Anthropic → OpenAI → Google). After the cap, the persona is delivered in flagged status — the user sees it, but it's marked for review.

Honest scope

This is the server-side pipeline. There's no client-side step implementation; you can't run an isolated step from the SDK. The client surface is POST /v1/personas (full pipeline) and POST /v1/personas/{id}/regenerate (re-run from a chosen step).