Transitions & Branching

Task chains are state machines. When a task finishes running its handler, the chain evaluates its transition rules to determine which task to execute next.

"transition": {
  "branches": [
    { "operator": "equals", "when": "tool-call", "goto": "run_tools" },
    { "operator": "default", "when": "",         "goto": "end" }
  ]
}

How transitions work

  1. The current task returns a result string (the "eval").
  2. The engine checks the transition.branches array from top to bottom.
  3. It evaluates the when condition against the eval string using the operator.
  4. The first branch that evaluates to true determines the next step (goto).

If the branch specifies "goto": "end", the chain terminates successfully.

on_failure

A task ID to jump to when the current task raises an error — evaluated before any branch conditions. If on_failure is absent and the task errors, the chain terminates.

"transition": {
  "on_failure": "error_handler",
  "branches": [
    { "operator": "default", "when": "", "goto": "next_step" }
  ]
}

Operators

OperatorHow it matchesExample
equalsExact string match"when": "tool-call" matches "tool-call"
containsSubstring match"when": "fail" matches "api_failure"
starts_withPrefix match"when": "err" matches "error_timeout"
ends_withSuffix match"when": "_ok" matches "write_ok"
>Numeric greater-than"when": "3" matches "5"
<Numeric less-than"when": "10" matches "7"
in_rangeInclusive numeric range (min,max)"when": "200,299" matches "201"
defaultAlways matchesUsed as the fallback at the end of the array

What do tasks return?

Each handler returns a different eval string that you can branch on:

  • chat_completion: Returns "stop", "tool-call", or "length".
  • execute_tool_calls: Returns "ok" or "error".
  • hook: Usually returns "ok" or "failed".
  • prompt_to_string: Returns the rendered template string.
  • prompt_to_int: Returns the decimal string of the parsed integer (e.g. "42").
  • noop: Passes the input through; eval string mirrors the input value.
  • raise_error: Terminates the chain with an error — no branch is evaluated.

Branch Composition

When a branch is taken, you can merge or store the task's output into a chain variable using the compose object.

{
  "operator": "default",
  "when": "",
  "goto": "next_step",
  "compose": {
    "with_var": "summary",
    "strategy": "append_string_to_chat_history"
  }
}
FieldDescription
with_varName of the chain variable to write to
strategyHow to combine the task output with the existing variable (see below)

Compose strategies:

StrategyBehaviour
overrideReplace the target variable with the task output. If both are maps, keys are merged (task output wins on conflict).
merge_chat_historiesConcatenate two chat histories — task output first, then the existing variable.
append_string_to_chat_historyAppend the task's string output as an assistant message to an existing chat history variable.

If strategy is absent, the engine auto-selects: merge_chat_histories when both values are chat histories, override otherwise. Later tasks can reference the variable with {{.summary}} in their templates.