Boruna Application Framework Specification
Overview
The framework defines a mandatory application protocol for all Boruna programs. Every application follows a strict structure: init → update → view → effects cycle.
The VM is the kernel. The framework is userland. The runtime does not depend on the framework.
1. Application Protocol
Every app must implement three functions, plus an optional fourth:
fn init() -> State
fn update(state: State, msg: Message) -> UpdateResult
fn view(state: State) -> UITree
fn policies() -> PolicySet // optional
Rules
update()must be pure — no capability annotations allowed.update()returnsUpdateResult { state: State, effects: List<Effect> }.view()must be pure — returns a declarative UITree.init()may use capabilities for initial setup.policies()declares required capabilities and constraints. It is optional: when it is missing, the runtime usesPolicySet::allow_all()andboruna framework validatereportspolicies: none (using defaults).
Compile-Time Validation
The framework validator (AppValidator) checks:
init(),update()andview()exist;policies()is optional.- Parameter counts:
init()0,update()2,view()1,policies()0. update(),view()andpolicies()have no capability annotations.
It also detects the State and Message types by name only (a type named State
or ending in State; Msg, Message, or ending in Msg) and reports them.
It does not check that State is serializable or that the Message type is an
enum — a record Msg passes.
2. Effect System
Effects are declarative descriptions of side effects:
type Effect {
kind: String, // one of the built-in effect kinds below
payload: Value, // structured payload (type depends on effect kind)
callback_tag: String, // message tag for delivering the result
}
Built-in effect kinds:
http_request— maps tonet.fetchcapabilitydb_query— maps todb.querycapabilityfs_read— maps tofs.readcapabilityfs_write— maps tofs.writecapabilitytimer— maps totime.nowcapabilityrandom— maps torandomcapabilityspawn_actor— maps toactor.spawncapability (creates child actor)send_to_actor— maps toactor.sendcapabilityllm_call— maps tollm.callcapabilityemit_ui— emits UI tree to host (ui.render)
AppRuntime::send validates effects against the policy and returns them; it
does not execute them. Execution happens only through an EffectExecutor
(AppRuntime::send_with_executor), which turns each effect result into a
message tagged with callback_tag for the next update() call.
3. State Management
- State must be a record type.
- State is serialized to JSON between cycles for snapshots.
- The Rust
StateMachinetype provides (these are Rust methods, not.axbuilt-ins):snapshot()— serialize current state to JSON stringrestore(json)— deserialize state from JSON stringdiff_values(old, new)/diff_from_cycle(cycle)— produce list of changed fields
4. UI Model
type UINode {
tag: String,
props: String,
children_json: String,
}
UITree is a UINode at the root, with children encoded as JSON. The view function returns a UINode.
Constraints:
- Pure function of State.
- No side effects.
- Host renders the tree.
- User events become Messages fed to
update().
5. Actor Integration
- Child actors use the same App protocol.
- A parent requests a child with the
spawn_actoreffect and messages it withsend_to_actor. - The framework runtime does not run actors itself: plain
sendonly returns these effects, and the bundled executors do not deliver them (the mock executor returns a fake actor id). See ACTORS_GUIDE.md for what each executor does. - Supervision exists in the VM’s actor system (a failed actor is marked failed, its children are stopped and the parent is notified), not at the framework level.
6. Policy Layer
type PolicySet {
capabilities: List<String>,
max_effects_per_cycle: Int,
max_steps: Int,
}
Policy violations:
- Abort safely with structured error.
- Error is replay-compatible.
7. Testing Harness
Testing functions are methods on the Rust TestHarness type, not .ax built-ins
(see FRAMEWORK_API.md):
simulate(messages)— run message sequence, return final stateassert_state(expected)/assert_state_field(index, expected)— check stateassert_effects(expected_kinds)— check effect kinds of the last cyclereplay_verify(source, messages)— re-run the messages and compare states
From the CLI, use boruna framework test / simulate / replay.
Testing does not require a host UI.
8. Implementation
The framework is a Rust crate boruna-framework that provides:
AppValidator— compile-time validation of App protocolAppRuntime— execution loop for the App protocolEffectExecutor— maps effects to capability callsStateMachine— state transition engine with snapshot/diffTestHarness— testing utilities
The framework compiles .ax sources through the normal compiler,
then wraps execution in the App protocol runtime.