> ## Documentation Index
> Fetch the complete documentation index at: https://docs.upliftai.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Build, refine & simulate

You describe the call. We write the Urdu prompt, rehearse it against tough callers, fix what breaks, and hand you an assistant that's already been through its worst conversations.

The pieces, and when you need each:

* **[Build](/api-reference/authoring-an-assistant/build-an-assistant-from-a-brief)** does the whole job in one call — it writes the prompt, simulates test calls against it, judges them, and fixes what breaks. You don't wire those steps yourself.
* **[Poll](/api-reference/authoring-an-assistant/poll-a-builds-progress)** because a build takes a couple of minutes to finish.
* **[Read the record](/api-reference/authoring-an-assistant/get-an-assistants-build-record)** if you want to peek at how the test transcripts came out.
* **[Simulate](/api-reference/authoring-an-assistant/rehearse-a-call-against-a-persona)** more conversations, optionally — your own personas, your own objections.
* **Change** the assistant directly via [the update API](/api-reference/assistants/update-an-assistant) or the portal — or through [refine](/api-reference/authoring-an-assistant/refine-a-built-assistants-prompt). Refine is not recommended when you're almost there: it reconsiders the whole prompt, and like all LLM work, that can be unstable.

## What a build does

One request kicks off the whole thing. An author writes the prompt from your brief. About ten test callers rehearse it in parallel: the busy one, the suspicious one, the one who tries to jailbreak it. A judge reviews every transcript, and the prompt gets rewritten against the findings. Up to a few rounds, until the findings hit zero or the rounds run out. It takes minutes, and it survives your refresh: the `assistantId` exists from the first response.

Poll every few seconds. The `phase` tells you where it is:

| `phase`               | What's happening                                                    |
| --------------------- | ------------------------------------------------------------------- |
| `authoring`           | Writing the Urdu script                                             |
| `generating_personas` | Lining up tough test callers                                        |
| `testing`             | Trying it on them — `transcriptsDone/transcriptsTotal` counts along |
| `judging`             | Listening back to every test call                                   |
| `refining`            | Fixing what the judge found                                         |
| `persisting`          | Saving your assistant                                               |
| `done`                | Finished — now check `result.passed`                                |
| `failed`              | The run stopped; `error` says why                                   |

<Warning>Don't put the assistant on a call before `done` — until then its entire prompt is the literal text `(building…)`.</Warning>

## Writing the brief

`context` is free text, but the briefs that build best read as labelled lines:

```
Business: Shifa Clinic, Lahore
Goal: Confirm tomorrow's doctor appointments
Key message: Confirm the time, offer to reschedule if they can't come
Audience: existing patients
Contact record columns: name, phone, doctor, appointmentTime
```

The key message is the line that matters. **Always include the concrete specifics: numbers, prices, deadlines, item names, follow-up promises.** "Tell postpaid customers about 3 GB extra data for 100 rupees more per month" builds a caller that says exactly that. "An important message about your package" gives the author nothing concrete to work with.

If you have a key message or a goal, bake it into the `context` brief. If there are extra variables or attributes unique to each caller, specify them in the brief, example:

```json POST /realtime-assistants/builds theme={null}
{
  "brief": {
    "goal": "payment_reminder",
    "voiceId": "helpdesk-agent",
    "gender": "female",
    "context": "Business: Al-Hamd Autos, Karachi\nGoal: Remind customers of the pending installment\nKey message: Installment of {Amount} is due on {DueDate}, ask if they will pay by then\nAudience: existing customers with one installment pending\nContact record columns: Name, Phone, Amount, DueDate",
    "sampleRows": [
      { "Name": "عدنان اقبال", "Phone": "+923001234567", "Amount": "12,500", "DueDate": "25 August" },
      { "Name": "ثناء ملک", "Phone": "+923218765432", "Amount": "8,000", "DueDate": "27 August" }
    ]
  }
}
```

`sampleRows` (send two or three real rows) serve two purposes: they ground the test callers in real customers, and they're injected into rehearsals exactly the way production hands the agent a record per call. **Use the same keys you'll send as `variables` on real calls** — the prompt's `{tokens}` are written against them. And name your columns like a human: `Amount`, `DueDate`, `AppointmentTime` — never `Detail 1`.

## Done is not passed

The status poll's `done` means the pipeline stopped. `result.passed` tells you whether the judge was satisfied. `passed: false` still saves a callable assistant. It just means the rounds ran out with findings open. When that happens, read the chosen negative transcript in the [build record](/api-reference/authoring-an-assistant/get-an-assistants-build-record) and find the ugly moment. A small flaw — one line, one phrase — is a direct edit to the prompt. A broader miss is worth a refine.

The record also has the two sample transcripts worth reading first: the cleanest happy call and the cleanest difficult one, with Roman transliteration alongside the Urdu.

## Simulate your own callers

The build already rehearsed the standard cast — the busy one, the suspicious one, the jailbreaker. Use [simulate](/api-reference/authoring-an-assistant/rehearse-a-call-against-a-persona) for the callers only you know: your objections, your pricing pushback, the caller who names your competitor.

Describe the persona by how they act, not an adjective: "interrupts early, demands to know where you got the number, hangs up if the answer is vague." One gotcha: omit `variables` and the test caller gets your brief's first sample row, not a blank slate (an assistant with no build brief does get the blank slate).

## Refine vs edit

Most changes don't need a refine. A knob (voice, model, tools) or a small prompt fix — a line you'd reword, an opener you'd tighten — is a direct edit via [the update API](/api-reference/assistants/update-an-assistant) or the portal. Refine is for real rework of what the agent says. It reruns the whole rehearse-and-grade loop (same minutes as a build), regenerates the config from the brief so hand-edits to voice or tools don't survive it, and like any LLM pass, the result can shift in ways you didn't ask for.

When you do refine, critique like you'd brief a copywriter: name the phrase, the word, the line that's off. "Still not right" burns a real build and fixes nothing. `ownerFeedback` in Urdu works — write it in the language you want acted on. And one refine at a time: a second one while the first runs comes back as `failed` in the poll.
