Files
suaveplan/openspec/changes/enterprise-gaming-behavior-tree/proposal.md
2026-05-27 23:29:53 +01:00

4.7 KiB

OpenSpec Change: enterprise-gaming-behavior-tree

  • Change ID: enterprise-gaming-behavior-tree
  • Package: @suaveplan/behavior-tree
  • Category: gaming/ai
  • Target path: gaming/ai/behavior-tree
  • Status: PROPOSED
  • Date: 2026-04-24
  • Reference spec: /mnt/s/web/suaveplan/enterprise/behavior-tree.md

Summary

Deliver @suaveplan/behavior-tree on the genesis branch from scratch at enterprise quality. The package provides a behavior tree engine with composite nodes (Sequence, Selector, Parallel), decorator nodes (Inverter, Repeater, Cooldown, Timeout), leaf nodes (Action, Condition, Wait), a typed Blackboard for shared agent state, and a fluent builder API. BehaviorTreeRunner advances the tree one tick at a time returning SUCCESS | FAILURE | RUNNING. Genesis adds Zod blackboard key schemas, structured errors, OTel tick-duration histogram, injectable clock, and property tests for tree traversal invariants.


Current-state audit (genesis)

Package does not exist on genesis yet — fresh build.


Available workspace deps on genesis

Package Role
@suaveplan/error (workspace:^) BehaviorTreeError; BT.* codes
@suaveplan/types (workspace:^) Clock
zod (catalog:forms) Blackboard key schemas
@opentelemetry/api (catalog:observability) Tick duration histogram

Public API surface

type NodeStatus = 'SUCCESS' | 'FAILURE' | 'RUNNING'

interface TreeNode {
  readonly name: string
  tick(blackboard: Blackboard, dt: number): NodeStatus
  reset(): void
}

// Composites
function sequence(name: string, children: TreeNode[]): TreeNode
function selector(name: string, children: TreeNode[]): TreeNode
function parallel(name: string, children: TreeNode[], successPolicy?: 'all' | 'any', failurePolicy?: 'all' | 'any'): TreeNode

// Decorators
function inverter(name: string, child: TreeNode): TreeNode
function repeater(name: string, child: TreeNode, times?: number): TreeNode   // undefined = forever
function cooldown(name: string, child: TreeNode, cooldownSeconds: number, clock?: Clock): TreeNode
function timeout(name: string, child: TreeNode, timeoutSeconds: number, clock?: Clock): TreeNode

// Leaves
function action(name: string, fn: (bb: Blackboard, dt: number) => NodeStatus): TreeNode
function condition(name: string, fn: (bb: Blackboard) => boolean): TreeNode
function wait(name: string, durationSeconds: number, clock?: Clock): TreeNode

// Blackboard
function createBlackboard<T extends Record<string, unknown>>(initial?: Partial<T>): Blackboard<T>

interface Blackboard<T extends Record<string, unknown> = Record<string, unknown>> {
  get<K extends keyof T>(key: K): T[K] | undefined
  set<K extends keyof T>(key: K, value: T[K]): void
  has(key: keyof T): boolean
  delete(key: keyof T): void
  clear(): void
  clone(): Blackboard<T>
}

// Runner
function createBehaviorTreeRunner(root: TreeNode, blackboard: Blackboard, clock?: Clock): BehaviorTreeRunner

interface BehaviorTreeRunner {
  tick(dt: number): NodeStatus
  reset(): void
  readonly lastStatus: NodeStatus | null
  readonly tickCount: number
}

// Fluent builder
function bt(name: string): BehaviorTreeBuilder

Error codes

type BtErrorCode =
  | 'BT_EMPTY_COMPOSITE'
  | 'BT_BLACKBOARD_KEY_NOT_FOUND'
  | 'BT_NODE_TICK_FAILED'
  | 'BT_INVALID_POLICY'

New additions for genesis

  1. Parallel policies — configurable success/failure policies for parallel composite.
  2. Cooldown decorator — injectable clock; skips subtree when cooldown active, returns FAILURE.
  3. Timeout decorator — returns FAILURE if child runs longer than timeout.
  4. Blackboard clone — clone() for subtree isolation in parallel branches.
  5. OTel — bt.tick_duration_ms histogram; bt.node_status_total counter by status.

File layout

gaming/ai/behavior-tree/
  package.json
  tsconfig.json
  vitest.config.ts
  src/
    index.ts
    error-codes.ts
    constants/index.ts
    types/common.ts
    types/common.md
    core/
      blackboard/
        blackboard.ts
        blackboard.md
        blackboard.types.ts
        blackboard.test.ts
        index.ts
      nodes/
        composites.ts
        composites.md
        composites.test.ts
        decorators.ts
        decorators.md
        decorators.test.ts
        leaves.ts
        leaves.md
        leaves.test.ts
      runner/
        runner.ts
        runner.md
        runner.types.ts
        runner.test.ts
        index.ts
    builder/
      builder.ts
      builder.md
      builder.test.ts
      index.ts
  tests/
    property.test.ts

Impact

Downstream: @suaveplan/npc builds per-NPC behavior trees; @suaveplan/r3f-npc renders debug tree overlays. Prerequisites: @suaveplan/error, @suaveplan/types.