Learn
Complete workflows
A functional language for parallel and distributed programming. The next chapter of Clio.
These are fresh Kalandra programs, not historical Clio compatibility claims. Their complete source lives in examples/workflows. Acceptance checks copy the projects outside the workspace, build and run them through both the source CLI and the isolated bundled CLI, and compare their results.
These examples use multiple files supplied in the Kalandra repository. Download the release source or check out the repository, then run the commands below from its root with the installed Kalandra CLI. The checkout supplies example programs and service configuration; you do not need to build the compiler. These are not single-file playground programs.
Invoices: modules, inheritance and JavaScript
The invoice project imports a local JavaScript package with explicit Kalandra signatures. DiscountedItem takes its own discount first, then the inherited price and quantity. Pricing crosses the JavaScript boundary using a known Number signature. This is an arithmetic example, not a currency precision model.
cd examples/workflows/invoices
bun install --offline --ignore-scripts
cd ../../..
kalandra build examples/workflows/invoices/main.kalandra --strict -o /tmp/kalandra-invoices
kalandra run examples/workflows/invoices/main.kalandra --strict Expected result: [35.91, 18]. The JavaScript package is included under vendor, so installation needs no registry dependency.
types.kalandra
export type Item:
Number price
Number quantity
export type DiscountedItem is Item:
Number discount pricing.kalandra
from "./types" import DiscountedItem
from "esm:invoice-math" import roundMoney
@params DiscountedItem
@returns Number
export fn total item:
roundMoney (item.price * item.quantity * (1 - item.discount)) main.kalandra
from "./types" import DiscountedItem
from "./pricing" import total
export fn main:
items = [(DiscountedItem 0.1 19.95 2) (DiscountedItem 0.25 8 3)]
items -> * total package.json
{
"name": "kalandra-invoice-example",
"private": true,
"type": "module",
"dependencies": {
"invoice-math": "file:./vendor/invoice-math"
}
} vendor/invoice-math/index.js
export const roundMoney = (value) => Math.round(value * 100) / 100; vendor/invoice-math/package.json
{
"name": "invoice-math",
"version": "1.0.0",
"type": "module",
"exports": "./index.js",
"kalandra": {
"types": "./kalandra.types.json"
}
} vendor/invoice-math/kalandra.types.json
{
"version": 1,
"modules": {
"esm:.": {
"exports": {
"roundMoney": {
"kind": "Callable",
"parameters": ["Number"],
"returns": "Number",
"async": false
}
}
}
}
} Local batch: nested workers and captures
Each mapped process task calls a nested calibrate task. The calibration record is a typed capture. Mutating its offset changes that invocation's snapshot only; both batches return the same calibrated values, and the original reading stays unchanged.
kalandra run examples/workflows/local-batch/main.kalandra --strict Expected result: [12, 22, 12, 22, 10]. The final 10 is the untouched input reading.
types.kalandra
export type Reading:
Number value
export type TaggedReading is Reading:
String label tasks.kalandra
from "./types" import TaggedReading
type Calibration:
Number offset
Calibration settings = Calibration 1
@params TaggedReading
@returns TaggedReading
fn calibrate reading:
settings.offset = settings.offset + 1
TaggedReading reading.label (reading.value + settings.offset)
@params TaggedReading
@returns TaggedReading
export fn process reading: await |calibrate| reading main.kalandra
from "./types" import TaggedReading
from "./tasks" import process
export fn main:
readings = [(TaggedReading "north" 10) (TaggedReading "south" 20)]
first = readings -> * [await] |process|
second = readings -> * [await] |process|
[first[0].value first[1].value second[0].value second[1].value readings[0].value] Remote batch: mapping, recovery and cleanup
The service owns its captured calibration settings. A local client worker maps remote calls over TaggedReading records, then repeats the batch to check isolation. The contract generates client constructors without loading server code.
First build the service and copy its contract:
kalandra build examples/workflows/remote-batch/service/main.kalandra --strict -o /tmp/kalandra-readings --service calibrate=calibrate --service broken=broken --service slow=slow
cp /tmp/kalandra-readings/kalandra.client.json examples/workflows/remote-batch/client/readings.client.json
export KALANDRA_REMOTE_TOKEN=$(bun -e 'console.log(crypto.randomUUID().replaceAll("-", ""))')
kalandra serve /tmp/kalandra-readings/kalandra.deployment.json --port 3000 In another terminal, set KALANDRA_REMOTE_TOKEN to the same value and run:
kalandra run examples/workflows/remote-batch/client/main.kalandra --strict --bindings examples/workflows/remote-batch/client/endpoints.json Expected result: [12, 22, 12, 22]. Keep the token in the environment; endpoints.json contains only the environment variable name. Rebuild and recopy the contract whenever the service changes.
To exercise failure cleanup, run client/failure.kalandra with the same bindings. It starts slow work and then fails deliberately. The CLI should exit with code 1 after cancelling its outstanding work. Run main.kalandra again to check recovery.
To exercise cancellation, run client/cancel.kalandra with the same bindings and press Ctrl+C while it is working. The client should exit with code 130 after cancellation is acknowledged. main.kalandra should still succeed. Stop the service with Ctrl+C when finished.
The automated network checks wait for an actual server worker before interrupting the client, verify the client and server worker processes exit, retry a successful batch after failures, and confirm service shutdown closes its listener. Signal and process checks run on Unix hosts.
service/main.kalandra
export type Reading:
Number value
export type TaggedReading is Reading:
String label
type Calibration:
Number offset
Calibration settings = Calibration 1
@params TaggedReading
@returns TaggedReading
export fn calibrate reading:
settings.offset = settings.offset + 1
TaggedReading reading.label (reading.value + settings.offset)
@params Number
@returns Number
export fn broken n:
n.missing ()
n
@params Number
@returns Number
export fn slow n:
if n < 2: n
else: (slow (n - 1)) + (slow (n - 2)) client/main.kalandra
from "remote:./readings.client.json" import TaggedReading calibrate
@params Number
fn batch start:
readings = [(TaggedReading "north" start) (TaggedReading "south" (start + 10))]
readings -> * [await] calibrate
export fn main:
first = await |batch| 10
second = await |batch| 10
[first[0].value first[1].value second[0].value second[1].value] client/failure.kalandra
from "remote:./readings.client.json" import broken slow
@params Number
fn work n:
pending = slow 45
await broken n
export fn main: await |work| 1 client/cancel.kalandra
from "remote:./readings.client.json" import slow
@params Number
fn work n: await slow n
export fn main: await |work| 45 client/endpoints.json
{
"version": 1,
"endpoints": {
"readings.client.json": {
"url": "http://127.0.0.1:3000",
"tokenEnv": "KALANDRA_REMOTE_TOKEN"
}
}
} What this establishes
These workflows test composition of implemented features. They do not establish full Clio parity, production hosting readiness or browser parity. The remote example uses authenticated loopback HTTP; TLS and public deployment remain separate work. Any historical comparison must first demonstrate that the selected program runs under the pinned Clio implementation.
Use bun run check for local examples and isolated builds. Use bun run test:network and, after building packages, bun run test:network --built for remote examples. The network checks need permission to open local sockets.