Skip to content

Branches and actions

Three branch types. One leaf type. That is the whole language.

A tick is one evaluation pass through the tree by the runtime: the cursor visits the current node, returns success or failure, and advances or retries.

Branches

Branches coordinate flow of control — which children run, in what order, what counts as success. They have children but do no work themselves.

Sequence

Run children in order. All must succeed. If any child fails, the sequence fails. Use it for linear workflows where each step depends on the previous.

yaml
type: sequence
name: Deploy_Service
children:
  - type: action
    name: Run_Tests
  - type: action
    name: Build_Image
  - type: action
    name: Push_To_Registry

If Run_Tests fails, the sequence aborts. The build never happens. The push never happens.

Selector

Run children in order until one succeeds. If all fail, the selector fails.

A selector is the decision-making primitive — the equivalent of an if/else chain.

yaml
type: selector
name: Choose_Greeting
children:
  - type: action
    name: Morning_Greeting
    steps:
      - evaluate: $VAR.time_of_day is "morning"
      - instruct: ...
  - type: action
    name: Afternoon_Greeting
    steps:
      - evaluate: $VAR.time_of_day is "afternoon"
      - instruct: ...

The selector tries Morning_Greeting's evaluate first. If it passes, the morning instruct runs and the selector finishes. Otherwise it falls through to Afternoon_Greeting.

Parallel

Run all children. All must succeed.

Use a parallel when steps are independent and can run in any order.

yaml
type: parallel
name: Gather_Context
children:
  - type: action
    name: Check_Weather
  - type: action
    name: Check_News

The agent receives both instruct requests and satisfies them in any order. If either fails, the parallel fails.

Actions

Actions are the leaves of the tree. Each is a small, focused unit of work made of two kinds of step:

yaml
type: action
name: Determine_Time
steps:
  - evaluate: $VAR.now is set
  - instruct: |
      Get the current hour from the system clock.
      Classify as "morning", "afternoon", or "evening".
      Store at $VAR.time_of_day.

evaluate

A precondition. A semantic boolean expression checked against $VAR and $CONST. The agent reads it, decides whether it is true, and submits the answer with eval(trace_output, true|false).

If false, the action fails immediately. The runtime advances by branch rules: a sequence aborts; a selector tries the next child.

instruct

The work. Free-form prose telling the agent what to do. The agent does it, writes results to $VAR, and calls submit(trace_output, "success") to advance.

An action can have multiple steps — alternating evaluates and instructs — to handle multi-stage logic in a single leaf.

Retries

Any node — composite or action — can carry a retries: N config. On failure the runtime wipes the node's internal bookkeeping (status, step index, descendants), bumps an internal retry counter, and re-ticks the node from a clean slate. After N retries are exhausted, the failure propagates normally. User state in $VAR persists across retries — that is the feedback channel between attempts.

yaml
type: sequence
name: Write_And_Review
retries: 2          # one initial attempt + 2 retries = 3 total attempts
children:
  - { type: action, name: Write,  steps: [...] }
  - { type: action, name: Review, steps: [...] }

The bundled hello-world tree — available from the Quick start panel at app.behaviors.sh — covers the first three primitives (sequence, selector, action) end-to-end.

Next

MIT licensed