Skip to content

One conversation, start to finish

Every conversation in a Convo corpus took the same path. It was planned from a seed, written by a model and checked three ways, and then it waited for a person to read it. Here is that path, one stop at a time.

Filters, cheapest firstMemory updatewhat the friend now knows, for the next conversation in this threadSeed(run_seed, index)Generateyour model, anyOpenAI-styleendpointRulesLayer 1no model callsDiversityLayer 2no model callsJudgeLayer 3one cheap callAcceptedjudge scoresstoredExportJSONLassistant_embodiednear_duplicatejudge_below_thresholdRejected, every one with a reasonFilters, cheapest firstMemory updatefor the nextconversation inthis threadSeed(run_seed, index)Generateyour model, anyOpenAI-styleendpointRulesLayer 1no model callsDiversityLayer 2no model callsJudgeLayer 3one cheap callAcceptedjudge scoresstoredExportJSONLassistant_embodiednear_duplicatejudge_below_thresholdRejected, every one with a reason

Who is talking, and why today

Before any model call, the run plans every conversation from its run seed and its position in the run: a persona, an assistant voice, a mood, an occasion, the threads the person will bring up, a length band, an ending and what the friend remembers from last time.

Every conversation stores the seed that planned it. By default the sampler leans toward personas earlier runs used less. Turn that cross-run weighting off, keep the same run seed, “Target count”, “Persona cap” and length mix, and a run plans the same people again, which is how we compared our own prompt sets. Threads can still differ a little, because memory carries over what earlier conversations produced. “Seed preview” shows the plan before you spend anything.

Seed preview listing planned conversations, one row per seed, with persona, voice, mood and occasion.

Assembled from slots, rendered for this seed

The generation prompt has 11 slots in a fixed order: frame, user persona, assistant voice, register, memory, occasion, threads, quirks, ending, examples and output rules. A prompt set picks one segment per slot, or a random one per conversation. Each segment is a template that reads differently for every seed.

The run keeps a snapshot of its config and the rendered segment bodies, so editing a segment later never changes what a finished run used.

The full assembled prompt for one seed. Each part is labelled with the slot and the segment it came from.

Single-pass or duo, on the backend you choose

In single-pass mode one model writes the whole conversation in a single call. In duo mode the person and the friend are two separate model roles taking turns, and the friend's side never sees the persona card. Either way the request goes to an OpenAI-compatible server: Ollama Cloud, a local Ollama, or anything else that speaks the same API.

The run page updates live: “Generated”, “Accepted”, “Rejected”, the “Rate”, the “ETA” and what the run has cost so far. “Pause”, “Resume” and “Cancel” are there when you need them.

A finished run page with its counters, the reject reasons and the diversity panel.

Cheapest check first

Layer 1 parses the text and applies hard rules. The friend never claims a body, a place or a shared past. No support-bot or therapy register. The friend only names people, places and events the person mentioned or that are in its memory of them. Turn lengths have to look like texting. Layer 2 compares the conversation with the rest of the workspace's conversations, so near-copies don't pile up. Layer 3 is a model judge that scores what passed the first two on warmth, mood response, naturalness and more, and stores the scores.

Layer 1 · Rulesno model callsParse, turn shape and length, plus phrase lists you edit in the appassistant_embodiedassistant_botspeakassistant_invented_memoryLayer 2 · Diversityno model callsMinHash against the rest of the workspacenear_duplicateLayer 3 · Judgeone cheap callScores are stored, so thresholdscan be re-cut without regeneratingjudge_below_thresholdAccepted

Every reject keeps its reason. Here is where the pilot's rejects happened.

From written to kept, paired pilot
102 conversations across 3 prompt sets
Source: Pilot runs, Convo database, as of 2026-10-30
From written to kept, paired pilot
StageRemainingShare of first stageRemoved at this stage
Written102100%-
Passed Layer 1: rules4241.2%60
Passed Layer 2: diversity4241.2%0
Passed Layer 3: judge3635.3%6
Why conversations were rejected
All 66 rejects, paired pilot
Source: Pilot runs, Convo database, as of 2026-10-30
Why conversations were rejected
CategoryValue
Friend knew a fact only the persona card had16
Person used the friend’s name too often14
Too long or too short for its length band11
Too few short, texty messages10
Stage directions like *smiles*5
Friend claimed a body or a place2
Support-bot phrasing1
Markdown formatting1
Judge scored it under a threshold6

Layer 2 rejected nothing in these runs: with a few dozen conversations per run, nothing came close enough to a copy. It matters more as a corpus grows.

The friend remembers, and only what it should

Conversations between one persona and one voice form a thread. When a conversation is accepted, Convo writes a short summary of it into the thread's memory, and the next conversation in the thread starts from that summary. Memory is the only shared history the friend has, which is why the memory check in Layer 1 can be strict.

A viewer that looks like a messaging app

Click a bubble to edit it. Insert, split, merge or swap turns. Find and replace within a conversation, or, as an admin, across a thread, a run or everything, with a preview of every match and “Undo batch” afterwards. “Review” steps through a run from the keyboard, and “Calibration” compares the judge with your labels.

A conversation in the viewer with the drawer open, showing its seed and judge scores.

JSONL with user and assistant roles

An export writes one conversation per line. Keep the seed, judge scores and generation details on each line, or tick “Roles only” for just the messages. A guard keeps persona names out of every file: a conversation that breaks the rule is left out and listed in a report, or the export is refused, your choice.

See how much of this you can change

The Export conversations dialog: run, statuses, Roles only, the files option and the persona-name guard.