Library / SDK
ashblue/fluid-behavior-tree avatar
ashblue/fluid-behavior-tree

Fluid Behavior Tree: a tree that remembers where it was, so Success does not mean what you expect

Behavior trees for Unity3D projects. Written with a code driven approach on the builder pattern.

1,184 stars125 forksC#MIT

At a glance

What is it?
A Unity behaviour tree library built in code with a builder pattern instead of an editor asset, where the engine tracks its position in the tree between frames, a runtime visualizer is the only visualisation, and the documented install pins a version two releases behind while a nightly channel exists.
Who is it for?
Adopt Fluid Behavior Tree if you want behaviour trees you can code review, because the trees are C# built in code rather than assets in the editor, your custom nodes live in your own project so a library upgrade does not overwrite them, and the project claims the workflow is written with test-driven development and unit tests.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 145 days ago.
What is it written in?
Mainly C#, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 1, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The tree tracks its position, and that redefines what a return value does

One feature bullet is the whole execution model, and it is easy to skim because it does not sound important. The library tracks the last position of your behaviour tree and restores it the next frame. That single sentence changes how you read every node you write. In the classic behaviour tree formulation, a tick restarts traversal from the root and the composite nodes decide which child runs by asking children for a status; a running node is one that returns a running status and the parent holds the position for it. Here the engine holds the position globally. The consequence shows up in what the three return values mean, and the readme is explicit. Success means the node has finished and the next tick will restart the tree if there are no other nodes to run. Failure means the same thing, except that it informs the node failed. Continue means rerun this node on the next tick, and the pointer that tracks it can only be cleared by calling Reset. So Success is not an instruction to move to the next sibling; it is a statement that this node is done, and the engine decides where to resume. And a pointer into the tree survives between frames until something resets it, which means a Continue that never returns anything else will be re-entered forever unless the caller intervenes. If you have written behaviour trees before, this is the assumption you have to unlearn, and it is worth reading those three bullets before you write your first node rather than after it misbehaves in a build.

Code-driven trees, and a visualizer that only works while the game runs

The readme calls this a code-driven approach written with the builder pattern, and the getting-started example shows what that means in practice. A tree is constructed in code, in a component's initialisation method, from a builder: you open a sequence, add a condition and an action as lambdas, close the sequence, and build. Then you tick the tree once per frame from the update method. Two consequences follow and they are the trade this library is making. The first is that the tree exists in your source code, so it goes through code review, it merges, it is diffed, and a change to your AI is reviewable. The readme's own claim is that this maximises maintainability on large projects, and that is a claim about process rather than about the runtime. The second is that there is nothing to author in an editor. The visualizer reflects that honestly. It works as long as your tree variable is public or carries the serialisation attribute, and it prints a visualisation while the game is running in the editor, and the readme says plainly that you cannot view a tree while the game is not running because the tree has to be built before it can be visualised. So debugging a tree means entering play mode. There is no inspector window, no authored graph, no drag and drop. If your team authors AI in the editor, that is the cost you are paying, and it is a real one; if your team reviews AI in pull requests, it is close to free.

Extension is a subclass and one extension method, which is what makes upgrades safe

The readme's claim about extending trees is specific and unusual, so it is worth unpacking. It says you can safely add new code to your behaviour trees with several lines, and that this lets you customise trees while supporting future version upgrades. The mechanism is visible in the example. You subclass a base action type and override a single update method that returns a status, and then, separately, you add an extension method on the builder that takes the builder as its receiver and returns the builder after adding your node. Two pieces, and the second one is the interesting half: because your node enters the tree through the same fluent chain as the built-in ones, a custom action reads identically to a built-in action in the source. So the code stays legible and the tree stays uniform. The upgrade argument is the one that matters for adoption, and it follows from the code-driven design. Your nodes and your trees are in your project, in your language, in files your version control owns. A new release of the library cannot overwrite them, and cannot change your behaviour because it changed a serialised asset format. That is a materially different upgrade risk from editor-based tree systems, where an asset can be rewritten by a tool version you did not choose. The built-in library is small and chosen: a handful of actions, a couple of conditions, four composites including a selector and a random variant, and decorators for inverting, forcing a status, and repeating forever or until a condition. There is no reactive node, which is consistent, because the execution model already polls every frame.

Installing means pointing Unity's package manager at npm

The install section is the part with an operational consequence, and it is short. The package is not published to a Unity registry; it is published to npm under a scope, and you make Unity's package manager read that registry by adding a scoped registry entry to the project manifest:

json
{
  "scopedRegistries": [
    {
      "name": "NPM",
      "url": "https://registry.npmjs.org",
      "scopes": [
        "com.fluid"
      ]
    }
  ],
  "dependencies": {
    "com.fluid.behavior-tree": "2.2.0"
  }
}

The readme explains why: it has to be done so the Unity editor can connect to the npm registry. So a Unity project that adopts this has a new dependency-resolution path. That is a small, explicit configuration and it is scoped, so it only affects packages under that name, which is the right way to do it. It does mean your project's package resolution now has a path that depends on an external registry being reachable, and that the lockfile-equivalent state of your project includes something published by an individual maintainer. The readme also notes a benefit of going through the package manager rather than copying files: you get version control over which version you use, visible in the package manager window. That is a genuine improvement over dropping an asset folder into a project. Note the version in the block, though. The newest release tag is 2.3.0 and the documentation pins 2.2.0, so the stable line the readme shows you is two patch generations behind the newest release, and the example was written before either. If you are starting fresh, read the releases page rather than copying the manifest block.

The repository is a Unity project, and the published version lives in git history

The top-level listing explains how this package is built, and the first thing to notice is that it is a Unity project rather than a package. There is an assets directory, a packages directory, a project settings directory and a user settings directory, all versioned. So the repository you clone is an openable Unity project that happens to produce a package, and a contributor is expected to open it in the editor. That has a real cost: Unity's project settings are opinionated, and importing a project whose settings are not your own is a known source of friction and of version-specific behaviour. It also explains the build arrangement. The package manifest's entry point is a Node build script rather than the library itself, and there is a build script wired to that entry. And the version field in the manifest reads zero, which is not an error: the release tooling computes the version from commit messages and writes the real one at publish time. That is why the tags in the release history follow a conventional-commit format, and it means the version you depend on is decided by the release pipeline rather than by a number anyone edited. The minimum Unity version is declared in the manifest as 2018.1, which is worth checking against your project because it is a much older floor than the tooling around it suggests.

The default branch is develop, the build badge watches master, and there is a nightly channel

Three small facts that together tell you the working rhythm. First, the default branch is not the one the readme's badges are for. The repository's default branch is a development branch, and the build status badge in the header points at a different branch and at a continuous integration service that has been superseded for most projects. So the badge in the readme is describing a build of a branch that is not what you get when you clone the repository, from a service that may not be reporting at all. That is peripheral, and it is the sort of thing that goes stale in a readme nobody owns, but it is worth knowing before you trust it. Second, the release rhythm is slow and irregular. Three recent tags: one in 2020, one in 2021, and one in 2024. For a game AI library that is a slow cadence, and it is the reason the third fact matters. Third, there is a nightly build channel: a documented section in the readme, a publish script in the repository, and the manifest includes a package populator tool whose purpose is assembling a package for the registry. So the project has answered the slow-release problem the way a lot of Unity packages do, by publishing an unstable channel alongside the stable one. The readme's install section never mentions it. If you want the current code, the nightly is where it is, and if you want a pinned version, the releases page is the place to read rather than the manifest block in the readme.

Editorial conclusion

Adopt Fluid Behavior Tree if you want behaviour trees you can code review, because the trees are C# built in code rather than assets in the editor, your custom nodes live in your own project so a library upgrade does not overwrite them, and the project claims the workflow is written with test-driven development and unit tests. Do not adopt it if you need to author trees visually at edit time, since the visualizer only runs in play mode and only after the tree has been built, which is the deliberate cost of the code-driven approach. Two things to check first. Read the execution model before you write your first node, because a task returning Success does not advance the way a classic composite does; the tree resumes from where it was, and only Reset clears that. And read the install section carefully, because the documented dependency version is two releases behind the newest tag, so decide whether you want the stable line the documentation shows or the nightly channel, and note that a Unity project depending on this now resolves packages through a configured npm registry.

Frequently asked questions

What do the three task statuses do in Fluid Behavior Tree?

Success means the node has finished and the next tick will restart the tree if there are no other nodes to run. Failure means the same except that it marks the node as failed. Continue means rerun that node on the next tick, and the pointer tracking it can only be cleared by calling tree.Reset().

How do I install Fluid Behavior Tree in a Unity project?

Add a scopedRegistries entry pointing at the npm registry with the scope com.fluid, plus a dependency on com.fluid.behavior-tree, to the project manifest file. That lets the Unity editor connect to the npm registry, and the version can then be controlled from the package manager window.

Can I visualise a Fluid Behavior Tree outside play mode?

No. The visualizer prints a visualisation while the game is running in the editor, and the readme states you cannot view trees while the game is not running because the tree has to be built in order to be visualised. The tree variable also has to be public or carry a serialisation attribute.

How do I add my own node to a Fluid Behavior Tree?

Subclass a base action type and override its update method returning a status, then add an extension method on the behavior tree builder that takes the builder as its receiver and returns it after adding your node, so custom nodes chain like the built-in ones.

What is the latest Fluid Behavior Tree release?

2.3.0, published on 2024-11-09, following 2.2.3 in March 2021 and 2.2.2 in June 2020. The install instructions in the readme pin 2.2.0, and the repository also publishes nightly builds, with the last push on 2026-05-08.

Official sources

  1. ashblue/fluid-behavior-tree on GitHub
  2. Issues
  3. License: MIT
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/ashblue-fluid-behavior-tree.svg)](https://hysenlabs.com/projects/ashblue-fluid-behavior-tree)