Install
$ agentstack add skill-jame581-godotprompter-limboai ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
LimboAI
> Related skills: ai-navigation for movement the tasks drive, state-machine for core-engine FSM (when you don't need an addon), godot-brainstorming for choosing an AI approach.
> Addon: LimboAI · version v1.7.1 · Godot 4.6+ · MIT · source: https://github.com/limbonaut/limboai · written in C++ (GDExtension; engine-module build also available). GDExtension exposes GDScript; C# requires the module build (not GDExtension in v1.7.1).
1. When to use LimboAI
| Approach | Best for | |---|---| | Core-engine FSM (state-machine skill) | Simple agents, void: # BTPlayer starts executing automatically (active = true by default). # Connect to updated(status) to react when the tree finishes. btplayer.updated.connect(onbtupdated)
func onbtupdated(status: int) -> void: if status == BT.SUCCESS: btplayer.restart() # loop the tree
### C#
```csharp
// EnemyAI.cs
using Godot;
public partial class EnemyAI : CharacterBody2D
{
[Export] private BTPlayer _btPlayer;
public override void _Ready()
{
_btPlayer.Updated += OnBtUpdated;
}
private void OnBtUpdated(int status)
{
if (status == (int)BT.Status.Success)
_btPlayer.Restart();
}
}
BTPlayer.UpdateMode controls when the tree ticks: IDLE (every _process), PHYSICS (every _physics_process, default), or MANUAL (call bt_player.update(delta) yourself).
4. Custom tasks
Subclass BTAction (multi-tick work) or BTCondition (immediate check). Annotate with @tool so _generate_name() and _get_configuration_warnings() work in the editor. Place scripts under res://ai/tasks/; subfolders become task categories.
GDScript
@tool
extends BTAction
## Moves the agent toward a blackboard position each tick.
@export var target_pos_var: StringName = &"target_pos"
@export var speed: float = 200.0
func _generate_name() -> String:
return "MoveToward %s" % LimboUtility.decorate_var(target_pos_var)
func _setup() -> void:
pass # one-time init; agent and blackboard are available here
func _enter() -> void:
pass # called when task transitions from non-RUNNING → RUNNING
func _tick(delta: float) -> Status:
var target: Vector2 = blackboard.get_var(target_pos_var, Vector2.ZERO)
if agent.global_position.distance_to(target) void:
pass # cleanup after SUCCESS or FAILURE
@tool
extends BTCondition
## Returns SUCCESS if the agent is within range of a target node.
@export var target_var: StringName = &"target"
@export var distance_max: float = 150.0
var _max_sq: float
func _setup() -> void:
_max_sq = distance_max * distance_max
func _tick(_delta: float) -> Status:
var target: Node2D = blackboard.get_var(target_var, null)
if not is_instance_valid(target):
return FAILURE
var in_range := agent.global_position.distance_squared_to(
target.global_position)
$"MoveToward {LimboUtility.DecorateVar(TargetPosVar)}";
public override void _Setup() { }
public override void _Enter() { }
public override Status _Tick(double delta)
{
var target = (Vector2)Blackboard.GetVar(TargetPosVar, Vector2.Zero);
var body = (CharacterBody2D)Agent;
if (body.GlobalPosition.DistanceTo(target) _maxSq = DistanceMax * DistanceMax;
public override Status _Tick(double delta)
{
var target = Blackboard.GetVar(TargetVar, default(Variant)).As();
if (!GodotObject.IsInstanceValid(target))
return Status.Failure;
var agent2D = (Node2D)Agent;
bool inRange = agent2D.GlobalPosition.DistanceSquaredTo(
target.GlobalPosition) Status:
# Read with a default; use no type annotation for object vars
# to avoid errors if the stored instance was freed.
var speed: float = blackboard.get_var(speed_var, 100.0)
var obj = blackboard.get_var(target_var, null)
if not is_instance_valid(obj):
return FAILURE
# Write back
blackboard.set_var(speed_var, speed * 1.1)
return RUNNING
C#
// C# has no generic GetVar — cast the returned Variant.
using Godot;
[Tool]
public partial class SampleTask : BTAction
{
[Export] public StringName SpeedVar { get; set; } = "speed";
[Export] public StringName TargetVar { get; set; } = "target";
public override Status _Tick(double delta)
{
float speed = (float)Blackboard.GetVar(SpeedVar, 100f);
var obj = Blackboard.GetVar(TargetVar, default(Variant)).As();
if (!GodotObject.IsInstanceValid(obj))
return Status.Failure;
Blackboard.SetVar(SpeedVar, speed * 1.1f);
return Status.Running;
}
}
Useful Blackboard methods: has_var(name), erase_var(name), list_vars(), get_vars_as_dict(), bind_var_to_property(name, obj, prop), link_var(name, target_bb, target_name), print_state() (debug).
BlackboardPlan defines the variable schema (types, defaults, hints) and is edited in the Inspector on BTPlayer or LimboHSM. Call blackboard_plan.create_blackboard(scene_root) to create a scoped Blackboard at runtime.
6. Hierarchical state machine (LimboHSM)
LimboHSM is a LimboState node that manages child LimboState nodes. Transitions fire when a state calls dispatch(event). See [references/hsm.md](references/hsm.md) for advanced patterns (any-state transitions, BTState, nested HSMs, guards).
GDScript — scene-tree setup
# Character.gd — scene tree: Character → LimboHSM → IdleState, MoveState
extends CharacterBody2D
@onready var hsm: LimboHSM = $LimboHSM
@onready var idle: LimboState = $LimboHSM/IdleState
@onready var move: LimboState = $LimboHSM/MoveState
func _ready() -> void:
hsm.add_transition(idle, move, idle.EVENT_FINISHED)
hsm.add_transition(move, idle, move.EVENT_FINISHED)
hsm.initialize(self)
hsm.set_active(true)
C# — scene-tree setup
// Character.cs
using Godot;
public partial class Character : CharacterBody2D
{
[Export] private LimboHSM _hsm;
[Export] private LimboState _idle;
[Export] private LimboState _move;
public override void _Ready()
{
_hsm.AddTransition(_idle, _move, _idle.EventFinished);
_hsm.AddTransition(_move, _idle, _move.EventFinished);
_hsm.Initialize(this);
_hsm.SetActive(true);
}
}
GDScript — state script
# IdleState.gd
extends LimboState
func _setup() -> void:
pass # agent and blackboard available; runs once during hsm.initialize()
func _enter() -> void:
agent.get_node("AnimationPlayer").play("idle")
func _exit() -> void:
pass
func _update(delta: float) -> void:
if Input.get_vector(&"ui_left", &"ui_right", &"ui_up", &"ui_down").length() > 0.1:
dispatch(EVENT_FINISHED)
C# — state script
// IdleState.cs
using Godot;
public partial class IdleState : LimboState
{
public override void _Setup() { }
public override void _Enter()
{
Agent.GetNode("AnimationPlayer").Play("idle");
}
public override void _Exit() { }
public override void _Update(double delta)
{
if (Input.GetVector("ui_left", "ui_right", "ui_up", "ui_down").Length() > 0.1f)
Dispatch(EventFinished);
}
}
Implementation checklist
- [ ]
BTPlayeradded as a child of the agent;behavior_treeresource assigned - [ ] Custom tasks annotated with
@tool(GDScript) or[Tool](C#) for editor display - [ ] Every
_tickreturnsSUCCESS,FAILURE, orRUNNING— nevervoid/null - [ ] Blackboard keys documented as exported
StringNameproperties (suffix_var) - [ ] C# Blackboard reads cast the
Variantexplicitly ((float)Blackboard.GetVar(...)) - [ ] C# uses module build (not GDExtension) for C# support
- [ ]
BTPlayer.updatedsignal used (not deprecatedbehavior_tree_finished) - [ ] HSM: all
LimboStatenodes wired withadd_transitionbeforeinitialize() - [ ] HSM:
set_active(true)called afterinitialize() - [ ] HSM transitions are exhaustive — every reachable state has an exit path
- [ ]
BBParaminspector binding: use module build; GDExtension lacks the param editor UI
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: jame581
- Source: jame581/GodotPrompter
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.