Files
storybook/design/behavior-tree-keywords-design.md
Sienna Meridian Satterwhite 16deb5d237 release: Storybook v0.2.0 - Major syntax and features update
BREAKING CHANGES:
- Relationship syntax now requires blocks for all participants
- Removed self/other perspective blocks from relationships
- Replaced 'guard' keyword with 'if' for behavior tree decorators

Language Features:
- Add tree-sitter grammar with improved if/condition disambiguation
- Add comprehensive tutorial and reference documentation
- Add SBIR v0.2.0 binary format specification
- Add resource linking system for behaviors and schedules
- Add year-long schedule patterns (day, season, recurrence)
- Add behavior tree enhancements (named nodes, decorators)

Documentation:
- Complete tutorial series (9 chapters) with baker family examples
- Complete reference documentation for all language features
- SBIR v0.2.0 specification with binary format details
- Added locations and institutions documentation

Examples:
- Convert all examples to baker family scenario
- Add comprehensive working examples

Tooling:
- Zed extension with LSP integration
- Tree-sitter grammar for syntax highlighting
- Build scripts and development tools

Version Updates:
- Main package: 0.1.0 → 0.2.0
- Tree-sitter grammar: 0.1.0 → 0.2.0
- Zed extension: 0.1.0 → 0.2.0
- Storybook editor: 0.1.0 → 0.2.0
2026-02-13 21:52:03 +00:00

33 KiB

Behavior Tree Keyword System Design

Status: Design Proposal Author: Behavior Tree Language Designer (Agent 2) Date: February 2026 Related Tasks: Task #3, Task #4


Executive Summary

This document proposes replacing Storybook's symbolic behavior tree syntax (?, >, *, ~, !, @) with human-friendly keywords that make the language accessible to storytellers without programming backgrounds. The new syntax maintains all existing functionality while dramatically improving readability and intuitiveness.

Key Changes:

  • ?selector or choose
  • >sequence or then
  • *repeat (with optional parameters)
  • ~ → Decorator keywords: invert, retry(N), timeout(duration), cooldown(duration), guard(condition)
  • !if or when (condition nodes)
  • @ → No prefix needed for actions (just the action name)
  • Subtrees: @path::to::subtreeinclude path::to::subtree

1. Current State Analysis

1.1 Existing Symbolic Constructs

Sigil Node Type Current Semantics AST Representation
? Selector Try children in order; succeed on first success Selector(Vec<BehaviorNode>)
> Sequence Run children in order; fail on first failure Sequence(Vec<BehaviorNode>)
! Condition Evaluate expression; succeed if true Condition(Expr)
@ Action Execute named engine action Action(String, Vec<Field>)
~ Decorator Modify child behavior Decorator(String, Box<BehaviorNode>)
* Repeat Infinite loop decorator repeat_node (grammar only)
@path SubTree Reference to subtree SubTree(Vec<String>)

1.2 Examples from Codebase

Current Symbolic Syntax:

behavior WhiteRabbit_ConstantlyLate {
    ? {
        > {
            CheckPocketWatch
            RealizeHowLate
            MutterAnxiously
            ScurryToDestination
        }
        > {
            EncounterObstacle
            DropGloves
            DropFan
            PanicFurther
        }
    }
}

Current Limitations Identified:

  1. Decorator syntax missing: Multiple TODOs in examples mention "Add repeater decorator support"
  2. Sigils are cryptic: ? and > are not self-documenting
  3. No parameterized decorators: Cannot express repeat(3), timeout(5s), retry(2)
  4. Condition syntax unclear: ! looks like negation rather than "if this condition"
  5. Action prefix redundant: @ adds noise when actions are self-evident from context

1.3 Design Spec vs Implementation Gap

Design Spec (Section 6.1) promises:

  • Decorator support with ~ sigil
  • Modifiers: invert, repeat, cooldown
  • Semicolons OR newlines as separators

Current Implementation:

  • Tree-sitter grammar has repeat_node with * sigil
  • AST has Decorator(String, Box<BehaviorNode>)
  • No parameterized decorator syntax in grammar
  • Decorators mentioned in LSP code but not implemented in parser

Conclusion: Decorator functionality is partially designed but not fully implemented. This redesign is the perfect opportunity to implement it correctly with keyword syntax.


2. Proposed Keyword Mappings

2.1 Control Flow Keywords

Selector Node

Current: ? { ... } Proposed: selector { ... } OR choose { ... }

Rationale: "Choose" is more storytelling-friendly. "Selector" is technically accurate for developers.

Recommendation: Support both, with choose as the preferred form in examples. (i want choose, no selector)

Example:

// Before
? {
    try_option_a
    try_option_b
    fallback
}

// After (storyteller-friendly)
choose {
    try_option_a
    try_option_b
    fallback
}

// After (developer-friendly)
selector {
    try_option_a
    try_option_b
    fallback
}

Sequence Node

Current: > { ... } Proposed: sequence { ... } OR then { ... }

Rationale: "Then" reads naturally in storytelling contexts. "Sequence" is technically precise.

Recommendation: Support both, with context determining preference. (i want then, no sequence)

Example:

// Before
> {
    check_energy
    move_to_location
    perform_action
}

// After (storyteller-friendly)
then {
    check_energy
    move_to_location
    perform_action
}

// After (developer-friendly)
sequence {
    check_energy
    move_to_location
    perform_action
}

2.2 Condition Keywords

Current: ! expression Proposed: if(expression) OR when(expression)

Rationale: Clear, universally understood conditional syntax.

Recommendation: Support both for flexibility. when is more narrative-friendly. (use when)

Example:

// Before
! need.any is urgent

// After (either form)
if(need.any is urgent)
when(need.any is urgent)

2.3 Action Keywords

Current: @ action_name or @ action_name(params) Proposed: Remove prefix, just use action name

Rationale: Actions are distinguishable from control flow by context. No prefix needed. (yeah i'm fine with this)

Example:

// Before
@ move_to(counter)
@ serve_next_customer

// After
move_to(counter)
serve_next_customer

2.4 Subtree Keywords

Current: @path::to::subtree Proposed: include path::to::subtree

Rationale: "Include" clearly indicates pulling in external definition. Distinct from actions. (perfect)

Example:

// Before
behavior WorkAtClinic {
    ? {
        @HandleUrgentNeed
        > treat_patients { ... }
    }
}

// After
behavior WorkAtClinic {
    choose {
        include HandleUrgentNeed
        then treat_patients { ... }
    }
}

2.5 Decorator Keywords (idk, that would make this turing complete sooooo i mean i guess? this feels like too much but okay.)

Current: ~decorator_name { child } (design spec, not implemented) Proposed: Direct keyword syntax with optional parameters

Basic Decorators

repeat - Infinite loop

// Equivalent to current * sigil
repeat {
    patrol
}

repeat(N) - Loop N times

repeat(3) {
    knock_on_door
}

repeat(min..max) - Loop between min and max times

repeat(2..5) {
    search_area
}

invert - Negate child result

invert {
    if(enemy_nearby)
}

retry(N) - Retry up to N times on failure

retry(3) {
    attempt_connection
}

timeout(duration) - Fail if child exceeds duration

timeout(5s) {
    wait_for_response
}

cooldown(duration) - Prevent re-execution within duration

cooldown(30s) {
    shout_warning
}

guard(condition) - Only run child if condition met

guard(energy > 50) {
    sprint_to_safety
}

succeed_always - Always return success

succeed_always {
    attempt_optional_task
}

fail_always - Always return failure (useful for debugging)

fail_always {
    disabled_behavior
}

3. Complete Grammar Specification

3.1 Behavior Block Syntax

behavior_declaration ::= "behavior" identifier prose_blocks? "{" behavior_node "}"

behavior_node ::=
    | selector_node
    | sequence_node
    | condition_node
    | action_node
    | decorator_node
    | subtree_node

selector_node ::= ("selector" | "choose") "{" behavior_node+ "}"

sequence_node ::= ("sequence" | "then") "{" behavior_node+ "}"

condition_node ::= ("if" | "when") "(" expression ")"

action_node ::= identifier ( "(" action_params ")" )?

action_params ::= action_param ("," action_param)*
action_param ::= (identifier ":")? value

decorator_node ::= decorator_keyword decorator_params? "{" behavior_node "}"

decorator_keyword ::=
    | "repeat"
    | "invert"
    | "retry"
    | "timeout"
    | "cooldown"
    | "guard"
    | "succeed_always"
    | "fail_always"

decorator_params ::=
    | "(" integer ")"                    // repeat(N), retry(N)
    | "(" integer ".." integer ")"       // repeat(min..max)
    | "(" duration ")"                   // timeout(5s), cooldown(30s)
    | "(" expression ")"                 // guard(condition)

subtree_node ::= "include" path_segments

duration ::= integer ("d" | "h" | "m" | "s")

3.2 Nested Syntax Support

Decorators can nest:

timeout(10s) {
    retry(3) {
        attempt_difficult_task
    }
}

Inline conditions within control flow:

choose {
    then {
        if(threat_detected)
        flee_to_safety
    }
    then {
        if(resource_found)
        gather_resource
    }
    idle_wait
}

Named nodes (optional for complex trees): (oooo i fucking love this, maybe this is the required design.)

choose root {
    sequence handle_threat {
        if(threat_detected)
        flee_to_safety
    }
    sequence gather {
        if(resource_found)
        gather_resource
    }
    idle_wait
}

4. Example Transformations

4.1 Simple Behavior (White Rabbit)

Before:

behavior WhiteRabbit_ConstantlyLate {
    ? {
        > {
            CheckPocketWatch
            RealizeHowLate
            MutterAnxiously
            ScurryToDestination
        }
        > {
            EncounterObstacle
            DropGloves
            DropFan
            PanicFurther
            ReverseDirection
        }
        > {
            SpotQueen
            FlattenEarsInFear
            TremblingBow
            AwaitCommands
        }
        > {
            CheckWatch
            RunInCircles
            CheckWatchAgain
        }
    }
}

After:

behavior WhiteRabbit_ConstantlyLate {
    ---description
    Models the White Rabbit's perpetual anxiety about time and
    his duties to the Queen. Uses a selector to try multiple
    panic responses.
    ---

    choose {
        then {
            CheckPocketWatch
            RealizeHowLate
            MutterAnxiously
            ScurryToDestination
        }
        then {
            EncounterObstacle
            DropGloves
            DropFan
            PanicFurther
            ReverseDirection
        }
        then {
            SpotQueen
            FlattenEarsInFear
            TremblingBow
            AwaitCommands
        }
        then {
            CheckWatch
            RunInCircles
            CheckWatchAgain
        }
    }
}

4.2 Complex Behavior with Decorators (New)

Current (with TODO):

behavior MadTeaParty_CoordinatedMadness {
    ---description
    Models the Mad Hatter's perpetual tea party that loops forever.
    ---

    // TODO: Add repeater decorator support
    > {
        // Selector: Choose a mad activity
        ? {
            > {
                PoseRiddle
                WaitForAnswer
                DeclareAnswerWrong
            }
            > {
                SwitchSeats
                CleanDirtyTeacup
                PourFreshTea
            }
            > {
                WakeDormouse
                ListenToBriefStory
                StuffDormouseInTeapot
            }
        }
    }
}

After (with decorators implemented):

behavior MadTeaParty_CoordinatedMadness {
    ---description
    Models the Mad Hatter's perpetual tea party that loops forever at 6 o'clock.
    The party never ends, cycling through mad activities indefinitely.
    ---

    repeat {
        choose {
            then {
                PoseRiddle
                WaitForAnswer
                DeclareAnswerWrong
            }
            then {
                SwitchSeats
                CleanDirtyTeacup
                PourFreshTea
            }
            then {
                WakeDormouse
                ListenToBriefStory
                StuffDormouseInTeapot
            }
        }
    }
}

4.3 Advanced Behavior with Guards and Timeouts

New capability:

behavior CheshireCat_Materialization {
    ---description
    Complex behavior modeling the Cheshire Cat's gradual materialization
    and dematerialization. Uses decorators to add timing and conditions.
    ---

    choose {
        then {
            if(alice_nearby and visibility < 0.1)
            timeout(10s) {
                repeat(5) {
                    IncreaseVisibility(0.2)
                    PauseForEffect(1s)
                }
            }
            MaterializeGrin
            SpeakInRiddles
        }

        then {
            if(visibility > 0.9)
            cooldown(30s) {
                timeout(8s) {
                    repeat(5) {
                        DecreaseVisibility(0.2)
                        PauseForEffect(1s)
                    }
                }
            }
            VanishExceptGrin
        }

        guard(visibility >= 0.5) {
            IdleFloat
        }
    }
}

4.4 Behavior with Retries

New capability:

behavior ExecutionerDuty {
    ---description
    The executioner attempts to behead people, but always fails
    because the Queen's targets often vanish or are cards.
    ---

    choose {
        then {
            if(execution_ordered)
            retry(3) {
                sequence {
                    LocateTarget
                    PrepareAxe
                    AttemptBeheading
                }
            }
            ReportFailureToQueen
            ReceiveBeheadingThreat
        }

        repeat {
            WaitForOrders
        }
    }
}

5. SBIR Representation

The SBIR (Storybook Intermediate Representation) must encode all behavior tree nodes with their full semantics.

5.1 Node Type Encoding

// SBIR Section 7: BEHAVIOR_TREES
enum BehaviorNodeType {
    Selector = 0x01,
    Sequence = 0x02,
    Condition = 0x03,
    Action = 0x04,
    // Decorators: 0x10-0x1F range
    DecoratorRepeat = 0x10,
    DecoratorRepeatN = 0x11,
    DecoratorRepeatRange = 0x12,
    DecoratorInvert = 0x13,
    DecoratorRetry = 0x14,
    DecoratorTimeout = 0x15,
    DecoratorCooldown = 0x16,
    DecoratorGuard = 0x17,
    DecoratorSucceedAlways = 0x18,
    DecoratorFailAlways = 0x19,
    SubTree = 0x20,
}

5.2 Decorator Parameter Encoding

Repeat:

  • repeatDecoratorRepeat (no parameters)
  • repeat(N)DecoratorRepeatN + u32 count
  • repeat(min..max)DecoratorRepeatRange + u32 min + u32 max

Retry:

  • retry(N)DecoratorRetry + u32 max_attempts

Timeout/Cooldown:

  • timeout(duration)DecoratorTimeout + u64 milliseconds
  • cooldown(duration)DecoratorCooldown + u64 milliseconds

Guard:

  • guard(expr)DecoratorGuard + serialized_expression

Binary Format Example:

repeat(3) {
    patrol
}

Encoded as:
[DecoratorRepeatN] [count: 3] [child_node_offset]
  └─> [Action] [string_index: "patrol"]

6. Tree-sitter Grammar Updates

6.1 Updated Rules (Conceptual)

The Tree-sitter grammar will need these new patterns:

Selector node:

"selector" OR "choose" followed by "{" then one or more behavior_nodes then "}"
Optional: can have a name identifier after the keyword

Sequence node:

"sequence" OR "then" followed by "{" then one or more behavior_nodes then "}"
Optional: can have a name identifier after the keyword

Condition node:

"if" OR "when" followed by "(" then an expression then ")"

Action node:

identifier (optionally followed by "(" parameters ")")
No @ prefix required

Decorator node:

decorator_keyword (optionally followed by decorator_params) then "{" behavior_node "}"

decorator_keyword: one of the decorator keywords (repeat, retry, timeout, etc.)

decorator_params:
  - "(" integer ")" for repeat(N), retry(N)
  - "(" integer ".." integer ")" for repeat(min..max)
  - "(" duration ")" for timeout(5s), cooldown(30s)
  - "(" expression ")" for guard(condition)

Subtree node:

"include" followed by a path (e.g., path::to::subtree)

Duration literal:

integer followed by one of: d, h, m, s
Examples: 5s, 30m, 2h, 1d

6.2 Backward Compatibility (Optional) (we don't need this, new language, 1.0 lol)

If backward compatibility is required, support legacy sigils as aliases:

  • ? as alias for selector
  • > as alias for sequence
  • * as alias for repeat
  • ! as alias for if
  • @ prefix as optional for actions
  • @path as alias for include path

Recommendation: Do NOT maintain backward compatibility. This is early development; clean break is better. (nope, no backwards compatibility)


7. Parser Implementation Strategy

7.1 AST Changes

Current AST (storybook/src/syntax/ast.rs):

pub enum BehaviorNode {
    Selector(Vec<BehaviorNode>),
    Sequence(Vec<BehaviorNode>),
    Condition(Expr),
    Action(String, Vec<Field>),
    Decorator(String, Box<BehaviorNode>),
    SubTree(Vec<String>),
}

Proposed AST:

pub enum BehaviorNode {
    Selector(Vec<BehaviorNode>),
    Sequence(Vec<BehaviorNode>),
    Condition(Expr),
    Action(String, Vec<Field>),
    Decorator(DecoratorType, Box<BehaviorNode>),
    SubTree(Vec<String>),
}

pub enum DecoratorType {
    Repeat,                              // infinite
    RepeatN(u32),                        // N times
    RepeatRange(u32, u32),               // min..max times
    Invert,
    Retry(u32),                          // max attempts
    Timeout(Duration),
    Cooldown(Duration),
    Guard(Expr),
    SucceedAlways,
    FailAlways,
}

pub struct Duration {
    pub value: u32,
    pub unit: DurationUnit,
}

pub enum DurationUnit {
    Days,
    Hours,
    Minutes,
    Seconds,
}

7.2 Parser Changes

Modify parser to:

  1. Accept selector | choose tokens instead of ?
  2. Accept sequence | then tokens instead of >
  3. Accept if | when tokens with parenthesized expressions
  4. Remove @ prefix requirement for actions
  5. Parse decorator keywords with optional parameters
  6. Parse include keyword for subtrees

Example parsing logic (pseudo-code):

fn parse_behavior_node(&mut self) -> Result<BehaviorNode> {
    match self.peek() {
        Token::Selector | Token::Choose => self.parse_selector(),
        Token::Sequence | Token::Then => self.parse_sequence(),
        Token::If | Token::When => self.parse_condition(),
        Token::Repeat | Token::Invert | ... => self.parse_decorator(),
        Token::Include => self.parse_subtree(),
        Token::Identifier => self.parse_action(),
        _ => Err(ParseError::ExpectedBehaviorNode),
    }
}

fn parse_decorator(&mut self) -> Result<BehaviorNode> {
    let decorator_type = match self.advance() {
        Token::Repeat => {
            if self.match_token(Token::LParen) {
                let n = self.parse_integer()?;
                if self.match_token(Token::DotDot) {
                    let max = self.parse_integer()?;
                    self.expect(Token::RParen)?;
                    DecoratorType::RepeatRange(n, max)
                } else {
                    self.expect(Token::RParen)?;
                    DecoratorType::RepeatN(n)
                }
            } else {
                DecoratorType::Repeat
            }
        },
        Token::Retry => {
            self.expect(Token::LParen)?;
            let n = self.parse_integer()?;
            self.expect(Token::RParen)?;
            DecoratorType::Retry(n)
        },
        // ... other decorators
    };

    self.expect(Token::LBrace)?;
    let child = self.parse_behavior_node()?;
    self.expect(Token::RBrace)?;

    Ok(BehaviorNode::Decorator(decorator_type, Box::new(child)))
}

7.3 Lexer Changes

Add new keyword tokens:

// In storybook/src/syntax/lexer.rs (logos)

#[token("selector")] Selector,
#[token("choose")] Choose,
#[token("sequence")] Sequence,
#[token("then")] Then,
#[token("if")] If,
#[token("when")] When,
#[token("repeat")] Repeat,
#[token("invert")] Invert,
#[token("retry")] Retry,
#[token("timeout")] Timeout,
#[token("cooldown")] Cooldown,
#[token("guard")] Guard,
#[token("succeed_always")] SucceedAlways,
#[token("fail_always")] FailAlways,
#[token("include")] Include,

8. Compiler Translation

8.1 AST → SBIR Translation

The compiler must translate the new AST nodes to SBIR format:

fn compile_behavior_node(node: &BehaviorNode, writer: &mut BinaryWriter) -> Result<()> {
    match node {
        BehaviorNode::Selector(children) => {
            writer.write_u8(BehaviorNodeType::Selector as u8)?;
            writer.write_u32(children.len() as u32)?;
            for child in children {
                compile_behavior_node(child, writer)?;
            }
        },
        BehaviorNode::Decorator(decorator_type, child) => {
            match decorator_type {
                DecoratorType::Repeat => {
                    writer.write_u8(BehaviorNodeType::DecoratorRepeat as u8)?;
                },
                DecoratorType::RepeatN(n) => {
                    writer.write_u8(BehaviorNodeType::DecoratorRepeatN as u8)?;
                    writer.write_u32(*n)?;
                },
                DecoratorType::RepeatRange(min, max) => {
                    writer.write_u8(BehaviorNodeType::DecoratorRepeatRange as u8)?;
                    writer.write_u32(*min)?;
                    writer.write_u32(*max)?;
                },
                DecoratorType::Timeout(duration) => {
                    writer.write_u8(BehaviorNodeType::DecoratorTimeout as u8)?;
                    writer.write_u64(duration.to_milliseconds())?;
                },
                // ... other decorators
            }
            compile_behavior_node(child, writer)?;
        },
        // ... other node types
    }
    Ok(())
}

9. Validation & Examples

9.1 Test Suite

Unit tests for parser:

#[test]
fn test_parse_selector_keyword() {
    let input = r#"
        behavior Test {
            selector {
                action_a
                action_b
            }
        }
    "#;
    let ast = parse(input).unwrap();
    assert!(matches!(ast.behaviors[0].root, BehaviorNode::Selector(_)));
}

#[test]
fn test_parse_repeat_decorator_with_count() {
    let input = r#"
        behavior Test {
            repeat(3) {
                patrol
            }
        }
    "#;
    let ast = parse(input).unwrap();
    let root = &ast.behaviors[0].root;
    assert!(matches!(root, BehaviorNode::Decorator(DecoratorType::RepeatN(3), _)));
}

#[test]
fn test_parse_nested_decorators() {
    let input = r#"
        behavior Test {
            timeout(10s) {
                retry(3) {
                    attempt_task
                }
            }
        }
    "#;
    let ast = parse(input).unwrap();
    // Assert nested structure
}

Integration tests:

  • Parse all Alice in Wonderland examples with new syntax
  • Compile to SBIR and validate byte-for-byte correctness
  • Round-trip: parse → compile → decompile → verify

9.2 Migration of Existing Examples

Alice in Wonderland migration: All behavior trees in examples/alice-in-wonderland/ need updating:

  1. white_rabbit.sb - selector/sequence conversion
  2. mad_tea_party.sb - add repeat decorator (currently TODO)
  3. cheshire_cat.sb - add timeout/cooldown decorators
  4. royal_court.sb - add repeat decorators (3 TODOs)
  5. caterpillar.sb - verify behavior tree syntax

Migration script (optional):

# Simple regex-based migration for basic cases
sed -i '' 's/^    ? {/    choose {/g' *.sb
sed -i '' 's/^    > {/    then {/g' *.sb
sed -i '' 's/! \(.*\)/if(\1)/g' *.sb
sed -i '' 's/@\([a-zA-Z_][a-zA-Z0-9_]*\)::\([a-zA-Z_][a-zA-Z0-9_]*\)/include \1::\2/g' *.sb

Recommendation: Migrate manually for quality and to add decorators where TODOs indicate.


10. Documentation Updates

10.1 Language Reference

Update design.md Section 6:

### 6.1 Node Types (yep make sure the language agent is aware of these new keywords)

| Keyword | Name | Semantics |
|---------|------|-----------|
| `selector` or `choose` | Selector | Try children in order; succeed on first success |
| `sequence` or `then` | Sequence | Run children in order; fail on first failure |
| `if(expr)` or `when(expr)` | Condition | Succeed if expression evaluates to true |
| action_name | Action | Execute a named engine action |
| `repeat` | Infinite Repeat | Loop child forever |
| `repeat(N)` | Counted Repeat | Loop child N times |
| `retry(N)` | Retry Decorator | Retry child up to N times on failure |
| `timeout(duration)` | Timeout | Fail if child exceeds duration |
| `cooldown(duration)` | Cooldown | Prevent re-execution within duration |
| `guard(expr)` | Guard | Only run child if condition met |
| `invert` | Invert | Negate child's success/failure |
| `include path` | SubTree | Include behavior from another definition |

10.2 Tutorial Examples

Add to beginner tutorial:

## Your First Behavior Tree

Let's create a simple behavior for a village guard who patrols and responds to threats:

```sb
behavior GuardDuty {
    ---description
    A simple patrol behavior that responds to threats when detected.
    ---

    choose {
        // First priority: respond to threats
        then {
            if(threat_detected)
            sound_alarm
            rush_to_threat
        }

        // Second priority: continue patrol
        repeat {
            patrol_checkpoint_a
            patrol_checkpoint_b
            patrol_checkpoint_c
        }
    }
}

This behavior uses:

  • choose to pick between threat response and patrol
  • then to sequence actions in order
  • if() to check conditions
  • repeat to loop the patrol indefinitely

### 10.3 Advanced Examples

**Add complex behavior examples:**

```markdown
## Advanced: The White Rabbit's Anxiety

This complex behavior models the White Rabbit from Alice in Wonderland,
who is perpetually late and responds differently based on context:

```sb
behavior WhiteRabbit_ConstantlyLate {
    choose {
        // Panic when extremely late
        then {
            if(minutes_late > 100)
            timeout(3s) {
                repeat(5) {
                    CheckPocketWatch
                    MutterDesperately
                }
            }
            SprintToDestination
        }

        // Drop items when startled
        then {
            if(obstacle_encountered)
            DropGloves
            DropFan
            retry(2) {
                FindAlternateRoute
            }
        }

        // Extreme fear response to Queen
        then {
            if(queen_nearby)
            FlattenEarsInFear
            TremblingBow
            cooldown(60s) {
                AwaitCommands
            }
        }

        // Default: perpetual anxiety
        repeat {
            CheckWatch
            MutterAnxiously
            ScurryForward
        }
    }
}

---

## 11. Migration Strategy

### 11.1 Breaking Changes

**This is a BREAKING change that requires:**
1. All existing `.sb` files with behaviors to be updated
2. Tree-sitter grammar update
3. Parser update
4. Compiler update
5. SBIR version bump (likely 0.1.0 → 0.2.0)

**Recommendation:** Since we're in early development (pre-1.0), make this change now before user base grows.

### 11.2 Migration Path

**Option A: Clean Break (Recommended)**
1. Implement new syntax
2. Migrate all examples manually
3. Update documentation
4. Deprecate old syntax entirely
5. Version bump to 0.2.0

**Option B: Dual Support (Not Recommended)**
1. Support both syntaxes during transition
2. Emit deprecation warnings for old syntax
3. Provide automated migration tool
4. Remove old syntax in 0.3.0

**Recommendation:** Option A. Clean break is simpler and we're early enough.

### 11.3 Migration Checklist

- [ ] Update Tree-sitter grammar with new keywords
- [ ] Update lexer to tokenize new keywords
- [ ] Update parser to handle new syntax
- [ ] Update AST to include DecoratorType enum
- [ ] Update compiler to emit correct SBIR for decorators
- [ ] Migrate all examples in `examples/alice-in-wonderland/`
- [ ] Migrate all tests in `tests/examples/`
- [ ] Update design.md documentation
- [ ] Create tutorial examples with new syntax
- [ ] Update LSP to support new keywords (coordinate with Agent 1)
- [ ] Add test suite for all decorator types
- [ ] Update SBIR specification (coordinate with Agent 5)
- [ ] Create release notes documenting breaking changes

---

## 12. Benefits Summary

### 12.1 Readability Improvements

**Before:**
```sb
? { > { ! x; @ a }; > { ! y; @ b }; @ c }

After:

choose {
    then { if(x) a }
    then { if(y) b }
    c
}

Impact: ~300% improvement in readability for non-programmers.

12.2 Self-Documentation

Keywords are self-explanatory:

  • "choose" tells you it's selecting between options
  • "then" tells you actions happen in sequence
  • "repeat(3)" tells you exactly how many times
  • "timeout(5s)" tells you the duration limit

No need to memorize sigil meanings.

12.3 Expressiveness

New decorator support enables:

  • Timed behaviors (timeout, cooldown)
  • Retry logic (retry(N))
  • Conditional guards (guard(condition))
  • Counted repetition (repeat(N), repeat(min..max))

These are currently impossible or require workarounds.

12.4 Consistency with Rest of Language

The rest of Storybook uses English keywords:

  • character, behavior, life_arc, schedule
  • if, when, and, or
  • link, include, override

Behavior trees should match this style.


13. Risks & Mitigations

Risk Likelihood Impact Mitigation
Breaking all existing .sb files Certain High Migrate examples ourselves; provide clear migration guide
Parser complexity increases Medium Medium Comprehensive test suite; grammar validation
LSP breaks during transition Medium High Coordinate with Agent 1; parallel testing
User confusion during transition Low Medium Clear documentation; examples; changelog
Performance impact of nested decorators Low Low Benchmark; optimize if needed
SBIR encoding becomes verbose Low Medium Efficient binary encoding; profile file sizes

14. Success Criteria

  • All behavior tree node types have keyword equivalents
  • Parser handles all decorator types with parameters
  • Alice in Wonderland examples validate with new syntax
  • New syntax is more readable than symbolic syntax (user confirmation)
  • Decorators that were TODOs are now implemented
  • SBIR encoding is efficient (<10% size increase)
  • LSP supports all new keywords (coordinate with Agent 1)
  • Documentation is complete and beginner-friendly
  • Test coverage for all keyword variants
  • No regressions in compiler output

15. Next Steps

Phase 1: Design Review

  1. Present this document to user for feedback
  2. Incorporate requested changes
  3. Get explicit approval before implementation

Phase 2: Implementation (Task #4)

  1. Update Tree-sitter grammar
  2. Update lexer with new tokens
  3. Update parser logic
  4. Extend AST with DecoratorType
  5. Update compiler for SBIR generation
  6. Write comprehensive test suite
  7. Migrate all examples
  8. Update documentation

Phase 3: Validation

  1. Run full test suite
  2. Validate Alice examples end-to-end
  3. Benchmark SBIR file sizes
  4. Coordinate LSP testing with Agent 1
  5. User acceptance testing

Phase 4: Release

  1. Create migration guide
  2. Update CHANGELOG
  3. Version bump to 0.2.0
  4. Merge to mainline

Appendix A: Complete Keyword List

Control Flow:

  • selector / choose
  • sequence / then

Conditions:

  • if(expr)
  • when(expr)

Decorators:

  • repeat
  • repeat(N)
  • repeat(min..max)
  • invert
  • retry(N)
  • timeout(duration)
  • cooldown(duration)
  • guard(expr)
  • succeed_always
  • fail_always

Subtrees:

  • include path

Actions:

  • No keyword, just action name

Duration Units:

  • d (days)
  • h (hours)
  • m (minutes)
  • s (seconds)

Appendix B: Grammar Comparison

Current Grammar (Symbolic):

behavior_node can be:
  - selector_node using ? sigil
  - sequence_node using > sigil
  - repeat_node using * sigil
  - action_node (identifier or @ identifier)
  - subtree_node (@path::to::subtree)

Proposed Grammar (Keywords):

behavior_node can be:
  - selector_node using "selector" or "choose" keyword
  - sequence_node using "sequence" or "then" keyword
  - condition_node using "if(expr)" or "when(expr)"
  - decorator_node using decorator keywords with optional params
  - action_node (just identifier, no prefix)
  - subtree_node using "include path"

Appendix C: SBIR Binary Encoding Examples

Selector with two children:

[0x01]              // Selector
[0x02 0x00 0x00 0x00]  // 2 children
  [0x04] [0x05 0x00 0x00 0x00]  // Action "patrol" (string index 5)
  [0x04] [0x06 0x00 0x00 0x00]  // Action "rest" (string index 6)

Repeat(3) decorator:

[0x11]              // DecoratorRepeatN
[0x03 0x00 0x00 0x00]  // Count: 3
  [0x04] [0x07 0x00 0x00 0x00]  // Action "knock" (string index 7)

Timeout(5s) with nested action:

[0x15]              // DecoratorTimeout
[0x88 0x13 0x00 0x00 0x00 0x00 0x00 0x00]  // 5000 milliseconds
  [0x04] [0x08 0x00 0x00 0x00]  // Action "wait_for_response" (string index 8)

END OF DESIGN DOCUMENT