This feature lets you link another aura from a BT/macro if that aura contains a C# Script action. In programming terms, this is similar to referencing another project.
All classes and types defined in that script then become available for use in the BT.
The reference mechanism has technically existed for several months, but until now it was mostly hidden because it was incomplete and did not work the way I wanted.

You can now create a C# class that analyzes the game—through computer vision triggers or by reading memory directly—and provides the data your BehaviorTree needs to make decisions.
Instead of cluttering the tree with dozens of variables and checks, you can create a single class, for example TheGame, that encapsulates all data collection.
This bot uses exactly the approach described below. It understands its environment, its own stats and the stats of nearby monsters, can build an action plan, and so on.
So far, the only limitation I’ve run into with this approach is my own ceiling.

Let’s look at the "Shared" aura and its files.
public sealed class TheGame {
public TheGame(IFluentLog log){
Log = log;
}
public IFluentLog Log {get;}
public int IntValue { get; private set; }
public void Refresh()
{
IntValue++; // в реальности здесь может быть чтение из памяти или обновление триггеров
Log.Info($"Refreshed the state, value: {IntValue}");
}
}
This class prepares everything needed by the logic: trigger initialization, memory reads, OSD creation—whatever is required.
When Refresh is called, the state is updated.
[Inject] IAuraTreeScriptingApi AuraTree {get; init;}
Log.Info("Bot is being started!");
var tree = AuraTree.GetBehaviorTreeByPath("./New tree");
var game = GetService<TheGame>();
tree["TheGame"] = game;
This is how the TheGame object is passed into the BT through variables.
This is the key part that was missing before. Objects passed through variables are now fully available, without restrictions.
Example tree structure:

var game = Variables.Get<CheatCrescendo.TheGame>("TheGame").Value;
game.Refresh();
In this node, we call Refresh, which updates the game state. By this point, the "TheGame" variable has already been initialized—either by the script or by another node.
return Run();
public IEnumerator<NodeStatus> Run(){
using var osd = GetService<IOnScreenCanvasScriptingApi>().Create();
var game = Variables.Get<CheatCrescendo.TheGame>("TheGame").Value;
var textOsd = osd.AddHtmlObject();
while (!cancellationToken.IsCancellationRequested){
textOsd.Html = $"{game.IntValue}";
yield return NodeStatus.Success;
}
}
This is an example of creating an OSD that displays the current IntValue.
It uses the new IEnumerator<NodeStatus> capability, which lets you split a node’s lifecycle into stages.
On the first run, the OSD is created; after that, it is simply updated.
Under the selector, you can place as many nodes as you want that check the current state.
All you need to do is access TheGame and call its methods.
For example, want to read HP directly from memory? Add a method to TheGame and call it from a BT node.
Need a color check via ColorSearch? Same idea.
Even movement between locations can be moved into a method: open a portal, select an option, click—everything lives in TheGame, and the BT just makes one call.
A number of performance-related improvements were added. If you notice any issues, please report them.
PoeShared.Blazor.Controls namespace, which contains UI controls, is now available in scripts by default