How to bring order to game and robotics AI logic with the Bonsai library

Anyone who has ever tried to program the behavior of a complex NPC for a game or an autonomous robot using finite state machines (FSM) knows this moment of despair. At first, everything is simple: three states ("patrol", "chase", "attack") and a handful of transitions. But the project grows. Health checks appear, reactions to shots from behind, seeking cover, weapon reloading. Suddenly, the transition graph turns into a tangled mess of spaghetti, where adding one new action breaks half of the old connections.
Game dev has long found a remedy for this pain in the form of Behavior Trees. They were popularized back in the day by Halo 2 and Unreal Engine. Today, this concept is actively used in robotics and autonomous systems.
Recently, I stumbled upon Bonsai — a lightweight and fast implementation of behavior trees in Rust, with Python bindings thrown in by the author.
What is a Behavior Tree in plain language
If we discard the academic terminology, a behavior tree is a hierarchical structure of rules that defines an agent's reaction to the world. The main advantage of this approach is modularity. Each node is isolated and returns one of three statuses to its parent:
Success(action completed successfully)Failure(action failed)Running(action is still running)
The parent node decides who to call next based on this result.
In Bonsai, logic is assembled from several basic node types:
// Выполняет A, затем B. Если A падает, цепочка прерывается
Sequence([A, B])
// Пробует A. Если падает, пробует B
Select([A, B])
// Классическое ветвление
If(condition, A, B)
// Выполняет A и B параллельно, ожидая завершения обоих
WhenAll([A, B])
// Запускает параллельно и ждет первого завершившегося
Race([A, B])
The tree is traversed from top to bottom, left to right. If an enemy disappears from the field of view right during aiming, the interruption branch will react instantly on the next tick cycle. You don't need to manually write hundreds of exit conditions for the current state, like in regular FSMs.
How Bonsai works under the hood
Bonsai is written in pure Rust without extra overhead. To add it to your project, just add the dependency to Cargo.toml:
[dependencies]
bonsai-bt = "*"
If you're working in tandem with Python (for example, for prototyping or scripting robots on ROS), the package is installed via pip:
pip install bonsai-bt
The problem of long-running tasks
The behavior tree must be polled regularly and without delays. If some node inside blocks the thread for half a second (say, performing heavy pathfinding or a network request to a sensor), the entire system will freeze.
The author of Bonsai solved this issue through the Running status and message channels. Long-running synchronous or asynchronous tasks are moved to background threads. The tree node simply returns Running on each tick until a completion or error signal arrives from the channel. The repository has a clear async drone example demonstrating drone control in asynchronous mode.
Where this comes in handy
The repository tags are not coincidentally home to ROS2, Bevy, and Unreal Engine. Here are typical scenarios where Bonsai saves your nerves:
- Games on Bevy or other Rust engines. For implementing enemy AI, allies, or procedural events.
- Robotics and drones. Building deterministic navigation algorithms, obstacle avoidance, and mission execution.
- Backend pipelines with complex branching. If you have a chain of tasks with retries, timeouts, and parallel branches, assembling it via Behavior Tree is often more convenient than building nested
matchandtry/catchstatements.
Pros and cons
The project leaves a pleasant impression with its minimalism. There are no overloaded abstractions here, the code is clean, and the determinism of the logic makes debugging predictable.
On the downside: the documentation in the README itself is quite brief. To understand all the nuances of parallel nodes (WhileAll, After), you'll need to look into the examples/ folder and tests. There's also no visual tree editor out of the box, so you'll have to build the tree in code.
If you need a clear, fast, and predictable tool for agent logic in Rust or Python without heavyweight dependencies, Bonsai definitely deserves a star on GitHub and a test in your side project.
Related projects