Rhizomorph Behavior Trees API Reference¶
Core Module¶
mycorrhizal.rhizomorph.core ¶
Rhizomorph - Asyncio Behavior Tree Framework
A dual-API framework for defining and executing behavior trees with support for asyncio, multi-file composition, and type-safe blackboard interfaces.
Two Usage Patterns:
-
Decorator DSL (Declarative): from mycorrhizal.rhizomorph.core import bt, Runner, Status
@bt.tree def MyBehaviorTree(): @bt.action async def do_work(bb) -> Status: return Status.SUCCESS
@bt.condition def should_work(bb) -> bool: return bb.work_available @bt.root @bt.sequence def root(): yield should_work yield do_workrunner = Runner(MyBehaviorTree, bb=blackboard) result = await runner.tick_until_complete()
-
TreeBuilder API (Programmatic): from mycorrhizal.rhizomorph.core import TreeBuilder, Runner, Status
builder = TreeBuilder("MyTree")
has_battery = builder.condition("has_battery", lambda bb: bb.battery > 20) move_forward = builder.action("move_forward", move_func)
Fluent wrapper chaining¶
protected_move = move_forward.gate(has_battery).timeout(5.0).retry(3)
patrol = builder.sequence(has_battery, protected_move, memory=True) tree = builder.build(patrol)
runner = Runner(tree, bb=blackboard) result = await runner.tick_until_complete()
Key Classes
Status - Result status for behavior tree nodes (SUCCESS, FAILURE, RUNNING, etc.) Runner - Runtime for executing behavior trees Node - Base class for all behavior tree nodes Action - Leaf node that executes a function Condition - Leaf node that evaluates a predicate Sequence - Composite that runs children in order Selector - Composite that runs children until one succeeds Parallel - Composite that runs children concurrently TreeBuilder - Programmatic API for building trees without decorators
Multi-file Composition
Use bt.subtree() or builder.subtree() to reference trees defined in other modules: from other_module import OtherTree
@bt.tree
def MainTree():
@bt.root
@bt.sequence
def root():
yield bt.subtree(OtherTree)
# Or with TreeBuilder:
builder = TreeBuilder("MainTree")
builder.root(builder.sequence(
builder.subtree(OtherTree),
other_action
))
Status ¶
Bases: Enum
Result status for behavior tree node execution.
Note
Composite nodes use these statuses to determine control flow: - Sequence stops on first FAILURE - Selector stops on first SUCCESS - Parallel waits for all children, fails if any fail
ExceptionPolicy ¶
Bases: Enum
Policy for handling exceptions in action/condition nodes.
RecursionError ¶
Bases: Exception
Raised when recursive behavior tree structure is detected
Node ¶
Node(name: Optional[str] = None, exception_policy: ExceptionPolicy = LOG_AND_CONTINUE)
Bases: Generic[BB]
Base class for behavior tree nodes.
All behavior tree nodes inherit from this class. Nodes are executed by calling the tick() method, which returns a Status indicating the result of execution.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
Optional[str]
|
Optional name for this node (used in debugging and logging) |
None
|
exception_policy
|
ExceptionPolicy
|
How to handle exceptions during execution |
LOG_AND_CONTINUE
|
Attributes:
| Name | Type | Description |
|---|---|---|
name |
str
|
Node name |
parent |
Optional[Node[BB]]
|
Parent node in the tree |
exception_policy |
Exception handling policy |
|
_entered |
bool
|
Whether on_enter has been called |
_last_status |
Optional[Status]
|
Last status returned by tick |
Methods:
| Name | Description |
|---|---|
tick |
Execute the node, return Status |
on_enter |
Called when node is first entered |
on_exit |
Called when node exits (not RUNNING) |
reset |
Reset node state for reuse |
Source code in src/mycorrhizal/rhizomorph/core.py
Action ¶
Action(func: Callable[..., Any], exception_policy: ExceptionPolicy = LOG_AND_CONTINUE)
Bases: Node[BB]
Leaf node that executes a function.
Action nodes wrap sync or async functions that perform work or check conditions. The function can return: - Status enum (SUCCESS, FAILURE, RUNNING, etc.) - bool (True -> SUCCESS, False -> FAILURE) - None (treated as SUCCESS)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
func
|
Callable[..., Any]
|
Function to execute (sync or async) |
required |
name
|
Optional name for this action |
required | |
exception_policy
|
ExceptionPolicy
|
How to handle exceptions |
LOG_AND_CONTINUE
|
The function signature can be: - func(bb) -> Status | bool | None - func(bb, tb) -> Status | bool | None
where bb is the blackboard and tb is an optional timebase.
Source code in src/mycorrhizal/rhizomorph/core.py
Condition ¶
Condition(func: Callable[..., Any], exception_policy: ExceptionPolicy = LOG_AND_CONTINUE)
Bases: Action[BB]
Boolean leaf: True→SUCCESS, False→FAILURE (status also accepted).
Source code in src/mycorrhizal/rhizomorph/core.py
Sequence ¶
Sequence(children: Sequence[Node[BB]], *, memory: bool = True, name: Optional[str] = None, exception_policy: ExceptionPolicy = LOG_AND_CONTINUE)
Bases: Node[BB]
Sequence (AND): fail/err fast; RUNNING bubbles; all SUCCESS → SUCCESS.
Memory Behavior
When memory=True (default), the sequence remembers its position across ticks. This allows the sequence to progress through its children incrementally.
When memory=False, the sequence restarts from the beginning on every tick. This is useful for reactive sequences that should always start from the first child.
Important Note on do_while Loops
If a sequence is used as the child of a do_while loop, it typically needs memory=True to make progress. Without memory, the sequence will restart from its first child on each tick, preventing it from completing all children.
Example: @bt.sequence(memory=True) # Required for progress def image_samples(): yield bt.subtree(MoveToSample) yield send_image_request yield bt.subtree(IncrementSampleCounter)
@bt.sequence(memory=True)
def happy_path():
yield bt.do_while(samples_remain)(image_samples)
yield set_pod_to_grow
Without memory=True on image_samples, the do_while loop would never progress past MoveToSample because the sequence would restart each tick.
Source code in src/mycorrhizal/rhizomorph/core.py
Selector ¶
Selector(children: Sequence[Node[BB]], *, memory: bool = True, name: Optional[str] = None, exception_policy: ExceptionPolicy = LOG_AND_CONTINUE)
Bases: Node[BB]
Selector (Fallback): first SUCCESS wins; RUNNING bubbles; else FAILURE.
Memory Behavior
When memory=True (default), the selector remembers its position across ticks. This allows the selector to continue trying children from where it left off.
When memory=False, the selector restarts from the beginning on every tick. This is useful for reactive selectors that should always re-evaluate from the first child.
Important Note on do_while Loops
Similar to Sequence, if a selector is used as the child of a do_while loop, it typically needs memory=True to make progress. Without memory, the selector will restart from its first child on each tick.
Source code in src/mycorrhizal/rhizomorph/core.py
Parallel ¶
Parallel(children: Sequence[Node[BB]], *, success_threshold: int, failure_threshold: Optional[int] = None, name: Optional[str] = None, exception_policy: ExceptionPolicy = LOG_AND_CONTINUE)
Bases: Node[BB]
Parallel: tick all children per tick concurrently. - success_threshold (k) SUCCESS to report SUCCESS - failure_threshold defaults to n-k+1 (cannot reach success anymore) to report FAILURE Otherwise RUNNING.
Source code in src/mycorrhizal/rhizomorph/core.py
RateLimit ¶
RateLimit(child: Node[BB], *, hz: Optional[float] = None, period: Optional[float] = None, name: Optional[str] = None, exception_policy: ExceptionPolicy = LOG_AND_CONTINUE)
Bases: Node[BB]
Throttle starting the child to at most 1 per period (or hz). If child is RUNNING, do not throttle (avoid starvation).
Source code in src/mycorrhizal/rhizomorph/core.py
Gate ¶
Gate(condition: Node[BB], child: Node[BB], name: Optional[str] = None, exception_policy: ExceptionPolicy = LOG_AND_CONTINUE)
Bases: Node[BB]
Guard a child with a condition
SUCCESS → tick child RUNNING → RUNNING else → FAILURE
Source code in src/mycorrhizal/rhizomorph/core.py
When ¶
When(condition: Node[BB], child: Node[BB], name: Optional[str] = None, exception_policy: ExceptionPolicy = LOG_AND_CONTINUE)
Bases: Node[BB]
Conditionally execute a child, returning SUCCESS if the condition fails.
Unlike gate(), when() does NOT fail the parent when the condition is false. This is useful for optional steps or feature flags in sequences.
Behavior
- If condition returns SUCCESS → execute child, return child's status
- If condition returns RUNNING → return RUNNING
- Otherwise → return SUCCESS (skip but don't fail parent)
Example
yield bt.when(feature_enabled)(optional_action)
If feature_enabled is false, returns SUCCESS and sequence continues¶
Source code in src/mycorrhizal/rhizomorph/core.py
Match ¶
Match(key_fn: Callable[[Any], Any], cases: List[Tuple[Any, Node[BB]]], name: Optional[str] = None, exception_policy: ExceptionPolicy = LOG_AND_CONTINUE)
Bases: Node[BB]
Pattern-matching dispatch node.
Evaluates a key function against the blackboard, then checks each case in order. The first matching case's child is executed. If the child completes (SUCCESS or FAILURE), that status is returned immediately.
Cases can match by
- Type: isinstance(value, case_type)
- Predicate: case_predicate(value) returns True
- Value: value == case_value
- Default: always matches (should be last)
If no case matches and there's no default, returns FAILURE.
Source code in src/mycorrhizal/rhizomorph/core.py
_matches ¶
Check if a matcher matches the given value.
Source code in src/mycorrhizal/rhizomorph/core.py
DoWhile ¶
DoWhile(condition: Node[BB], child: Node[BB], name: Optional[str] = None, exception_policy: ExceptionPolicy = LOG_AND_CONTINUE)
Bases: Node[BB]
Loop decorator that repeats its child while a condition is true.
Behavior
- Evaluate condition
- If condition is FALSE → return SUCCESS (loop complete)
- If condition is TRUE → tick child
- If child returns RUNNING → return RUNNING (resume child next tick)
- If child returns SUCCESS → reset child, return RUNNING (re-check condition next tick)
- If child returns FAILURE → return FAILURE (loop aborted)
The "return RUNNING after child SUCCESS" prevents infinite loops within a single tick.
Source code in src/mycorrhizal/rhizomorph/core.py
TryCatch ¶
TryCatch(try_block: Node[BB], catch_block: Node[BB], name: Optional[str] = None, exception_policy: ExceptionPolicy = LOG_AND_CONTINUE)
Bases: Node[BB]
Try-catch error handling node.
Executes the try block first. If it returns SUCCESS, that status is returned. If the try block returns FAILURE, the catch block is executed instead. Returns SUCCESS if either block succeeds, FAILURE if both fail.
This is semantically equivalent to a selector with two children, but provides clearer intent and better visualization with labeled edges.
Source code in src/mycorrhizal/rhizomorph/core.py
_DefaultCase ¶
Sentinel for default case in match expressions.
CaseSpec
dataclass
¶
Specification for a case in a match expression.
_WrapperChain ¶
_WrapperChain(builders: Optional[List[Callable[..., Any]]] = None, labels: Optional[List[str]] = None, metadata: Optional[List[Dict[str, Any]]] = None)
Fluent factory for decorator stacks that read left→right.
chain = bt.failer().gate(battery_ok).timeout(0.12)
yield chain(engage)
Source code in src/mycorrhizal/rhizomorph/core.py
when ¶
Add a conditional wrapper that executes the child only when condition is true.
Unlike gate(), when() returns SUCCESS (not FAILURE) when the condition fails. This allows sequences to continue when optional steps are skipped.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
condition_spec_or_fn
|
Union['NodeSpec', Callable[[Any], Any]]
|
A node spec or callable that returns True/False |
required |
Returns:
| Type | Description |
|---|---|
'_WrapperChain'
|
The chain for further wrapping |
Example
yield bt.when(is_enabled)(optional_action)
If is_enabled is False, returns SUCCESS and sequence continues¶
Source code in src/mycorrhizal/rhizomorph/core.py
__call__ ¶
Apply the chain to a child spec → nested decorator NodeSpecs. Left→right call order becomes outermost→…→innermost when built.
Source code in src/mycorrhizal/rhizomorph/core.py
_CaseBuilder ¶
_MatchBuilder ¶
_DoWhileBuilder ¶
_BT ¶
User-facing decorator/constructor namespace.
Source code in src/mycorrhizal/rhizomorph/core.py
action ¶
Decorator to mark a function as an action node.
Source code in src/mycorrhizal/rhizomorph/core.py
condition ¶
Decorator to mark a function as a condition node.
Source code in src/mycorrhizal/rhizomorph/core.py
sequence ¶
sequence(*args: Union[F, NodeSpec, Callable[[Any], Any]], memory: bool = True) -> Union[F, Callable[[F], F], NodeSpec]
Decorator to mark a generator function as a sequence composite.
Can be used in three ways
Memory Parameter
The memory parameter controls whether the sequence remembers its position across ticks:
- memory=None (default): Use the Runner's memory setting
- memory=True: Remember position, allowing incremental progress
- memory=False: Restart from beginning each tick (reactive behavior)
IMPORTANT: If a sequence is inside a do_while loop and needs to execute all its children incrementally, use memory=True. Otherwise, the sequence will restart from the first child on every tick and never complete.
Example: # CORRECT - sequence progresses through children @bt.sequence(memory=True) def process_samples(): yield move_to_sample yield capture_image yield bt.do_while(samples_remain)(process_samples)
# WRONG - sequence restarts at move_to_sample every tick
@bt.sequence(memory=False)
def process_samples():
yield move_to_sample
yield capture_image # Never reached!
yield bt.do_while(samples_remain)(process_samples)
Source code in src/mycorrhizal/rhizomorph/core.py
1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 | |
_sequence_from_children ¶
Create a sequence NodeSpec from child nodes.
Source code in src/mycorrhizal/rhizomorph/core.py
_sequence_impl ¶
Implementation of sequence decorator.
Source code in src/mycorrhizal/rhizomorph/core.py
selector ¶
selector(*args: Union[F, NodeSpec, Callable[[Any], Any]], memory: bool = True) -> Union[F, Callable[[F], F], NodeSpec]
Decorator to mark a generator function as a selector composite.
Can be used in three ways
The memory parameter defaults to None, which means use the Runner's memory setting. Explicitly set to True or False to override the Runner's setting.
Source code in src/mycorrhizal/rhizomorph/core.py
_selector_from_children ¶
Create a selector NodeSpec from child nodes.
Source code in src/mycorrhizal/rhizomorph/core.py
_selector_impl ¶
Implementation of selector decorator.
Source code in src/mycorrhizal/rhizomorph/core.py
parallel ¶
Decorator to mark a generator function as a parallel composite.
Source code in src/mycorrhizal/rhizomorph/core.py
when ¶
when(condition: Union[NodeSpec, Callable[[Any], Any]]) -> _WrapperChain
Create a conditional wrapper that executes the child only when condition is true.
Unlike gate(), when() returns SUCCESS (not FAILURE) when the condition fails. This is useful for optional steps or feature flags in sequences.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
condition
|
Union[NodeSpec, Callable[[Any], Any]]
|
A node spec or callable that returns True/False |
required |
Returns:
| Type | Description |
|---|---|
_WrapperChain
|
A wrapper chain that can be applied to a child node |
Example
@bt.sequence def my_sequence(): yield bt.when(feature_enabled)(optional_feature) yield next_step # Always reached, even if flag is disabled
Source code in src/mycorrhizal/rhizomorph/core.py
match ¶
Create a pattern-matching dispatch node.
Usage
bt.match(lambda bb: bb.current_action, name="action_type")( bt.case(ImageAction)(bt.subtree(handle_image)), bt.case(MoveAction)(bt.subtree(handle_move)), bt.case(lambda a: a.priority > 5)(bt.subtree(handle_urgent)), bt.defaultcase(log_unknown), )
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key_fn
|
Callable[[Any], Any]
|
Function that extracts the value to match against from the blackboard |
required |
name
|
Optional[str]
|
Optional display name for the match node (useful when key_fn is a lambda) |
None
|
Returns:
| Type | Description |
|---|---|
'_MatchBuilder'
|
A builder that accepts case specs and returns a NodeSpec |
Source code in src/mycorrhizal/rhizomorph/core.py
case ¶
Define a case for a match expression.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
matcher
|
Any
|
Can be: - A type: matches via isinstance(value, matcher) - A callable: matches if matcher(value) returns True - Any other value: matches via value == matcher |
required |
Returns:
| Type | Description |
|---|---|
'_CaseBuilder'
|
A builder that accepts a child node spec |
Source code in src/mycorrhizal/rhizomorph/core.py
defaultcase ¶
defaultcase(child: Union[NodeSpec, Callable[[Any], Any]]) -> CaseSpec
Define a default case for a match expression (matches anything).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
child
|
Union[NodeSpec, Callable[[Any], Any]]
|
The node to execute if this case matches |
required |
Returns:
| Type | Description |
|---|---|
CaseSpec
|
A CaseSpec that always matches |
Source code in src/mycorrhizal/rhizomorph/core.py
do_while ¶
Create a loop that repeats its child while a condition is true.
Usage
@bt.condition def samples_remain(bb): return bb.sample_index < bb.total_samples
yield bt.do_while(samples_remain)(process_sample)
Behavior
- Evaluate condition
- If condition is FALSE → return SUCCESS (loop complete)
- If condition is TRUE → tick child
- If child returns RUNNING → return RUNNING (resume child next tick)
- If child returns SUCCESS → reset child, return RUNNING (re-check next tick)
- If child returns FAILURE → return FAILURE (loop aborted)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
condition
|
Union[NodeSpec, Callable[[Any], Any]]
|
A condition node or function to evaluate each iteration |
required |
Returns:
| Type | Description |
|---|---|
'_DoWhileBuilder'
|
A builder that accepts a child node spec |
Source code in src/mycorrhizal/rhizomorph/core.py
try_catch ¶
try_catch(try_block: Union[NodeSpec, Callable[[Any], Any]]) -> Callable[[Union[NodeSpec, Callable[[Any], Any]]], NodeSpec]
Create a try-catch error handling pattern.
Usage
Define try and catch blocks with explicit memory settings¶
@bt.sequence(memory=True) def try_block(): yield action1 yield action2
@bt.sequence(memory=True) def catch_block(): yield cleanup
Use in the tree¶
@bt.root @bt.sequence def root(): yield bt.try_catch(try_block)(catch_block)
Behavior
- Execute try block
- If try block returns SUCCESS → return SUCCESS
- If try block returns FAILURE → execute catch block
- Return SUCCESS if either block succeeds, FAILURE if both fail
This is semantically equivalent to a selector with two children
- First child (try) runs first
- Second child (catch) runs only if try fails
- Returns SUCCESS if either succeeds
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
try_block
|
Union[NodeSpec, Callable[[Any], Any]]
|
The node to try first (pre-defined sequence/selector/etc with explicit memory settings) |
required |
Returns:
| Type | Description |
|---|---|
Callable[[Union[NodeSpec, Callable[[Any], Any]]], NodeSpec]
|
A callable that accepts a catch block (pre-defined sequence/selector/etc with explicit memory settings) |
Source code in src/mycorrhizal/rhizomorph/core.py
subtree ¶
Mount another tree's root spec as a subtree.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tree
|
SimpleNamespace
|
A tree namespace created with @bt.tree |
required |
Source code in src/mycorrhizal/rhizomorph/core.py
tree ¶
Decorator to create a behavior tree namespace.
Usage
@bt.tree def MyTree(): @bt.action def my_action(bb: BB) -> Status: ...
@bt.sequence()
def root():
yield my_action
Source code in src/mycorrhizal/rhizomorph/core.py
root ¶
Mark a composite as the root of the tree.
Source code in src/mycorrhizal/rhizomorph/core.py
as_spec ¶
Convert a function or NodeSpec to a NodeSpec.
Source code in src/mycorrhizal/rhizomorph/core.py
_NodeWrapper ¶
Fluent wrapper for programmatic nodes that enables decorator-like chaining.
Similar to _WrapperChain but for NodeSpecs created via TreeBuilder.
Example
wrapped = builder.action("scan", scan_func).timeout(1.0).retry(3)
Source code in src/mycorrhizal/rhizomorph/core.py
timeout ¶
Wrap with a Timeout decorator
Source code in src/mycorrhizal/rhizomorph/core.py
retry ¶
retry(max_attempts: int, retry_on: Tuple[Status, ...] = (FAILURE, ERROR)) -> '_NodeWrapper'
Wrap with a Retry decorator
Source code in src/mycorrhizal/rhizomorph/core.py
ratelimit ¶
Wrap with a RateLimit decorator
Source code in src/mycorrhizal/rhizomorph/core.py
gate ¶
Wrap with a Gate decorator - fails when condition is false
Source code in src/mycorrhizal/rhizomorph/core.py
when ¶
Wrap with a When decorator - succeeds when condition is false (no-op)
Source code in src/mycorrhizal/rhizomorph/core.py
succeeder ¶
Wrap with a Succeeder decorator - always returns SUCCESS
Source code in src/mycorrhizal/rhizomorph/core.py
failer ¶
Wrap with a Failer decorator - always returns FAILURE
Source code in src/mycorrhizal/rhizomorph/core.py
inverter ¶
Wrap with an Inverter decorator - inverts SUCCESS/FAILURE
Source code in src/mycorrhizal/rhizomorph/core.py
TreeBuilder ¶
Programmatic builder for behavior trees.
Provides an imperative API for constructing behavior trees without decorators. Similar to NetBuilder in Hypha.
Example
builder = TreeBuilder("MyTree")
has_battery = builder.condition("has_battery", lambda bb: bb.battery > 20) move_forward = builder.action("move_forward", move_func)
patrol = builder.sequence(has_battery, move_forward, memory=True) tree = builder.root(patrol)
runner = Runner(tree, bb=blackboard) await runner.tick()
Source code in src/mycorrhizal/rhizomorph/core.py
action ¶
action(name: str, func: Callable[..., Any]) -> _NodeWrapper
Create an action node.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Name for the action |
required |
func
|
Callable[..., Any]
|
Action function (can be async) that takes (bb) and returns Status |
required |
Returns:
| Type | Description |
|---|---|
_NodeWrapper
|
_NodeWrapper for fluent chaining |
Source code in src/mycorrhizal/rhizomorph/core.py
condition ¶
condition(name: str, func: Callable[[Any], bool]) -> _NodeWrapper
Create a condition node.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Name for the condition |
required |
func
|
Callable[[Any], bool]
|
Condition function that takes (bb) and returns bool |
required |
Returns:
| Type | Description |
|---|---|
_NodeWrapper
|
_NodeWrapper for fluent chaining |
Source code in src/mycorrhizal/rhizomorph/core.py
sequence ¶
sequence(*children: Union[NodeSpec, _NodeWrapper, Callable[[Any], Any]], memory: bool = True) -> NodeSpec
Create a sequence composite.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
*children
|
Union[NodeSpec, _NodeWrapper, Callable[[Any], Any]]
|
Child nodes (NodeSpec, _NodeWrapper, or callables with node_spec) |
()
|
memory
|
bool
|
Whether to remember position across ticks |
True
|
Returns:
| Type | Description |
|---|---|
NodeSpec
|
NodeSpec for the sequence |
Source code in src/mycorrhizal/rhizomorph/core.py
selector ¶
selector(*children: Union[NodeSpec, _NodeWrapper, Callable[[Any], Any]], memory: bool = True) -> NodeSpec
Create a selector composite.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
*children
|
Union[NodeSpec, _NodeWrapper, Callable[[Any], Any]]
|
Child nodes (NodeSpec, _NodeWrapper, or callables with node_spec) |
()
|
memory
|
bool
|
Whether to remember position across ticks |
True
|
Returns:
| Type | Description |
|---|---|
NodeSpec
|
NodeSpec for the selector |
Source code in src/mycorrhizal/rhizomorph/core.py
parallel ¶
parallel(*children: Union[NodeSpec, _NodeWrapper, Callable[[Any], Any]], success_threshold: int, failure_threshold: Optional[int] = None) -> NodeSpec
Create a parallel composite.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
*children
|
Union[NodeSpec, _NodeWrapper, Callable[[Any], Any]]
|
Child nodes (NodeSpec, _NodeWrapper, or callables with node_spec) |
()
|
success_threshold
|
int
|
Minimum number of children that must succeed |
required |
failure_threshold
|
Optional[int]
|
Minimum number of children that must fail (None = len(children)) |
None
|
Returns:
| Type | Description |
|---|---|
NodeSpec
|
NodeSpec for the parallel node |
Source code in src/mycorrhizal/rhizomorph/core.py
subtree ¶
Mount another tree's root spec as a subtree.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tree
|
Union[SimpleNamespace, Callable[..., Any]]
|
A tree namespace created with @bt.tree, or a tree built by TreeBuilder |
required |
Returns:
| Type | Description |
|---|---|
NodeSpec
|
NodeSpec for the subtree |
Example
DSL tree¶
engage_tree = Engage # @bt.tree decorated function
Programmatic tree¶
builder = TreeBuilder("Demo") builder.root(builder.sequence( builder.subtree(engage_tree), other_action ))
Two programmatic trees¶
engage_builder = TreeBuilder("Engage")
... build engage ...¶
engage_tree_func = engage_builder.build()
demo_builder = TreeBuilder("Demo") demo_builder.root(demo_builder.sequence( demo_builder.subtree(engage_tree_func), other_action ))
Source code in src/mycorrhizal/rhizomorph/core.py
as_spec ¶
as_spec(maybe: Union[NodeSpec, _NodeWrapper, Callable[[Any], Any]]) -> NodeSpec
Convert various node types to a NodeSpec.
Handles: - NodeSpec: returns as-is - _NodeWrapper: extracts the spec - Callable with node_spec attribute: extracts the spec
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
maybe
|
Union[NodeSpec, _NodeWrapper, Callable[[Any], Any]]
|
NodeSpec, _NodeWrapper, or callable with node_spec |
required |
Returns:
| Type | Description |
|---|---|
NodeSpec
|
NodeSpec |
Raises:
| Type | Description |
|---|---|
TypeError
|
If the input cannot be converted to a NodeSpec |
Source code in src/mycorrhizal/rhizomorph/core.py
root ¶
root(child: Union[NodeSpec, _NodeWrapper, Callable[[Any], Any]]) -> Callable[..., Any]
Set the root of the tree and return a tree function.
The returned function is compatible with the Runner API and has a _spec attribute that holds the root NodeSpec.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
child
|
Union[NodeSpec, _NodeWrapper, Callable[[Any], Any]]
|
Root node (NodeSpec, _NodeWrapper, or callable with node_spec) |
required |
Returns:
| Type | Description |
|---|---|
Callable[..., Any]
|
A callable function with _spec attribute for use with Runner |
Example
builder = TreeBuilder("MyTree") action1 = builder.action("act1", func1) action2 = builder.action("act2", func2) root_seq = builder.sequence(action1, action2) tree = builder.root(root_seq)
runner = Runner(tree, bb=blackboard) await runner.tick()
Source code in src/mycorrhizal/rhizomorph/core.py
2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 | |
build ¶
build(child: Optional[Union[NodeSpec, _NodeWrapper, Callable[[Any], Any]]] = None) -> Callable[..., Any]
Build and return the tree function.
This is an alias for root() that makes the intent clearer when you're at the end of building a tree.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
child
|
Optional[Union[NodeSpec, _NodeWrapper, Callable[[Any], Any]]]
|
Root node (optional if already set via root()) |
None
|
Returns:
| Type | Description |
|---|---|
Callable[..., Any]
|
A callable function with _spec attribute for use with Runner |
Example
builder = TreeBuilder("MyTree") tree = builder.build( builder.sequence( builder.action("act", func) ) )
Source code in src/mycorrhizal/rhizomorph/core.py
to_mermaid ¶
Generate Mermaid flowchart diagram for this tree.
Returns:
| Type | Description |
|---|---|
str
|
Mermaid flowchart syntax as a string |
Example
builder = TreeBuilder("MyTree") tree = builder.build(...) print(tree.to_mermaid())
Source code in src/mycorrhizal/rhizomorph/core.py
to_dict ¶
Serialize the tree to a dictionary.
Creates a JSON-serializable representation of the tree structure that can be saved to a file or transmitted over network.
Returns:
| Type | Description |
|---|---|
Dict[str, Any]
|
Dictionary representation of the tree |
Example
builder = TreeBuilder("MyTree") tree = builder.build(...) tree_dict = tree.to_dict()
import json with open("tree.json", "w") as f: json.dump(tree_dict, f, indent=2)
Source code in src/mycorrhizal/rhizomorph/core.py
2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 | |
from_dict
classmethod
¶
Deserialize a tree from a dictionary with function registry.
Reconstructs a TreeBuilder from a serialized dictionary. You must provide a registry of functions to restore node behaviors.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
Dict[str, Any]
|
Dictionary output from to_dict() |
required |
function_registry
|
Dict[str, Callable[..., Any]]
|
Dict mapping function names to callable functions |
required |
Returns:
| Type | Description |
|---|---|
'TreeBuilder'
|
A new TreeBuilder instance |
Example
Define your functions¶
async def my_action(bb): return Status.SUCCESS
def my_condition(bb): return True
Build and save tree¶
builder = TreeBuilder("MyTree") action = builder.action("my_action", my_action) cond = builder.condition("my_condition", my_condition) tree = builder.build(builder.sequence(cond, action)) tree_dict = tree.to_dict()
Load tree later¶
registry = { "my_action": my_action, "my_condition": my_condition, } loaded_builder = TreeBuilder.from_dict(tree_dict, function_registry=registry) loaded_tree = loaded_builder.build()
Source code in src/mycorrhizal/rhizomorph/core.py
2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 | |
Runner ¶
Runner(tree: SimpleNamespace, bb: BB, tb: Optional[Timebase] = None, exception_policy: ExceptionPolicy = LOG_AND_CONTINUE, trace: Optional[Logger] = None)
Bases: Generic[BB]
Runtime for executing behavior trees.
The Runner manages the execution of a behavior tree, handling tick calls, timebase management, and result processing.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tree
|
SimpleNamespace
|
A behavior tree namespace with a 'root' attribute (from @bt.tree) |
required |
bb
|
BB
|
Blackboard containing shared state |
required |
tb
|
Optional[Timebase]
|
Optional timebase for time management (defaults to MonotonicClock) |
None
|
exception_policy
|
ExceptionPolicy
|
How to handle exceptions during tree execution |
LOG_AND_CONTINUE
|
trace
|
Optional[Logger]
|
Optional logger instance for tracing action/condition execution |
None
|
Methods:
| Name | Description |
|---|---|
tick |
Execute one tick of the behavior tree |
tick_until_complete |
Run the tree until it returns a terminal status |
Example
@bt.tree def MyTree(): @bt.root @bt.sequence def root(): yield check_condition yield do_work
runner = Runner(MyTree, bb=blackboard) result = await runner.tick_until_complete()
Tracing
import logging trace_logger = logging.getLogger("bt.trace") runner = Runner(MyTree, bb=blackboard, trace=trace_logger) result = await runner.tick_until_complete()
Logs: "action: module.do_work | SUCCESS"¶
"condition: module.check_condition | SUCCESS"¶
Source code in src/mycorrhizal/rhizomorph/core.py
_clear_interface_view_cache ¶
Clear the interface view cache. Useful for testing.
Source code in src/mycorrhizal/rhizomorph/core.py
_create_interface_view_if_needed ¶
Create a constrained view if the function has an interface type hint on its blackboard parameter.
This enables type-safe, constrained access to blackboard state based on interface definitions created with @blackboard_interface.
The function signature can use an interface type
async def my_action(bb: MyInterface) -> Status: # bb is automatically a constrained view return Status.SUCCESS
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
bb
|
Any
|
The blackboard instance |
required |
func
|
Callable
|
The function to check for interface type hints |
required |
Returns:
| Type | Description |
|---|---|
Any
|
Either the original blackboard or a constrained view based on interface metadata |
Raises:
| Type | Description |
|---|---|
TypeError
|
If func is not callable or type hints are malformed |
AttributeError
|
If type hints reference undefined types |
Source code in src/mycorrhizal/rhizomorph/core.py
_supports_timebase ¶
Check if a function accepts a 'tb' parameter.
_call_node_function
async
¶
Call a node function with appropriate parameters based on its signature.
If the function has an interface type hint on its 'bb' parameter, a constrained view will be created automatically to enforce access control.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
func
|
Callable
|
The function to call |
required |
bb
|
Any
|
The blackboard |
required |
tb
|
Timebase
|
The timebase |
required |
supports_timebase
|
bool
|
Cached flag indicating if func accepts 'tb' parameter |
required |
Source code in src/mycorrhizal/rhizomorph/core.py
_fully_qualified_name ¶
Get the fully qualified name of a function.
Returns module.function_name if the function has a module, otherwise returns just the function name.
Source code in src/mycorrhizal/rhizomorph/core.py
_bt_expand_children ¶
_bt_expand_children(factory: Callable[..., Generator[Any, None, None]], expansion_stack: Optional[Set[str]] = None) -> List[NodeSpec]
Execute a composite factory to get child specs.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
factory
|
Callable[..., Generator[Any, None, None]]
|
The generator function that yields child specs |
required |
expansion_stack
|
Optional[Set[str]]
|
Stack of factory names to detect recursion |
None
|
Source code in src/mycorrhizal/rhizomorph/core.py
1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 | |
_generate_mermaid ¶
Render a static structure graph for a tree namespace.
Source code in src/mycorrhizal/rhizomorph/core.py
2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 | |
Utilities¶
mycorrhizal.rhizomorph.util ¶
Rhizomorph Behavior Tree Utilities
Utility functions for behavior tree operations like Mermaid diagram generation.
to_mermaid ¶
Generate Mermaid diagram from a behavior tree namespace.
This is a utility wrapper that accesses the tree's internal to_mermaid method. Use this when you have a tree namespace and want to generate a diagram.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tree
|
SimpleNamespace
|
The behavior tree namespace (created with @bt.tree decorator) |
required |
Returns:
| Type | Description |
|---|---|
str
|
Mermaid diagram as a string |