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();
URP Pattern Every backend block follows the same pattern: read a JSON envelope from STDIN, extract 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();
Domain vs Primitive Primitive blocks handle generic operations (math, strings). Domain blocks encode business logic specific to your application (orders, pricing, users). The layer determines where the block lives in 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,
  };
}
UI Block Pattern UI blocks use 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 };
}
What is MOCK? The 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;
}
Error Handling Pattern Declare an error handler block and reference it in your workflow with 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
Data Flow Each 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()
Polyglot Support BOA supports any language that can read STDIN and write STDOUT JSON. The Universal Runtime Protocol makes this possible. Write blocks in Node, Python, Go, Rust, Java, or any other language — the framework handles execution and data passing automatically.