2026-02-13 21:52:03 +00:00
# Storybook Intermediate Representation (SBIR) v0.2.0 Specification
**Version:** 0.2.0
2026-02-14 15:35:41 +00:00
**Status:** Archived (superseded by v0.3.0)
2026-02-13 21:52:03 +00:00
**Date:** February 2026
2026-02-14 15:35:41 +00:00
> **Note:** This is a historical specification for SBIR v0.2.0. The current specification
> is [SBIR v0.3.0](./SBIR-v0.3.0-SPEC.md). Type names in this document (Int, Float,
> String, Bool) reflect v0.2.0 terminology; v0.3.0 renamed these to Number, Decimal,
> Text, and Boolean respectively.
2026-02-13 21:52:03 +00:00
---
## Table of Contents
1. [Introduction ](#1-introduction )
2. [File Format Overview ](#2-file-format-overview )
3. [Section 1: Header ](#3-section-1-header )
4. [Section 2: String Table ](#4-section-2-string-table )
5. [Section 3: Types ](#5-section-3-types )
6. [Section 4: Characters ](#6-section-4-characters )
7. [Section 5: Templates ](#7-section-5-templates )
8. [Section 6: Species ](#8-section-6-species )
9. [Section 7: Behaviors ](#9-section-7-behaviors )
10. [Section 8: Schedules ](#10-section-8-schedules )
11. [Section 9: Institutions ](#11-section-9-institutions )
12. [Section 10: Relationships ](#12-section-10-relationships )
13. [Section 11: Locations ](#13-section-11-locations )
14. [Section 12: Life Arcs ](#14-section-12-life-arcs )
15. [Section 13: Enums ](#15-section-13-enums )
16. [Changelog ](#16-changelog )
---
## 1. Introduction
### 1.1 Purpose
The Storybook Intermediate Representation (SBIR) is a binary format that represents compiled Storybook programs. It serves as the interchange format between the Storybook compiler and runtime engines.
### 1.2 Design Goals
- **Compact:** Efficient binary encoding for large story worlds
- **Fast to load:** Direct memory mapping when possible
- **Versioned:** Clear version tracking for format evolution
- **Complete:** Represents all semantic information from source
- **Runtime-ready:** Minimal post-processing required
### 1.3 Changes in v0.2.0
**Major additions:**
1. **Resource Linking System ** - Characters and institutions can link to behaviors and schedules with conditions and priorities
2. **Year-Long Schedule System ** - Schedules support temporal patterns (day-specific, seasonal, recurrence)
3. **Behavior Tree Enhancements ** - Named nodes, decorator parameters, keyword transformations
**Breaking changes:**
- CHARACTERS section extended with behavior_links and schedule_links
- INSTITUTIONS section extended with behavior_links and schedule_links
- SCHEDULES section redesigned with patterns and inheritance
- BEHAVIORS section extended with named nodes and parameterized decorators
---
## 2. File Format Overview
### 2.1 File Structure
```
[Header]
[String Table]
[Type Definitions]
[Characters Section]
[Templates Section]
[Species Section]
[Behaviors Section]
[Schedules Section]
[Institutions Section]
[Relationships Section]
[Locations Section]
[Life Arcs Section]
[Enums Section]
```
### 2.2 Primitive Types
| Type | Size | Description |
|------|------|-------------|
| `u8` | 1 byte | Unsigned 8-bit integer |
| `u16` | 2 bytes | Unsigned 16-bit integer (little-endian) |
| `u32` | 4 bytes | Unsigned 32-bit integer (little-endian) |
| `u64` | 8 bytes | Unsigned 64-bit integer (little-endian) |
| `i32` | 4 bytes | Signed 32-bit integer (little-endian) |
| `i64` | 8 bytes | Signed 64-bit integer (little-endian) |
| `f32` | 4 bytes | IEEE 754 single-precision float |
| `f64` | 8 bytes | IEEE 754 double-precision float |
| `bool` | 1 byte | 0 = false, 1 = true |
| `String` | Variable | Length-prefixed UTF-8: `u32 length` + `[u8; length]` |
| `StringRef` | 4 bytes | Index into string table (u32) |
### 2.3 Common Structures
#### Option<T>
Optional values are encoded with a discriminant byte followed by the value if present:
```
u8 discriminant:
0 = None → No additional bytes, next field starts immediately
1 = Some → T data follows immediately after discriminant
```
**Encoding:**
- **None case:** Just 1 byte (0x00), nothing else
- **Some case:** 1 byte (0x01) + full T encoding
**Examples:**
`Option<StringRef>` when None:
```
0x00 ← 1 byte total
```
`Option<StringRef>` when Some(42):
```
0x01 ← discriminant (Some)
0x2A 0x00 0x00 0x00 ← StringRef = 42 (u32)
← 5 bytes total
```
`Option<Vec<Field>>` when None:
```
0x00 ← 1 byte total
```
`Option<Vec<Field>>` when Some([field1, field2]):
```
0x01 ← discriminant (Some)
0x02 0x00 0x00 0x00 ← count = 2 (u32)
[Field 1 encoding] ← First field
[Field 2 encoding] ← Second field
← 5+ bytes (depends on field sizes)
```
#### Vec<T>
```
u32 count
[T; count]
```
### 2.4 Binary Format Conventions
**IMPORTANT: SBIR is a packed binary format with no separators.**
#### No Delimiter Bytes
All data is laid out **sequentially in memory ** with **no separator characters ** between:
- Items in a Vec<T>
- Fields in a struct
- Sections in the file
- Values of any kind
The file is a continuous stream of bytes where each element's size determines where the next element begins.
#### Length-Prefix Pattern
All variable-length data uses a **length-prefix pattern ** :
1. **Length/count field ** (u32) tells you "how much data is coming"
2. **Data bytes ** - read exactly that amount
3. **Next field ** starts immediately after (no gap, no separator)
#### Reading Variable-Length Vec<T>
When `T` itself is variable-length, each item carries its own size information:
**Example: Vec<String>**
```
u32 count = 3 ← "There are 3 strings"
String 1:
u32 length = 5 ← "First string is 5 bytes"
[u8; 5] = "hello" ← Read 5 bytes, next item starts immediately
String 2:
u32 length = 5 ← "Second string is 5 bytes"
[u8; 5] = "world" ← Read 5 bytes
String 3:
u32 length = 3 ← "Third string is 3 bytes"
[u8; 3] = "foo" ← Read 3 bytes
```
**Example: Vec<Character>** (complex variable-length structs)
```
u32 count = 2 ← "There are 2 characters"
Character 1:
u32 name_len = 6
[u8; 6] = "Martha"
u8 species_discriminant = 1 ← Option::Some
u32 species_ref = 10
u32 fields_count = 2
Field 1: (name_ref, value_discriminant, value_data)
Field 2: (name_ref, value_discriminant, value_data)
u32 template_refs_count = 1
StringRef = 15
u32 behavior_links_count = 0
u32 schedule_links_count = 0
Character 2:
(starts immediately after Character 1 ends)
u32 name_len = 5
[u8; 5] = "David"
... (continues)
```
#### Parsing Algorithm
The parser reads **sequentially ** using each length field to know how many bytes to consume:
```
position = 0
while position < file_size:
read_length_or_discriminant()
read_exactly_that_many_bytes()
position += bytes_read
// Next field starts here (no seeking, no separator scanning)
```
#### Key Rules
1. **Fixed-size types ** (u8, u32, f64, etc.) take their exact size - no padding
2. **Variable-size types ** always start with a length prefix (u32)
3. **Option<T> ** starts with a discriminant byte (0=None, 1=Some)
4. **Enums/discriminated unions ** start with a discriminant byte
5. **No alignment padding ** - all data is tightly packed
There are no:
- No newline characters (`\n` )
- No separators (`,` , `;` , spaces)
- No null terminators (except inside UTF-8 string data)
- No padding bytes between fields (unless explicitly specified)
- No section markers or headers (sections just follow each other)
The documentation uses newlines and indentation for **readability only ** - the actual binary file is a continuous stream of bytes with no whitespace.
---
## 3. Section 1: Header
```
Magic: [u8; 4] // "SBIR" (0x53 0x42 0x49 0x52)
Version: u16 // Major version (0x0002 for v0.2.0)
MinorVersion: u16 // Minor version (0x0000)
Flags: u32 // Reserved (0x00000000)
SectionCount: u32 // Number of sections (currently 13)
```
**Version History:**
- v0.1.0: Implicit version (pre-release)
- v0.2.0: First formal versioned release
---
## 4. Section 2: String Table
The string table stores all strings used in the SBIR file.
```
Count: u32
Strings: [String; Count]
```
**Usage:** All `StringRef` types reference an index in this table.
**Encoding:** UTF-8 with length prefix.
**Example:**
```
Count: 3
Strings:
[0]: "Alice"
[1]: "Wonderland"
[2]: "rabbit_hole"
```
---
## 5. Section 3: Types
**Note:** This section is reserved for future type system enhancements. Currently unused.
```
Count: u32 // 0 in v0.2.0
Types: []
```
---
## 6. Section 4: Characters
### 6.1 Structure
```
Count: u32
Characters: [Character; Count]
```
### 6.2 Character Encoding
```
Character:
name: StringRef
species: Option<StringRef>
fields: Map<StringRef, Value>
template_refs: Vec<StringRef> // Templates this character uses
behavior_links: Vec<BehaviorLink> // NEW in v0.2.0
schedule_links: Vec<ScheduleLink> // NEW in v0.2.0
```
### 6.3 BehaviorLink (NEW in v0.2.0)
```
BehaviorLink:
behavior_id: u32 // Index into BEHAVIORS section
priority: u8 // 0=Low, 1=Normal, 2=High, 3=Critical
condition: Option<Expression> // Optional activation condition
is_default: bool // Default behavior (no condition)
```
**Priority Encoding:**
```
enum Priority {
Low = 0,
Normal = 1,
High = 2,
Critical = 3,
}
```
**Selection Algorithm:**
1. Filter links where `condition` evaluates to true (or is None)
2. Sort by priority (descending)
3. Return highest priority link
4. If tie, use declaration order
### 6.4 ScheduleLink (NEW in v0.2.0)
```
ScheduleLink:
schedule_id: u32 // Index into SCHEDULES section
condition: Option<Expression> // Optional activation condition
is_default: bool // Default schedule (fallback)
```
**Selection Algorithm:**
1. Iterate schedule_links in order
2. Skip default links initially
3. Return first link where `condition` is true (or None)
4. If no match, use default link (if present)
### 6.5 Value Encoding
```
Value:
discriminant: u8
data: <depends on discriminant>
```
**Discriminants:**
```
0x01 = Int(i64)
0x02 = Float(f64)
0x03 = String(StringRef)
0x04 = Bool(bool)
0x05 = Range(Value, Value)
0x06 = Time(u8 hour, u8 minute, u8 second)
0x07 = Duration(u32 hours, u32 minutes, u32 seconds)
0x08 = Identifier(Vec<StringRef>) // Qualified path
0x09 = List(Vec<Value>)
0x0A = Object(Vec<Field>)
0x0B = ProseBlock(StringRef tag, String content)
0x0C = Override(...)
```
### 6.6 Expression Encoding
```
Expression:
discriminant: u8
data: <depends on discriminant>
```
**Discriminants:**
```
0x01 = IntLit(i64)
0x02 = FloatLit(f64)
0x03 = StringLit(StringRef)
0x04 = BoolLit(bool)
0x05 = Identifier(Vec<StringRef>)
0x06 = FieldAccess(Box<Expr>, StringRef)
0x07 = Comparison(Box<Expr>, CompOp, Box<Expr>)
0x08 = Logical(Box<Expr>, LogicalOp, Box<Expr>)
0x09 = Unary(UnaryOp, Box<Expr>)
0x0A = Quantifier(QuantifierKind, StringRef var, Box<Expr> collection, Box<Expr> predicate)
```
**CompOp:** `u8` (0x01=Eq, 0x02=Ne, 0x03=Lt, 0x04=Le, 0x05=Gt, 0x06=Ge)
**LogicalOp:** `u8` (0x01=And, 0x02=Or)
**UnaryOp:** `u8` (0x01=Not, 0x02=Neg)
**QuantifierKind:** `u8` (0x01=ForAll, 0x02=Exists)
---
## 7. Section 5: Templates
```
Count: u32
Templates: [Template; Count]
Template:
name: StringRef
strict: bool
includes: Vec<StringRef>
fields: Map<StringRef, Value>
```
---
## 8. Section 6: Species
```
Count: u32
Species: [Species; Count]
Species:
name: StringRef
includes: Vec<StringRef>
fields: Map<StringRef, Value>
```
---
## 9. Section 7: Behaviors
### 9.1 Structure
```
Count: u32
Behaviors: [Behavior; Count]
```
### 9.2 Behavior Encoding
```
Behavior:
name: StringRef
root: BehaviorNode
```
### 9.3 BehaviorNode Encoding
```
BehaviorNode:
discriminant: u8
data: <depends on discriminant>
```
#### Node Type Discriminants
```
0x01 = Selector
0x02 = Sequence
0x03 = Condition
0x04 = Action
0x10 = DecoratorRepeat
0x11 = DecoratorRepeatN
0x12 = DecoratorRepeatRange
0x13 = DecoratorInvert
0x14 = DecoratorRetry
0x15 = DecoratorTimeout
0x16 = DecoratorCooldown
0x17 = DecoratorGuard
0x18 = DecoratorSucceedAlways
0x19 = DecoratorFailAlways
0x20 = SubTree
```
#### Selector Node (0x01)
```
label: Option<StringRef> // NEW in v0.2.0
children: Vec<BehaviorNode>
```
**Keyword Mapping:** `selector` or `choose`
#### Sequence Node (0x02)
```
label: Option<StringRef> // NEW in v0.2.0
children: Vec<BehaviorNode>
```
**Keyword Mapping:** `sequence` or `then`
#### Condition Node (0x03)
```
expression: Expression
```
**Keyword Mapping:** `if` or `when`
#### Action Node (0x04)
```
name: StringRef
parameters: Vec<Field>
```
**Keyword Mapping:** No prefix (just action name)
#### Decorator Nodes (0x10-0x19)
**DecoratorRepeat (0x10):**
```
child: Box<BehaviorNode>
```
Keyword: `repeat { ... }`
**DecoratorRepeatN (0x11):**
```
count: u32
child: Box<BehaviorNode>
```
Keyword: `repeat(N) { ... }`
**DecoratorRepeatRange (0x12):**
```
min: u32
max: u32
child: Box<BehaviorNode>
```
Keyword: `repeat(min..max) { ... }`
**DecoratorInvert (0x13):**
```
child: Box<BehaviorNode>
```
Keyword: `invert { ... }`
**DecoratorRetry (0x14):**
```
max_attempts: u32
child: Box<BehaviorNode>
```
Keyword: `retry(N) { ... }`
**DecoratorTimeout (0x15):**
```
milliseconds: u64 // Duration in milliseconds
child: Box<BehaviorNode>
```
Keyword: `timeout(duration) { ... }`
Example: `timeout(5s)` , `timeout(30m)` , `timeout(2h)`
**DecoratorCooldown (0x16):**
```
milliseconds: u64 // Cooldown period in milliseconds
child: Box<BehaviorNode>
```
Keyword: `cooldown(duration) { ... }`
**DecoratorIf (0x17):**
```
condition: Expression
child: Box<BehaviorNode>
```
Keyword: `if(condition) { ... }`
**DecoratorSucceedAlways (0x18):**
```
child: Box<BehaviorNode>
```
Keyword: `succeed_always { ... }`
**DecoratorFailAlways (0x19):**
```
child: Box<BehaviorNode>
```
Keyword: `fail_always { ... }`
#### SubTree Node (0x20)
```
path: Vec<StringRef> // Qualified path to subtree
```
Keyword: `include path::to::subtree`
---
## 10. Section 8: Schedules
### 10.1 Structure
```
Count: u32
Schedules: [Schedule; Count]
```
### 10.2 Schedule Encoding (REDESIGNED in v0.2.0)
```
Schedule:
name: StringRef
parent_schedule_id: Option<u32> // Index into SCHEDULES section (for inheritance)
blocks: Vec<ScheduleBlock>
patterns: Vec<SchedulePattern> // Day-specific, seasonal, recurrence patterns
```
### 10.3 ScheduleBlock
```
ScheduleBlock:
name: StringRef // Required in v0.2.0
start: u16 // Minutes since midnight (0-1439)
end: u16 // Minutes since midnight (0-1439)
behavior_ref: Option<Vec<StringRef>> // Reference to behavior (qualified path)
fields: Map<StringRef, Value>
```
**Changes from v0.1.0:**
- `name` is now required (was optional)
- `behavior_ref` replaces `activity: String`
- Time is encoded as minutes since midnight
### 10.4 SchedulePattern (NEW in v0.2.0)
```
SchedulePattern:
kind: u8 // Pattern discriminant
specification: Vec<u8> // Pattern-specific data
blocks: Vec<ScheduleBlock> // Blocks to apply when pattern matches
```
**Pattern Kind Discriminants:**
```
0x01 = DayPattern
0x02 = SeasonPattern
0x03 = RecurrencePattern
```
#### DayPattern (0x01)
```
specification:
day_enum_value: StringRef // References user-defined DayOfWeek enum
```
Example: `on Fireday` → references "Fireday" from user's DayOfWeek enum
#### SeasonPattern (0x02)
```
specification:
season_enum_values: Vec<StringRef> // Multiple seasons allowed
```
Example: `season (EarlySummer, LateSummer)` → references Season enum values
#### RecurrencePattern (0x03)
```
specification:
name: StringRef // Recurrence name
spec: RecurrenceSpec
```
**RecurrenceSpec:**
```
RecurrenceSpec:
discriminant: u8
data: <depends on discriminant>
Discriminants:
0x01 = Every(u32 days) // every N days
0x02 = WeeklyOn(Vec<StringRef>) // weekly on [days]
0x03 = MonthlyOnDay(u8 day) // monthly on day N
0x04 = Annually(u8 month, u8 day) // annually on month/day
```
### 10.5 Runtime Schedule Evaluation
**Algorithm:**
1. Resolve character's schedule via ScheduleLink (conditional selection)
2. Merge inherited schedules (parent → child, depth-first)
3. Evaluate patterns for current day/season
4. Overlay patterns on base blocks (later patterns override earlier ones)
5. Produce final 24-hour schedule
6. Return ordered list of (time, behavior_ref) pairs
---
## 11. Section 9: Institutions
### 11.1 Structure (EXTENDED in v0.2.0)
```
Count: u32
Institutions: [Institution; Count]
Institution:
name: StringRef
fields: Map<StringRef, Value>
behavior_links: Vec<BehaviorLink> // NEW in v0.2.0
schedule_links: Vec<ScheduleLink> // NEW in v0.2.0
```
**Note:** BehaviorLink and ScheduleLink are identical to Character section (§6.3, §6.4)
---
## 12. Section 10: Relationships
```
Count: u32
Relationships: [Relationship; Count]
Relationship:
name: StringRef
participants: Vec<Participant>
fields: Map<StringRef, Value>
Participant:
role: Option<StringRef>
name: Vec<StringRef> // Qualified path
self_block: Option<Vec<Field>>
other_block: Option<Vec<Field>>
```
---
## 13. Section 11: Locations
```
Count: u32
Locations: [Location; Count]
Location:
name: StringRef
fields: Map<StringRef, Value>
```
---
## 14. Section 12: Life Arcs
```
Count: u32
LifeArcs: [LifeArc; Count]
LifeArc:
name: StringRef
states: Vec<ArcState>
ArcState:
name: StringRef
on_enter: Option<Vec<Field>>
transitions: Vec<Transition>
Transition:
to: StringRef
condition: Expression
```
---
## 15. Section 13: Enums
### 15.1 Structure
```
Count: u32
Enums: [EnumDecl; Count]
```
### 15.2 EnumDecl Encoding
```
EnumDecl:
name: StringRef // u32 index into string table
variants: Vec<StringRef> // Encoded as below
```
**Variants encoding (Vec<StringRef>):**
```
u32 variant_count // Number of enum variants
[StringRef; variant_count] // Array of variant names (each is u32)
```
### 15.3 Binary Example
**Source:**
```storybook
enum SkillLevel {
Novice,
Beginner,
Intermediate,
Advanced,
Expert,
Master
}
```
**Binary encoding:**
```
EnumDecl:
name: StringRef = 42 // "SkillLevel" (4 bytes)
u32 variant_count = 6 // 6 variants (4 bytes)
variants:
StringRef = 43 // "Novice" (4 bytes)
StringRef = 44 // "Beginner" (4 bytes)
StringRef = 45 // "Intermediate" (4 bytes)
StringRef = 46 // "Advanced" (4 bytes)
StringRef = 47 // "Expert" (4 bytes)
StringRef = 48 // "Master" (4 bytes)
Total: 32 bytes (4 + 4 + 6*4)
```
### 15.4 Usage
**Usage:** Enums are used for:
- Calendar definitions (DayOfWeek, Season, Month)
- Custom enumerated values
- Pattern matching in schedules
**Standard Calendar Enums (optional):**
- `DayOfWeek` : Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday
- `Season` : Spring, Summer, Fall, Winter
- `Month` : January, February, ..., December
---
## 16. Changelog
### v0.2.0 (February 2026)
**Major Features:**
- Resource linking system for behaviors and schedules
- Year-long schedule patterns (day, season, recurrence)
- Schedule inheritance and composition
- Behavior tree keyword support (named nodes)
- Parameterized decorators (repeat, retry, timeout, cooldown, if)
**Breaking Changes:**
- CHARACTERS section: added behavior_links, schedule_links
- INSTITUTIONS section: added behavior_links, schedule_links
- SCHEDULES section: complete redesign with patterns and inheritance
- BEHAVIORS section: added named node support
**Deprecations:**
- None (first versioned release)
**Bug Fixes:**
- N/A (first formal release)
### v0.1.0 (Implicit, Pre-Release)
**Initial format** (inferred from existing codebase):
- Basic entity storage (characters, templates, species)
- Simple schedules (time blocks with activities)
- Behavior trees (symbolic syntax)
- Relationships, locations, life arcs
- Enum support
---
## Appendix A: Binary Encoding Examples
### Example 1: Character with Resource Links
**Source:**
```storybook
character Alice: Human {
age: 7
uses behavior: CuriousBehavior, when: self.location == Wonderland, priority: High
uses behavior: DefaultBehavior, default: true
uses schedule: AdventureSchedule, when: self.in_wonderland
uses schedule: NormalSchedule, default: true
}
```
**Binary (conceptual):**
```
Character:
name: StringRef(0) // "Alice"
species: Some(StringRef(1)) // "Human"
fields: [
("age", Int(7))
]
template_refs: []
behavior_links: [
BehaviorLink {
behavior_id: 3
priority: 2 // High
condition: Some(Comparison(FieldAccess(...), Eq, Identifier(...)))
is_default: false
},
BehaviorLink {
behavior_id: 5
priority: 1 // Normal
condition: None
is_default: true
}
]
schedule_links: [
ScheduleLink {
schedule_id: 1
condition: Some(FieldAccess(...))
is_default: false
},
ScheduleLink {
schedule_id: 2
condition: None
is_default: true
}
]
```
### Example 2: Schedule with Patterns
**Source:**
```storybook
2026-02-16 22:55:04 +00:00
schedule WorkWeek modifies BaseSchedule {
2026-02-13 21:52:03 +00:00
block morning { 08:00 - 12:00: WorkTasks }
block lunch { 12:00 - 13:00: EatLunch }
block afternoon { 13:00 - 17:00: WorkTasks }
on Friday {
override afternoon { 13:00 - 15:00: FinishWeek }
}
season (Summer) {
override morning { 07:00 - 11:00: WorkEarly }
}
}
```
**Binary (conceptual):**
```
Schedule:
name: StringRef(10) // "WorkWeek"
parent_schedule_id: Some(0) // BaseSchedule index
blocks: [
ScheduleBlock {
name: StringRef(11) // "morning"
start: 480 // 08:00 in minutes
end: 720 // 12:00 in minutes
behavior_ref: Some(["WorkTasks"])
fields: []
},
ScheduleBlock {
name: StringRef(12) // "lunch"
start: 720
end: 780
behavior_ref: Some(["EatLunch"])
fields: []
},
ScheduleBlock {
name: StringRef(13) // "afternoon"
start: 780
end: 1020
behavior_ref: Some(["WorkTasks"])
fields: []
}
]
patterns: [
SchedulePattern {
kind: 0x01 // DayPattern
specification: StringRef(14) // "Friday"
blocks: [
ScheduleBlock {
name: StringRef(13) // "afternoon" (override)
start: 780
end: 900
behavior_ref: Some(["FinishWeek"])
fields: []
}
]
},
SchedulePattern {
kind: 0x02 // SeasonPattern
specification: [StringRef(15)] // ["Summer"]
blocks: [
ScheduleBlock {
name: StringRef(11) // "morning" (override)
start: 420
end: 660
behavior_ref: Some(["WorkEarly"])
fields: []
}
]
}
]
```
---
## Appendix B: File Size Estimates
**Assumptions:**
- Average character: 500 bytes
- Average behavior tree: 1 KB
- Average schedule: 800 bytes
- 1000 characters, 500 behaviors, 300 schedules
**Estimated size:**
- Characters: 500 KB
- Behaviors: 500 KB
- Schedules: 240 KB
- Other sections: 100 KB
- **Total: ~1.34 MB**
**Compression:** Typical compression (gzip/zstd) achieves 60-70% reduction → ~400-500 KB
---
## Appendix C: Version History
| Version | Date | Major Changes |
|---------|------|---------------|
| 0.1.0 | (Implicit) | Initial format |
| 0.2.0 | Feb 2026 | Resource linking, year-long schedules, behavior keywords |
---
**END OF SPECIFICATION**