> For the index of every page in Orbital's docs, read https://docs.beta.runorbital.dev/llms.txt.

# Add branches

> Send a run to different steps with conditions on its edges

Send a run to different steps depending on what it has just learned. Put a `condition` on each edge that leaves the step, and the run follows the first one that matches.

```dot title="conditional.dot"
classify [prompt="If the goal asks for a greeting, choose greet. Otherwise choose explain.", outputs="route:choice"]
classify -> greet [condition="route == 'greet'", weight="2"]
classify -> explain [condition="route == 'explain'", weight="1"]
```

## How conditions choose the next step

Routing lives on edges, not in a decision node. Each edge that leaves a step either carries a `condition` or is the fallback. A condition compares one context value with a literal, such as `verdict == 'pass'`, or tests a value on its own, such as `pr.mergeable`.

When a step succeeds, Orbital tries its conditioned edges from the highest `weight` down and takes the first match. Only then does it consider the fallback. Two conditioned edges from one step cannot share a weight.

You cannot combine conditions or compare two context values, so every route stays readable in the workflow. The [`condition`](/reference/attributes/#condition) entry lists every form a condition takes.

![The workflow editor canvas shows edges leaving an agent step, each labelled with a condition and a weight such as verdict == 'reject' · w3, and a dashed edge labelled else.](/screenshots/workflow-editor.webp?v=85a9c6275a)

*Each conditioned edge shows its condition and weight; the dashed else edge is the fallback.*

## Choose what to branch on

Decide first what produces the value you branch on. The answer changes the cost and the reliability of the branch.

- Use a built-in probe when Orbital already observes the fact. The [ticket workflow](/examples/workflows/ticket/) routes on pull request state without asking an agent whether a merge happened.
- For another exact observation, use a script command with declared `bool`, `number` or `text` facts. Its last line of output must be the JSON object exactly as declared. Keep the script read-only when it only inspects something.
- For judgement, give an agent a `choice` output. Orbital takes the allowed values from the conditions on the step's outgoing edges and refuses any other answer. So `outputs="verdict:choice"` with edges for `pass` and `reject` accepts nothing else.

A probe or a script gives an exact answer at no agent cost. The example below branches on judgement, so an agent makes the choice.

## Cover every case

A branching step needs a fallback, an edge with no condition, unless its conditions already cover every value of its `choice` output. A run where no edge matches stops with an error, so validation asks for the fallback before the run starts.

:::note
A fallback handles successful results outside your named cases. It never handles a failed step. Route a failure with its own condition, `outcome == 'failed'`, as [Add a loop](/workflows/add-a-loop/) and [Error handling](/reference/error-handling/) explain.
:::

## Before you start

You need a harness you have signed in to, and a project in Orbital. Any project works. It does not need to be a Git repository, unless you run the example with Codex, which needs one. See [Projects and folders](/projects/).

## 1. Download the example

[Download the example](/conditional.zip) and unpack it into `~/.orbital/workflows/`. Keep every relative path.

![classify selects greet or explain; both reach done.](/conditional.svg?v=56bd802163)

```dot title="conditional.dot"
digraph conditional {
  graph [version="1", entry="classify"]
  classify [tool_access="Read only", prompt="If the goal asks for a greeting, choose greet. Otherwise choose explain.", outputs="route:choice"]
  greet [tool_access="Read only", prompt="Write a friendly greeting."]
  explain [tool_access="Read only", prompt="Explain the goal in one sentence."]
  done [shape="Msquare"]
  classify -> greet [condition="route == 'greet'", weight="2"]
  classify -> explain [condition="route == 'explain'", weight="1"]
  greet -> done
  explain -> done
}
```

`classify` declares `outputs="route:choice"`. Orbital takes the allowed values, `greet` and `explain`, from the conditions on its outgoing edges, and refuses any other answer before it reaches context. The two edges carry different weights, so the higher one is tried first. The conditions cover every allowed value, so this step needs no fallback.

Every step has the Read only tool access, so none of them can change files. Codex can run commands to read files because its read-only sandbox prevents writes.

[Download conditional.dot](/examples/conditional/conditional.dot)

## 2. Validate it

```sh
orbital validate ~/.orbital/workflows/conditional.dot
```

## 3. Run it

Choose **New task**, pick any project, and choose the `conditional` workflow and your harness. One project serves every example. Use a greeting as the goal to select `greet`, or any other goal to select `explain`.

Exactly one response step runs before `done`. The run's **Context** tab shows each value the run holds and the step that set it.

![The run page's Context tab lists the values held by the run, each with the step that set it on the right.](/screenshots/run-context.webp?v=3e79bd8607)

*The Context tab shows which step set each value.*

:::caution
A later step that reads a value produced on only one branch fails validation. Check [Error handling](/reference/error-handling/) before you join branches back together.
:::

## Related

- [`condition`](/reference/attributes/#condition): every form a condition takes, and the fallback rules.
- [Add a loop](/workflows/add-a-loop/): send rejected work back for repair, with a bound.
- [Pass context between steps](/workflows/pass-context/): the values a condition can read.
- [Error handling](/reference/error-handling/): what happens when a step fails.
