Skip to Content
Behavior Tree JSON

Behavior Tree JSON

This page is the format reference for the JSON that defines an agent’s behavior tree. It covers where the file lives, the top-level structure, the fields every node shares, and the fields specific to each node type. For the concepts behind these trees, see Behavior Trees.

You usually do not hand-write this JSON. The chat surface and LLM-powered tools generate and edit behavior trees for you, then you refine them. See Authoring Behavior Trees for the recommended workflow.

Where it lives

Each agent type has one behavior tree file:

.agentloop/agents/<type>/<type>.bt.json

For example, a custom reviewer agent reads .agentloop/agents/reviewer/reviewer.bt.json. The file is plain JSON, so you can version it with the rest of your project. Editing it changes how that agent thinks the next time it runs.

Top-level structure

The file is a single JSON object. The name and tree fields are required; everything else is optional.

{ "name": "engineer", "description": "Implements a task, validates, and commits", "version": "2.0.0", "mode": "reactive", "tree": { "type": "root", "child": { "type": "sequence", "children": [] } }, "subtrees": { "runValidation": { "type": "root", "child": { "type": "action", "call": "RunTests" } } }, "blackboardDefaults": { "maxRetries": 3 } }
FieldTypeDescription
namestringIdentifier for the tree. Required.
descriptionstringHuman-readable summary.
versionstringSemantic version string.
mode"reactive" | "proactive"Execution mode. reactive waits for signals (messages, tasks); proactive polls.
treeobjectRoot node. Must be type: "root" with a single child. Required.
subtreesobjectNamed subtrees, each a root node, invoked from a branch node.
blackboardDefaultsobjectInitial values for the blackboard, the shared state all nodes can read and write.

Common node fields

Every node is an object with a type. These fields are available on any node:

FieldApplies toDescription
typeallNode type. Required.
nameallDisplay name, used in debugging and visualization.
commentallDocumentation string.
childdecoratorsA single child node (retry, repeat, flip, wait, forEach).
childrencompositesAn array of child nodes (sequence, selector, parallel, race, lotto, utility-selector).
whileallGuard { call, args, succeedOnAbort } re-checked each tick; aborts the node if it fails.
untilallExit condition { call, args }; succeeds the node when it becomes true.
entry / exit / stepallLifecycle callback names invoked on enter, leave, and each tick.

Leaf nodes (action, condition, plugin-action, logic-policy, logic-introspect) have no children. Decorators take one child. Composites take a children array. Nodes nest to arbitrary depth.

Leaf nodes

action / condition

{ "type": "action", "call": "RunTests", "args": [] }
FieldDescription
callName of the action or condition function to invoke.
argsOptional arguments array passed to the function.

An action performs work and reports success or failure. A condition checks state and reports true or false.

plugin-action

{ "type": "plugin-action", "call": "doThing", "args": [] }

Like action, but call resolves to a function supplied by a loaded plugin rather than a built-in. Use it to invoke custom tools your project registers.

Composite nodes

sequence / selector / parallel / race

{ "type": "sequence", "children": [ { "type": "condition", "call": "CheckPrecondition" }, { "type": "action", "call": "Execute" } ] }
TypeBehavior
sequenceRuns children in order; all must succeed.
selectorTries children in order; succeeds on the first that succeeds.
parallelRuns all children concurrently.
raceRuns children concurrently; terminates when the first succeeds.

lotto

{ "type": "lotto", "weights": [0.3, 0.5, 0.2], "children": [] }
FieldDescription
weightsNumeric weights for random selection; length must equal children.length.

utility-selector

Picks a child by score. Scores can be static inline weights or come from a learned model in the model store.

FieldDescription
mode"max" (greedy), "distribution" (weighted sample), or "threshold-then-random".
weightsStatic inline weights. Mutually exclusive with weightsRef.
weightsRefReference to a learned model, e.g. "my-policy@v1".
defaultScoresAuthor-provided preview scores for the UI; length equals children.length.
featuresFromBlackboard keys (dot-notation) feeding the scorer.
inertiaBonusBonus for the currently-running child, to prevent flipping.
thresholdCutoff for "threshold-then-random" mode (0–1; default 0.5).
fallbackChildChild index used when scoring fails.
exploreEpsilonExploration probability during training (0–1; typically 0 in production).

Decorator nodes

TypeFieldsBehavior
retryattempts, childRetries the child on failure up to attempts times.
repeatiterations, childRepeats the child iterations times (omit for infinite).
flipchildInverts the child’s success and failure.
waitduration, childWaits duration ms before running the child.
forEachcollection, itemKey, indexKey, continueOnFailure, childIterates an array from the blackboard.
branchrefInvokes a named subtree from the top-level subtrees map.

For forEach, collection is a dot-notation blackboard path to an array, itemKey and indexKey are where the current item and 0-based index are stored, and continueOnFailure decides whether a failed iteration aborts the loop.

LLM-powered nodes

These nodes call a model at tick time. The neurosymbolic loop relies on them; see The Neurosymbolic Loop.

llm-condition

A boolean decision from a model.

FieldDescription
promptHandlebars template with {{contextKey}} placeholders.
contextKeysBlackboard keys included in the prompt.
outputKeyBlackboard key where the boolean result is stored.
temperatureModel temperature (0–2).
confidenceThresholdMinimum confidence to trust the decision (0–1; default 0.7).
fallbackValueBoolean used when confidence is too low.
modelModel name ("haiku", "sonnet", "opus", or custom).
maxRetriesRetries on API failure.
timeoutMilliseconds before timeout.

llm-action

Structured generation, optionally with an agentic tool loop.

FieldDescription
promptHandlebars template.
contextKeysBlackboard keys to inject.
outputSchemaJSON Schema validating the structured output.
outputKeyBlackboard key for the result.
temperatureModel temperature.
cacheScope"process" caches results for the daemon lifetime, keyed on context + prompt.
allowedToolsTool names the model may invoke, enabling multi-turn loops.
maxTurns / minTurnsUpper and lower bounds on agentic turns.
subagentLoad tool, MCP, and system-prompt restrictions from a subagent template, e.g. "engineer".

llm-selector

The model chooses a named branch.

FieldDescription
branchesMap of branch name to { description, child }.
defaultBranchBranch taken when confidence is too low.
confidenceThresholdMinimum confidence to trust the selection.
contextKeysBlackboard keys included in the prompt.

llm-sequence

The model decides which optional steps run.

FieldDescription
stepsArray of { name, description, child, required? }.
minStepsMinimum number of steps that must execute.

Logic nodes

Deterministic symbolic reasoning over a rule program. See Logic Programming for the rule syntax and a full walkthrough.

logic-policy

Evaluates rules over a set of facts and writes the matching solutions to the blackboard.

FieldDescription
programRequired. Inline rule program — the relations and rules to evaluate.
queryRequired. Name of the relation to read. Supports {{key}} interpolation and optional column filters, e.g. "may_auto_merge({{changeId}})".
outputKeyRequired. Blackboard key where the result object is written.
factsInline facts (array of predicate(arg, arg) strings).
factsKeyBlackboard key holding extracted facts; supports dotted paths. Merged with facts.
ruleSelectionRule-set names to enable, each asserted as rule_enabled("Name").
ruleSelectionKeyBlackboard key holding the rule selection.
semiringHow confidence is combined: { "kind": "top-k-proofs", "k": 3 } (default) or { "kind": "min-max-prob" }.
minProbabilityDrop solutions below this probability floor. Default 0.0.
succeedOnSolutionsIf true (default), the node succeeds only when the query has at least one solution.

logic-introspect

Projects a rule program’s schema (its predicates, argument types, and vocabulary) onto the blackboard, so an upstream llm-action can be told exactly which facts it may extract.

FieldDescription
programRequired. The rule program to introspect.
outputKeyRequired. Blackboard key where the projected schema is written.

Examples

A simple sequence:

{ "name": "basic-sequence", "description": "Three actions in order", "version": "1.0.0", "tree": { "type": "root", "child": { "type": "sequence", "children": [ { "type": "action", "call": "Prepare" }, { "type": "action", "call": "Execute" }, { "type": "action", "call": "Cleanup" } ] } } }

A retry loop around an llm-action that generates code and validates it, retrying up to three times:

{ "name": "llm-with-retry", "description": "Generate code; retry up to 3 times on validation failure", "version": "1.0.0", "tree": { "type": "root", "child": { "type": "retry", "attempts": 3, "child": { "type": "sequence", "children": [ { "type": "llm-action", "name": "GenerateCode", "prompt": "Write a function to {{requirement}}", "contextKeys": ["requirement"], "outputSchema": { "type": "object", "properties": { "code": { "type": "string" } }, "required": ["code"] }, "outputKey": "generatedCode" }, { "type": "action", "call": "ValidateCode" } ] } } } }

A utility-selector that chooses an implementation strategy from features on the blackboard:

{ "name": "strategy-picker", "description": "Choose implementation strategy based on task complexity", "version": "1.0.0", "tree": { "type": "root", "child": { "type": "utility-selector", "name": "ChooseApproach", "mode": "max", "weights": [0.7, 0.2, 0.1], "featuresFrom": ["taskAnalysis.complexity", "taskAnalysis.riskLevel"], "defaultScores": [0.8, 0.5, 0.2], "fallbackChild": 1, "children": [ { "type": "action", "call": "DirectImplementation" }, { "type": "sequence", "name": "PlanFirst", "children": [ { "type": "action", "call": "CreatePlan" }, { "type": "action", "call": "ImplementByPlan" } ] }, { "type": "action", "call": "Escalate" } ] } } }

A few fields must stay in sync or the tree will fail to load: defaultScores, weights, and lotto weights must each have the same length as their children array, and a branch node’s ref must name an entry in the top-level subtrees map. The authoring tools keep these aligned for you.

Last updated on
AgentLoop — Multi-agent loops you can see and control