How transitions work
When a node completes, it produces an outcome with a status (success, fail, partial_success) and optional signals like a preferred label or suggested next node. Fabro evaluates the outgoing edges in a fixed priority order:
- Condition match — Edges with a
conditionattribute are evaluated first. If one or more conditions match, the edge with the highestweightwins (lexical tiebreak on target node ID). - Preferred label — If the node’s outcome includes a preferred label (e.g. from a human gate selection), the edge whose
labelmatches is chosen. - Suggested next — If the node suggests a specific next node ID, the edge pointing to that node is chosen.
- Unconditional fallback — Edges without conditions are considered last, again using
weightthen lexical tiebreak.
Edge attributes
| Attribute | Description |
|---|---|
label | Display text on the edge; also used for human gate option matching |
condition | Boolean expression that must evaluate to true for this edge (see below) |
weight | Numeric priority for tiebreaking (higher wins, default: 0) |
Conditions
Edge conditions are boolean expressions evaluated against the stage outcome and run context. Conditions go in thecondition attribute on an edge:
Available keys
| Key | Resolves to |
|---|---|
outcome | The stage status: success, fail, or partial_success |
preferred_label | The label selected by a human gate |
context.KEY | A value from the run context (e.g. context.tests_passed) |
KEY | Shorthand for context lookup (without the context. prefix) |
Operators
| Operator | Example | Description |
|---|---|---|
= | outcome=success | Equality |
!= | outcome!=fail | Inequality |
> | context.score > 80 | Greater than (numeric) |
< | context.count < 5 | Less than (numeric) |
>= | context.score >= 80 | Greater than or equal (numeric) |
<= | context.count <= 10 | Less than or equal (numeric) |
contains | context.message contains error | Substring match, or array membership |
matches | context.version matches ^v\d+ | Regular expression match |
"false", and not "0":
Combining conditions
Use&& (AND), || (OR), and ! (NOT) to build compound expressions. && binds tighter than ||:
Agent transitions
Agent and prompt nodes can influence which edge is taken by including a JSON object in their response with routing directives. Fabro scans the LLM output for the last JSON object containing any of these fields:| Field | Effect |
|---|---|
preferred_next_label | Matched against edge labels (same as human gate selection) |
suggested_next_ids | Ordered list of preferred target node IDs |
context_updates | Key-value pairs merged into the run context for downstream conditions |
Human gate transitions
Human gates use edge labels to present options to the user. The selected label becomes thepreferred_label in the outcome, and Fabro matches it to the corresponding edge:
[A], [R], [S] prefixes are keyboard accelerators — Fabro strips them when matching, so the user can type just the letter.
Unconditional edges
An edge without acondition attribute always matches. When a node has a single outgoing edge, it doesn’t need a condition:
Weight tiebreaking
When multiple edges match (e.g. two unconditional edges),weight determines the winner. Higher weight wins: