🔥 Explore this awesome post from Hacker News 📖
📂 **Category**:
✅ **What You’ll Learn**:
go-bt is a Behavior Tree library for Go.
Designed for background workers, game AI, mundane task automation, and asynchronous logic.
Instead of time.Sleep or infinite while loops, go-bt uses a cooperative multitasking model. Nodes return state instantly, yielding control back to the supervisor.
- Stateless Nodes: Nodes (
Sequence,Selector, etc.) do not hold runtime state. All temporal memory and execution states live entirely within the genericBTContext[T]. - The Magic Numbers: Every node’s
Runmethod returns exactly one of three integers:1(Success): The task is done and successful.0(Running): The task needs more time (e.g., waiting on I/O, or sleeping). It yields the thread.-1(Failure): The task failed.
- First-Class Context:
BTContext[T]directly embeds Go’s standardcontext.Context, ensuring your trees natively respect global cancellation tokens and timeouts. - Time-Travel Testing: The engine uses an injected clock directly on the context, allowing you to instantly test a 5-minute
TimeoutorSleepnode in your unit tests without actually waiting.
go-bt provides a minimalist set of core nodes that can be combined to create any logical control flow:
- Composites:
Selector(Stateless Priority / Fallback),Sequence(Stateless AND gate),MemSequence(Stateful chronological execution) - Decorators:
Inverter(NOT gate),Optional(Swallows failures),Timeout,Retry,Repeat - Leaves:
Condition(Instant memory read),Action(Execution),Sleep(Non-blocking wait)
1. Define your Blackboard
Your blackboard is the custom state your tree will read and manipulate. Because the library uses Go Generics, it can be any struct.
type WorkerState struct 🔥
You can use the go-bt nodes to assemble your logic. This example asserts that the worker is connected before attempting to process tasks:
package main
import (
"time"
"context"
"go-bt/core"
"go-bt/composite"
"go-bt/leaf"
)
func BuildWorkerTree(cancel context.CancelFunc) core.Command[WorkerState] {
return composite.NewSelector(
composite.NewSequence(
composite.NewSelector(
leaf.NewCondition(func(blackboard *WorkerState) bool {
// Assert connected
// Here you'd check whether the connection is valid, etc.
return blackboard.IsConnected
}),
leaf.NewAction(func(ctx *core.BTContext[WorkerState]) int {
// Make a network connection
// Here you'd actually connect to a database
ctx.Blackboard.IsConnected = true
return 1
}),
),
leaf.NewAction(func(ctx *core.BTContext[WorkerState]) int {
// Process Tasks if connected
if ctx.Blackboard.PendingTasks <= 0 {
cancel()
return 1
}
ctx.Blackboard.PendingTasks--
return 1
}),
),
)
}
3. Start the Supervisor Daemon
go-bt provides a concurrent, panic-safe Supervisor to drive your tree. It spins up in the background and continuously ticks the logic without blocking your main application thread.
func main() {
state := &WorkerState{IsConnected: false, PendingTasks: 2}
// Initialize the context with a global cancellation token
ctx, cancel := context.WithCancel(context.Background())
btCtx := core.NewBTContext(ctx, state)
tree := BuildWorkerTree(cancel)
// Create a Supervisor that ticks every 100ms
supervisor := core.NewSupervisor(tree, 100*time.Millisecond, func(err any) {
println("Tree panicked, safely recovered:", err)
})
// Start the daemon in the background
wg := supervisor.Start(btCtx)
// Wait for the global context to be cancelled
wg.Wait()
}
You can check examples in the example directory.
Testing & Clock Injection
Testing temporal logic (like Sleep or Timeout) in CI/CD pipelines usually results in slow, flaky tests. go-bt solves this by exposing the Now function directly on the BTContext.
In your tests, simply replace the standard clock with a mock closure. This allows you to artificially advance time by hours or days in a single microsecond, instantly triggering your Timeout or Sleep node’s success/failure states to assert structural correctness.
{💬|⚡|🔥} **What’s your take?**
Share your thoughts in the comments below!
#️⃣ **#rvitorpergobt #Minimalist #implementation #GitHub**
🕒 **Posted on**: 1775660796
🌟 **Want more?** Click here for more info! 🌟
