Studio is "build a persona" as an app function, live at chat.xbbapp.com/builder. Name a figure (or describe one), give one identity-confirmation tap, and the machine runs unattended — gather with verbatim VERIFY, curate, author, mechanical checks, two cold auditors — and the persona lands in your Studio. Status: built · live at /builder. This page reflects the shipped code; it folds together the four earlier design notes (the v1 persona-builder, the v2 "one machine" redraw, the v2 UI mockup, and the Persona Studio home).
1 · what it is 2 · the one machine 3 · the build pipeline 4 · the Studio home 5 · the building page 6 · visibility & ownership
The persona pipeline began as a Claude-Code authoring kit — a human running a multi-session gather → author → cold-audit flow by hand. The Studio is that pipeline ported into the API-only server as an unattended state machine, with a home wrapped around it. One human decision remains — which identity — and everything after it is the machine's.
profile.md + tags.txt (+ a corpus/ of verified quotes for real figures). The Studio's job is to manufacture that data honestly: every claimed fact traceable to a fetched page, and every gap between what's known and what's written disclosed rather than hidden.It opens to every logged-in user, gated only by a per-user spend cap (build spend counts against the same daily/weekly budget as chat). Your builds are yours — born private, listed only to you — until an admin publishes them into the shared library.
Five real builds during validation showed the original three build types (public record · your sources · invented) leaking into each other: almost every persona is a mixture of web-found, user-supplied, and AI-filled content. So there are not three pipelines — there is one build() path with switches. The switches:
| switch | in code | what it controls |
|---|---|---|
| Referent class | btype = public · supplied · invented; identity kind = person | character | Who answers for the persona, and how much invention is legitimate. A character gets a CANON LOCK overlay; a revered real figure gets the REVERED overlay (faithful is ceiling and floor). An invented persona is its own ground truth — no corpus to contradict. |
| Evidence pool | metas = ingest_metas + web_metas | Web fan-out and your uploaded material are different axes, not substitutes. A documented public figure gets the full web gather even when you supply files; the material is your emphasis ("it leads where both speak"), never a replacement. Both pass the same VERIFY discipline — a quote enters the corpus only as a normalized substring of the page it came from. |
| The meter | coverage_gate() (web) · supplied_gate() (material) | Counts verified quotes, distinct domains, and thin facets — how far the evidence actually stretches. Thin → one targeted re-gather. The material meter is lenient (SUPPLIED_MIN_ITEMS = 25 is the floor); the one refusal in the whole machine is failed: nothing-to-build-from when nothing verifies at all. |
| Imagination | decide_imagination() → faithful · extended · free | System-set, not a user dial. The referent class sets a ceiling; the meter picks the notch within it. The app never exposes this control (the CLI may request up to the ceiling with --imagination). |
| Provenance | inline tags + compute_made_from() | The disclosure. In-prose tags mark what isn't corpus-attested — [public] (true but uncited), [inferred], [hedged], [paraphrase], [representative construction]; corpus-grade facts carry no tag and quotation marks appear only on verbatim lines. The made-from bar is the outward summary. |
Imagination is decided in two moves: the referent class caps how far invention may reach, and the evidence decides where inside that cap the build actually sits.
decide_imagination() actually sets it. A revered figure is pinned to faithful; a real person defaults to extended but a rich corpus (≥25 verified items) pulls it back to faithful; a character or invented persona runs free. The user never turns this dial.At publish, compute_made_from() renders one bar: a solid attested share sized by the imagination notch (faithful ≈ 85% · extended ≈ 60% · free ≈ 45%), split web-vs-material by where the verified items came from, and the remainder marked AI fills. It rides the confirm screen as a forecast (hatched) and the finished report as the result (solid), and a compact version sits on the persona card.
One build() state machine runs eleven stages, front to back. Every stage is a breakpoint: a kill or crash pauses the build (state persists in _job.json), it never loses work — a resumed build skips whatever's already on disk.
| # | stage · label | what it does | runs on |
|---|---|---|---|
| 1 | Identity lock identity | SERP probes fan out; the model resolves candidate identities (person/character · living · record rich/thin · revered · rights). Supports descriptive search (no name → "the best realtor in the Bay Area", ranked by independent coverage). The one human tap picks a candidate. | v4-pro |
| 2 | Ingest your sources ingest | Only when material is supplied. Mines uploaded files (.txt/.md/.pdf/.epub) + endorsed links into supplied facets, same VERIFY discipline as the web; auto-detects transcript-vs-polished per document. | v4-flash |
| 3 | Gather gather | Per-facet loop over five facets (biography · worldview · interviews · manner · positions): PLAN → SEARCH → TRIAGE → FETCH+extract → MINE → VERIFY → GATE, up to three rounds. | v4-flash |
| 4 | Coverage probe coverage | One thinking call — "what famous episodes of this life are missing?" — seeds a targeted gather round for the gaps quota-hunting skipped. | v4-pro |
| 5 | Curate curate | Writes sources.md (reliability tiers · conflicts · a knowledge-horizon paragraph); drops lock-mismatched URLs from disk. | v4-pro |
| 6 | Coverage gate gate | "The meter" in code — floors on verified quotes / distinct domains / thin facets, triggers one re-gather, sets the imagination notch. The one refusal lives here. | code |
| 7 | Author author | Writes profile.md + tags.txt from the kit template and the corpus, with stacked overlays (supplied / character / revered). Code owns the slug + ULID. | v4-pro |
| 8 | Mechanical checks checks | Frontmatter card keys · 9 required sections · banned analyst labels · quote oracle (verbatim) · tags rubric · single-source shingle scan. | code |
| 9 | Patch patch | Repairs against the findings list — and is never allowed to leave the profile mechanically worse (net-harm patches revert). | v4-pro |
| 10 | Cold audit ×2 audit | Two adversarial cold auditors (seats A/B), worst-of verdict (PASS / FIX-THEN-PASS / RE-AUTHOR), then a fix-verify loop; RE-AUTHOR buys one full re-author + re-panel. A dead seat degrades to one voice. | 2 models |
| 11 | Built publish | Computes made_from, generates the 4-prompt live-room test checklist (supplied builds), finishes the job. "Publish" now means admin-publish; the build's own final state is Built. | code |
Each stage's model + thinking level is a preset (PRESETS — a default and an all-deepseek), console-editable at /api/admin/builder-config. The running spine shows a model chip per stage — with two deliberate exceptions: checks/gate show a code chip, and the auditors' models are never revealed ("don't leak the auditor").
| stage | model · thinking (default preset) |
|---|---|
| identity | v4-pro · off |
| gather · ingest | v4-flash · off |
| curate · coverage | v4-pro · high |
| author | v4-pro · high |
| patch | v4-pro · off |
| audit A / audit B | v4-pro · high / gemini-3.5-flash · high (hidden in the UI) |
The home lives at /builder: a list of the personas you made plus a + New build form. The list is owner-scoped — only builds where built_by_uid is you (CLI / Claude-Code builds have no uid and never appear) — in three sections: In progress (parked or running), Finished (built), and Deleted (dimmed, with Restore).
Each row is the house cast-card — slug-hashed avatar colour, name + local name, role, a chip row, and a made-from mini-bar. The chips read the record: a status chip (built = green · pick-identity / awaiting-confirm = yellow · building = slate shimmer · interrupted = muted · failed = red), a visibility chip (public = coral · private = muted), a type chip (your sources = plum · invented = lilac), and a cost chip in gold.
| state | actions |
|---|---|
| built (published-to-you) | Built summary (opens the step-4 report) · Delete |
| parked probe | Continue · Delete |
| interrupted | Resume · Delete |
| failed / aborted | Restart · Delete |
| deleted | Restore only |
Delete is a centred confirm (Cancel / red Delete). A built persona soft-deletes — a tombstone; the files stay, chats where it's seated keep working, and it's restorable — while a parked or failed scaffold hard-deletes and frees the slug. Clone, promote, and demote are not here — they're admin-console verbs (see §6); the owner's Studio does build / delete / restore.
A pinned spend meter appears only when a cap is set (it dims + New when over). Build spend counts toward the same daily/weekly cap as chat.
/builder (the list), lazy-loaded, gated by the persona_studio visibility flag./builder?create=1 (create-only: hides the list, lands on the form).?resume=<slug> resumes a build in the dialog; ?report=<slug> jumps any owner's build to its finished report (the console uses this).A running build renders a spine — one row per stage, driven by an SSE snapshot-then-tail over the job journal: a status dot (· / ● / ✓ / ✗), the stage name (shimmering while live), a model or code chip, the stage message, and sub-rows (gather facets ◔/✓, ingest docs, audit seats — a dead seat gets a "restart from here" button). A sticky ticker shows stage · $ · elapsed.
Regular users don't need the machine-room. When the admin flag studio_details ("Show build details", under Who sees what → Persona Studio, admin-on / tester-off) is off, the page adds html.hide-details and the spine collapses to the level-one named progress — just the dots and stage names, Identity lock → Built. The finished report collapses to its headline too: the verdict and the built-from bar stay (plus the cost bill if studio_costs is on); coverage-by-facet, the audit.md / sources.md folds, and the test checklist are hidden.
studio_details off (left) leaves only the named progress and the verdict; on (right) it exposes the per-stage detail lines, model chips, facet/seat sub-rows, and the full finished report. Shipped in v422.While a build runs, a reassurance card sits at the foot of the page: "Building in the background. You can leave this page — we'll notify you the moment it's ready." — a bell icon and a ← Go back button, both inside the box. The build keeps running server-side; a notice fires build:done / build:failed over the user's SSE stream (a toast, the ≡ dot, the notification centre). A mutex on the confirm screen enforces one build at a time per user.
Top to bottom: the verdict headline ("✓ built · 7m 58s" or "✗ reason · time") · the built-from bar (solid) · coverage by facet (verified-item counts, a source chip, a "thin" mark) · the cost bill (by-stage and by-API tables) · the audit.md and sources.md folds · the live-room test checklist (supplied builds — the kit's mandatory 4-prompt extrapolation test) · and the actions View profile / Resume build / All builds. Everything below the built-from bar is what studio_details hides.
A build is born private — listed only to you, seatable only by you. Making it available to everyone is an admin act, and it never happens to your work behind your back.
private | public · deletion: alive | deleted — plus immutable created_by. One predicate every discovery surface calls: alive AND (public OR mine). One invariant: an admin never raises the visibility of someone else's persona — promotion crosses ownership by copy (clone → test → promote).Inside the Studio you see only the parts that touch your own builds: born-private, the public/private chip, and Delete / Restore (deleting requires private first, so public always means alive-and-listed). Clone / promote / demote live in the admin console's Personas tab. The full model — the state graph, the five verbs, the seating door, and every leak the audit closed — is its own page:
→ Persona visibility — permission & lifecycle
chat.xbbapp.com/builder. This page folds together four earlier notes (persona-builder v1 · builder-v2 "one machine" · the v2 UI mockup · Persona Studio home) into one current-implementation record. Source of truth: lib/builder.py · lib/builder-ui.html · lib/run_room.py. Related: Persona visibility · Vibes content engine · Current functions.