Purpose: Complete API reference for all built-in functions available in Meridian's Starlark runtime.
Audience: Developers, AI assistants, and tenants writing Starlark scripts.
Related:
- Style Guide - Syntax and conventions
- Patterns - Common workflow patterns
- Service Catalog - Service module handlers
- Core DSL Functions
- Financial Types
- Service Orchestration
- Expression Evaluation
- Reference Resolution
- Ledger Operations
- Logging & Debugging
- Safe Stdlib Functions
- Blocked Functions
Define a saga workflow.
Parameters:
name(string, required): Unique saga name
Returns: SagaDefinition object
Example:
withdrawal_saga = saga(name="current_account_withdrawal")Usage: Call once at module level to define saga metadata.
Define a saga step for compensation tracking.
Parameters:
name(string, required): Step name (descriptive, action-oriented)
Returns: StepDefinition object
Example:
step(name="log_position")
result = position_keeping.initiate_log(...)Compensation: If this step fails, all previous steps are compensated in LIFO order (declared in handlers.yaml).
Best practice: Call immediately before each service module operation.
Explicitly fail the saga with a custom error message.
Parameters:
message(string, required): Error message for audit trail
Returns: Never returns (raises error)
Example:
if amount <= Decimal("0"):
fail("Withdrawal amount must be positive")Compensation: Triggers automatic compensation of all completed steps.
Audit: Failure reason logged to audit trail.
Create arbitrary-precision decimal for financial calculations.
Parameters:
value(string or number, required): Initial value
Returns: Decimal object
Example:
# ALWAYS use Decimal for money
amount = Decimal("100.50")
rate = Decimal("1.05")
total = amount * rate # Decimal("105.525")
# Convert string input
amount = Decimal(input_data["amount"])Supported operations:
- Arithmetic:
+,-,*,/ - Comparison:
<,<=,>,>=,==,!= - String conversion:
str(amount)→"100.50"
Why Decimal:
- No floating-point errors
- Maintains precision for regulatory compliance
- Deterministic across platforms
Anti-pattern:
# ❌ WRONG - Float loses precision
amount = 100.50
total = amount * 1.05 # Floating point errors
# ✅ CORRECT
amount = Decimal("100.50")
total = amount * Decimal("1.05")Invoke a child saga (saga composition).
Parameters:
saga_name(string, required): Name of child sagainput(dict, optional): Input data for child saga
Returns: SagaResult object with fields:
execution_id(string): Child saga execution IDstatus(string):"COMPLETED","FAILED", etc.output(dict): Child saga output datasteps_completed(int): Number of steps executed
Example:
# Invoke child saga
result = invoke_saga(
saga_name="send_notification",
input={
"recipient": customer_id,
"message": "Withdrawal complete"
}
)
if result.status != "COMPLETED":
fail(f"Notification failed: {result.execution_id}")Scope inheritance: Child saga inherits parent's PartyScope (cannot escalate permissions).
Circular detection: Runtime prevents circular saga invocations.
Compensation: If parent fails, child saga's compensation is triggered automatically.
Evaluate a CEL (Common Expression Language) expression.
Parameters:
expression(string, required): CEL expressionvariables(dict, optional): Variables for expression context
Returns: Expression result (type depends on expression)
Example:
# Simple calculation
rate = cel_eval("spot * coefficient * markup", {
"spot": Decimal("50.00"),
"coefficient": Decimal("1.02"),
"markup": Decimal("1.05")
})
# Result: Decimal("53.55")
# Conditional logic
valid = cel_eval("amount > 0 && amount <= limit", {
"amount": Decimal("100.00"),
"limit": Decimal("1000.00")
})
# Result: True
# Access saga context
execution_id = cel_eval("ctx.saga_execution_id", {})Available variables:
ctx.saga_execution_id- Current saga execution IDctx.correlation_id- Correlation IDinput.<key>- Variables passed tocel_eval()
Use cases:
- Financial calculations (pricing, valuation)
- Validation rules
- Conditional logic that's tenant-configurable
CEL reference: CEL Specification
Performance: ~100ns per evaluation (much faster than Starlark)
Resolve account ID from a reference (bi-temporal lookup).
Parameters:
reference(string, required): Account reference
Returns: Account ID (string)
Example:
# Resolve clearing account
clearing_id = resolve_account("CLEARING_GBP")
# Use in posting
financial_accounting.capture_posting(
account_id=clearing_id,
amount=amount,
direction="CREDIT"
)Bi-temporal: Uses saga's knowledge_at timestamp for deterministic replay.
Caching: Results cached for duration of saga execution.
Error: Raises error if reference not found.
Resolve instrument ID from a reference (bi-temporal lookup).
Parameters:
reference(string, required): Instrument reference
Returns: Instrument ID (string)
Example:
# Resolve currency instrument
gbp_id = resolve_instrument("GBP")
# Use in quantity
quantity = {
"amount": Decimal("100.00"),
"instrument_id": gbp_id
}Bi-temporal: Uses knowledge_at for deterministic replay.
Caching: Results cached per saga execution.
Create a ledger posting (double-entry accounting).
Parameters:
debit(string, required): Debit account IDcredit(string, required): Credit account IDamount(string or Decimal, required): Posting amount
Returns: Posting object
Example:
# Create posting
p = posting(
debit="CUSTOMER_ACCOUNT",
credit="CLEARING_ACCOUNT",
amount=Decimal("100.00")
)
# Use in batch
postings = [
posting(debit=customer_id, credit=clearing_id, amount=amount),
posting(debit=fee_account, credit=income_account, amount=fee)
]Note: This function creates a posting object. To actually post to the ledger, use financial_accounting.post_entries().
Log a message to the audit trail.
Parameters:
message(string, required): Log message
Returns: None
Example:
log(f"Processing withdrawal for account {account_id}")
# Conditional logging
if debug_mode:
log(f"Intermediate calculation: {rate}")Audit trail: All logs are persisted with saga execution metadata.
Performance: Non-blocking (asynchronous audit write).
Print values (routed to audit logger).
Parameters:
*args(any, variadic): Values to print
Returns: None
Example:
print("Amount:", amount, "Currency:", currency)
# Output: "Amount: 100.50 Currency: GBP"Note: Unlike standard Python print(), this routes to structured logging.
Audit: Logged as saga script print event.
Meridian includes a whitelisted subset of Starlark's standard library.
str(x)- Convert to stringint(x)- Convert to integerfloat(x)- Convert to float (preferDecimal()for money)bool(x)- Convert to booleanlist(x)- Convert to listdict(**kwargs)- Create dictionarytuple(x)- Convert to tuple
len(x)- Length of collectionrange(start, stop, step)- Generate rangeenumerate(iterable)- Enumerate with indiceszip(*iterables)- Zip multiple iterablessorted(iterable, key=None, reverse=False)- Sort collectionreversed(iterable)- Reverse collection
min(iterable)- Minimum valuemax(iterable)- Maximum valuesum(iterable)- Sum valuesany(iterable)- True if any element truthyall(iterable)- True if all elements truthy
abs(x)- Absolute value
type(x)- Get type namerepr(x)- Get representation stringdir(x)- List attributeshasattr(x, name)- Check if attribute existsgetattr(x, name, default)- Get attribute valuehash(x)- Get hash value
True- Boolean trueFalse- Boolean falseNone- Null value
For security and determinism, these functions are not available:
- ❌
open()- File operations - ❌
load()- Load external modules
- ❌
time.now()- Current time (use bi-temporalknowledge_at) - ❌
random()- Random numbers (non-deterministic)
- ❌
exec()- Execute code - ❌
compile()- Compile code - ❌
eval()- Evaluate string as code (usecel_eval()instead)
- ❌
http.*- HTTP requests
- Determinism: Sagas must replay identically
- Security: Prevent arbitrary code execution
- Audit: All external calls must route through service modules
Alternative:
- Time: Use saga's
knowledge_atparameter - Random: Generate IDs in Go, pass to saga
- External data: Fetch via service module handlers
- File I/O: Not needed (scripts are stateless)
See handlers.yaml for complete list of service module handlers.
Available modules:
position_keeping- Position logs, balancesfinancial_accounting- Booking logs, postingscurrent_account- Account operationsreference_data- Instruments, validationparty- Party informationmarket_information- Market data, settlement
Example:
# Position keeping
result = position_keeping.initiate_log(
position_id=account_id,
amount=amount,
direction="DEBIT"
)
# Financial accounting
financial_accounting.capture_posting(
account_id=account_id,
amount=amount,
direction="DEBIT"
)Sagas execute with thread-local context:
Available via thread locals:
saga.StarlarkContext- Execution metadatasaga_execution_id- Current execution IDcorrelation_id- Request correlationknowledge_at- Bi-temporal timestampparty_scope- Authorization scope
Accessed via:
cel_eval()- Exposesctx.*variablesresolve_account(),resolve_instrument()- Useknowledge_atinvoke_saga()- Inheritsparty_scope
Starlark doesn't support try/except.
Error propagation:
- Service module handler fails → Error returned to Starlark
- Starlark raises error → Saga runtime catches
- Saga runtime triggers compensation → LIFO order
- Compensation completes → Error reported to caller
Explicit failure:
if not valid:
fail("Validation failed: amount too large")Implicit failure:
# Service call fails
result = position_keeping.initiate_log(...)
# Error propagates automatically, compensation triggeredUnit tests in Go:
// Load script
scriptBytes, _ := os.ReadFile("my_saga.star")
script := string(scriptBytes)
// Create runner
runner, _ := saga.NewStarlarkSagaRunner(config)
// Execute with input
inputData := map[string]interface{}{
"account_id": "ACC-001",
"amount": "100.50",
}
result, err := runner.Execute(ctx, script, inputData)
require.NoError(t, err)
assert.Equal(t, "COMPLETED", result["status"])Validation:
- Syntax errors caught at script load time
- Type errors caught at runtime
- Service module calls validated against
handlers.yaml
| Operation | Latency | Use Case |
|---|---|---|
cel_eval() |
~100ns | High-frequency calculations |
Decimal() operations |
~1μs | Financial math |
resolve_account() (cached) |
~10ns | Repeated lookups |
resolve_account() (uncached) |
~5ms | First lookup (RPC) |
| Service module handler | ~10-50ms | Database operations |
invoke_saga() |
Variable | Child saga execution time |
Optimization:
- Use CEL for stateless calculations
- Cache reference resolutions (automatic)
- Minimize service module calls
- Batch operations when possible
Guarantees:
- ✅ No file I/O
- ✅ No network access
- ✅ No arbitrary code execution
- ✅ Bounded execution (no
whileloops) - ✅ Memory limits enforced
- ✅ CPU timeout enforced
- ✅ Party scope enforcement (authorization)
Threat model:
- Malicious tenants cannot DoS platform
- Scripts cannot access other tenants' data
- Scripts cannot escalate privileges
- Scripts are deterministic (replay-safe)
- Starlark Language Spec - Full language reference
- CEL Specification - Expression language
- handlers.yaml - Service module API
- Style Guide - Conventions and best practices
- Patterns - Common workflow patterns