This guide walks through creating a simple two-step workflow from scratch, running it, and inspecting the evidence it produces.
Time required: ~15 minutes
Prerequisites: Boruna built (cargo build --workspace)
A workflow that fetches a number and doubles it — two steps connected in sequence. Simple enough to fit in your head, realistic enough to demonstrate every core concept: DAG definition, .ax step code, capability policies, and evidence.
mkdir -p my-first-workflow/steps
cd my-first-workflowCreate workflow.json:
{
"id": "double-it",
"name": "Double It",
"description": "Fetch a number, double it, return the result.",
"steps": [
{
"id": "fetch",
"name": "Fetch Number",
"source": "steps/fetch.ax",
"capabilities": []
},
{
"id": "double",
"name": "Double It",
"source": "steps/double.ax",
"capabilities": [],
"depends_on": ["fetch"]
}
],
"edges": [
{ "from": "fetch", "to": "double" }
]
}The depends_on field defines the DAG edge. double runs after fetch completes.
steps/fetch.ax — returns a number (demo mode; live mode would call net.fetch):
fn get_number() -> Int {
42
}
fn main() -> Int {
let n: Int = get_number()
n
}
steps/double.ax — doubles the input:
fn double(n: Int) -> Int {
n * 2
}
fn main() -> Int {
let input: Int = 42
let result: Int = double(input)
result
}
Before running, validate the DAG structure:
cd ..
cargo run --bin boruna -- workflow validate my-first-workflow/
# Expected output:
# Workflow 'double-it': valid
# Steps: 2
# Edges: 1
# Topological order: fetch → double
# No cycles detected.Validation checks: all referenced step files exist, the graph is acyclic, and every depends_on refers to a real step.
cargo run --bin boruna -- workflow run my-first-workflow/ --policy allow-all
# Expected output:
# Running workflow: double-it
#
# [1/2] fetch → ok
# [2/2] double → ok
#
# Workflow completed in 0.01s
# Output: 84cargo run --bin boruna -- workflow run my-first-workflow/ --policy allow-all --record
# Expected output:
# Running workflow: double-it
# ...
# Workflow completed in 0.01s
# Bundle written to: .boruna/runs/20260319-120000-abc12/cargo run --bin boruna -- evidence inspect .boruna/runs/20260319-120000-abc12/
# Expected output:
# Run ID: 20260319-120000-abc12
# Workflow: double-it
# Started: 2026-03-19T12:00:00Z
# Completed: 2026-03-19T12:00:00Z
# Policy: allow-all
# Steps: 2 completed, 0 failed
#
# Step Results:
# fetch → ok (0.0s)
# double → ok (0.0s)
#
# Chain: valid (2 entries, no gaps)cargo run --bin boruna -- evidence verify .boruna/runs/20260319-120000-abc12/
# Expected output:
# Chain integrity: VALID
# All step hashes: MATCH
# Environment fingerprint: PRESENT
# Verification: PASSEDThat's a complete workflow: defined, validated, executed, recorded, and verified.
- The workflow runner read
workflow.jsonand sorted steps topologically. - Each
.axfile was compiled to bytecode and run on the VM. - Every step's output was captured and written to the evidence bundle.
- The audit log was hash-chained so no entry can be modified undetected.
evidence verifyconfirmed the chain was unbroken.
- Add a real capability: modify
steps/fetch.axto declare!{net.fetch}and run with--live - See a production-scale example: examples/workflows/llm_code_review
- Add an approval gate: customer support triage workflow
- Read the .ax language reference