# Mecha10 Behavior Runtime

A unified behavior composition system for robotics and AI that enables building complex robot behaviors from simple, composable pieces.

## Overview

The behavior runtime provides a **tick-based execution model** where all behaviors implement a single `BehaviorNode` trait. This creates a uniform interface for:

- Custom Rust behaviors (complex logic, high performance)
- AI inference nodes (YOLO, LLMs, RL policies)
- Planning and navigation (A*, RRT, SLAM)
- Composition primitives (Sequence, Selector, Parallel)

## Quick Start

```rust
use mecha10_behavior_runtime::prelude::*;

// Define a custom behavior
#[derive(Debug)]
struct MyBehavior;

#[async_trait]
impl BehaviorNode for MyBehavior {
    async fn tick(&mut self, ctx: &Context) -> anyhow::Result<NodeStatus> {
        // Your behavior logic here
        println!("Hello from my behavior!");
        Ok(NodeStatus::Success)
    }
}

// Execute it
#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let ctx = Context::new("my_node").await?;
    let behavior = Box::new(MyBehavior);
    let mut executor = BehaviorExecutor::new(behavior, 30.0); // 30 Hz

    executor.init(&ctx).await?;
    let (status, stats) = executor.run_until_complete(&ctx).await?;

    println!("Completed with status: {} in {} ticks", status, stats.tick_count);
    Ok(())
}
```

## Core Concepts

### BehaviorNode Trait

All behaviors implement this single trait:

```rust
#[async_trait]
pub trait BehaviorNode: Send + Sync + Debug {
    async fn tick(&mut self, ctx: &Context) -> anyhow::Result<NodeStatus>;

    fn name(&self) -> &str { /* ... */ }
    async fn reset(&mut self) -> anyhow::Result<()> { /* ... */ }
    async fn on_init(&mut self, ctx: &Context) -> anyhow::Result<()> { /* ... */ }
    async fn on_terminate(&mut self, ctx: &Context) -> anyhow::Result<()> { /* ... */ }
}
```

### Node Status

Behaviors return one of three statuses:

- `NodeStatus::Success` - Behavior completed successfully
- `NodeStatus::Failure` - Behavior failed (irrecoverable error)
- `NodeStatus::Running` - Behavior is still executing

### Composition Primitives

#### Sequence Node

Executes children in order until one fails or all succeed.

```rust
let sequence = SequenceNode::new(vec![
    Box::new(ApproachObject),
    Box::new(GraspObject),
    Box::new(LiftObject),
]);
```

#### Selector Node (Fallback)

Tries children until one succeeds or all fail.

```rust
let selector = SelectOrNode::new(vec![
    Box::new(UseHighPrecisionSensor),
    Box::new(UseLowPrecisionSensor),
    Box::new(UseEstimatedPosition),
]);
```

#### Parallel Node

Executes all children concurrently.

```rust
let parallel = ParallelNode::new(
    vec![
        Box::new(MonitorObstacles),
        Box::new(MoveToGoal),
        Box::new(UpdateMap),
    ],
    ParallelPolicy::RequireAll,
);
```

## Node Registry & Loading

The behavior runtime provides a powerful system for loading behavior trees from JSON configurations. This enables configuration-driven behavior and separation between behavior logic (Rust) and composition (JSON). Hot-reloading support is planned for future releases (see Hot Reload Status below).

### Registering Custom Nodes

Create a `NodeRegistry` and register your custom behavior types:

```rust
use mecha10_behavior_runtime::prelude::*;

// Define your custom behavior
#[derive(Debug)]
struct MoveToGoal {
    speed: f64,
}

impl MoveToGoal {
    fn from_config(config: serde_json::Value) -> anyhow::Result<Self> {
        let speed = config.get("speed")
            .and_then(|v| v.as_f64())
            .unwrap_or(1.0);
        Ok(Self { speed })
    }
}

#[async_trait]
impl BehaviorNode for MoveToGoal {
    async fn tick(&mut self, ctx: &Context) -> anyhow::Result<NodeStatus> {
        // Your behavior logic here
        Ok(NodeStatus::Success)
    }
}

// Register it with the registry
let mut registry = NodeRegistry::new();
registry.register("move_to_goal", |config| {
    Ok(Box::new(MoveToGoal::from_config(config)?))
});
```

### Loading Behavior Trees

Use the `BehaviorLoader` to load behavior trees from JSON:

```rust
// Create a loader with your registry
let loader = BehaviorLoader::new(registry);

// Option 1: Load from a JSON string
let json = r#"{
    "name": "my_behavior",
    "root": {
        "type": "node",
        "node": "move_to_goal",
        "config": { "speed": 2.0 }
    }
}"#;
let behavior = loader.load_from_json(json)?;

// Option 2: Load from a file
let behavior = loader.load_from_file("behaviors/patrol.json")?;

// Option 3: Load from a parsed config
let config = BehaviorConfig::from_file("behaviors/patrol.json")?;
let behavior = loader.load(&config)?;
```

### Complete Workflow

Here's the complete workflow from registration to execution:

```rust
// 1. Create registry and register nodes
let mut registry = NodeRegistry::new();
registry.register("move_to_goal", |config| {
    Ok(Box::new(MoveToGoal::from_config(config)?))
});
registry.register("detect_obstacles", |config| {
    Ok(Box::new(DetectObstacles::from_config(config)?))
});

// 2. Create loader and load behavior tree
let loader = BehaviorLoader::new(registry);
let behavior = loader.load_from_file("patrol_mission.json")?;

// 3. Create executor and run
let ctx = Context::new("robot").await?;
let mut executor = BehaviorExecutor::new(behavior, 30.0);
executor.init(&ctx).await?;

let (status, stats) = executor.run_until_complete(&ctx).await?;
println!("Completed with status: {} in {} ticks", status, stats.tick_count);
```

See `examples/load_and_execute.rs` for a complete working example.

## JSON Configuration

Behaviors can be defined in JSON for dynamic composition:

```json
{
  "$schema": "https://mecha10.dev/schemas/behavior-composition-v1.json",
  "name": "patrol_mission",
  "root": {
    "type": "sequence",
    "children": [
      {
        "type": "node",
        "node": "safety_check",
        "config_ref": "safety"
      },
      {
        "type": "selector",
        "children": [
          {
            "type": "node",
            "node": "detect_obstacles"
          },
          {
            "type": "node",
            "node": "wander"
          }
        ]
      }
    ]
  },
  "configs": {
    "safety": { "max_speed": 1.0 }
  }
}
```

Load and execute:

```rust
// Step 1: Create a registry and register your node types
let mut registry = NodeRegistry::new();
registry.register("safety_check", |config| {
    Ok(Box::new(SafetyCheck::from_config(config)?))
});
registry.register("detect_obstacles", |config| {
    Ok(Box::new(DetectObstacles::from_config(config)?))
});
registry.register("wander", |config| {
    Ok(Box::new(Wander::from_config(config)?))
});

// Step 2: Create a loader and load the behavior tree
let loader = BehaviorLoader::new(registry);
let behavior = loader.load_from_file("patrol_mission.json")?;

// Step 3: Execute with the behavior executor
let mut executor = BehaviorExecutor::new(behavior, 30.0);
let (status, stats) = executor.run_until_complete(&ctx).await?;
```

## Built-in Action Nodes

The runtime includes several built-in action nodes for common robotics tasks. Register them with:

```rust
use mecha10_behavior_runtime::register_builtin_actions;

let mut registry = NodeRegistry::new();
register_builtin_actions(&mut registry);
```

### WanderNode

Generates random movement commands for exploration:

```json
{
  "type": "wander",
  "config": {
    "topic": "/motor/cmd_vel",
    "linear_speed": 0.3,
    "angular_speed": 0.5,
    "change_interval_secs": 3.0
  }
}
```

**Parameters:**
- `topic`: Topic to publish velocity commands (required)
- `linear_speed`: Forward speed in m/s (default: 0.3)
- `angular_speed`: Max turning speed in rad/s (default: 0.5)
- `change_interval_secs`: Seconds between direction changes (default: 3.0)

**Behavior:** Publishes constant linear velocity with periodically changing random angular velocity. Returns `Running` continuously.

### MoveNode

Executes a fixed velocity command for a specified duration:

```json
{
  "type": "move",
  "config": {
    "topic": "/motor/cmd_vel",
    "linear": 0.5,
    "angular": 0.0,
    "duration_secs": 2.0
  }
}
```

**Parameters:**
- `topic`: Topic to publish velocity commands (required)
- `linear`: Forward/backward velocity in m/s (required)
- `angular`: Turning velocity in rad/s (required)
- `duration_secs`: Duration to execute (optional, null = forever)

**Behavior:** Publishes the specified velocity command. Returns `Running` while executing, `Success` when duration elapses. If no duration specified, runs forever.

### TimerNode

Waits for a specified duration before succeeding:

```json
{
  "type": "timer",
  "config": {
    "duration_secs": 5.0
  }
}
```

**Parameters:**
- `duration_secs`: Duration to wait in seconds (required)

**Behavior:** Returns `Running` until the duration elapses, then returns `Success`. Useful for delays in sequences.

### SensorCheckNode

Checks sensor conditions (placeholder for future implementation):

```json
{
  "type": "sensor_check",
  "config": {
    "topic": "/sensors/distance",
    "field": "value",
    "operator": "less_than",
    "threshold": 0.5
  }
}
```

**Parameters:**
- `topic`: Sensor topic to subscribe to (required)
- `field`: Field name in sensor message (required)
- `operator`: Comparison operator - `less_than`, `greater_than`, `equal` (required)
- `threshold`: Comparison value (required)

**Current Status:** Returns `Success` immediately (stub). Full sensor subscription implementation pending.

## Seed Templates

The package includes production-ready behavior tree templates in the `seeds/` directory:

- **basic_navigation.json** - Simple waypoint navigation with battery check and path planning
- **obstacle_avoidance.json** - Reactive collision avoidance using sensor fusion
- **patrol_simple.json** - Basic patrol loop cycling through waypoints
- **idle_wander.json** - Random wandering for exploration and idle movement

You can use these templates as starting points for your own behavior trees or load them directly:

```rust
let loader = BehaviorLoader::new(registry);
let behavior = loader.load_from_file("seeds/basic_navigation.json")?;
```

### Creating Behavior Trees with the CLI

The Mecha10 CLI provides an interactive wizard for creating behavior trees:

```bash
# Interactive mode - wizard will guide you through template selection
mecha10 behaviors create

# Create with specific template
mecha10 behaviors create --name my_behavior --template navigation

# List available templates
mecha10 behaviors list

# Validate an existing behavior tree
mecha10 behaviors validate behaviors/my_behavior.json
```

## Configuration Validation

The runtime provides comprehensive validation for behavior trees before execution:

```rust
use mecha10_behavior_runtime::{validate_behavior_config, NodeRegistry, register_builtin_actions};
use serde_json::json;

let mut registry = NodeRegistry::new();
register_builtin_actions(&mut registry);

let config = json!({
    "name": "wander_behavior",
    "root": {
        "type": "sequence",
        "children": [
            {
                "type": "wander",
                "config": {
                    "topic": "/motor/cmd_vel",
                    "linear_speed": 0.5
                }
            }
        ]
    }
});

let result = validate_behavior_config(&config, &registry)?;
if !result.valid {
    for error in &result.errors {
        eprintln!("Error: {}", error);
    }
}
for warning in &result.warnings {
    eprintln!("Warning: {}", warning);
}
```

**Validation Checks:**
- Required fields (`name`, `root`)
- Node types are registered or are composition nodes
- Tree structure is well-formed
- Children arrays exist for composition nodes
- Schema reference is present (warning if missing)
- Empty children arrays (warning)

**ValidationResult:**
```rust
pub struct ValidationResult {
    pub valid: bool,
    pub errors: Vec<String>,
    pub warnings: Vec<String>,
}
```

## Environment-Specific Configuration

Behavior trees support a three-tier configuration hierarchy for environment-specific overrides:

1. **Template** (required): `behaviors/wander.json` - Base behavior tree
2. **Common** (optional): `configs/common/behaviors/wander.json` - Shared overrides
3. **Environment** (optional): `configs/dev/behaviors/wander.json` - Environment-specific overrides

Configurations are deep-merged, with later tiers overriding earlier ones.

### Loading Environment-Specific Configs

```rust
use mecha10_behavior_runtime::{load_behavior_config, detect_project_root, get_current_environment};

// Auto-detect project root (walks up to find mecha10.json)
let project_root = detect_project_root()?;

// Get environment from MECHA10_ENVIRONMENT or default to "dev"
let environment = get_current_environment();

// Load with environment-specific overrides
let config = load_behavior_config("wander", &project_root, &environment).await?;
```

### Example: Environment Overrides

**Base Template** (`behaviors/wander.json`):
```json
{
  "name": "wander_behavior",
  "root": {
    "type": "wander",
    "config": {
      "topic": "/motor/cmd_vel",
      "linear_speed": 0.3,
      "angular_speed": 0.5,
      "change_interval_secs": 3.0
    }
  }
}
```

**Development Override** (`configs/dev/behaviors/wander.json`):
```json
{
  "root": {
    "config": {
      "linear_speed": 0.1,
      "angular_speed": 0.2
    }
  }
}
```

**Production Override** (`configs/production/behaviors/wander.json`):
```json
{
  "root": {
    "config": {
      "linear_speed": 0.5,
      "angular_speed": 0.8,
      "change_interval_secs": 5.0
    }
  }
}
```

**Result:** In development, the robot moves slowly (0.1 m/s linear). In production, it moves faster (0.5 m/s linear) with wider turns.

### Deep Merge Behavior

The merge is recursive for nested objects:

```rust
// Base
{ "a": 1, "b": { "x": 1, "y": 2 } }

// Override
{ "b": { "y": 3, "z": 4 }, "c": 5 }

// Result
{ "a": 1, "b": { "x": 1, "y": 3, "z": 4 }, "c": 5 }
```

Non-object values are replaced entirely.

## Composition Patterns

### Pattern 1: Sequential Execution (Sequence Node)

Use sequences when tasks must be performed in order, and all must succeed:

```json
{
  "type": "sequence",
  "children": [
    { "type": "node", "node": "check_battery" },
    { "type": "node", "node": "plan_path" },
    { "type": "node", "node": "follow_path" },
    { "type": "node", "node": "check_arrival" }
  ]
}
```

**Behavior**: Executes children left-to-right. If any child fails, the sequence fails immediately. All children must succeed for the sequence to succeed.

**Use cases**: Multi-step tasks, initialization sequences, workflows

### Pattern 2: Fallback/Priority (Selector Node)

Use selectors when you have multiple strategies and want to try them in priority order:

```json
{
  "type": "selector",
  "children": [
    { "type": "node", "node": "use_high_precision_sensor" },
    { "type": "node", "node": "use_low_precision_sensor" },
    { "type": "node", "node": "use_estimated_position" }
  ]
}
```

**Behavior**: Tries children left-to-right. If a child succeeds, the selector succeeds immediately. If all children fail, the selector fails.

**Use cases**: Fallback strategies, priority-based behavior selection, fault tolerance

### Pattern 3: Concurrent Execution (Parallel Node)

Use parallel nodes when tasks can run simultaneously:

```json
{
  "type": "parallel",
  "policy": "require_all",
  "children": [
    { "type": "node", "node": "monitor_obstacles" },
    { "type": "node", "node": "move_to_goal" },
    { "type": "node", "node": "update_map" }
  ]
}
```

**Behavior**: Executes all children concurrently. Success/failure depends on the policy:
- `require_all`: All children must succeed
- `require_one`: At least one child must succeed
- `require_n(N)`: At least N children must succeed

**Use cases**: Monitoring + action, sensor fusion, multi-tasking

### Pattern 4: Subsumption Architecture

Layered behavior with priority suppression (high-priority behaviors override low-priority ones):

```json
{
  "type": "selector",
  "name": "subsumption_layers",
  "children": [
    {
      "type": "sequence",
      "name": "emergency_layer",
      "children": [
        { "type": "node", "node": "detect_emergency" },
        { "type": "node", "node": "emergency_stop" }
      ]
    },
    {
      "type": "sequence",
      "name": "avoidance_layer",
      "children": [
        { "type": "node", "node": "detect_obstacles" },
        { "type": "node", "node": "avoid_obstacles" }
      ]
    },
    {
      "type": "sequence",
      "name": "navigation_layer",
      "children": [
        { "type": "node", "node": "check_goal" },
        { "type": "node", "node": "navigate_to_goal" }
      ]
    },
    { "type": "node", "node": "idle" }
  ]
}
```

**Use cases**: Safety-critical systems, reactive robotics, behavior hierarchies

See `packages/behavior-patterns/seeds/safety_subsumption.json` for a complete example.

### Pattern 5: Ensemble/Fusion

Multiple models or sensors providing input for a single decision:

```json
{
  "type": "sequence",
  "children": [
    { "type": "node", "node": "capture_sensor_data" },
    {
      "type": "parallel",
      "policy": "require_all",
      "children": [
        { "type": "node", "node": "yolo_detector" },
        { "type": "node", "node": "mobilenet_detector" },
        { "type": "node", "node": "depth_detector" }
      ]
    },
    { "type": "node", "node": "fuse_detections" },
    { "type": "node", "node": "make_decision" }
  ]
}
```

**Use cases**: Sensor fusion, multi-model AI, robust perception

See `packages/behavior-patterns/seeds/multi_model_ensemble.json` for a complete example.

## Execution Engine

The `BehaviorExecutor` manages tick-based execution:

```rust
let executor = BehaviorExecutor::new(behavior, 30.0)  // 30 Hz tick rate
    .with_max_ticks(1000);  // Optional timeout

// Run until completion
let (status, stats) = executor.run_until_complete(&ctx).await?;

// Or run for a fixed duration
let (status, stats) = executor.run_for_duration(&ctx, Duration::from_secs(10)).await?;
```

Execution statistics:

```rust
println!("Ticks: {}", stats.tick_count);
println!("Duration: {:?}", stats.total_duration);
println!("Avg tick: {:?}", stats.avg_tick_duration);
println!("Min/Max: {:?}/{:?}", stats.min_tick_duration, stats.max_tick_duration);
```

## Architecture

### Philosophy

- **Behavior Logic** = Rust code (complex logic, high performance)
- **Behavior Composition** = JSON config (simple orchestration, will support hot-reloading)
- **Configuration** = JSON with validation (parameters only)

### Benefits

- **Unified Interface**: Everything is a BehaviorNode
- **Composable**: Mix and match behaviors freely
- **Type-Safe**: Rust's type system ensures correctness
- **Performance**: Zero-cost abstractions, compiled Rust
- **Debuggable**: Clear execution model with stats

## Integration with Mecha10

This package is part of the Mecha10 framework and integrates with:

- **mecha10-core**: Provides `Context` for messaging and state
- **AI nodes** (planned): YOLO, LLMs, RL policies
- **Planning nodes** (planned): A*, RRT, SLAM
- **Dashboard**: Real-time behavior visualization

## Status

**Current Status**: Phase 5 Complete - Config Loading & Validation ✅

Implemented:
- ✅ Core `BehaviorNode` trait
- ✅ `NodeStatus` enum
- ✅ Composition primitives (Sequence, Selector, Parallel)
- ✅ JSON configuration types with JSON Schema
- ✅ Tick-based execution engine
- ✅ Execution statistics
- ✅ Node registry for dynamic node instantiation
- ✅ Behavior loader for loading trees from JSON
- ✅ Integration examples and documentation
- ✅ Production-ready seed templates (6 templates)
- ✅ CLI wizard for creating behavior trees
- ✅ Comprehensive composition pattern documentation
- ✅ JSON Schema for validation and IDE support
- ✅ **Built-in action nodes** (WanderNode, MoveNode, TimerNode, SensorCheckNode)
- ✅ **Configuration validation** (validate_behavior_config with detailed errors/warnings)
- ✅ **Environment-specific configuration** (three-tier: template → common → environment)
- ✅ **BehaviorExecutor node** (mecha10-nodes-behavior-executor for integration)
- ✅ **Integration tests** (14 tests for action nodes and config validation)

Next Steps (Priority 7 - see CLAUDE_TODO.md):
- [ ] Behavior tree catalog service (REST API + PostgreSQL)
- [ ] AI node library (Vision, Language, Speech)
- [ ] Planning nodes (Path planning, SLAM, OpenCV)
- [ ] Dashboard monitoring interface
- [ ] Hot-reload support for behavior trees

## Hot Reload Status

**Current**: The behavior runtime supports loading behavior trees from JSON files at startup. You can modify JSON files and restart your nodes to load updated behavior trees.

**Planned**: Automatic hot-reloading of behavior trees while nodes are running. This will enable:
- File system watching for JSON behavior tree changes
- Validation of new behavior trees before applying
- Seamless tree swapping without node restart
- State preservation for stateful nodes (optional)
- Rollback on reload errors

**Timeline**: Hot-reload functionality is tracked in CLAUDE_TODO.md under P2 (Medium Priority) tasks.

**Current Workflow**:
1. Edit your behavior tree JSON file
2. Stop your running node (Ctrl+C)
3. Restart the node with `mecha10 run <node-name>`
4. The node will load the updated behavior tree

## Testing

The package currently builds successfully. Integration tests require a running Redis instance (provided by mecha10-core Context).

```bash
cargo build -p mecha10-behavior-runtime
cargo test -p mecha10-behavior-runtime
```

## License

MIT

## See Also

- [AI Features Documentation](../../docs/AI_FEATURES.md)
- [CLAUDE_TODO.md](../../CLAUDE_TODO.md) - Priority 7: AI Native
