MistreevousSharp
Deterministic, lightweight behaviour trees for C#. JSON & DSL support. Built for game AI, real-time agents, and rapid iteration.
Install / Use
/learn @guinhx/MistreevousSharpREADME
MistreevousSharp
MistreevousSharp is a lightweight, C# behaviour tree library for .NET 9.0 and .NET Standard 2.1, ported from the original mistreevous TypeScript library. Define complex AI behaviours using either JSON or a clean, minimal DSL (MDSL). Built for modularity, clarity, and fast iteration — perfect for games, simulations, and interactive agents.

✨ Key Features
🔹 Minimal DSL or JSON-based definitions – define behaviours clearly and concisely
🔹 Built-in composite, decorator & leaf nodes – model complex logic using a toolbox of predefined node types
🔹 Async & promise-based actions – handle long-running behaviours and actions asynchronously
🔹 Lifecycle callbacks – define callbacks to invoke when tree nodes start, resume, or finish processing
🔹 Global functions & subtrees – reuse logic and subtree definitions across multiple agents
🔹 Guards – dynamically interrupt or cancel long-running behaviours
🔹 Randomised behaviour – weighted choices, random delays, seedable RNG for deterministic tree processing
🔹 Debugging tools – inspect the state of running tree instances and track node state changes
🔹 Optimized for performance – reduced memory allocations, perfect for Unity, Godot, or game servers
🔹 Cross-platform – works on .NET 9.0, .NET Standard 2.1, Unity, and more
🌳 What are Behaviour Trees?
Behaviour trees are hierarchical structures designed to model decision-making processes and are used to create complex AI via the modular composition of individual tasks, making it easy to sequence actions, handle conditions, and control flow in a readable and maintainable way.
🛠️ There is an in-browser editor and tree visualiser for the original TypeScript library that you can try HERE (MDSL definitions are compatible!)
Install
NuGet Package Manager
Install-Package MistreevousSharp
.NET CLI
dotnet add package MistreevousSharp
PackageReference
<PackageReference Include="MistreevousSharp" Version="1.0.0" />
Example
using Mistreevous;
// Define some behaviour for an agent.
var definition = @"root {
sequence {
action [Walk]
action [Fall]
action [Laugh]
}
}";
// Create an agent that we will be modelling the behaviour for.
var agent = new MyAgent();
// Create the behaviour tree, passing our tree definition and the agent.
var behaviourTree = new BehaviourTree(definition, agent);
// Step the tree.
behaviourTree.Step();
// Output:
// 'walking!'
// 'falling!'
// 'laughing!'
Agent Implementation
public class MyAgent : IAgent
{
public object? this[string propertyName] =>
GetType().GetProperty(propertyName)?.GetValue(this);
public State Walk()
{
Console.WriteLine("walking!");
return State.Succeeded;
}
public State Fall()
{
Console.WriteLine("falling!");
return State.Succeeded;
}
public State Laugh()
{
Console.WriteLine("laughing!");
return State.Succeeded;
}
}
Behaviour Tree Methods
IsRunning()
Returns true if the tree is in the RUNNING state, otherwise false.
GetState()
Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.
Step()
Carries out a node update that traverses the tree from the root node outwards to any child nodes, skipping those that are already in a resolved state of SUCCEEDED or FAILED. After being updated, leaf nodes will have a state of SUCCEEDED, FAILED or RUNNING. Leaf nodes that are left in the RUNNING state as part of a tree step will be revisited each subsequent step until they move into a resolved state of either SUCCEEDED or FAILED, after which execution will move through the tree to the next node with a state of READY.
Calling this method when the tree is already in a resolved state of SUCCEEDED or FAILED will cause it to be reset before tree traversal begins.
Reset()
Resets the tree from the root node outwards to each nested node, giving each a state of READY.
GetTreeNodeDetails()
Gets the details of every node in the tree, starting from the root. This will include the current state of each node, which is useful for debugging a running tree instance.
Behaviour Tree Options
The BehaviourTree constructor can take an options object as an argument, the properties of which are shown below.
| Option | Type | Description |
| :--------------------|:- |:- |
| GetDeltaTime | Func<double> | A function returning a delta time in seconds that is used to calculate the elapsed duration of any wait nodes. If this function is not defined then DateTime.UtcNow is used instead by default. |
| Random | Func<double> | A function returning a floating-point number between 0 (inclusive) and 1 (exclusive). If defined, this function is used to source a pseudo-random number to use in operations such as the selection of active children for any lotto nodes as well as the selection of durations for wait nodes, iterations for repeat nodes and attempts for retry nodes when minimum and maximum bounds are defined. If not defined then Random.NextDouble() will be used instead by default. This function can be useful in seeding all random numbers used in the running of a tree instance to make any behaviour completely deterministic. |
| OnNodeStateChange | Action<NodeStateChange> | An event handler that is called whenever the state of a node changes. The change object will contain details of the updated node and will include the previous state and current state. |
Nodes
States
Behaviour tree nodes can be in one of the following states:
- READY A node is in the
READYstate when it has not been visited yet in the execution of the tree. - RUNNING A node is in the
RUNNINGstate when it is still being processed, these nodes will usually represent or encompass a long-running action. - SUCCEEDED A node is in a
SUCCEEDEDstate when it is no longer being processed and has succeeded. - FAILED A node is in the
FAILEDstate when it is no longer being processed but has failed.
Composite Nodes
Composite nodes wrap one or more child nodes, each of which will be processed in a sequence determined by the type of the composite node. A composite node will remain in the RUNNING state until it is finished processing the child nodes, after which the state of the composite node will reflect the success or failure of the child nodes.
Sequence
This composite node will update each child node in sequence. It will move to the SUCCEEDED state if all of its children have moved to the SUCCEEDED state and will move to the FAILED state if any of its children move to the FAILED state. This node will remain in the RUNNING state if one of its children remains in the RUNNING state.
MDSL
root {
sequence {
action [Walk]
action [Fall]
action [Laugh]
}
}
JSON
{
"type": "root",
"child": {
"type": "sequence",
"children": [
{
"type": "action",
"call": "Walk"
},
{
"type": "action",
"call": "Fall"
},
{
"type": "action",
"call": "Laugh"
}
]
}
}
Selector
This composite node will update each child node in sequence. It will move to the FAILED state if all of its children have moved to the FAILED state and will move to the SUCCEEDED state if any of its children move to the SUCCEEDED state. This node will remain in the RUNNING state if one of its children is in the RUNNING state.
MDSL
root {
selector {
action [TryThis]
action [ThenTryThis]
action [TryThisLast]
}
}
JSON
{
"type": "root",
"child": {
"type": "selector",
"children": [
{
"type": "action",
"call": "TryThis"
},
{
"type": "action",
"call": "ThenTryThis"
},
{
"type": "action",
"call": "TryThisLast"
}
]
}
}
Parallel
This composite node will update each child node concurrently. It will move to the SUCCEEDED state if all of its children have moved to the SUCCEEDED state and will move to the FAILED state if any of its children move to the FAILED state, otherwise it will remain in the RUNNING state.
MDSL
root {
parallel {
action [RubBelly]
action [PatHead]
}
}
JSON
{
"type": "root",
"child": {
"type": "parallel",
"children": [
{
"type": "action",
"call": "RubBelly"
},
{
"type": "action",
"call": "PatHead"
}
]
}
}
Race
This composite node will update each child node concurrently. It will move to the SUCCEEDED state if any of its children have moved to the SUCCEEDED state and will move to the FAILED state if all of its children move to the FAILED state, otherwise it will remain in the RUNNING state.
MDSL
root {
race {
action [UnlockDoor]
action [FindAlternativePath]
}
}
JSON
{
"type": "root",
"child": {
"type": "race",
"children": [
{
"type": "
Related Skills
node-connect
341.6kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
84.6kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
341.6kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
commit-push-pr
84.6kCommit, push, and open a PR
