Examples
Real-world code samples for backend blocks, UI blocks, workflows, and framework integrations.
Backend Block — Add (Primitive)
The simplest kind of BOA block. A primitive layer block that adds two numbers. It reads JSON from STDIN, processes it, and writes JSON to STDOUT — the Universal Runtime Protocol (URP) pattern.
block.boa
block.boa
BLOCK Add 1.0.0
LAYER primitive
RUNTIME node
ENTRY index.js
DESC Adds two numbers.
INTENT Basic arithmetic addition for calculations.
RULE Both inputs must be numbers.
RULE Returns the sum of a and b.
TAGS math, arithmetic, primitive
IN a:number!
IN b:number!
OUT result:number
FIXTURE {"a":3,"b":5} -> {"result":8}
FIXTURE {"a":-1,"b":1} -> {"result":0}
FIXTURE {"a":0,"b":0} -> {"result":0}
ERR ValidationError
index.ts
TypeScript
async function main() {
const chunks: Buffer[] = [];
for await (const chunk of process.stdin)
chunks.push(chunk as Buffer);
const envelope = JSON.parse(
Buffer.concat(chunks).toString("utf-8")
);
const { a, b } = envelope.input;
if (typeof a !== "number" ||
typeof b !== "number") {
console.log(JSON.stringify({
success: false,
error: {
type: "ValidationError",
message: "Inputs must be numbers"
}
}));
return;
}
console.log(JSON.stringify({
success: true,
output: { result: a + b }
}));
}
main();
envelope.input, process it, and write a JSON result to STDOUT. This is the Universal Runtime
Protocol.
Backend Block — CalculateOrderValue (Domain)
A domain layer block that computes the subtotal from an array of order
items. Each item has a price and quantity. The block multiplies them, sums the
results, and rounds to two decimal places.
block.boa
block.boa
BLOCK CalculateOrderValue 1.0.0
LAYER domain
RUNTIME node
ENTRY index.js
DESC Computes subtotal from order items.
INTENT Calculate the total value of a cart.
RULE subtotal = sum of price * quantity.
RULE Round to 2 decimal places.
RULE Items array must not be empty.
TAGS order, pricing, cart, domain
IN items:array!
OUT subtotal:number
FIXTURE {"items":[
{"price":50,"quantity":2}
]} -> {"subtotal":100}
FIXTURE {"items":[
{"price":29.99,"quantity":3},
{"price":9.50,"quantity":1}
]} -> {"subtotal":99.47}
ERR ValidationError
index.ts
TypeScript
async function main() {
const chunks: Buffer[] = [];
for await (const chunk of process.stdin)
chunks.push(chunk as Buffer);
const envelope = JSON.parse(
Buffer.concat(chunks).toString("utf-8")
);
const { items } = envelope.input;
if (!Array.isArray(items) ||
items.length === 0) {
console.log(JSON.stringify({
success: false,
error: {
type: "ValidationError",
message: "Items must be a non-empty array"
}
}));
return;
}
const raw = items.reduce(
(sum: number, i: any) =>
sum + i.price * i.quantity,
0
);
const subtotal =
Math.round(raw * 100) / 100;
console.log(JSON.stringify({
success: true,
output: { subtotal }
}));
}
main();
src/.
UI Block — deriveCheckoutState (Pure)
A ui-block layer block that runs in the browser. Unlike backend blocks, UI blocks export a default function instead of using STDIN/STDOUT. This block derives checkout readiness from cart state.
block.boa
block.boa
BLOCK deriveCheckoutState 1.0.0
LAYER ui-block
RUNTIME js
ENTRY index.js
DESC Derives checkout readiness from cart state.
INTENT Determine if the user can checkout based on their cart.
RULE canCheckout is true when itemCount > 0.
RULE subtotal rounds to 2 decimal places.
RULE Pure function, no side effects.
TAGS ui, checkout, cart, derive
IN cart:object!
OUT canCheckout:boolean
OUT itemCount:number
OUT subtotal:number
FIXTURE {"cart":{"items":[
{"price":10,"quantity":2},
{"price":5,"quantity":1}
]}} -> {"canCheckout":true,
"itemCount":2,"subtotal":25}
FIXTURE {"cart":{"items":[]}}
-> {"canCheckout":false,
"itemCount":0,"subtotal":0}
index.ts
TypeScript
export default function deriveCheckoutState(
input: {
cart: {
items: Array<{
price: number;
quantity: number;
}>
}
}
) {
const { cart } = input;
const itemCount = cart.items.length;
return {
canCheckout: itemCount > 0,
itemCount,
subtotal:
Math.round(
cart.items.reduce(
(s, i) =>
s + i.price * i.quantity,
0
) * 100
) / 100,
};
}
export default function instead of STDIN/STDOUT. They are pure functions that run
synchronously in the browser. The framework calls them directly — no child process spawning.
UI Capability Block — fetchCart (with MOCK)
A ui-capability block that performs I/O (fetching data from an API).
Capability blocks declare MOCK responses so workflows can be tested without real network calls.
block.boa
block.boa
BLOCK fetchCart 1.0.0
LAYER ui-capability
RUNTIME js
ENTRY index.js
DESC Fetches cart data from the API.
INTENT Load the user's cart from the server.
RULE Returns cart object with items array.
RULE Throws FetchError on network failure.
TAGS ui, cart, fetch, capability, api
IN cartId:number!
OUT cart:object
MOCK {"cartId":42} -> {
"cart": {
"items": [
{"price":29.99,"quantity":2},
{"price":9.99,"quantity":1}
]
}
}
MOCK {"cartId":99} -> {
"cart": {"items": []}
}
ERR FetchError
index.ts
TypeScript
export default async function fetchCart(
input: { cartId: number }
) {
const response = await fetch(
`/api/carts/${input.cartId}`
);
if (!response.ok) {
throw {
type: "FetchError",
message:
`Cart ${input.cartId} not found`,
};
}
const cart = await response.json();
return { cart };
}
MOCK keyword declares fake responses for capability blocks. During testing and development,
the workflow engine uses MOCK data instead of making real API calls. This lets you test entire workflows
offline, with deterministic results. MOCKs follow the same input -> output syntax as FIXTUREs.
Error Handler — handleUIError
A standard error-handling block that maps raw errors into user-friendly messages. Workflows reference it with
ON_ERROR so any step failure is caught and transformed automatically.
block.boa
block.boa
BLOCK handleUIError 1.0.0
LAYER ui-block
RUNTIME js
ENTRY index.js
DESC Maps errors to user-friendly messages.
INTENT Show helpful error messages to the user.
RULE FetchError is recoverable.
RULE ValidationError is not recoverable.
RULE Unknown errors get a generic message.
TAGS error, handler, ui, utility
IN error:object!
OUT userMessage:string
OUT code:string
OUT recoverable:boolean
FIXTURE {"error":{"type":"FetchError",
"message":"Cart 42 not found"}}
-> {"userMessage":"Unable to load data. Please try again.",
"code":"FETCH_ERROR",
"recoverable":true}
FIXTURE {"error":{"type":"ValidationError",
"message":"Invalid input"}}
-> {"userMessage":"Something went wrong. Please contact support.",
"code":"VALIDATION_ERROR",
"recoverable":false}
index.ts
TypeScript
const ERROR_MAP: Record<string, {
userMessage: string;
code: string;
recoverable: boolean;
}> = {
FetchError: {
userMessage:
"Unable to load data. Please try again.",
code: "FETCH_ERROR",
recoverable: true,
},
ValidationError: {
userMessage:
"Something went wrong. Please contact support.",
code: "VALIDATION_ERROR",
recoverable: false,
},
};
const FALLBACK = {
userMessage: "An unexpected error occurred.",
code: "UNKNOWN_ERROR",
recoverable: false,
};
export default function handleUIError(
input: {
error: { type: string; message: string }
}
) {
return ERROR_MAP[input.error.type]
|| FALLBACK;
}
ON_ERROR handleUIError@1.0.0. When any step fails, the workflow engine automatically routes the
error through this block before returning it to the caller.
Workflow — CheckoutUIWorkflow
A complete workflow that chains multiple blocks together. This example demonstrates all major workflow
features: CONFIG, ON_ERROR, WHEN (conditional execution), and
MAP (data passing).
workflow.boa
WORKFLOW CheckoutUIWorkflow 1.0.0
DESC Load cart, derive state, compute discount, format price.
# Global configuration — available to all steps
CONFIG currency = "USD"
# Error handler — catches failures from any step
ON_ERROR handleUIError@1.0.0
# Step 1: Fetch the cart from the API
STEP load = fetchCart@1.0.0
MAP cartId <- _initial.cartId
# Step 2: Derive checkout state from the cart
STEP derive = deriveCheckoutState@1.0.0
MAP cart <- load.cart
# Step 3: Only compute discount if more than 3 items
STEP discount = computeDiscount@1.0.0
WHEN $steps.derive.output.itemCount > 3
MAP itemCount <- derive.itemCount
MAP subtotal <- derive.subtotal
# Step 4: Format the final price for display
STEP summary = formatPrice@1.0.0
MAP amount <- discount.finalAmount
Workflow Annotations
| Keyword | Purpose | In This Example |
|---|---|---|
CONFIG |
Global key-value pairs available to all steps | Sets currency to "USD" |
ON_ERROR |
Error handler block for the entire workflow | Routes failures through handleUIError@1.0.0 |
STEP |
Declares a block execution with a step ID | Four steps: load, derive, discount, summary |
MAP |
Passes data from a previous step or _initial input |
cart <- load.cart feeds the fetched cart into the derive step |
WHEN |
Conditional execution — step only runs if the expression is true | Discount step skipped if 3 or fewer items |
MAP expression references either _initial.field (the workflow input) or
stepId.field (a previous step's output). The workflow engine resolves these references
automatically and passes the data between blocks.
Framework Integration
BOA's UI framework is framework-agnostic. The same createBoaUI() SDK works with React, Vue,
Angular, or vanilla JavaScript. Here are examples for each.
React
JSX
import { createBoaUI } from "@boa-framework/ui";
import { useState, useEffect } from "react";
const boa = createBoaUI();
// ... register blocks and workflows ...
function CheckoutPage({ cartId }) {
const [result, setResult] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
boa.run("CheckoutUIWorkflow", { cartId })
.then(setResult)
.finally(() => setLoading(false));
}, [cartId]);
if (loading) return <div>Loading...</div>;
if (!result.success)
return <div>Error: {result.error.userMessage}</div>;
return (
<div>
<h1>Checkout</h1>
<p>Items: {result.steps.derive.output.itemCount}</p>
<p>Total: {result.steps.summary.output.formatted}</p>
</div>
);
}
Vue
JavaScript
import { createBoaUI } from "@boa-framework/ui";
const boa = createBoaUI();
// ... register blocks and workflows ...
export default {
data() {
return { result: null, loading: true };
},
async mounted() {
this.result = await boa.run(
"CheckoutUIWorkflow",
{ cartId: this.$route.params.id }
);
this.loading = false;
}
};
Vanilla JavaScript
JavaScript
import { createBoaUI } from "@boa-framework/ui";
const boa = createBoaUI();
// ... register blocks and workflows ...
document.getElementById("checkout-btn")
.addEventListener("click", async () => {
const result = await boa.run(
"CheckoutUIWorkflow",
{ cartId: 42 }
);
if (result.success) {
document.getElementById("total")
.textContent =
result.steps.summary.output.formatted;
}
});
Python Block (Polyglot)
BOA is polyglot — blocks can be written in any language. Here is a Python block that computes tax using the same URP pattern: read JSON from STDIN, process, write JSON to STDOUT.
block.boa
block.boa
BLOCK ComputeTax 1.0.0
LAYER domain
RUNTIME python
ENTRY main.py
DESC Computes tax from subtotal and rate.
INTENT Calculate tax for an order.
RULE tax = subtotal * taxRate.
RULE total = subtotal + tax.
RULE Round both to 2 decimal places.
TAGS tax, pricing, python, domain
IN subtotal:number!
IN taxRate:number!
OUT tax:number
OUT total:number
FIXTURE {"subtotal":100,"taxRate":0.08}
-> {"tax":8.0,"total":108.0}
FIXTURE {"subtotal":49.99,"taxRate":0.1}
-> {"tax":5.0,"total":54.99}
ERR ValidationError
main.py
Python
import sys
import json
def main():
raw = sys.stdin.read()
envelope = json.loads(raw)
inp = envelope["input"]
subtotal = inp["subtotal"]
tax_rate = inp["taxRate"]
if not isinstance(subtotal, (int, float)):
json.dump({
"success": False,
"error": {
"type": "ValidationError",
"message": "Invalid subtotal"
}
}, sys.stdout)
return
tax = round(subtotal * tax_rate, 2)
total = round(subtotal + tax, 2)
json.dump({
"success": True,
"output": {
"tax": tax,
"total": total
}
}, sys.stdout)
if __name__ == "__main__":
main()