diff --git a/.gitattributes b/.gitattributes
index 63a9c23..036fe66 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -2,3 +2,5 @@
calcit.cirru -diff linguist-generated
yarn.lock -diff linguist-generated
LICENSE -diff linguist-generated
+
+Agents.md -diff linguist-generated
\ No newline at end of file
diff --git a/Agents.md b/Agents.md
new file mode 100644
index 0000000..8be3d6b
--- /dev/null
+++ b/Agents.md
@@ -0,0 +1,1352 @@
+# MoonBit Project Layouts
+
+You have the ability to detect specific types of MoonBit projects and work with
+them adaptively.
+
+MoonBit source files use the `.mbt` extension and interface files `.mbti`. At
+the top-level of a MoonBit project there is a `moon.mod.json` file specifying
+the metadata of the project. The project may contain multiple packages, each
+with its own `moon.pkg.json` file.
+
+Here are some typical project layouts you may encounter:
+
+- **Module**: When you see a `moon.mod.json` file in the project directory, you
+ are already in a MoonBit project.
+ A MoonBit _module_ is like a Go module.
+ It is a collection of packages, usually corresponding to a repository or project.
+ Module boundaries matter for dependency management and import paths.
+ A module contains many packages in subdirectories.
+
+- **Package**: When you see a `moon.pkg.json` file, but not a `moon.mod.json`
+ file, it means you are in a MoonBit package. All subcommands of `moon` will
+ still be executed in the directory of the module (where `moon.mod.json` is
+ located), not the current package.
+ A MoonBit _package_ is the actual compilation unit (like a Go package).
+ All source files in the same package are concatenated into one unit.
+ The `package` name in the source defines the package, not the file name.
+ Imports refer to module + package paths, NEVER to file names.
+
+- **Files**:
+ A `.mbt` file is just a chunk of source inside a package.
+ File names do NOT create modules or namespaces.
+ You may freely split/merge/move declarations between files in the same package.
+ Any declaration in a package can reference any other declaration in that package, regardless of file.
+
+## Coding/layout rules you MUST follow:
+
+1. Prefer many small, cohesive files over one large file.
+
+ - Group related types and functions into focused files (e.g. http_client.mbt, router.mbt).
+ - If a file is getting large or unfocused, create a new file and move related declarations into it.
+
+2. You MAY freely move declarations between files inside the same package.
+
+ - Moving a function/struct/trait between files does not change semantics, as long as its name and pub-ness stay the same.
+ - It is safe to refactor by splitting or merging files inside a package.
+
+3. File names are purely organizational.
+
+ - Do NOT assume file names define modules, and do NOT use file names in type paths.
+ - Choose file names to describe a feature or responsibility, not to mirror type names rigidly.
+
+4. When adding new code:
+
+ - Prefer adding it to an existing file that matches the feature.
+ - If no good file exists, create a new file under the same package with a descriptive name.
+ - Avoid creating giant “misc” or “util” files.
+
+5. Tests:
+ - Place tests in dedicated test files (e.g. \*\_test.mbt) within the appropriate package.
+ - It is fine—and encouraged—to have multiple small test files.
+
+## `.mbti` Files - Package Interface Documentation
+
+MoonBit interface files (`pkg.generated.mbti`) are compiler-generated summaries of each package's public API surface. They provide a formal, concise overview of all exported types, functions, and traits without implementation details.
+
+**Standard library interfaces** are available in `~/.moon/lib/core`:
+
+```
+$ tree -P '*.mbti' -I 'internal' --prune ~/.moon/lib/core # ignore internal packages
+/Users/username/.moon/lib/core
+├── builtin
+│ └── pkg.generated.mbti
+├── array
+│ └── pkg.generated.mbti
+├── bench
+│ └── pkg.generated.mbti
+├── bigint
+│ └── pkg.generated.mbti
+├── bool
+│ └── pkg.generated.mbti
+├── buffer
+│ └── pkg.generated.mbti
+.....
+```
+
+**When to use each approach**:
+
+- Use `moon doc` for interactive API discovery (preferred, see "API Discovery with `moon doc`" section below)
+- Read `.mbti` files directly when you need the complete API surface at once or when working offline
+
+**Reading `.mbti` files for API discovery**:
+
+- **Start with `builtin/pkg.generated.mbti`** - contains core types (String, Int, Array, etc.) and their fundamental APIs
+- **Note**: Some builtin types like `String` expose APIs in both `builtin` and their dedicated packages (e.g., `String`)
+- **Local dependencies**: Find `.mbti` files in the `.mooncakes` directory by searching for `pkg.generated.mbti`
+- **Your own packages**: After running `moon info`, check the generated `.mbti` in each package directory to verify public API changes
+
+# MoonBit Language Fundamentals
+
+## Core Facts
+
+Core facts that impact how you write and refactor code.
+
+- **Expression‑oriented**: `if`, `match`, loops return values; last expression is the return.
+- **References by default**: Arrays/Maps/structs mutate via reference; use `Ref[T]` for primitive mutability.
+- **Errors**: Functions declare `raise ...`; use `try?` for `Result` or `try { } catch { }` to handle.
+- **Blocks**: Separate top‑level items with `///|`. Generate code block‑by‑block.
+- **Visibility**: `fn` private by default; `pub` exposes read/construct as allowed; `pub(all)` allows external construction.
+- **Naming convention**: lower_snake for values/functions; UpperCamel for types/enums; enum variants start UpperCamel.
+- **Packages**: No `import` in code files; call via `@alias.fn`. Configure imports in `moon.pkg.json`.
+- **Placeholders**: `...` is a valid placeholder in MoonBit code for incomplete implementations.
+- **Global values**: immutable by default and generally require type annotations.
+- **Garbage collection**: MoonBit has a GC, there is no lifetime annotation, there's no ownership system.
+ Delimit top-level items with `///|` comments so tools can split the file reliably.
+
+
+Quick reference:
+
+```mbt check
+///|
+/// comments doc string
+pub fn sum(x : Int, y : Int) -> Int {
+ x + y
+}
+
+///|
+/// error declaration and usage
+suberror MySubError
+
+///|
+fn risky() -> Int raise MySubError {
+ raise MySubError::MySubError
+}
+
+///|
+struct Rect {
+ width : Int
+ height : Int
+}
+
+///|
+fn Rect::area(self : Rect) -> Int {
+ self.width * self.height
+}
+
+///|
+impl Show for Rect with output(self, logger) {
+ logger.write_string("Rect")
+}
+
+///|
+enum MyOption {
+ MyNone
+ MySome(Int)
+} derive(Show, ToJson, Eq, Compare)
+
+///|
+/// match + loops are expressions
+test "everything is expression in MoonBit" {
+ // tuple
+ let (n, opt) = (1, MySome(2))
+ // if expressions return values
+ let msg : String = if n > 0 { "pos" } else { "non-pos" }
+ let res = match opt {
+ MySome(x) => {
+ inspect(x, content="2")
+ 1
+ }
+ MyNone => 0
+ }
+ let status : Result[Int, String] = Ok(10)
+ // match expressions return values
+ let description = match status {
+ Ok(value) => "Success: \{value}"
+ Err(error) => "Error: \{error}"
+ }
+ let array = [1, 2, 3, 4, 5]
+ let mut i = 0 // mutable bindings (local only, globals are immutable)
+ let target = 3
+ // loops return values with 'break'
+ let found : Int? = while i < array.length() {
+ if array[i] == target {
+ break Some(i) // Exit with value
+ }
+ i = i + 1
+ } else { // Value when loop completes normally
+ None
+ }
+ assert_eq(found, Some(2)) // Found at index 2
+}
+
+///|
+/// global bindings
+pub let my_name : String = "MoonBit"
+
+///|
+pub const PI : Double = 3.14159 // constants use UPPER_SNAKE or PascalCase
+
+///|
+pub fn maximum(xs : Array[Int]) -> Int raise {
+ // Toplevel functions are *mutually recursive* by default
+ // `raise` annotation means the function would raise any Error
+ // Only add `raise XXError` when you do need track the specific error type
+ match xs {
+ [] => fail("Empty array") // fail() is built-in for generic errors
+ [x] => x
+ // pattern match over array, the `.. rest` is a rest pattern
+ // it is of type `ArrayView[Int]` which is a slice
+ [x, .. rest] => {
+ let mut max_val = x // `mut` only allowed in local bindings
+ for y in rest {
+ if y > max_val {
+ max_val = y
+ }
+ }
+ max_val // return can be omitted if the last expression is the return value
+ }
+ }
+}
+
+///|
+/// pub(all) means it can be both read and created outside the package
+pub(all) struct Point {
+ x : Int
+ mut y : Int
+} derive(Show, ToJson)
+
+///|
+pub enum MyResult[T, E] {
+ MyOk(T) // semicolon `;` is optional when we have a newline
+ MyErr(E) // Enum variants must start uppercase
+} derive(Show, Eq, ToJson)
+// pub means it can only be pattern matched outside the package
+// but it can not be created outside the package, use `pub(all)` otherwise
+
+///|
+/// pub (open) means the trait can be implemented for outside packages
+pub(open) trait Comparable {
+ compare(Self, Self) -> Int // `Self` refers to the implementing type
+}
+
+///|
+test "inspect test" {
+ let result = sum(1, 2)
+ inspect(result, content="3")
+ // The `content` can be auto-corrected by running `moon test --update`
+ let point = Point::{ x: 10, y: 20 }
+ // For complex structures, use @json.inspect for better readability:
+ @json.inspect(point, content={ "x": 10, "y": 20 })
+}
+```
+
+## Integers, Char
+
+MoonBit supports Byte, Int16, Int, UInt16, UInt, Int64, UInt64, etc. When the type is known,
+the literal can be overloaded:
+
+```mbt test
+let a0 = 1 // a is Int by default
+let (int, uint, uint16, int64, byte) : (Int, UInt, UInt16, Int64, Byte) = (
+ 1, 1, 1, 1, 1,
+)
+assert_eq(int, uint16.to_int())
+// when the type is known, the literal can be overloaded
+let a1 : Int = 'b' // this also works, a5 will be the unicode value
+let a2 : Char = 'b'
+```
+
+## Bytes
+
+Bytes is immutable; Indexing (`b[i]`) returns a `Byte`.
+
+```mbt test
+let b0 : Bytes = b"abcd"
+let b1 : Bytes = "abcd" // b" prefix is optional, when we know the type
+let b2 : Bytes = [0xff, 0x00, 0x01] // Array literal overloading
+assert_eq(b0[0], b'a') // indexing returns Byte
+```
+
+## Array
+
+MoonBit Array is resizable array, FixedArray is fixed size array.
+
+```mbt test
+let a0 : Array[Int] = [1, 2, 3] // resizable
+// Array literal overloading (disambiguated via type in the current context)
+let a1 : FixedArray[Int] = [1, 2, 3]
+let a2 : ReadOnlyArray[Int] = [1, 2, 3]
+let a3 : ArrayView[Int] = [1, 2, 3]
+```
+
+## String
+
+MoonBit's String is immutable utf16 encoded, `s.code_unit_at(i)` returns a code unit (UInt16),
+`s.get_char(i)` returns `Option[Char]`.
+Since MoonBit supports char literal overloading, you can write code snippets like this:
+
+```mbt test
+let s = "hello world"
+let b0 : UInt16 = s.code_unit_at(0)
+assert_true(b0 is ('\n' | 'h' | 'b' | 'a'..='z'))
+// In check mode (expression with explicit type), ('\n' : Int) is valid.
+// Here the compiler knows `s[i]` is Int
+
+// Using get_char for Option handling
+let b1 : Char? = s.get_char(0)
+assert_true(b1 is Some('a'..='z'))
+
+// ⚠️ Important: Variables won't work with direct indexing
+let eq_char : Char = '='
+// s.code_unit_at(0) == eq_char // ❌ Won't compile - eq_char is not a literal, lhs is UInt while rhs is Char
+// Use: s.code_unit_at(0) == '=' or s.get_char(0) == Some(eq_char)
+let bytes = @encoding/utf8.encode("中文") // utf8 encode package is in stdlib
+assert_true(bytes is [0xe4, 0xb8, 0xad, 0xe6, 0x96, 0x87])
+let s2 : String = @encoding/utf8.decode(bytes) // decode utf8 bytes back to String
+assert_true(s2 is "中文")
+```
+
+#### String Interpolation
+
+MoonBit uses `\{}` for string interpolation:
+
+```mbt test
+let point : Point = { x: 10, y: 20 }
+let name : String = "Moon"
+let config = { "cache": 123 }
+let version = 1.0
+let message = "Hello \{name} v\{version}" // "Hello Moon v1.0"
+let desc = "Point at \{point}" // Uses point.to_string()
+// Works with any type implementing Show
+
+// ❌ Wrong - quotes inside interpolation not allowed:
+// println(" - Checking if 'cache' section exists: \{config["cache"]}")
+
+// ✅ Correct - extract to variable first:
+let has_key = config["cache"] // `"` not allowed in interpolation
+println(" - Checking if 'cache' section exists: \{has_key}")
+```
+
+ expressions inside `\{}` can only be basic expressions (no quotes, newlines, or nested interpolations). String literals are not allowed as it makes lexing too difficult.
+
+
+#### Multiple line strings
+
+```mbt test
+let multi_line_string : String =
+ #|Hello
+ #|World
+ #|
+inspect(
+ multi_line_string,
+ content=(
+ #|Hello
+ #|World
+ #|
+ ), // when multiple line string is passed as argument, `()` wrapper is required
+)
+```
+
+## Map
+
+A built-in `Map` type that preserves insertion order (like
+JavaScript's Map):
+
+```mbt test
+// Map literal syntax
+let map : Map[String, Int] = { "a": 1, "b": 2, "c": 3 }
+
+// Empty map
+let empty : Map[String, Int] = {}
+
+// From array of pairs
+let from_pairs : Map[String, Int] = Map::from_array([("x", 1), ("y", 2)])
+
+// Set/update value
+map["new-key"] = 3
+map["a"] = 10 // Updates existing key
+
+// Get value - returns Option[T]
+assert_eq(map.get("new-key"), Some(3))
+assert_eq(map.get("missing"), None)
+
+// Direct access (panics if key missing)
+let value : Int = map["a"] // value = 10
+
+// Iteration preserves insertion order
+for k, v in map {
+ println("\{k}: \{v}") // Prints: a: 10, b: 2, c: 3, new-key: 3
+}
+
+// Other common operations
+map.remove("b")
+assert_eq(map.contains("b"), false)
+assert_eq(map.length(), 3)
+```
+
+## View Types
+
+**Key Concept**: View types (`StringView`, `BytesView`, `ArrayView[T]`) are zero-copy, non-owning read-only slices created with the `[:]` syntax. They don't allocate memory and are ideal for passing sub-sequences without copying data.
+
+- `String` → `StringView` via `s[:]` or `s[start:end]`
+- `Bytes` → `BytesView` via `b[:]` or `b[start:end]`
+- `Array[T]` → `ArrayView[T]` via `a[:]` or `a[start:end]`
+
+**Important**: StringView slice is slightly different due to unicode safety:
+`s[a:b]` may raise an error at surrogate boundaries (UTF-16 encoding edge case). You have two options:
+
+- Use `try! s[a:b]` if you're certain the boundaries are valid (crashes on invalid boundaries)
+- Let the error propagate to the caller for proper handling
+
+**When to use views**:
+
+- Pattern matching with rest patterns (`[first, .. rest]`)
+- Passing slices to functions without allocation overhead
+- Avoiding unnecessary copies of large sequences
+
+Convert back with `.to_string()`, `.to_bytes()`, or `.to_array()` when you need ownership.
+
+## Complex Types
+
+```mbt check
+///|
+type UserId = Int // Int is aliased to UserId - like symlink
+
+///|
+/// Tuple-struct for callback
+struct Handler((String) -> Unit) // A newtype wrapper
+
+///|
+/// Tuple-struct syntax for single-field newtypes
+struct Meters(Int) // Tuple-struct syntax
+
+///|
+let distance : Meters = Meters(100)
+
+///|
+let raw : Int = distance.0 // Access first field with .0
+
+///|
+struct Addr {
+ host : String
+ port : Int
+} derive(Show, Eq, ToJson, FromJson)
+
+///|
+/// Structural types with literal syntax
+let config : Addr = {
+ // `Type::` can be omitted if the type is already known
+ // otherwise `Type::{...}`
+ host: "localhost",
+ port: 8080,
+}
+
+///|
+/// Recursive enum for trees
+enum Tree[T] {
+ Leaf(T)
+ Node(left~ : Tree[T], T, right~ : Tree[T]) // enum can use labels
+}
+
+// Pattern match on enum variants
+
+///|
+fn sum_tree(tree : Tree[Int]) -> Int {
+ match tree {
+ Leaf(x) => x
+ Node(left~, x, right~) => sum_tree(left) + x + sum_tree(right)
+ }
+}
+```
+
+## Common Derivable Traits
+
+Most types can automatically derive standard traits using the `derive(...)` syntax:
+
+- **`Show`** - Enables `to_string()` and string interpolation with `\{value}`
+- **`Eq`** - Enables `==` and `!=` equality operators
+- **`Compare`** - Enables `<`, `>`, `<=`, `>=` comparison operators
+- **`ToJson`** - Enables `@json.inspect()` for readable test output
+- **`Hash`** - Enables use as Map keys
+
+```mbt check
+///|
+struct Coordinate {
+ x : Int
+ y : Int
+} derive(Show, Eq, ToJson)
+
+///|
+enum Status {
+ Active
+ Inactive
+} derive(Show, Eq, Compare)
+```
+
+**Best practice**: Always derive `Show` and `Eq` for data types. Add `ToJson` if you plan to test them with `@json.inspect()`.
+
+## Reference Semantics by Default
+
+MoonBit passes most types by reference semantically (the optimizer may copy
+immutables):
+
+```mbt check
+///|
+/// Structs with 'mut' fields are always passed by reference
+struct Counter {
+ mut value : Int
+}
+
+///|
+fn increment(c : Counter) -> Unit {
+ c.value += 1 // Modifies the original
+}
+
+///|
+/// Arrays and Maps are mutable references
+fn modify_array(arr : Array[Int]) -> Unit {
+ arr[0] = 999 // Modifies original array
+}
+
+///|
+/// Use Ref[T] for explicit mutable references to primitives
+fn swap_values(a : Ref[Int], b : Ref[Int]) -> Unit {
+ let temp = a.val
+ a.val = b.val
+ b.val = temp
+}
+
+///|
+test "ref swap" {
+ let x : Ref[Int] = Ref::new(10)
+ let y : Ref[Int] = Ref::new(20)
+ swap_values(x, y) // x.val is now 20, y.val is now 10
+}
+```
+
+## Pattern Matching
+
+MoonBit's pattern matching is comprehensive and exhaustive:
+
+```mbt check
+///|
+/// Destructure arrays with rest patterns
+fn process_array(arr : Array[Int]) -> String {
+ match arr {
+ [] => "empty"
+ [single] => "one: \{single}"
+ [first, .. _middle, last] => "first: \{first}, last: \{last}"
+ // middle is of type ArrayView[Int]
+ }
+}
+
+///|
+fn analyze_point(point : Point) -> String {
+ match point {
+ { x: 0, y: 0 } => "origin"
+ { x, y } if x == y => "on diagonal"
+ { x, .. } if x < 0 => "left side"
+ _ => "other"
+ }
+}
+
+///|
+/// StringView pattern matching for parsing
+fn is_palindrome(s : StringView) -> Bool {
+ loop s {
+ [] | [_] => true
+ [a, .. rest, b] if a == b => continue rest
+ // a is of type Char, rest is of type StringView
+ _ => false
+ }
+}
+```
+
+## Functional `loop` control flow
+
+The `loop` construct is unique to MoonBit:
+
+```mbt check
+///|
+/// Functional loop with pattern matching on loop variables
+/// @list.List is from the standard library
+fn sum_list(list : @list.List[Int]) -> Int {
+ loop (list, 0) {
+ (Empty, acc) => acc // Base case returns accumulator
+ (More(x, tail=rest), acc) => continue (rest, x + acc) // Recurse with new values
+ }
+}
+
+///|
+/// Multiple loop variables with complex control flow
+fn find_pair(arr : Array[Int], target : Int) -> (Int, Int)? {
+ loop (0, arr.length() - 1) {
+ (i, j) if i >= j => None
+ (i, j) => {
+ let sum = arr[i] + arr[j]
+ if sum == target {
+ Some((i, j)) // Found pair
+ } else if sum < target {
+ continue (i + 1, j) // Move left pointer
+ } else {
+ continue (i, j - 1) // Move right pointer
+ }
+ }
+ }
+}
+```
+
+**Note**: You must provide a payload to `loop`. If you want an infinite loop, use `while true { ... }` instead. The syntax `loop { ... }` without arguments is invalid.
+
+## Functional `for` control flow
+
+`for` loops have unique MoonBit features:
+
+```mbt test
+// For loop with multiple loop variables,
+// i and j are loop state
+let sum_result : Int = for i = 0, sum = 0 {
+ if i <= 10 {
+ continue i + 1, sum + i
+ // update new loop state in a functional way
+ } else { // Continue with new values
+ break sum // Final value when loop completes normally
+ }
+}
+inspect(sum_result, content="55")
+
+// special form with condition and state update in the `for` header
+let sum_result2 : Int = for i = 0, sum = 0; i <= 10; i = i + 1, sum = sum + i {
+
+} else {
+ sum
+}
+inspect(sum_result2, content="55")
+```
+
+## Label and Optional Parameters
+
+```mbt check
+///|
+type Window
+
+///|
+fn create_window(
+ title~ : String, // Required labeled parameter
+ width? : Int = 800, // Optional labeled parameter with default
+ height? : Int = 600,
+ resizable? : Bool = true,
+) -> Window {
+ ... // `...` is a valid placeholder in MoonBit
+}
+
+///|
+/// Only type checked, skipped in test runs
+/// we can skip tests during prototyping and remove it when we fixed it
+#skip
+test "use function with label and optional parameter" {
+ // Call with named arguments in any order
+ let win1 : Window = create_window(title="App", height=400, width=1024)
+ let win2 : Window = create_window(title="Dialog", resizable=false)
+ // Pun syntax for named arguments
+ let width = 1920
+ let height = 1080
+ let win3 : Window = create_window(title="Fullscreen", width~, height~)
+ // Same as width=width, height=height
+}
+```
+
+## Checked Errors
+
+MoonBit uses **checked** error-throwing functions, not unchecked exceptions,
+it is recommended to use `raise` for functions and use `Result` in testing.
+
+```mbt check
+///|
+/// Declare error types with 'suberror'
+suberror ValueError String
+
+///|
+struct Position(Int, Int) derive(ToJson, Show, Eq)
+
+///|
+pub(all) suberror ParseError {
+ InvalidChar(Position, Char)
+ InvalidEof
+ InvalidNumber(Position, String)
+ InvalidIdentEscape(Position)
+} derive(Eq, ToJson, Show)
+
+///|
+/// Functions declare what they can throw
+fn parse_int(s : String) -> Int raise ParseError {
+ // 'raise' throws an error
+ if s.is_empty() {
+ raise ParseError::InvalidEof
+ }
+ ... // parsing logic
+}
+
+///|
+fn div(x : Int, y : Int) -> Int raise {
+ if y == 0 {
+ raise Failure("Division by zero")
+ }
+ x / y
+}
+
+///|
+test "inspect raise function" {
+ inspect(
+ try? div(1, 0),
+ content=(
+ #|Err(Failure("Division by zero"))
+ ),
+ ) // Result[Int, MyError]
+}
+
+// Three ways to handle errors:
+
+///|
+/// Propagate automatically
+fn use_parse() -> Int raise ParseError {
+ let x = parse_int("123")
+ // Error *auto* propagates by default.
+ // *unlike* Swift, you don't need mark `try` for functions that can raise errors,
+ // compiler infers it automatically. This makes error-handling code cleaner
+ // while still being type-safe and explicit about what errors can occur.
+ x * 2
+}
+
+///|
+/// Mark `raise` for all possible errors, don't care what error it is
+/// If you are doing a quick prototype, just mark it as raise is good enough.
+fn use_parse2() -> Int raise {
+ let x = parse_int("123")
+ x * 2
+}
+
+///|
+/// Convert to Result with try?
+fn safe_parse(s : String) -> Result[Int, ParseError] {
+ let val1 : Result[_] = try? parse_int(s) // Returns Result[Int, ParseError]
+ // try! is rarely used - it panics on error, similar to unwrap() in Rust
+ // let val2 : Int = try! parse_int(s) // Returns Int otherwise crash
+
+ // Alternative explicit handling:
+ let val3 = try parse_int(s) catch {
+ err => Err(err)
+ } noraise { // noraise block is optional - handles the success case
+ v => Ok(v)
+ }
+ ...
+}
+
+///|
+/// 3. Handle with try-catch
+fn handle_parse(s : String) -> Int {
+ parse_int(s) catch {
+ ParseError::InvalidEof => {
+ println("Parse failed: InvalidEof")
+ -1 // Default value
+ }
+ _ => 2
+ }
+}
+```
+
+# Methods and Traits
+
+Methods use `Type::method_name` syntax, traits require explicit implementation:
+
+```mbt check
+///|
+struct Rectangle {
+ width : Double
+ height : Double
+}
+
+///|
+// Methods are prefixed with Type::
+fn Rectangle::area(self : Rectangle) -> Double {
+ self.width * self.height
+}
+
+///|
+/// Static methods don't need self
+fn Rectangle::new(w : Double, h : Double) -> Rectangle {
+ { width: w, height: h }
+}
+
+///|
+/// Show trait now uses output(self, logger) for custom formatting
+/// to_string() is automatically derived from this
+pub impl Show for Rectangle with output(self, logger) {
+ logger.write_string("Rectangle(\{self.width}x\{self.height})")
+}
+
+///|
+/// Traits can have non-object-safe methods
+trait Named {
+ name() -> String // No 'self' parameter - not object-safe
+}
+
+///|
+/// Trait bounds in generics
+fn[T : Show + Named] describe(value : T) -> String {
+ "\{T::name()}: \{value.to_string()}"
+}
+
+///|
+/// Trait implementation
+impl Hash for Rectangle with hash_combine(self, hasher) {
+ hasher..combine(self.width)..combine(self.height)
+}
+```
+
+## Operator Overloading
+
+MoonBit supports operator overloading through traits:
+
+```mbt check
+///|
+struct Vector(Int, Int)
+
+///|
+/// Implement arithmetic operators
+pub impl Add for Vector with add(self, other) {
+ Vector(self.0 + other.0, self.1 + other.1)
+}
+
+///|
+pub impl Mul for Vector with mul(self, other) {
+ Vector(self.0 * other.0, self.1 * other.1)
+}
+
+///|
+struct Person {
+ age : Int
+} derive(Eq)
+
+///|
+/// Comparison operators
+pub impl Compare for Person with compare(self, other) {
+ self.age.compare(other.age)
+}
+
+///|
+test "overloading" {
+ let v1 : Vector = Vector(1, 2)
+ let v2 : Vector = Vector(3, 4)
+ let _v3 : Vector = v1 + v2
+
+}
+```
+
+## Access Control Modifiers
+
+MoonBit has fine-grained visibility control:
+
+```mbt check
+///|
+/// `fn` defaults to Private - only visible in current package
+fn internal_helper() -> Unit {
+ ...
+}
+
+///|
+pub fn get_value() -> Int {
+ ...
+}
+
+///|
+// Struct (default) - type visible, implementation hidden
+struct DataStructure {}
+
+///|
+/// `pub struct` defaults to readonly - can read, pattern match, but not create
+pub struct Config {}
+
+///|
+/// Public all - full access
+pub(all) struct Config2 {}
+
+///|
+/// Abstract trait (default) - cannot be implemented by
+/// types outside this package
+pub trait MyTrait {}
+
+///|
+/// Open for extension
+pub(open) trait Extendable {}
+```
+
+# Best Practices and Reference
+
+## Common Pitfalls to Avoid
+
+1. **Don't use uppercase for variables/functions** - compilation error
+2. **Don't forget `mut` for mutable fields** - immutable by default
+3. **Don't assume value semantics** - most types pass by reference
+4. **Don't ignore error handling** - errors must be explicitly handled
+5. **Don't use `return` unnecessarily** - last expression is the return value
+6. **Don't create methods without Type:: prefix** - methods need explicit type prefix
+7. Don't forget to handle array bounds - use get() for safe access
+8. Don't mix up String indexing (returns Int). Use `for char in s {...}` for char iteration
+9. Don't forget @package prefix when calling functions from other packages
+10. Don't use ++ or -- (not supported), use `i = i + 1` or `i += 1`
+11. **Don't add explicit `try` for error-raising functions** - errors propagate automatically (unlike Swift)
+12. **Legacy syntax**: Older code may use `function_name!(...)` or `function_name(...)?` - these are deprecated; use normal calls and `try?` for Result conversion
+
+# MoonBit Build System - Essential Guide
+
+## Idiomatic Project Structure
+
+MoonBit projects use `moon.mod.json` (module descriptor) and `moon.pkg.json`
+(package descriptor):
+
+```
+my_module
+├── Agents.md # Guide to Agents
+├── README.mbt.md # Markdown with tested code blocks (`test {...}`)
+├── README.md -> README.mbt.md
+├── cmd # Command line directory
+│ └── main
+│ ├── main.mbt
+│ └── moon.pkg.json # executable package with {"is_main": true}
+├── liba/ # Library packages
+│ └── moon.pkg.json # Referenced by other packages as `@username/my_module/liba`
+│ └── libb/ # Library packages
+│ └── moon.pkg.json # Referenced by other packages as `@username/my_module/liba/libb`
+├── moon.mod.json # Module metadata, source field(optional) specifies the source directory of the module
+├── moon.pkg.json # Package metadata (each directory is a package like Golang)
+├── user_pkg.mbt # Root packages, referenced by other packages as `@username/my_module`
+├── user_pkg_wbtest.mbt # White-box tests (only needed for testing internal private members, similar to Golang's package mypackage)
+└── user_pkg_test.mbt # Black-box tests
+└── ... # More package files, symbols visible to current package (like Golang)
+```
+
+## Essential Commands
+
+- `moon new my_project` - Create new project
+- `moon run cmd/main` - Run main package
+- `moon build` - Build project
+- `moon check` - Type check without building, use it regularly
+- `moon check --target all` - Type check for all backends
+- `moon add package` - Add dependency
+- `moon remove package` - Remove dependency
+- `moon fmt` - Format code
+
+### Test Commands
+
+- `moon test` - Run all tests
+- `moon test --update`
+- `moon test -v` - Verbose output with test names
+- `moon test dirname` - Test specific directory
+- `moon test filename` - Test specific file in a directory
+- `moon coverage analyze` - Analyze coverage
+
+## Package Management
+
+### Adding Dependencies
+
+```bash
+moon add moonbitlang/x # Add latest version
+moon add moonbitlang/x@0.4.6 # Add specific version
+```
+
+### Updating Dependencies
+
+```bash
+moon update # Update package index
+```
+
+## Key Configuration
+
+### Module (`moon.mod.json`)
+
+```json
+{
+ "name": "username/hello", // Required format for published modules
+ "version": "0.1.0",
+ "source": ".", // Source directory(optional, default: ".")
+ "repository": "", // Git repository URL
+ "keywords": [], // Search keywords
+ "description": "...", // Module description
+ "deps": {
+ // Dependencies from mooncakes.io, using`moon add` to add dependencies
+ "moonbitlang/x": "0.4.6"
+ }
+}
+```
+
+### Package (`moon.pkg.json`)
+
+```json
+{
+ "is_main": true, // Creates executable when true
+ "import": [ // Package dependencies
+ "username/hello/liba", // Simple import, use @liba.foo() to call functions
+ {
+ "path": "moonbitlang/x/encoding",
+ "alias": "libb" // Custom alias, use @libb.encode() to call functions
+ }
+ ],
+ "test-import": [...], // Imports for black-box tests, similar to import
+ "wbtest-import": [...] // Imports for white-box tests, similar to import (rarely used)
+}
+```
+
+Packages per directory, packages without `moon.pkg.json` are not recognized.
+
+## Package Importing (used in moon.pkg.json)
+
+- **Import format**: `"module_name/package_path"`
+- **Usage**: `@alias.function()` to call imported functions
+- **Default alias**: Last part of path (e.g., `liba` for `username/hello/liba`)
+- **Package reference**: Use `@packagename` in test files to reference the
+ tested package
+
+**Package Alias Rules**:
+
+- Import `"username/hello/liba"` → use `@liba.function()` (default alias is last path segment)
+- Import with custom alias `{"path": "moonbitlang/x/encoding", "alias": "enc"}` → use `@enc.function()`
+- In `_test.mbt` or `_wbtest.mbt` files, the package being tested is auto-imported
+
+Example:
+
+```mbt
+///|
+/// In main.mbt after importing "username/hello/liba" in `moon.pkg.json`
+fn main {
+ println(@liba.hello()) // Calls hello() from liba package
+}
+```
+
+## Using Standard Library (moonbitlang/core)
+
+**MoonBit standard library (moonbitlang/core) packages are automatically imported** - DO NOT add them to dependencies:
+
+- ❌ **DO NOT** use `moon add` to add standard library packages like `moonbitlang/core/strconv`
+- ❌ **DO NOT** add standard library packages to `"deps"` field of `moon.mod.json`
+- ❌ **DO NOT** add standard library packages to `"import"` field of `moon.pkg.json`
+- ✅ **DO** use them directly: `@strconv.parse_int()`, `@list.List`, `@array.fold()`, etc.
+
+If you get an error like "cannot import `moonbitlang/core/strconv`", remove it from imports - it's automatically available.
+
+## Creating Packages
+
+To add a new package `fib` under `.`:
+
+1. Create directory: `./fib/`
+2. Add `./fib/moon.pkg.json`: `{}` -- Minimal valid moon.pkg.json
+3. Add `.mbt` files with your code
+4. Import in dependent packages:
+
+ ```json
+ {
+ "import": [
+ "username/hello/fib",
+ ...
+ ]
+ }
+ ```
+
+## Conditional Compilation
+
+Target specific backends/modes in `moon.pkg.json`:
+
+```json
+{
+ "targets": {
+ "wasm_only.mbt": ["wasm"],
+ "js_only.mbt": ["js"],
+ "debug_only.mbt": ["debug"],
+ "wasm_or_js.mbt": ["wasm", "js"], // for wasm or js backend
+ "not_js.mbt": ["not", "js"], // for nonjs backend
+ "complex.mbt": ["or", ["and", "wasm", "release"], ["and", "js", "debug"]] // more complex conditions
+ }
+}
+```
+
+**Available conditions:**
+
+- **Backends**: `"wasm"`, `"wasm-gc"`, `"js"`, `"native"`
+- **Build modes**: `"debug"`, `"release"`
+- **Logical operators**: `"and"`, `"or"`, `"not"`
+
+## Link Configuration
+
+### Basic Linking
+
+```json
+{
+ "link": true, // Enable linking for this package
+ // OR for advanced cases:
+ "link": {
+ "wasm": {
+ "exports": ["hello", "foo:bar"], // Export functions
+ "heap-start-address": 1024, // Memory layout
+ "import-memory": {
+ // Import external memory
+ "module": "env",
+ "name": "memory"
+ },
+ "export-memory-name": "memory" // Export memory with name
+ },
+ "wasm-gc": {
+ "exports": ["hello"],
+ "use-js-builtin-string": true, // JS String Builtin support
+ "imported-string-constants": "_" // String namespace
+ },
+ "js": {
+ "exports": ["hello"],
+ "format": "esm" // "esm", "cjs", or "iife"
+ },
+ "native": {
+ "cc": "gcc", // C compiler
+ "cc-flags": "-O2 -DMOONBIT", // Compile flags
+ "cc-link-flags": "-s" // Link flags
+ }
+ }
+}
+```
+
+## Warning Control
+
+Disable specific warnings in `moon.mod.json` or `moon.pkg.json`:
+
+```json
+{
+ "warn-list": "-2-29" // Disable unused variable (2) & unused package (29)
+}
+```
+
+**Common warning numbers:**
+
+- `1` - Unused function
+- `2` - Unused variable
+- `11` - Partial pattern matching
+- `12` - Unreachable code
+- `29` - Unused package
+
+Use `moonc build-package -warn-help` to see all available warnings.
+
+## Pre-build Commands
+
+Embed external files as MoonBit code:
+
+```json
+{
+ "pre-build": [
+ {
+ "input": "data.txt",
+ "output": "embedded.mbt",
+ "command": ":embed -i $input -o $output --name data --text"
+ },
+ ... // more embed commands
+ ]
+}
+```
+
+Generated code example:
+
+```mbt check
+///|
+let data : String =
+ #|hello,
+ #|world
+ #|
+```
+
+# Documentation
+
+Write documentation using `///` comments (started with `///|` to delimit the
+block code)
+
+````mbt check
+///|
+/// Get the largest element of a non-empty `Array`.
+///
+/// # Example
+/// ```mbt test
+/// inspect(sum_array([1, 2, 3, 4, 5, 6]), content="21")
+/// ```
+///
+/// # Panics
+/// Panics if the `xs` is empty.
+pub fn sum_array(xs : Array[Int]) -> Int {
+ xs.fold(init=0, (a, b) => a + b)
+}
+````
+
+The MoonBit code in docstring will be type checked and tested automatically.
+(using `moon test --update`)
+
+# Development Workflow
+
+## MoonBit Tips
+
+- MoonBit code is organized in files/block style.
+ A package is composed of a list of files, their order does not matter,
+ keep them separate so that it is easy to focus on critical parts.
+
+ Each block is separated by `///|`, the order of each block is irrelevant too. You can process
+ block by block independently.
+
+ You are encouraged to generate code in a block-by-block manner.
+
+ You are encouraged to search and replace block by block instead of
+ replacing the whole file.
+
+ You are encouraged to keep each file focused.
+
+- SPLIT the large file into small files, the order does not matter.
+
+- Try to keep deprecated blocks in file called `deprecated.mbt` in each
+ directory.
+
+- `moon fmt` is used to format your code properly.
+
+- `moon info` is used to update the generated interface of the package
+ **in current project**. Each package has a generated interface file `.mbti`,
+ it is a brief formal description of the package. If nothing in `.mbti`
+ changes, this means your change does not bring the visible changes to the
+ external package users, it is typically a safe refactoring.
+ **Note**: `moon info` will only work with packages in the current project, and
+ therefore you cannot use `moon info` to generate interface for dependencies
+ like standard library.
+
+- So in the last step, you typically run `moon info && moon fmt` to update the
+ interface and format the code. You also check the diffs of `.mbti` file to see
+ if the changes are expected.
+
+- You should run `moon test` to check the test is passed. MoonBit supports
+ snapshot testing, so in some cases, your changes indeed change the behavior of
+ the code, you should run `moon test --update` to update the snapshot.
+
+- You can run `moon check` to check the code is linted correctly, run it
+ regularly to ensure you are not in a messy state.
+
+- MoonBit packages are organized per directory; each directory has a
+ `moon.pkg.json` listing its dependencies. Each package has its files and
+ blackbox test files (common, ending in `_test.mbt`) and whitebox test files
+ (ending in `_wbtest.mbt`).
+
+- In the toplevel directory, there is a `moon.mod.json` file describing the
+ module and metadata.
+
+## MoonBit Package `README` Generation Guide
+
+- Output `README.mbt.md` in the package directory.
+ `*.mbt.md` file treats `mbt test` and `mbt check` specially, `mbt test` block will be wrapped using `test { ... }` and run by `moon check` and `moon test`.
+ `mbt check` block will be included directly as code and also run by `moon check` and `moon test`.
+ If you are only referencing types from the package, you should use `mbt` which will only be syntax highlighted.
+ Symlink `README.mbt.md` to `README.md` to adapt to systems that expect `README.md`.
+- Aim to cover ≥90% of the public API with concise sections and examples.
+- Organize by feature: construction, consumption, transformation, and key usage tips.
+
+## MoonBit Testing Guide
+
+Practical testing guidance for MoonBit. Keep tests black-box by default and rely on snapshot `inspect(...)`.
+
+- Black-box by default: Call only public APIs via `@package.fn`. Use white-box tests only when private members matter.
+- **Snapshots**: Prefer `inspect(value, content="...")`. If unknown, write `inspect(value)` and run `moon test --update` (or `moon test -u`).
+ - Use regular `inspect()` for simple values (uses `Show` trait)
+ - Use `@json.inspect()` for complex nested structures (uses `ToJson` trait, produces more readable output)
+ - It is encouraged to `inspect` or `@json.inspect` the whole return value of a function if
+ the whole return value is not huge, this makes test simple. You need `impl (Show|ToJson) for YourType` or `derive (Show, ToJson)`.
+ - **Update workflow**: After changing code that affects output, run `moon test --update` to regenerate snapshots, then review the diffs in your test files (the `content=` parameter will be updated automatically).
+- Grouping: Combine related checks in one `test { ... }` block for speed and clarity.
+- Panics: Name test with prefix `test "panic ..." {...}`; if the call returns a value, wrap it with `ignore(...)` to silence warnings.
+- Errors: Use `try? f()` to get `Result[...]` and `inspect` it when a function may raise.
+- Verify: Run `moon test` (or `-u` to update snapshots) and `moon fmt` afterwards.
+
+## API Discovery with `moon doc`
+
+**CRITICAL**: `moon doc ''` is your PRIMARY tool for discovering available APIs, functions, types, and methods in MoonBit. It is **more powerful and accurate** than `grep_search`, `semantic_search`, or any file-based searching tools. Always prefer `moon doc` over other approaches when exploring what APIs are available.
+
+### Query Syntax
+
+`moon doc` uses a specialized query syntax designed for symbol lookup:
+
+- **Empty query**: `moon doc `
+
+ - In a module: shows all available packages in current module
+ - In a package: shows all symbols in current package
+ - Outside package: shows all available packages
+
+- **Function/value lookup**: `moon doc "[@pkg.]sym"`
+- **Type lookup**: `moon doc "[@pkg.]Sym"`
+
+- **Method/field lookup**: `moon doc "[@pkg.]T::sym"`
+
+- **Package exploration**: `moon doc "@pkg"`
+ - Show package `pkg` and list all its exported symbols
+ - Example: `moon doc "@json"` - explore entire `@json` package
+ - Example: `moon doc "@encoding/utf8"` - explore nested package
+
+### Workflow for API Discovery
+
+1. **Finding functions**: Use `moon doc "@pkg.function_name"` before grep searching
+2. **Exploring packages**: Use `moon doc "@pkg"` to see what's available in a package
+3. **Method discovery**: Use `moon doc "Type::method"` to find methods on types
+4. **Type inspection**: Use `moon doc "TypeName"` to see type definition and methods
+5. **Package exploration**: Use `moon doc ""` at module root to see all available packages, including dependencies and stdlib
+6. **Globbing**: Use `*` wildcard for partial matches, e.g. `moon doc "String::*rev*"` to find all String methods with "rev" in their name
+
+### Examples
+
+```bash
+# search for String methods in standard library:
+$ moon doc "String"
+
+type String
+
+ pub fn String::add(String, String) -> String
+ pub fn String::at(String, Int) -> Int
+ # ... more methods omitted ...
+
+# list all symbols in a standard library package:
+$ moon doc "@buffer"
+moonbitlang/core/buffer
+
+fn from_array(ArrayView[Byte]) -> Buffer
+fn from_bytes(Bytes) -> Buffer
+# ... more functions omitted ...
+
+# list the specific function in a package:
+$ moon doc "@buffer.new"
+package "moonbitlang/core/buffer"
+
+pub fn new(size_hint? : Int) -> Buffer
+ Creates a new extensible buffer with specified initial capacity. If the
+ initial capacity is less than 1, the buffer will be initialized with capacity
+ 1.
+# ... more details omitted ...
+
+$ moon doc "String::*rev*"
+package "moonbitlang/core/string"
+
+pub fn String::rev(String) -> String
+ Returns a new string with the characters in reverse order. It respects
+ Unicode characters and surrogate pairs but not grapheme clusters.
+
+pub fn String::rev_find(String, StringView) -> Int?
+ Returns the offset (charcode index) of the last occurrence of the given
+ substring. If the substring is not found, it returns None.
+
+# ... more details omitted ...
+
+**Best practice**: When implementing a feature, start with `moon doc` queries to discover available APIs before writing code. This is faster and more accurate than searching through files.
+```
diff --git a/llms/Agents.md b/llms/Agents.md
new file mode 100644
index 0000000..639f7e9
--- /dev/null
+++ b/llms/Agents.md
@@ -0,0 +1,494 @@
+# Respo MoonBit 应用开发指南 (for LLM Agents)
+
+本文档面向 LLM 编程助手,介绍如何使用 Respo 框架编写 MoonBit 前端应用组件。
+
+## 概述
+
+Respo 是一个虚拟 DOM 框架,采用类似 React 的函数式组件设计模式,但使用 MoonBit 语言编写,编译为 JavaScript 运行于浏览器。
+
+核心特点:
+
+- **函数式组件**:组件是返回 `RespoNode[ActionOp]` 的函数
+- **不可变状态管理**:全局 Store + 局部 States Tree
+- **声明式 UI**:使用 DSL 风格的元素构建函数
+
+## 依赖导入
+
+常用导入模式:
+
+```moonbit
+///|
+using @respo_node {
+ type RespoNode,
+ type RespoEvent,
+ type DispatchFn,
+ type RespoCommonError,
+ text_node,
+ div,
+ input,
+ button,
+ span,
+ space,
+ static_style,
+ respo_attrs,
+}
+
+///|
+using @css {respo_style}
+
+///|
+using @respo {type RespoStatesTree}
+```
+
+## 组件结构
+
+### 基本组件函数
+
+组件是一个函数,接收 states 和 props 参数,返回 `RespoNode[ActionOp]`:
+
+```moonbit
+///|
+fn comp_example(
+ states : RespoStatesTree,
+ some_prop : String,
+) -> RespoNode[ActionOp] {
+ div([
+ text_node("Hello, \{some_prop}"),
+ ])
+}
+```
+
+### 局部状态 (Local State)
+
+使用 `states.local_pair()` 获取局部状态和 cursor:
+
+```moonbit
+///|
+struct MyState {
+ count : Int
+} derive(Default, ToJson, FromJson)
+
+///|
+fn comp_counter(states : RespoStatesTree) -> RespoNode[ActionOp] {
+ // 获取局部状态和 cursor
+ let ((state : MyState), cursor) = states.local_pair()
+
+ div([
+ text_node("Count: \{state.count}"),
+ button(
+ inner_text="Increment",
+ class_name=@respo.ui_button,
+ on_click=fn(_e, dispatch) {
+ // 更新局部状态
+ dispatch.set_state(cursor, { count: state.count + 1 })
+ },
+ ),
+ ])
+}
+```
+
+**注意事项**:
+
+- State 结构体必须 derive `Default`, `ToJson`, `FromJson`
+- 使用 `dispatch.set_state(cursor, new_state)` 更新状态
+
+### 子状态传递
+
+向子组件传递 states 时使用 `states.pick("key")`:
+
+```moonbit
+///|
+fn comp_parent(states : RespoStatesTree) -> RespoNode[ActionOp] {
+ div([
+ comp_child(states.pick("child1")),
+ comp_child(states.pick("child2")),
+ ])
+}
+```
+
+## 元素构建
+
+### 常用元素函数
+
+```moonbit
+// div 容器
+div(class_name="my-class", style=respo_style(padding=Px(8)), [
+ // children...
+])
+
+// 带 key 的列表 (用于高效 diff)
+div_listed([
+ (RespoIndexKey("item-1"), comp_item(item1)),
+ (RespoIndexKey("item-2"), comp_item(item2)),
+])
+
+// span
+span(inner_text="text content", [])
+
+// 文本节点
+text_node("Hello World")
+
+// 按钮
+button(
+ inner_text="Click me",
+ class_name=@respo.ui_button,
+ on_click=fn(e, dispatch) { /* handler */ },
+)
+
+// 输入框
+input(
+ class_name=@respo.ui_input,
+ value=state.value,
+ placeholder="Enter text...",
+ on_input=fn(e, dispatch) {
+ if e is Input(value~, ..) {
+ dispatch.set_state(cursor, { value: value })
+ }
+ },
+)
+
+// 空白间隔
+space(width=8) // 水平间距
+space(height=8) // 垂直间距
+```
+
+### 属性设置
+
+```moonbit
+// 使用 respo_attrs 创建属性
+div(
+ attrs={
+ let t = respo_attrs(id="my-id", class_name="my-class")
+ t.set("data-custom", "value")
+ t
+ },
+ [],
+)
+```
+
+## 事件处理
+
+### 事件类型
+
+```moonbit
+// 点击事件
+on_click=fn(e, dispatch) {
+ if e is Click(original_event~, ..) {
+ original_event.prevent_default()
+ }
+ dispatch.run(SomeAction)
+}
+
+// 输入事件
+on_input=fn(e, dispatch) {
+ if e is Input(value~, ..) {
+ dispatch.set_state(cursor, { draft: value })
+ }
+}
+
+// 键盘事件
+on_keydown=fn(e, dispatch) {
+ if e is Keyboard(key~, ..) {
+ if key == "Enter" {
+ dispatch.run(SubmitAction)
+ }
+ }
+}
+
+// 焦点事件
+on_focus=fn(e, dispatch) { /* ... */ }
+on_blur=fn(e, dispatch) { /* ... */ }
+```
+
+### Dispatch 操作
+
+```moonbit
+// 分发全局 Action
+dispatch.run(SomeAction)
+
+// 更新局部状态
+dispatch.set_state(cursor, new_state)
+
+// 清空局部状态
+dispatch.empty_state(cursor)
+```
+
+## 样式系统
+
+### 内联样式
+
+使用 `respo_style()` 创建样式:
+
+```moonbit
+respo_style(
+ padding=Px(8),
+ margin=Px(4),
+ color=Hsl(200, 80, 50),
+ background_color=White,
+ display=Flex,
+ flex_direction=Column,
+ justify_content=Center,
+ align_items=Center,
+)
+```
+
+### 静态样式 (CSS 类)
+
+使用 `static_style` 声明静态 CSS 规则:
+
+```moonbit
+///|
+let style_container : String = static_style([
+ ("&", respo_style(margin=Px(4), background_color=Hsl(200, 90, 96))),
+ ("&:hover", respo_style(background_color=Hsl(200, 90, 90))),
+])
+
+// 使用
+div(class_name=style_container, [])
+```
+
+### 预定义 UI 类
+
+```moonbit
+@respo.ui_button // 按钮样式
+@respo.ui_button_primary // 主要按钮
+@respo.ui_button_danger // 危险按钮
+@respo.ui_input // 输入框样式
+@respo.ui_center // 居中布局
+@respo.ui_column // 列布局
+@respo.ui_row_middle // 行布局居中
+@respo.ui_row_parted // 行布局两端对齐
+@respo.ui_fullscreen // 全屏
+@respo.ui_global // 全局样式
+```
+
+## 组件与 Effect
+
+### 命名组件
+
+使用 `RespoComponent::named` 创建带 effect 的命名组件:
+
+```moonbit
+///|
+struct MyEffect {
+ some_data : String
+} derive(ToJson)
+
+///|
+impl @node.RespoEffect for MyEffect with mounted(_self, el) {
+ @dom_ffi.log("Component mounted")
+}
+
+///|
+impl @node.RespoEffect for MyEffect with updated(_self, el) {
+ @dom_ffi.log("Component updated")
+}
+
+///|
+fn comp_with_effect(states : RespoStatesTree) -> RespoNode[ActionOp] {
+ let effect_data : MyEffect = { some_data: "value" }
+
+ @node.RespoComponent::named(
+ "my-component",
+ effects=[effect_data],
+ div([
+ text_node("Component with effect"),
+ ]),
+ ).to_node()
+}
+```
+
+### Effect 生命周期
+
+```moonbit
+impl @node.RespoEffect for MyEffect with mounted(_self, el) -> Unit {
+ // 组件挂载后
+}
+
+impl @node.RespoEffect for MyEffect with before_update(_self, el) -> Unit {
+ // 更新前
+}
+
+impl @node.RespoEffect for MyEffect with updated(_self, el) -> Unit {
+ // 更新后
+}
+
+impl @node.RespoEffect for MyEffect with before_unmount(_self, el) -> Unit {
+ // 卸载前
+}
+```
+
+## Store 和 Action
+
+### 定义 Store
+
+```moonbit
+///|
+struct Store {
+ mut count : Int
+ states : @respo.RespoStatesTree
+} derive(ToJson, FromJson)
+
+///|
+impl Default for Store with default() -> Store {
+ { count: 0, states: @respo.RespoStatesTree::default() }
+}
+
+///|
+fn Store::get_states(self : Store) -> @respo.RespoStatesTree {
+ self.states
+}
+```
+
+### 定义 Action
+
+```moonbit
+///|
+enum ActionOp {
+ Noop
+ StatesChange(@respo.RespoUpdateState)
+ Increment
+ Decrement
+} derive(Eq, ToJson)
+
+///|
+impl Default for ActionOp with default() -> ActionOp {
+ Noop
+}
+
+///|
+impl @respo_node.RespoAction for ActionOp with build_states_action(cursor, a, j) {
+ StatesChange({
+ cursor,
+ data: if a is Some(a) { Some(@dom_ffi.js_obscure_to_v(a)) } else { None },
+ backup: j,
+ })
+}
+```
+
+### 更新 Store
+
+```moonbit
+///|
+fn Store::update(self : Store, op : ActionOp) -> Unit {
+ match op {
+ Increment => self.count += 1
+ Decrement => self.count -= 1
+ StatesChange(change) => self.states.set_in_mut(change)
+ Noop => ()
+ }
+}
+```
+
+## 记忆化 (Memoization)
+
+使用 `memo_once1` 等函数缓存组件以优化性能:
+
+```moonbit
+///|
+let memo_comp_panel : (RespoStatesTree) -> RespoNode[ActionOp] = @respo.memo_once1(
+ comp_panel,
+)
+
+// 在父组件中使用
+fn view(states : RespoStatesTree) -> RespoNode[ActionOp] {
+ div([
+ memo_comp_panel(states.pick("panel")),
+ ])
+}
+```
+
+可用的记忆化函数:
+
+- `memo_once1` ~ `memo_once5`:单槽缓存
+- `memoize1` ~ `memoize5`:多槽 hashmap 缓存
+
+## 列表渲染
+
+使用 `div_listed` 和 `RespoIndexKey` 进行高效列表渲染:
+
+```moonbit
+///|
+fn comp_list(
+ states : RespoStatesTree,
+ items : Array[Item],
+) -> RespoNode[ActionOp] {
+ let children : Array[(RespoIndexKey, RespoNode[ActionOp])] = []
+ for item in items {
+ children.push(
+ (RespoIndexKey(item.id), comp_item(states.pick(item.id), item)),
+ )
+ }
+ div_listed(children)
+}
+```
+
+## 常用模式
+
+### 条件渲染
+
+```moonbit
+if condition {
+ div([content()])
+} else {
+ span([]) // 占位符
+}
+```
+
+### 外部 JS 函数
+
+```moonbit
+///|
+extern "js" fn random_id() -> String =
+ #| () => Math.random().toString(36).slice(2)
+```
+
+### 日志输出
+
+```moonbit
+@dom_ffi.log("info message")
+@dom_ffi.warn_log("warning message")
+@dom_ffi.error_log("error message")
+```
+
+## 示例:完整组件
+
+```moonbit
+///|
+struct FormState {
+ name : String
+ submitted : Bool
+} derive(Default, ToJson, FromJson)
+
+///|
+fn comp_form(states : RespoStatesTree) -> RespoNode[ActionOp] {
+ let ((state : FormState), cursor) = states.local_pair()
+
+ div(class_name=@respo.ui_column, style=respo_style(padding=Px(16)), [
+ input(
+ class_name=@respo.ui_input,
+ value=state.name,
+ placeholder="Enter your name",
+ on_input=fn(e, dispatch) {
+ if e is Input(value~, ..) {
+ dispatch.set_state(cursor, { ..state, name: value })
+ }
+ },
+ ),
+ space(height=8),
+ button(
+ inner_text="Submit",
+ class_name=@respo.ui_button_primary,
+ on_click=fn(_e, dispatch) {
+ dispatch.run(SubmitName(state.name))
+ dispatch.set_state(cursor, { ..state, submitted: true })
+ },
+ ),
+ if state.submitted {
+ text_node("Submitted: \{state.name}")
+ } else {
+ span([])
+ },
+ ])
+}
+```