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

# The Flow Builder

> Steps, how they connect, and how a turn moves through them

Open **Flow** in the agent's left rail. The flow is a set of **steps** on a canvas. Every step has **exits** — the lines out of it — and each exit points at the step that comes next.

## The canvas

| Control | What it does |
| - | - |
| **Add step** | Opens the step menu — every [step type](/chat-agents/advanced/step-types) with a one-line description, in two columns. The new step lands beside the selected one. |
| **+** at the end of a line | Every exit that points nowhere ends in a dashed line and a **+**. Pick a step type there and the new step is created already connected to that exit. |
| **Test chat** | Opens [Test Chat](/chat-agents/advanced/testing) beside the canvas, with the live step highlight. |
| **Tidy up** | Re-arranges every step left to right along its connections, so none sit on top of each other, and brings the view back to Start. Only positions change; it is saved with the next **Update**. |
| **Not publishable / Check warnings** | Appears when the flow has a problem. Hover or click it for the list; every item has **Go to step**. |
| **Find a step…** | Search by step name, step type or step number (`S12`). Picking a result zooms to the step and opens it. |

**Connecting steps.** Drag from the dot at the right of an exit row to the dot on the left of the next step. Or, in the step editor, pick the destination in the exit's **Goes to** / **Next step** box — easier when the two steps are far apart.

**Following a connection.** Each exit row on a box shows where it goes (`→ S5 Pick a day`). Click it to jump to that step, wherever it is on the canvas. **Open that step** under every **Goes to** box does the same.

**Disconnecting and deleting.** Hover a line and click the **×** in its middle to disconnect it. Hover a box and click its trash icon — or select it and press Delete — to delete a step. Lines into a deleted step are left unconnected, not removed.

**Hover.** Pointing at a box highlights every line in and out of it.

## Step numbers

Steps are numbered **S1, S2, …** breadth-first from Start, then the branches of each global intent, then anything not connected. The same numbers appear on the canvas, in the search, under each Test Chat reply, and in the plan the AI follows. They change when you rewire the flow — that is safe, because messages are tagged with the step itself, not its number.

## The step editor

Click a step to open its editor on the right. Every editor starts with a short note explaining the step type, then the step's name — shown on the canvas and read by the AI as the step's title, so name steps for what they do ("Ask for the email", not "Step 4").

## How a turn moves through the flow

A **turn** is everything the agent does in reply to one user message.

> [!NOTE]
>
> **Wait for the reply** is the central idea. A step that waits sends its message and ends the turn: the user answers it, and the next turn continues from there. A step that does not wait runs straight into the next one, in the same turn.

| Waits | Step types |
| - | - |
| Always | Send buttons, Ask & save |
| When it has buttons or AI branches, or **Wait for the reply** is on | Send template |
| When **Wait for the reply** is on | Send text, Send media, Custom function |
| Never | Condition, Update contact, Schedule call, Send contact card, Global intent |
| — | End finishes the planned flow |

So a chain like *Send text → Custom function → Condition → Send template* runs in one turn, and the user sees the text and the template together.

Within one turn the agent calls every function the turn needs first, then sends the turn's messages together, in step order. If the AI sends a step that does not wait and stops there, it is told to carry on, and the turn continues to the next step.

## Exact text or AI writes it

Steps that send a message — Send text, Send buttons, Ask & save, End — have two modes:

* **Exact text** — sent word for word by code. The AI never retypes it.
* **AI writes it** — what you write is **guidance**, and the AI writes the message from it, in the conversation's language. Use it for anything that should adapt: a greeting by name, an answer that depends on a function result, a multilingual chat.

Each message step shows a WhatsApp-style **Preview**.

### Variables in exact text

Exact text can carry values that code fills in when it is sent:

| Write | Becomes |
| - | - |
| `{{contact.first_name}}` | The contact's `first_name` attribute |
| `{{contact.first_name\|there}}` | The same, or `there` when it is empty |
| `{{contact.phone_number}}` | The contact's phone number |
| `{{book_slot.booking_id}}` | The `booking_id` field of the latest result of the `book_slot` function |
| `{{check_slots.slots.0}}` | The first item of the `slots` list in `check_slots`'s result |

A function result is available from the turn the function ran in onward — a template two turns later can still use it — for as long as that turn is within the history the agent reads ([Context Length](/chat-agents/configuration/conversation-and-features)).

## Where a value comes from

Template variables, media links, captions, file names and contact updates each take a **source**:

| Source | Filled in by | Use it for |
| - | - | - |
| **Fixed value** | Code | A link, a constant, or text with `{{contact.…}}` variables |
| **Contact attribute** | Code | Anything already on the CRM record |
| **Function result** | Code | A field of a custom function's latest result, by path (`data.slot`, `slots.0`) |
| **AI decides (prompt)** | The AI | Something only the conversation knows — "the time the user picked" |

Contact attribute and Function result sources take an optional **fallback**, used when the value is empty. Without one, a step whose code-filled value is empty is not sent, and the AI is told why.

## An exit left unconnected

An unconnected exit is allowed. It means **nothing more is planned there**: after that step the AI keeps helping within the persona's role and goal. Inside a global intent's branch it means **return to the step the conversation was on** — that is how a detour ends.

The issues list mentions an unconnected branch on the main path as a warning, so a step you have not built yet is easy to find.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.