> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://poly-ai.ferndocs.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://poly-ai.ferndocs.com/_mcp/server.

# Transition functions

> Use transition functions to control how your agent moves between steps and flows

**Prerequisites:** Familiarity with Python and [Flows](/agent-studio/flows/overview). This page covers writing code to control flow routing.

A transition function is any function that contains `flow.goto_step()` or `conv.goto_flow()`. Transition functions control how your agent moves between steps within a flow – or between flows entirely.

* **`flow.goto_step()`** moves the agent to another step in the current flow. This must be a **flow function** (scoped to the flow).
* **`conv.goto_flow()`** moves the agent to a different flow. This can be called from a flow function **or** a [global function](/agent-studio/tools/overview).

Transition functions should not be confused with [global functions](/agent-studio/tools/overview), which are shared across [flows](/agent-studio/flows/overview), [global rules](/agent-studio/behavior/general/behavior), and [Knowledge topics](/agent-studio/knowledge/fa-qs/fa-qs).

## Recognizing transition vs global functions in the UI

Global functions are distinguished in flow steps by the function symbol . You can edit them from the flow editor, but changes apply everywhere the function is used in Agent Studio.

![Global function icon shown next to a function reference in a flow step](/_fern-files/_img/84fb2832dea604fa83fc2b09f0d7b2b0b15a818eaad6cafc0de8a7f8d0dbfbfe.webp)

Global functions also have profile items in the functions tab.

![Global functions listed in the functions tab with profile details](/_fern-files/_img/f1077ad61a428cc57c624c03603bce3e5ad5afbed63c37dd22a36ef222f6230f.webp)

Transition functions (flow-scoped) only appear in the **Flow Functions** modal – they do not show up in the functions tab.

## Viewing and managing flow functions

To view and manage transition functions, click the&#x20;**&#x20;Flow functions** button in the bottom-right corner of the Flow Editor. This opens a searchable modal showing all flow functions associated with the current flow.

![Flow functions modal showing a list of transition functions for the current flow](/_fern-files/_img/f027936109c25f1fab2a0e753922a8522fbb4a42effd68ff4c4bd31e99dcf8fd.webp)

You can manage transition functions in two ways:

* **From a step** – open the step's context menu and select an existing transition or create a new one.
* **From the Flow Functions modal** – view, rename, delete, or connect transitions to steps.

Duplicating a transition auto-generates a unique name. You can then update the logic or connect it to different steps.

## Creating a transition function

1. **Connect two steps** – if no transition exists, linking two steps prompts you to create one.
2. **Name your transition** – you'll be asked to name the new function. Use a [retrospective, intent-based name](#naming-functions).
3. **Handle name conflicts** – if the name is already in use, the UI shows an error. Rename before proceeding.
4. **View usage references** – after creation, the UI shows how many times the function is referenced in prompts.

![Transition function editor showing code and step references](/_fern-files/_img/bd8a46105ff7e0acf40e5d26837435fcdafff0cc31abf1f5328819a69fc30c68.webp)

## `flow.goto_step()` signature

```python
flow.goto_step("step_name")
flow.goto_step("step_name", "condition_label")
```

* **`step_name`** (required) – the name of the target step, exactly as it appears in the Flow Editor. This is **case-sensitive**.
* **`condition_label`** (optional) – a label for the transition edge. In [Function steps](/agent-studio/flows/no-code/overview), this label appears on the edge in the visual editor and can help with readability, but routing is determined by your code, not the label.

## Example: conditional transition logic

A transition function typically checks state and moves to the appropriate step:

```mermaid
stateDiagram-v2
    [*] --> CheckVerified: check_user_verified()
    CheckVerified --> AccountDetails: user_verified = true
    CheckVerified --> VerifyIdentity: user_verified = false
    AccountDetails --> [*]
    VerifyIdentity --> CheckVerified: After verification
```

```python
def check_user_verified(conv: Conversation, flow: Flow):
    if conv.state.user_verified:
        flow.goto_step("Account details")
        return
    flow.goto_step("Verify identity")
    return
```

## Switching to a different flow with `conv.goto_flow()`

Use `conv.goto_flow()` when the conversation needs to leave the current flow entirely – for example, to start an identity verification or escalation flow.

```python
def check_verification(conv: Conversation, flow: Flow):
    attempts = conv.state.verification_attempts or 0
    if not conv.state.is_verified:
        attempts += 1
        conv.state.verification_attempts = attempts
        if attempts >= 3:
            conv.goto_flow("Identity Verification")
            return
        flow.goto_step("Retry verification")
        return
    flow.goto_step("Continue booking")
    return
```

See [triggering flows](/agent-studio/flows/triggering-flows) for more on `conv.goto_flow()`.

## Naming functions

Function names directly shape LLM behavior. Use **retrospective, intent-based names** that describe what just happened or what was resolved – not where the flow is going next.

* Good: `last_name_given`, `phone_number_collected`, `reservation_confirmed`
* Also good: `save_postcode`, `check_availability`
* Avoid: `goto_next_step`, `continue_flow`, `go_to_collect_phone_number`

Retrospective names anchor the LLM's reasoning around what the user accomplished, which produces more natural responses. Forward-looking names like `start_confirmation` can cause the model to narrate its own flow logic ("Okay, moving on to confirmation now").

Some teams use past-tense verbs for transition functions (`phone_number_given`) and present-tense for global functions (`get_status_of_order`). Pick a convention and keep it consistent across your project.

## Common mistakes

#### Avoid

Never chain multiple tool calls in a single step. This increases the failure rate and makes flow behavior unpredictable.

```python
save_user_input()
check_availability()
flow.goto_step("Next")
```

#### Instead, use

Consolidate step logic into one function wherever possible.

```python
def save_and_check(conv: Conversation, flow: Flow, value: str):
    conv.state.value = value
    if check_availability(value):
        flow.goto_step("Confirm booking")
        return
    flow.goto_step("Unavailable")
    return
```

## Best practices

* Always use `return` immediately after `flow.goto_step()` or `conv.goto_flow()`. Omitting it can lead to unexpected behavior – only the **last** `goto_step()` call in a function is executed.
* Keep transition functions focused – one decision, one outcome.
* Transition functions are only visible to the LLM if referenced in the current step's prompt.
* Use them to encapsulate branching logic and control step sequencing – not to generate agent responses.
* If your transition function needs to trigger user-facing output, return a message string **instead of** calling `goto_step()`. These are two separate patterns – don't mix them in the same code path.

> **Warning**
>
> **Debugging silent transition failures**
>
> If a transition seems to do nothing, the most common cause is a step name mismatch. Because `flow.goto_step()` is **case-sensitive**, `"CollectName"` and `"collectname"` are different targets. A mismatched name fails silently – there is no error message.
>
> To diagnose:
>
> * Open the **Flow Functions** modal and check the exact step name spelling.
> * Look for trailing spaces or special characters in step names.
> * Use `flow.current_step` in your function to log the current step name for debugging.
>
> When you rename a step in the Flow Editor, Agent Studio automatically updates `flow.goto_step()` and `conv.goto_flow()` references across the project. However, always verify after renaming – especially if you have step names referenced in strings or variables that the auto-rename may not catch.

## Next steps

#### [Flow object](/advanced/code-driven-flows/object)

Python reference for goto_step() and current_step.

#### [Triggering flows](/agent-studio/flows/triggering-flows)

All the ways to start a flow using conv.goto_flow().

#### [No-code flows](/agent-studio/flows/no-code/overview)

Default steps vs Function steps and how routing works.