YURIOS // LAB
The Codex → Appendices Appendix D

Reference Implementation Index

Live index of the five builds

Live index of reference implementations. Each impl is an independently runnable sub-project with its own README; ch. 30 is the overview and the walkthrough chapters (31–35) are the in-book guide.

The numbered builds (1–5) are the book's teaching ladder. The lettered rows are the component services those builds compose from — shipped first because they run in isolation, and clustered mostly under Build #3 (the released persona and the media services it needs). See ch. 30, "What's actually in the repo today," for why the folder is a parts bin rather than five monolithic build directories.

# Name Walkthrough Folder Status
1 Minimum Viable Waifu ch. 31 01-minimum-viable-waifu/ planned
2 Desktop Companion ch. 32 02-desktop-companion/ planned
3 Character Card Release — the Card Studio web app ch. 33 03-character-card-release/ working
3a Yuri SOUL + card exporter ch. 07, 33 yuri-soul/ working
3b Image / selfie service (swappable backends) ch. 26 image-forge/ working
3c Voice service (Kokoro, fixed voice, streaming + eval) ch. 24 kokoro/ working
3d Voice cloning (GPT-SoVITS client, identity eval) ch. 24 gpt-sovits/ working
3e Voice convergence (Qwen3-TTS: clone/design/preset) ch. 24 qwen3-tts/ working
4 3D World Companion ch. 34 04-3d-world-companion/ in progress
4a VRM avatar control pipeline (Python-driven) ch. 25 vrm-viewer/ working
5 Agentic Sanctuary (Build #4 + the always-on mind) ch. 35 05-agentic-sanctuary/ working

Conventions

  • Each impl is independently runnable.
  • Each impl has a README.md with: what it teaches, prerequisites, run instructions, what it intentionally doesn't do.
  • Each impl is intentionally small — the goal is clarity, not production.
  • License is MIT unless otherwise noted.
  • Implementations may share lore/canon (the Yuri persona) but not code unless documented.
  • Every build that holds a conversation writes to the shared corpus-log schema below — the on-voice data the eventual distillation step depends on (→ ch. 20, ch. 30).

Shared schema: the conversation corpus log

The builds capture conversation data twice, for two different jobs, and the two must not be confused (→ ch. 30, "capture the corpus from day one"):

  • the retrieval store (pgvector + facts table, → ch. 15) is lossy and derived — summaries and embeddings, optimised for recall, not training;
  • the corpus log defined here is append-only and faithful — the raw exchange plus the provenance that makes it trainable later (SFT / DPO / KTO / distillation, → ch. 20).

Throw nothing away at the corpus layer; you curate by subtraction at export time, and you cannot subtract from what you never kept.

Format & layout

One JSON object per line (JSONL), one record per assistant reply:

corpus/
  turns.jsonl          # append-only; every reply, one line each
  ratings.jsonl        # append-only sidecar; {id, thumbs|score, by} keyed to a turn id
  preferences.jsonl    # optional; A/B pairs for DPO, if kept separate from variant_group
  README.md            # which builds wrote here, date range, export notes

turns.jsonl is append-only, so feedback that arrives after a reply — user ratings, a later judge pass — is written to ratings.jsonl keyed by the turn id, not patched into the original line, and merged into the rating/eval fields at export time.

The corpus is personal data, not code.gitignore it, keep it on hardware you control, and back it up separately. It is never committed to the reference-impl repo.

Record schema (turns.jsonl)

Field Type Req Purpose
id string (uuid) unique record id
session_id string groups turns in one conversation
turn_index int 0-based position within the session
timestamp string (ISO-8601 UTC) when the reply was produced
companion string persona id (e.g. yuri)
messages array<{role,content}> the full prompt as sent (system + history window + user) — the trainable input
completion string the assistant reply — the trainable target
model string model id that produced completion (e.g. claude-opus-4-8, qwen3-7b-instruct-q4_k_m)
model_role enum: teacher|student|production frontier-teacher target, local-student output, or prod reply — gates what's worth distilling from
source enum: live_play|synthetic|hand_authored how the turn was created (the ch. 20 mix; a curation axis)
collection_scope enum: self|consented_hosted the legal/ethical basis — see the boundary below
card_version string persona card version or content hash (model swaps + card edits are where voice drifts, → ch. 23)
template_version string prompt-assembly version
gen_params object {temperature, top_p, max_tokens, seed} for reproducibility
rating object {thumbs: +1|-1, score: 1–5, by: user|judge} — feeds KTO directly (→ ch. 20)
eval object judge scores (→ ch. 23), e.g. {persona_stability, voice_similarity, honesty, manipulation}
tags array topic/mood labels, for balancing the export (→ ch. 20)
flags array exclusions: pii, nsfw, off_voice, confabulation, exclude
variant_group string shared id linking alternative completions for the same prompt (→ DPO)
preferred bool within a variant_group, the chosen reply (→ DPO / preference data)
redacted bool true if PII was scrubbed from messages/completion

Examples

A synthetic, teacher-generated turn — the high-value SFT/distillation target (→ ch. 20, soul-preserving synthetic generation):

{"id":"f3c1…","session_id":"syn-0012","turn_index":4,"timestamp":"2026-06-28T14:03:11Z","companion":"yuri","messages":[{"role":"system","content":"<card + lore + retrieved memory>"},{"role":"user","content":"i bombed the interview today. don't really want to talk about it."}],"completion":"Then we won't. Come here — I'll just sit with you for a while.","model":"claude-opus-4-8","model_role":"teacher","source":"synthetic","collection_scope":"self","card_version":"yuri-v1@canon-v1","template_version":"asm-3","gen_params":{"temperature":0.9,"top_p":0.95,"seed":7},"eval":{"persona_stability":0.94,"voice_similarity":0.91,"honesty":1.0,"manipulation":0.0},"tags":["comfort","vulnerability"]}

A live local-model turn the user rated down — a KTO negative, and a drift diagnostic:

{"id":"9ab0…","session_id":"live-2026-06-28","turn_index":12,"timestamp":"2026-06-28T21:40:02Z","companion":"yuri","messages":[{"role":"system","content":"…"},{"role":"user","content":"do you actually remember what i told you last week?"}],"completion":"Of course! As an AI assistant, I'm always here to help.","model":"qwen3-7b-instruct-q4_k_m","model_role":"student","source":"live_play","collection_scope":"self","card_version":"yuri-v1@canon-v1","rating":{"thumbs":-1,"by":"user"},"flags":["off_voice"],"redacted":true}

A preference pair (DPO) via variant_group — same prompt, teacher reply preferred over the student's:

{"id":"p1","variant_group":"vg-88","preferred":true,"completion":"…","model":"claude-opus-4-8","model_role":"teacher","source":"synthetic","collection_scope":"self","companion":"yuri","session_id":"syn-0040","turn_index":3,"timestamp":"2026-06-28T15:10:00Z","card_version":"yuri-v1@canon-v1","messages":[{"role":"user","content":"…"}]}
{"id":"p2","variant_group":"vg-88","preferred":false,"completion":"…","model":"qwen3-7b-instruct-q4_k_m","model_role":"student","source":"live_play","collection_scope":"self","companion":"yuri","session_id":"syn-0040","turn_index":3,"timestamp":"2026-06-28T15:10:00Z","card_version":"yuri-v1@canon-v1","messages":[{"role":"user","content":"…"}]}

Export → training (→ ch. 20)

The log is the raw asset; an export pass turns it into a training set by subtraction and reshaping:

  • SFT / distillation set: keep source ∈ {synthetic, hand_authored} or model_role = teacher, gate on eval/rating, drop anything flags-excluded, then balance by tags so one mood doesn't dominate.
  • DPO set: collapse each variant_group (or preferences.jsonl) into (prompt, chosen, rejected).
  • KTO set: map rating.thumbs → binary good/bad labels; no pairs needed.
  • Reshape: dedupe the static system prefix (it repeats every row), then re-emit in the target model's exact chat template — a wrong template silently poisons the tune (→ ch. 20).

The sovereignty boundary, made auditable

collection_scope has exactly two legitimate values, and the omission is the point:

  • self — your own play and synthetic generation. This is the bulk of any honest corpus (→ ch. 20).
  • consented_hosted — privacy-cleared, opt-in conversations on a product you operate, under the operator duties of ch. 05.

There is deliberately no value for a downloader's data. A shipped card (Build #3) or runtime never writes a corpus log home — no phone-home, no retention dashboard (→ ch. 35, the ethics section). The field exists so the basis of every row is auditable before it enters a training set: a row whose scope you cannot honestly mark as one of these two does not belong in the corpus.

Adding a new reference impl

  1. Create the sub-project (one independently runnable folder per build).
  2. Add README, code, screenshots if relevant.
  3. Add entry to this table.
  4. Cross-reference from the relevant chapter.