Skip to main content

README.md

# Jido Behavior Tree

[![Hex.pm](https://img.shields.io/hexpm/v/jido_behaviortree.svg)](https://hex.pm/packages/jido_behaviortree)
[![Hex Docs](https://img.shields.io/badge/hex-docs-lightgreen.svg)](https://hexdocs.pm/jido_behaviortree/)
[![CI](https://github.com/agentjido/jido_behaviortree/actions/workflows/ci.yml/badge.svg)](https://github.com/agentjido/jido_behaviortree/actions/workflows/ci.yml)
[![License](https://img.shields.io/hexpm/l/jido_behaviortree.svg)](https://github.com/agentjido/jido_behaviortree/blob/main/LICENSE.md)
[![Website](https://img.shields.io/badge/website-jido.run-0f172a.svg)](https://jido.run)
[![Ecosystem](https://img.shields.io/badge/ecosystem-jido.run-0ea5e9.svg)](https://jido.run/ecosystem)
[![Discord](https://img.shields.io/badge/discord-join-5865F2.svg?logo=discord&logoColor=white)](https://jido.run/discord)

An Elixir behavior tree implementation designed for Jido agents with integrated action support and AI compatibility.

## Features

- **Complete Behavior Tree Engine** - Full implementation with composite, decorator, and leaf nodes
- **Stateful Execution** - GenServer-based agents with manual and automatic execution modes
- **Blackboard Pattern** - Shared state management between nodes
- **Jido Action Integration** - Execute Jido actions directly within behavior tree nodes
- **AI Tool Compatible** - Convert behavior trees to OpenAI-compatible tool definitions
- **Telemetry Support** - Built-in instrumentation for monitoring and debugging
- **Type Safety** - Full typing with Zoi schemas and @spec annotations

## Installation

Add to your `mix.exs`:

```elixir
def deps do
  [
    {:jido_behaviortree, "~> 1.0"}
  ]
end
```

## Quick Start

### Building a Tree with Actions

```elixir
alias Jido.BehaviorTree
alias Jido.BehaviorTree.Nodes.{Sequence, Action}

# Define your actions
defmodule MyApp.Actions.ValidateInput do
  use Jido.Action,
    name: "validate_input",
    description: "Validates user input"

  def run(params, _context) do
    if params[:input] && String.length(params[:input]) > 0 do
      {:ok, %{validated: true}}
    else
      {:error, "Input is required"}
    end
  end
end

defmodule MyApp.Actions.ProcessData do
  use Jido.Action,
    name: "process_data",
    description: "Processes validated data"

  def run(params, _context) do
    {:ok, %{processed: String.upcase(params[:input])}}
  end
end

# Build the tree
tree = BehaviorTree.new(
  Sequence.new([
    Action.new(MyApp.Actions.ValidateInput, %{input: "hello"}),
    Action.new(MyApp.Actions.ProcessData, %{input: "hello"})
  ])
)

# Execute
tick = BehaviorTree.tick()
{status, _updated_tree} = BehaviorTree.tick(tree, tick)
# => {:success, %BehaviorTree.Tree{...}}
```

### Agent-based Execution

For stateful execution across multiple ticks:

```elixir
{:ok, agent} = BehaviorTree.start_agent(
  tree: tree,
  blackboard: %{user_id: 123},
  mode: :manual
)

# Execute ticks
status = BehaviorTree.Agent.tick(agent)

# Access blackboard
BehaviorTree.Agent.put(agent, :result, "success")
value = BehaviorTree.Agent.get(agent, :result)

# Switch to auto mode for continuous execution
BehaviorTree.Agent.set_mode(agent, :auto)
```

### Jido AgentServer Strategy Integration

For full Jido signal routing and directive execution, use the strategy with a
`Jido.Agent` module and run it through `Jido.AgentServer`:

```elixir
defmodule MyApp.BTAgent do
  use Jido.Agent,
    name: "my_bt_agent",
    strategy: {Jido.Agent.Strategy.BehaviorTree, tree: tree}
end

{:ok, pid} = Jido.AgentServer.start_link(agent: MyApp.BTAgent)

# Route through strategy signal routes
signal = Jido.Signal.new!("jido.bt.tick", %{}, source: "/myapp")
{:ok, _agent} = Jido.AgentServer.call(pid, signal)
```

Built-in strategy signals:
- `jido.bt.tick`
- `jido.bt.blackboard.put`
- `jido.bt.blackboard.merge`
- `jido.bt.halt`
- `jido.bt.reset`

## Node Types

### Composite Nodes

Control the execution flow of multiple children:

| Node | Behavior |
|------|----------|
| **Sequence** | Executes children in order. Fails if any child fails. |
| **Selector** | Tries children in order until one succeeds. |

### Decorator Nodes

Modify the behavior of a single child:

| Node | Behavior |
|------|----------|
| **Inverter** | Inverts success/failure of child |
| **Succeeder** | Always returns success when child completes |
| **Failer** | Always returns failure when child completes |
| **Repeat** | Repeats child N times |

### Leaf Nodes

Perform actual work:

| Node | Behavior |
|------|----------|
| **Action** | Executes a Jido Action |
| **Wait** | Waits for a specified duration |
| **SetBlackboard** | Sets values in the blackboard |

## The Blackboard

Shared data structure enabling communication between nodes:

```elixir
# Reference blackboard values in actions
action = Action.new(MyApp.Actions.ProcessData, %{
  data: {:from_blackboard, :input_data}
})

# Set values with SetBlackboard node
alias Jido.BehaviorTree.Nodes.SetBlackboard

SetBlackboard.new(:status, :ready)
SetBlackboard.new(%{status: :ready, count: 0})
```

## Node Status

Every node returns one of these statuses:

- `:success` - Node completed successfully
- `:failure` - Node failed to complete
- `:running` - Node is still executing (will be ticked again)
- `{:error, reason}` - Node raised an execution error

## Telemetry

The library emits telemetry events for monitoring:

- `[:jido, :bt, :node, :tick, :start]` - Node tick started
- `[:jido, :bt, :node, :tick, :stop]` - Node tick completed
- `[:jido, :bt, :node, :tick, :exception]` - Node tick raised an exception
- `[:jido, :bt, :agent, :tick, :start]` - Agent tick started
- `[:jido, :bt, :agent, :tick, :stop]` - Agent tick completed

## Guides

- [Getting Started](guides/getting-started.md) - Installation and basic usage
- [Node Reference](guides/nodes.md) - Complete node documentation
- [Creating Custom Nodes](guides/custom-nodes.md) - Build your own nodes with Zoi
- [Migration Guide](guides/migration.md) - Upgrade notes for production semantics

## Production Guarantees

- Runtime support: Elixir `1.18+`, OTP `27/28`
- Dependency baseline: stable Jido `2.0.x` stack from Hex
- Coverage policy: `>=85%` overall with critical module gates
- `Skill.run/3` returns `{:error, reason}` for tree `:failure`, timeouts, and execution errors
- Blackboard updates from context-aware nodes (including `SetBlackboard`) persist through `Agent` ticks
- Strategy snapshots always expose atom status values (`:idle`, `:running`, `:waiting`, `:success`, `:failure`)

## Development

```bash
# Run tests
mix test

# Run quality checks
mix quality

# Generate docs
mix docs
```

## Integration with Jido

This package integrates with the broader Jido ecosystem:

- **jido_action** - Execute Jido actions within behavior tree nodes
- **jido** - Main agent framework for autonomous systems
- **jido_signal** - Signal processing and event handling

## License

Apache 2.0 - See [LICENSE.md](https://github.com/agentjido/jido_behaviortree/blob/main/LICENSE.md)

---

**Part of the [Jido](https://jido.run/ecosystem) ecosystem for building autonomous agent systems.**