13. Built-in Functions
This chapter is the stdlib catalog: conversion, math, strings, files, JSON, dates, and error helpers. Agent tools, task plans, durable workflow operations, and ui.* are indexed at the end of the chapter and documented in their home chapters.
13.1 Type Conversion
var num = int("123"); // Convert string to integer
var floatVal = float("3.14"); // Convert string to float
var str = string(42); // Convert number to string
13.1.1 Safe Integer Conversion Helpers
Use these helpers when input may be empty, null, or malformed.
var page = toIntOr(query.page, 1); // Fallback when null/empty/unparseable
var limit = toIntOr(query.limit, 50); // Always returns integer
var ownerId = toIntOrNull(query.ownerId); // Returns null when missing/unparseable
toIntOr(value, fallback)- returns parsed integer when possible, otherwisefallback.toIntOrNull(value)- returns parsed integer ornullwhen value is null/empty/unparseable.- Both functions accept integer, float, boolean, and numeric string values.
13.2 Stdlib Namespaces and Flat Aliases
Most of the standard library is reachable in two spellings: a namespaced call through a module object, and a flat global of the same name. Both resolve to the same implementation and behave identically at runtime.
print(math.sqrt(16)); // namespaced
print(sqrt(16)); // flat alias, same result
print(str.join(str.split("a,b", ","), "|")); // a|b
print(io.readFile("config.json"));
The module objects
| Module | Covers |
|---|---|
math | Rounding, trigonometry, aggregates, random helpers, LLM math, and the constants math.PI, math.E, math.TAU, math.INF, math.NaN |
str | Case, trimming, splitting and joining, padding, regex helpers, similarity, base64, md5 / sha256 |
io | print, input, file and path helpers, glob, grep, environment variables, git helpers |
pdf | extractText — read text from a PDF file (digital text layer; no OCR) |
doc | extractText — read text from a Word .docx (Open XML; not legacy .doc) |
result | ok, err, map, unwrapOr, isOk, isErr — see 13.19.1 |
option | some, none, map, unwrapOr, isSome, isNone — see 13.19.1 |
Math (capital M) is a deprecated alias for the same object as math.
Which flat names are deprecated
Only the flat names that have a math., str., or io. counterpart are considered deprecated aliases. Calling one produces an IDE and language-server warning from source malda-style, in the form Prefer 'io.print(...)' instead of 'print(...)' (deprecated flat alias). The warning is advisory: nothing is removed at runtime and the transpilers accept both spellings.
The affected names, mirroring MaldaLang/BuiltIns/StdLibNamespaces.cs:
- math:
abs,sum,average,max,min,pow,sqrt,floor,ceil,round,trunc,sign,exp,log,log10,log2,sin,cos,tan,asin,acos,atan,atan2,hypot,clamp,degToRad,radToDeg,rsqrt,randn,argmax,argmin,logSumExp,softmax,crossEntropyFromLogits,randomChoiceWeighted,seed,random,randomInt,randomFloat - str:
length,upper,lower,trim,text,trimText,substring,indexOf,replace,split,normalizeText,tokenize,tokenOverlap,similarity,extractNumbers,regexMatch,regexReplace,regexFind,startsWith,endsWith,padStart,padEnd,includes,join,repeat,base64Encode,base64Decode,md5,sha256 - io:
print,input,readFile,writeFile,readFileBase64,writeFileBase64,readTextFileLines,deleteFile,hasFile,hasDirectory,ensureDir,listDirectory,hasEmbeddedFolder,embeddedFolderRoot,glob,grep,replaceInFile,pathExists,pathJoin,pathNormalize,pathGetExtension,isPathUnder,getEnv,getEnvOr,hasEnv,getFileName,getDirectoryName,gitStatus,gitAdd,gitCommit,gitDiff,gitLog,gitBranch,gitCheckout,gitPull,gitPush
Every other built-in in this chapter — sleep, runCommand, parseJson, the agent and workflow helpers, and so on — has no module counterpart and no deprecation attached to it.
Examples/ use the flat spelling (print(...), sqrt(...)) because it is shorter and it is what existing MALDA code looks like. Read those as equivalent to the namespaced form. In new code, prefer the namespaced spelling if you want the editor to stay warning-free.
13.3 Mathematical Functions
Math operations are available as math.* (preferred), deprecated flat built-ins, and Math.* (deprecated alias).
// Flat built-ins (deprecated flat alias; still supported)
var absVal = abs(-5); // Absolute value
var total = sum([1, 2, 3, 4]); // 10
var avg = average([1, 2, 3, 4]); // 2.5
var maxVal = max(10, 20); // Maximum of two values
var maxArr = max([10, 20, 5]); // Maximum in a numeric array
var minVal = min(10, 20); // Minimum of two values
var minArr = min([10, 20, 5]); // Minimum in a numeric array
var powVal = pow(2, 3); // Power: 2^3 = 8
var sqrtVal = sqrt(16); // Square root: 4
// Extended math (rounding and sign)
var f = floor(3.7); // 3
var c = ceil(3.2); // 4
var r = round(2.5); // 2 (banker’s rounding, .NET default)
var t = trunc(-3.9); // -3
var s1 = sign(-10); // -1
var s2 = sign(0); // 0
var s3 = sign(10); // 1
// Extended math (exponential and logarithm)
var e = exp(1); // ~2.718281828 (Math.E)
var ln = log(Math.E); // Natural log, ~1
var lg = log10(1000); // Base-10 log, 3
var lb = log2(8); // Base-2 log, 3
// Extended math (trigonometry, radians)
var halfPi = degToRad(90); // Convert degrees to radians
var s = sin(halfPi); // ~1.0
var c0 = cos(0); // ~1.0
var t = tan(0); // 0.0
var a = atan2(1, 1); // ~PI/4
// Inverse trigonometry (single argument, result in radians)
var as1 = asin(1); // ~PI/2
var ac1 = acos(1); // 0.0
var at1 = atan(1); // ~PI/4
var outOfDomain = asin(2); // NaN: no error is raised
// Extended math (utility)
var h = hypot(3, 4); // 5 (sqrt(3*3 + 4*4))
var cl1 = clamp(-1, 0, 10); // 0
var cl2 = clamp(5, 0, 3); // 3
var rad = degToRad(180); // PI
var deg = radToDeg(Math.PI / 2); // 90
// LLM-oriented math helpers
seed(42); // Deterministic random stream
var n = randn(0.1); // Gaussian random ~ N(0, 0.1^2)
var inv = rsqrt(16); // 0.25 (1/sqrt(x))
var idxMax = argmax([0.1, 0.7, 0.2]); // 1
var idxMin = argmin([0.1, 0.7, 0.2]); // 0
var probs = softmax([2.0, 1.0, 0.0]); // Probability array
var lse = logSumExp([2.0, 1.0, 0.0]); // Stable log(sum(exp(x)))
var ce = crossEntropyFromLogits([2.0, 1.0, 0.0], 0); // NLL for target index
var sampled = randomChoiceWeighted([0.1, 0.7, 0.2]); // Weighted sampled index
// All trigonometric functions take angles in radians, accept an integer or a
// float, and return a float. Out-of-domain input yields NaN rather than an error.
// Preferred: math.* module (Math.* is deprecated alias)
var cCirc = 2 * math.PI * r;
var cCircLegacy = 2 * Math.PI * r; // deprecated alias
var total2 = Math.sum([1, 2, 3]); // Same as sum(...)
var avg2 = Math.average([1, 2, 3]); // Same as average(...)
var powVal2 = Math.pow(2, 3); // 8
var sqrtVal2 = Math.sqrt(16); // 4
var floorVal = Math.floor(3.7); // 3
var sinVal = Math.sin(degToRad(90)); // ~1.0
var rand = Math.random(); // Random float between 0.0 and 1.0
var randInt = Math.randomInt(1, 10); // Random integer between 1 and 10 (inclusive)
var randFloat = Math.randomFloat(0.0, 100.0); // Random float between 0.0 and 100.0
var n2 = Math.randn(0.1); // Same as randn(0.1)
var probs2 = Math.softmax([2.0, 1.0, 0.0]); // Same as softmax(...)
sum(values) returns the total of a numeric array. average(values) returns the arithmetic mean of a non-empty numeric array as a float.
max and min support both (a, b) and (values) forms. When passed a single array argument, the array must be non-empty and contain only numbers.
For numeric arrays, these aggregate operations are also available as methods: values.sum(), values.average(), values.min(), and values.max().
13.3.1 LLM-oriented Math Helpers (Reference)
These helpers are available as math.softmax(values) (preferred), flat softmax(values) (deprecated), and Math.softmax(values) (deprecated alias).
seed(seedValue)
Sets the global pseudo-random seed used by random(), randomInt(), randomFloat(), randn(), and randomChoiceWeighted(). Argument must be an integer. Returns null.
seed(42);
print(random()); // Deterministic across runs with same seed
print(Math.random());
randn(std?, mean?)
Generates a normally distributed random float using Box-Muller transform. Signature: randn(std = 1.0, mean = 0.0). Returns a float.
var z1 = randn(); // N(0, 1)
var z2 = randn(0.1); // N(0, 0.1^2)
var z3 = randn(0.1, 1.5); // N(1.5, 0.1^2)
rsqrt(x)
Returns reciprocal square root: 1 / sqrt(x). Useful in attention and normalization formulas. Returns a float.
print(rsqrt(16)); // 0.25
print(Math.rsqrt(4)); // 0.5
argmax(values)
Returns the index of the maximum value in a non-empty numeric array. If multiple values tie for maximum, returns the first index. Returns an integer.
print(argmax([0.1, 0.7, 0.2])); // 1
print(argmax([3, 3, 1])); // 0 (first max)
argmin(values)
Returns the index of the minimum value in a non-empty numeric array. If multiple values tie for minimum, returns the first index. Returns an integer.
print(argmin([0.1, 0.7, 0.2])); // 0
print(argmin([3, 1, 1])); // 1 (first min)
logSumExp(values)
Computes numerically stable log(sum(exp(values[i]))) over a non-empty numeric array. Returns a float.
var lse = logSumExp([2.0, 1.0, 0.0]);
print(lse);
softmax(values, temperature?)
Computes softmax probabilities from a non-empty numeric array. Optional temperature defaults to 1.0 and must be > 0. Returns an array of floats that sum to approximately 1.
var p1 = softmax([2.0, 1.0, 0.0]); // temperature = 1.0
var p2 = softmax([2.0, 1.0, 0.0], 0.5); // Sharper distribution
print(p1);
crossEntropyFromLogits(logits, targetIndex)
Computes negative log-likelihood directly from logits for one target class: -log(softmax(logits)[targetIndex]). targetIndex must be a valid integer index in the logits array. Returns a float.
var loss = crossEntropyFromLogits([2.0, 1.0, 0.0], 0);
print(loss);
randomChoiceWeighted(weights)
Samples and returns an index from a non-empty numeric weight array. All weights must be >= 0 and their total must be > 0.
var idx = randomChoiceWeighted([0.1, 0.7, 0.2]); // Often 1
print(idx);
Error behavior: these helpers throw runtime errors for invalid argument counts/types, empty arrays where not allowed, out-of-range target indices, non-positive softmax temperature, negative weights, or zero total weight.
13.4 String Functions
String operations are available as flat built-in functions (e.g. upper(s)) and as extension-style methods on string values (e.g. s.upper()). Both forms work in the interpreter and in transpiled code.
var len = length("Hello"); // String length
var upper = upper("hello"); // Convert to uppercase
var lower = lower("HELLO"); // Convert to lowercase
var trimmed = trim(" hello "); // Remove leading and trailing whitespace (returns "hello")
var substr = substring("Hello", 0, 3); // Extract substring: start at index 0, take 3 characters (returns "Hel")
// substring(text, startIndex, length) - third parameter is COUNT/LENGTH, not end index
var singleChar = substring("Hello", 1, 1); // Get single character at index 1 (returns "e")
var pos = indexOf("hello world", "world"); // Find position (returns 6, 0-indexed)
var notFound = indexOf("hello", "xyz"); // Returns -1 if not found
var replaced = replace("Hello world", "world", "MALDA"); // Replace all occurrences (returns "Hello MALDA")
var parts = split("a,b,c", ","); // Split string into array (returns ["a", "b", "c"])
var normalized = normalizeText(" Città, 42! "); // "citta 42"
var words = tokenize("Uno, due, tre!"); // ["uno", "due", "tre"]
var score = similarity("equazione lineare", "equazioni lineari");
var numbers = extractNumbers("x=12, y=3.5"); // [12, 3.5]
var joined = parts.join(","); // Join array into string (returns "a,b,c")
// Null-safe boundary helpers (prefer str.* spelling):
var asText = str.text(maybeNull); // null → "" (unlike string(null) → "null")
var cleaned = str.trimText(maybeNull); // null → ""; else string then trim
str.text(value) coerces any value to a string, mapping null to "". str.trimText(value) is str.trim(str.text(value)). Use these at env / JSON / CLI boundaries instead of nesting null checks before str.trim.
Extension-style string methods
The functions length, upper, lower, trim, substring, indexOf, replace, split, startsWith, endsWith, padStart, padEnd, and repeat can also be called as methods on any string value. The receiver is treated as the first argument. This is similar to extension methods in VB.NET/C#.
var name = "pippo";
var nameUpper = string(name).upper(); // same as upper(string(name)) or upper(name)
print("hello".upper()); // HELLO
print("HELLO".lower()); // hello
var s = "Hello";
print(s.length()); // 5
print(s.substring(0, 3)); // Hel
print(s.indexOf("ll")); // 2
print(s.replace("He", "Ye")); // Yello
print("abc".repeat(2)); // abcabc
var f = "world".upper; // method as value
print(f()); // WORLD
Calling an unsupported member on a string (e.g. s.foo()) causes a runtime error.
Regular Expression Functions
var matches = regexMatch("test123", "\\d+"); // Check if pattern matches (returns true)
var result = regexReplace("abc123", "\\d+", "456"); // Replace matches (returns "abc456")
// Use $1, $2, etc. for capture groups in replacement
var swapped = regexReplace("John Doe", "(\\w+) (\\w+)", "$2, $1"); // Returns "Doe, John"
var matches = regexFind("test123 test456", "\\d+"); // Find all matches (returns array of match objects)
Additional String Functions
var starts = startsWith("Hello", "He"); // Check if string starts with prefix (returns true)
var ends = endsWith("Hello", "lo"); // Check if string ends with suffix (returns true)
var padded = padStart("5", 3, "0"); // Pad string to length from left (returns "005")
var padded2 = padEnd("5", 3, "0"); // Pad string to length from right (returns "500")
var repeated = repeat("Hi", 3); // Repeat string N times (returns "HiHiHi")
Text Matching Helpers
var normalizedText = normalizeText(" Città, 42! "); // "citta 42"
var tokens = tokenize("CPU, RAM e disco"); // ["cpu", "ram", "e", "disco"]
var overlap = tokenOverlap("cpu memoria cache", "cache cpu");
print(overlap.sharedCount); // 2
print(overlap.jaccard); // 0.66...
var sim1 = similarity("equazione lineare", "equazioni lineari");
var sim2 = similarity("processore", "processor", "char-ngram");
var nums = extractNumbers("x=12, y=3.5, z=-2"); // [12, 3.5, -2]
Path Functions
var filename = getFileName("ReferenceManual/09-functions.html"); // Returns "09-functions.html"
var dir = getDirectoryName("ReferenceManual/09-functions.html"); // Returns "ReferenceManual"
var dir2 = getDirectoryName("09-functions.html"); // Returns "" (empty for files in current directory)
var joined = pathJoin("dir1", "dir2", "file.txt"); // Join path segments (returns "dir1/dir2/file.txt" or "dir1\\dir2\\file.txt" on Windows)
var normalized = pathNormalize("./dir/../file.txt"); // Normalize path (returns absolute path)
var exists = pathExists("file.txt"); // Check if path exists (file or directory)
var ext = pathGetExtension("file.txt"); // Get file extension (returns ".txt")
var under = isPathUnder("brain", "brain/notes/a.md"); // true when path resolves under root (disk or embed:)
var escape = isPathUnder("brain", "brain/../secret.txt"); // false
isPathUnder(root, path) — Returns true when path resolves to the same location as root or to a descendant. Uses full-path comparison with a directory-separator boundary (so demo does not match demo-evil). Works for disk paths and embed:<alias>/… virtual roots. Returns false on invalid or cross-scheme pairs.
MALDA home and config
These functions support the personal assistant and CLI config directory ~/.malda.
var home = getMaldaHome(); // Returns "~/.malda" (e.g. C:\Users\You\.malda on Windows)
var config = getMaldaConfig(); // Returns config object from ./.malda/config.json or ~/.malda/config.json, or null
getMaldaHome() — Returns the path to the MALDA user directory (no arguments).
getMaldaConfig() — Reads the first existing config file from ./.malda/config.json or ~/.malda/config.json, parses it as JSON, and returns the result as an object. Returns null if neither file exists or parsing fails. Use it to read providers.openrouter.apiKey, agents.defaults.model, tools.web.search.apiKey, etc.
getAssistantMemory(path?) — Returns a GraphMemory instance initialized with MALDA_MEMORY_EMBED (default hash) and loaded from ~/.malda/memory/assistant when artifacts exist. Optional path overrides the storage base path (without extension).
Skills
These functions support loading skills from ~/.malda/skills/.
var names = getSkillNames(); // Returns array of skill base names, e.g. ["github", "weather"]
var skill = loadSkill("github"); // Loads ~/.malda/skills/github.malda, returns object with module globals (e.g. skill.tools, skill.agent)
var skills = loadSkillsFromDir(); // Scans ~/.malda/skills/*.malda; each entry has name + exports (or error)
getSkillNames() — Returns an array of strings: the base names (without .malda) of all .malda files in ~/.malda/skills/. Returns [] if the directory does not exist or is empty. No arguments.
loadSkill(name) — Loads the skill file ~/.malda/skills/<name>.malda, runs it in an isolated environment, and returns an object whose properties are the module’s global variables. Convention: skills export a tools array (and optionally agent). Returns null if the file does not exist or name is empty. One argument: the skill name (string).
loadSkillsFromDir(path?) — Scans a directory (default ~/.malda/skills) for *.malda files and returns an array of objects. Each object includes name plus the skill module globals (tools, agent, etc.). On load failure, the object has name and error instead. Optional first argument: directory path (string).
13.5 Environment and Host
How-to and the getEnv / str.trim footgun: 12.5 Environment and Host.
var apiKey = getEnv("OPENAI_API_KEY"); // string, or null when unset
var apiKeyOr = io.getEnvOr("OPENAI_API_KEY"); // "" when unset (optional 2nd arg = default)
var hasKey = hasEnv("API_KEY"); // Check if environment variable exists
io.getEnvOr(name, default?) — same lookup as getEnv, but never returns null: missing variables yield default (empty string when omitted). Prefer this before str.trim / other string sinks.
13.5.1 Host Information
Argument-less built-ins describe the machine and invocation the program is running under. Passing any argument raises an error.
var host = getHostPlatform();
print(host.os); // Operating system identifier
print(host.arch); // Process architecture
print(host.pathSeparator); // "\" on Windows, "/" elsewhere
print(host.description); // Full OS description string
var args = getCommandLineArgs();
// Arguments passed to the program, excluding the program name itself
if (args.length > 0) {
print("first argument: " + args[0]);
}
// Folder of the .malda script (interpreter) or of the compiled .exe (transpile)
var programDir = getProgramDirectory();
var modelPath = io.pathJoin(programDir, "bge-m3-Q4_K_M.gguf");
getHostPlatform() returns an object with the four fields shown above. getCommandLineArgs() returns an array of strings and is the way to read CLI arguments from a MALDA program, in both interpreted and transpiled runs. getProgramDirectory() returns the absolute directory of the running .malda source file under the interpreter, or AppContext.BaseDirectory (the folder containing the compiled executable) after malda compile.
13.5.2 Web search (Brave Search API)
webSearch(query, apiKey?) — Performs a web search using the Brave Search API. query is the search string. apiKey is optional; if omitted, the key is taken from (in order) the apiKey argument, the BRAVE_SEARCH_API_KEY environment variable, or tools.web.search.apiKey in ~/.malda/config.json (see Personal Assistant and CLI). Returns an object: { ok: true, results: [{ title, url, description }, ...], moreResultsAvailable: bool } on success, or { ok: false, error: "message" } on failure.
var r = webSearch("MALDA programming language"); // Uses BRAVE_SEARCH_API_KEY or config
var r2 = webSearch("weather London", "your-brave-api-key"); // Explicit key
if (r.ok) { for (var i = 0; i < r.results.length; i++) print(r.results[i].title); }
13.5.3 HTTP auth token helpers
These helpers extract tokens from request-like objects used by HttpServer handlers.
var bearer = httpBearerToken(req); // Reads Authorization: Bearer <token>
var cookie = httpCookieToken(req, "app_session", "cookie-secret"); // Signed cookie token
var token = httpAuthToken(req, {
"allowBearer": true,
"allowCookie": true,
"allowBody": true,
"cookieName": "app_session",
"cookieSecret": "cookie-secret",
"bodyKey": "auth"
});
httpBearerToken(request)- returns bearer token string or empty string.httpCookieToken(request, cookieName, cookieSecret?)- returns decoded cookie token (or verified secure-cookie value when secret is provided), otherwise empty string.httpAuthToken(request, options?)- tries bearer/cookie/body in order and returns first non-empty token.
13.6 Array Utility Functions
var arr = [1, 2, 3, 4, 5];
var total = sum(arr); // 15
var avg = average(arr); // 3.0
var smallest = min(arr); // 1
var largest = max(arr); // 5
var total2 = arr.sum(); // 15
var avg2 = arr.average(); // 3.0
var smallest2 = arr.min(); // 1
var largest2 = arr.max(); // 5
var joined = join(arr, ", "); // Join array elements into string (returns "1, 2, 3, 4, 5")
var reversed = reverse(arr); // Return reversed array (returns [5, 4, 3, 2, 1])
var sorted = sort([3, 1, 4, 1, 5]); // Sort array (returns [1, 1, 3, 4, 5])
var sortedDesc = sort([3, 1, 2], (a, b) => b - a); // Custom compare: descending (interpreter and transpiled)
var hasValue = includes(arr, 3); // Check if array contains value (returns true)
sort(array, compareFn?) — With one argument, returns a new array sorted with default comparison (numbers then strings). With an optional compareFn, the second argument must be a function (a, b) => number: return negative if a before b, 0 if equal, positive if a after b. Custom compare is supported in both interpreter and transpiled mode.
sum(array) returns the total of a numeric array. average(array) returns the arithmetic mean of a non-empty numeric array as a float. min(array) and max(array) return the smallest and largest numeric element in a non-empty array.
The same aggregate operations also support array-method syntax: array.sum(), array.average(), array.min(), and array.max().
13.6.1 CSV Export Helper
var rows = [
{"name": "Alice", "score": 95},
{"name": "Bob", "score": 88}
];
var csv1 = toCsv(rows, ["name", "score"]); // With explicit column order
var csv2 = toCsv(rows); // Infer columns from first row
var csv3 = toCsv(rows, ["name", "score"], {
"delimiter": ";",
"includeHeader": true,
"quoteAll": false,
"newline": "\n"
});
toCsv(rows, columns?, options?) converts an array of rows to CSV text. It escapes quotes and wraps cells when required (delimiter/newlines/quotes). Useful for reports and data export endpoints.
13.7 JSON Functions
var jsonStr = toJSON(obj); // Convert object to JSON string
var obj = parseJSON('{"name":"Alice","age":30}'); // Parse JSON string to object
parseJSON parses arbitrary JSON into MALDA values. parseJson(jsonString, schemaName) parses JSON and validates it against a registered schema declaration, throwing on mismatch.
schema Answer {
text: string;
sources: string[];
}
var parsed = parseJson('{"text":"ok","sources":["a.md"]}', "Answer");
print(parsed.text); // ok
print(parsed.sources[0]); // a.md
Array field types use type[] syntax (e.g. string[], int[], or OtherSchema[]). Field types may also name another declared schema (nested object shapes are expanded for validation and typed prompts) or a declared sum type (tagged oneOf JSON). Optional fields append ? after the type. Unknown field type names and cyclic schema references raise an error when the schema is resolved.
13.7.1 validate(schema, value)
Checks a value that you already have against a schema, without parsing JSON. Unlike parseJson, a validation failure is not an exception: the result is always an object reporting the outcome.
- On success:
{ ok: true, data: value } - On failure:
{ ok: false, error: "message" }
The first argument is either the name of a registered schema or sum type, or an inline schema object. An unknown name raises Unknown schema 'Name'. On success, data is the original value — a tagged dict stays a dict (it is not coerced to a variant). Use await prompt … -> Intent when you need a variant for match.
schema Answer {
text: string;
sources: string[];
}
var candidate = dict { "text": "ok", "sources": ["a.md"] };
var checked = validate("Answer", candidate);
if (checked.ok) {
print(checked.data.text); // ok
} else {
print("invalid: " + checked.error);
}
type Intent = Search(query) | Buy(sku, qty);
var tagged = dict { "tag": "Buy", "sku": "SKU-9", "qty": 2 };
var checkedIntent = validate("Intent", tagged);
if (checkedIntent.ok) {
print(checkedIntent.data.tag);
}
type Intent = Search(query: string) | Buy(sku: string, qty: int);
var tagged = dict { "tag": "Buy", "sku": "SKU-9", "qty": "x" };
var checkedTyped = validate("Intent", tagged);
print(checkedTyped.ok);
memory.validate() on a GraphMemory instance, which checks graph integrity rather than a schema. The two share a name but are unrelated.
13.7.2 AI Pipeline Functions
These built-ins compose with the pipe operator (|>) for retrieval-augmented generation (RAG) and structured LLM output. See also 15. VectorDB (asRetriever) and Examples/Prompts/rag_pipeline.malda.
// Load text files matching a glob pattern (default directory: current)
var docs = loadDocuments("**/*.md", "docs/");
// Split long documents into overlapping chunks
var chunks = splitDocuments(docs, 512, 64);
// Index documents into a VectorDB (embeds content, preserves metadata)
indexInto(vdb, chunks);
// Format retrieved documents for prompt context
var context = query |> retriever.get |> formatRetrievedDocs;
// Execute a PromptInstance with the default or supplied LLM client
var response = await (promptInstance |> runPrompt(client));
// Stream tokens while the model responds
var seen = "";
function onTok(token) { seen = seen + token; }
var response = await runPrompt(promptInstance, client, { onToken: onTok });
// Stream model reasoning/thinking deltas (OpenRouter-compatible providers)
var reasoning = "";
function onReason(token) { reasoning = reasoning + token; }
var response = await runPrompt(promptInstance, client, { onReasoning: onReason });
// Attach runtime few-shot examples to a prompt instance
var p = classify("query") |> withExamples(dynamicExamples);
// Validate LLM JSON output against a schema
var parsed = response |> parseJson("Answer");
// Advanced composition: sequence + parallel branches
var pipeline = composePipe(formatRetrievedDocs, (ctx) => answerPrompt(q, ctx));
var context = question |> pipeline;
var branches = parallelRun(question, {
context: (q) => q |> retriever.get,
tags: classifyIntent
});
var merged = mergeRetrievedDocs(branches.context, branches.tags);
| Function | Description |
|---|---|
loadDocuments(pattern, dirPath?) | Glob-matches files under dirPath (default "."); returns { content, metadata: { source } } per file |
splitDocuments(docs, chunkSize, overlap?) | Splits document content into overlapping chunks; copies metadata to each chunk |
indexInto(vdb, docs) | Embeds and adds each document to a VectorDB via its calculator; stores metadata with hits |
formatRetrievedDocs(docs) | Formats document arrays as [source: …] blocks joined for prompt context |
composePipe(step1, step2, …) | Composes 2+ callables (functions, lambdas, built-ins, prompts) left-to-right into a reusable function (input) => …. Awaits async steps. Pipe-friendly: input |> composePipe(f, g) |
parallelRun(input, branches) | RunnableParallel: feeds the same input to each named branch concurrently; returns an object/map of results. Use await when branches include async steps. |
mergeRetrievedDocs(docArrays…) | Flattens multiple Document[] arrays (e.g. from parallelRun) into one array; dedupes by source+chunk metadata or content |
withExamples(prompt, examples, options?) | Returns a copy of a PromptInstance with runtime few-shot examples. Pass { merge: true } to append after any static examples from the prompt declaration. Pipe-friendly. |
runPrompt(prompt, client?, options?) | Async: runs a PromptInstance through an LLM; returns response text. Optional options: { onToken: (token) => ... } for streamed content tokens; { onReasoning: (token) => ... } for streamed reasoning/thinking tokens. Both work in interpreted and transpiled mode with await and pipe steps. |
parseJson(json, schemaName) | Parses and validates JSON against a schema declaration; returns a typed object |
13.8 File System Functions
How-to, failure styles, line ranges, capability tokens, and backend notes: 12. Input/Output. This section is the signature catalog.
var content = readFile("example.txt"); // Read entire file
var lines = readFile("example.txt", 10, 20); // Read lines 10-20 (1-indexed)
var fromLine = readFile("example.txt", 5); // Read from line 5 to end
writeFile("output.txt", "Hello"); // Write content to file
var exists = hasFile("example.txt"); // Check if file exists
var dirExists = hasDirectory("mydir"); // Check if directory exists
ensureDir("path/to/dir"); // Create directory and parents if missing
var files = listDirectory("."); // List directory contents
ensureDir(path) — Creates the directory and any missing parent directories. Does nothing if the directory already exists. Useful for creating ~/.malda/memory before saving assistant memory.
13.8.0 Embedded folders (embed:)
Compile with malda compile … --embed-folder <dir[=alias]> to pack a directory into the executable as assembly resources. At runtime, read those files with the virtual scheme embed:<alias>/<relative> — nothing is extracted to disk. Writes (writeFile, ensureDir, …) reject embed: paths.
if (io.hasEmbeddedFolder("secondbrain")) {
var root = io.embeddedFolderRoot("secondbrain"); // "embed:secondbrain"
var catalog = io.readFile(io.pathJoin(root, "brain.json"));
var entries = io.listDirectory(root);
}
hasEmbeddedFolder(alias) returns whether that alias was embedded. embeddedFolderRoot(alias) returns embed:<alias>, or null when the alias is missing. Agent tools such as createReadFileTool, createGrepTool, and createListDirectoryTool accept an embed:<alias> working directory.
replaceInFile("file.txt", "old", "new", 3); // Replace text in file (single replacement)
var edits = [{"oldText": "old1", "newText": "new1"}, {"oldText": "old2", "newText": "new2"}];
var result = editFile("file.txt", edits); // Apply multiple edits to file
13.8.1 Line, Binary, Delete, and PDF Text
| Function | Returns | Behavior |
|---|---|---|
pdf.extractText(path, password?) | string | Extracts text from a PDF using PdfPig (ContentOrderTextExtractor). Optional password for encrypted files. Throws when the path is missing or the PDF cannot be opened. Digital text only — scanned/image PDFs need OCR elsewhere. Prefer the namespaced spelling; the CallBuiltIn name is extractPdfText. |
doc.extractText(path) | string | Extracts body paragraph text from a Word .docx using the Open XML SDK. Throws when the path is missing, the file is not .docx, or the package cannot be opened. Legacy binary .doc is not supported. Prefer the namespaced spelling; the CallBuiltIn name is extractDocxText. |
readTextFileLines(path) | array of strings, or null | Reads the file as UTF-8 and splits it into lines. Returns null when the file is missing or cannot be read. |
deleteFile(path) | boolean | Deletes the file. Returns true when the file was deleted or was already absent; false on an empty path or an I/O failure. |
insertAtLine(path, lineNumber, content, insertAfter?) | boolean | Inserts content (which may span several lines) at a 1-indexed line. Returns false if the file does not exist. |
readFileBase64(path) | string, or null | Reads the file as bytes and returns base64. Returns null when the file is missing. |
writeFileBase64(path, base64Content) | boolean | Decodes base64 and writes the bytes. Returns false when the input is not valid base64 or the write fails. |
var lines = readTextFileLines("notes.txt");
if (lines != null) {
print("line count: " + lines.length);
}
insertAtLine("notes.txt", 1, "# Header"); // Insert before line 1
insertAtLine("notes.txt", 3, "appended", true); // Insert after line 3
var encoded = readFileBase64("logo.png");
writeFileBase64("logo-copy.png", encoded);
deleteFile("scratch.txt");
var pdfText = pdf.extractText("manual.pdf");
// var unlocked = pdf.extractText("secret.pdf", "password");
var docText = doc.extractText("brief.docx");
For insertAtLine, a lineNumber of 0 or less inserts at the start of the file, and a value beyond the last line appends to the end. insertAfter defaults to false, meaning the content is inserted before the given line.
readTextFileLines, deleteFile, insertAtLine, and the base64 helpers report ordinary failures through their return value (false or null) rather than by throwing. They only raise an error when called with the wrong number of arguments or the wrong argument types. Check the result rather than relying on try/catch. pdf.extractText and doc.extractText throw on missing files and parse failures.
insertAtLine is interpreter-only: it is not available in transpiled executables. The other file helpers, pdf.extractText / extractPdfText, and doc.extractText / extractDocxText are supported by the C# transpiler.
13.8.2 Searching Files: glob and grep
glob finds paths by pattern, and grep searches file contents. Both take a required argument first and then a series of optional, positional arguments.
glob(pattern, dirPath?, maxResults?, includeDirectories?, excludeDirs?, workingDirectory?)
dirPathdefaults to".",maxResultsto200(capped at 500),includeDirectoriestofalse, and the two remaining string arguments to"".- On success it returns an object
{ items, count, truncated }, where each item is{ name, type, path }andtruncatedreports whether the result hitmaxResults.
var found = glob("**/*.malda", "Examples");
print(found.count);
print(found.truncated);
var first = found.items[0];
print(first.path + " (" + first.type + ")");
grep(pattern, filePath, useRegex?, caseInsensitive?, includeLineNumbers?, contextLines?, countOnly?, recursive?, workingDirectory?)
- Defaults:
useRegexfalse,caseInsensitivefalse,includeLineNumberstrue,contextLines3,countOnlyfalse,recursivetrue. - Normally returns an array of matches shaped
{ filePath, content, lineNumber, contextBefore, contextAfter }. WithcountOnlyset it returns{ count, filesSearched }instead. - Files that cannot be read are skipped silently.
var matches = grep("function ", "Examples");
for (var m in matches) {
print(m.filePath + ":" + m.lineNumber + " " + m.content);
}
var summary = grep("TODO", "Examples", false, true, true, 0, true);
print(summary.count + " hits in " + summary.filesSearched + " files");
glob and grep return an error message instead of their normal result. Guard with typeOf(result) == "string" before treating the value as a collection.
var result = grep("needle", "does-not-exist");
if (typeOf(result) == "string") {
print("search failed: " + result);
}
13.9 Git Functions
var status = gitStatus("."); // Get repository status
gitAdd(".", "."); // Stage files
gitCommit(".", "Fix bug"); // Create commit
var commits = gitLog(".", 10); // Get last 10 commits
var diff = gitDiff(".", null, false); // Get unstaged diff
var branches = gitBranch(".", "list"); // List all branches
gitBranch(".", "create", "feature-x"); // Create new branch
// Note: Branch deletion is disabled for safety
gitCheckout(".", "main", false); // Switch to branch
gitPush(".", "origin", "main"); // Push to remote
gitPull(".", "origin", "main"); // Pull from remote
13.10 Command Execution Functions
// Execute shell commands
var result = runCommand("dotnet", ["build"], ".", 30000); // Run dotnet build with 30s timeout
// Returns: {exitCode: 0, stdout: "...", stderr: ""}
var result = runCommand("npm", ["test"]); // Run npm test (no timeout)
var result = runCommand("python", ["script.py"], "./scripts"); // Run with custom working directory
// Result object structure:
// - exitCode (integer): Process exit code (0 typically indicates success)
// - stdout (string): Standard output from the command
// - stderr (string): Standard error output from the command
13.11 MALDA Execution Functions
// Execute MALDA code from file or string
var result = runMALDA("example.malda"); // Execute from file
var result = runMALDA("print('Hello');"); // Execute from string
var result = runMALDA("example.malda", "input data"); // Execute with stdin input
// Result object structure:
// - success (boolean): true if execution completed without errors
// - output (string): Standard output from the program
// - error (string): Parse error message if any, empty string otherwise
// - runtimeError (string, optional): Runtime error message if any
// Compile a .malda program to an executable (optional embed folder = CLI --embed-folder)
var packed = compileMALDA("app.malda", "dist/app.exe", "transpile", "secondbrain");
// embedFolder may be "path" or "path=alias"; result: { success, outputPath, error, errors }
13.10.1 getSymbols(sourceOrFilePath)
Parses MALDA code and extracts structured symbol information (classes, functions, actors, prompts) with line numbers and signatures. Accepts one string argument: a file path to a .malda file or MALDA source code. If the string looks like a file path (contains path separators or ends with .malda) and the file exists, the file is read and its content is parsed; otherwise the argument is treated as source code. Path traversal (.., ~) is rejected. Returns an object with classes, functions, actors, prompts, and parseErrors (all arrays). Each class/actor has name, line, column, members; each function has name, line, column, parameters, signature; each prompt has name, line, column, parameters, returnType?, signature. Parse errors have line, column, message.
var sym = getSymbols("Examples/OOP/classes_objects.malda"); // From file
var sym2 = getSymbols("function f() { } class C { }"); // From source
// sym.classes, sym.functions, sym.actors, sym.prompts, sym.parseErrors
13.10.2 getParseErrors(sourceOrFilePath)
Parses MALDA code and returns only parse errors (no execution). Accepts the same argument as getSymbols: file path or source string. Path resolution and security checks are the same. Returns { parseErrors: [{ line, column, message }, ...] }. Use to validate syntax without running or compiling.
var errs = getParseErrors("var x = ;"); // Invalid: empty rhs
// errs.parseErrors is non-empty with line, column, message
var ok = getParseErrors("var x = 1;"); // Valid: parseErrors is []
runCommand function includes comprehensive safety checks:
- Dangerous commands are blocked (e.g.,
rm,del,format,shutdown,powershell,cmd, etc.) - Working directory is validated and normalized to prevent path traversal
- Maximum timeout limit of 1 hour (3,600,000ms) to prevent indefinite waits
- Command paths are validated for absolute paths
- Path traversal attempts (
..,~) are detected and blocked
13.12 Spectre.Console Integration
MALDA exposes a global AnsiConsole object that wraps the .NET Spectre.Console library and provides rich console output:
// Markup (colors, bold, links, etc.)
AnsiConsole.markupLine("[green]Hello[/] [bold red]Spectre.Console[/]!"); // Appends a newline
AnsiConsole.markup("[dim]no newline, [/]"); // Stays on the same line
AnsiConsole.markupLine("[cyan]rest of the line[/]");
// Tables
var rows = [
{"Name": "Alice", "Score": 95},
{"Name": "Bob", "Score": 88}
];
AnsiConsole.table(rows, "Scores");
// Panels (body and title accept markup)
AnsiConsole.panel("[bold]Important[/] message", "Info", "rounded");
// Trees
var treeData = {
"root": "Project",
"children": [
{"label": "src"},
{"label": "tests"}
]
};
AnsiConsole.tree("Project", treeData);
// Status
AnsiConsole.status("Processing...", () => {
// Long-running work here
});
// Prompt (configuration object)
AnsiConsole.prompt({
"type": "text",
"message": "Enter your name"
});
// Progress - New callback-based syntax (recommended)
AnsiConsole.progress((ctx) => {
ctx.addTask("Loading World Map", 100);
while (!ctx.isFinished()) {
ctx.increment("Loading World Map", 1.5);
sleep(50);
}
});
// Progress - Object-based syntax (legacy)
AnsiConsole.progress({
"tasks": [
{"name": "Task 1", "maxValue": 100}
],
"action": (progressObj) => {
var current = 0;
while (current < 100) {
current = current + 10;
// Update progress by setting the value
progressObj["Task 1"] = current;
sleep(50);
}
}
});
AnsiConsole.markupLine(text)writes the text and appends a newline. It is the right call for a standalone line of output.AnsiConsole.markup(text)writes the text with no trailing newline, so consecutive calls run together on one line. Use it to compose a line from several styled fragments, then close the line withmarkupLine.- Both parse markup tags such as
[bold],[green]and[/]. To print a literal bracket, double it:[[and]]. AnsiConsole.panel(body, title?, border?)parses markup in both the body and the title. Content that is not valid markup — arbitrary JSON, code, or error text containing brackets — is rendered literally instead of raising an error.
- Callback-based syntax: Pass a function that receives a context object with methods:
ctx.addTask(name, maxValue)- Add a progress taskctx.increment(taskName, value)- Increment a task's progress by the given valuectx.isFinished()- Check if all tasks are finished
- Object-based syntax: Pass an object with a
tasksarray and anactioncallback. The callback receives a progress object where you can read and update progress values by setting properties:progressObj["Task Name"] = value
- Command-line interpreter: When you run
maldain a real terminal, MALDA configures UTF-8 and enables ANSI escape sequences on supported Windows consoles so Spectre.Console markup renders with full colors and styling. - Transpiled executables: Generated C# executables enable ANSI escape sequences at startup on Windows, so
AnsiConsole.*calls render correctly in compatible terminals. - Desktop IDE: The IDE output panel is plain text. On first use of
AnsiConsole, MALDA automatically opens a separate console window and routes output to both the IDE panel (plain text) and the console (rich Spectre.Console rendering).
13.13 Date and Time Functions
var timestamp = now(); // Get current timestamp in milliseconds (Unix epoch)
var formatted = formatDate(timestamp, "yyyy-MM-dd HH:mm:ss"); // Format timestamp (default: "yyyy-MM-dd HH:mm:ss")
var parsed = parseDate("2026-01-26 10:30:00"); // Parse date string to timestamp
var tomorrow = addDays(timestamp, 1); // Add days to timestamp
var inHours = addHours(timestamp, 2); // Add hours to timestamp
- Timestamps are in milliseconds since Unix epoch (January 1, 1970 UTC)
formatDateuses standard .NET date format strings (e.g., "yyyy-MM-dd", "HH:mm:ss", "dd/MM/yyyy")parseDateaccepts common date formats and converts to timestamp
13.14 Random Number Functions
var rand = math.random(); // Random float between 0.0 and 1.0
var randInt = math.randomInt(1, 10); // Random integer, 1 and 10 both included
var randFloat = math.randomFloat(0.0, 100.0); // Random float between 0.0 and 100.0
math.seed(7); // Pin the sequence for reproducible runs
var pinned = math.randomInt(1, 100); // Always 39 after seed(7)
randomInt(min, max)includes both endpoints, unlike the half-open ranges common in other languages.math.seed(n)resets the shared generator behindrandom,randomInt,randomFloatandrandn. Seed at the top of a program to make a run deterministic, which is what makes a random program testable.- The flat spellings
randomInt(1, 10)andMath.randomInt(1, 10)still run, but the language server reports both as deprecated aliases. Prefermath., as described in 13.2 Stdlib Namespaces and Flat Aliases.
13.15 Type Checking Functions
var isNum = isNumber(42); // Check if value is a number (integer or float)
var isStr = isString("hello"); // Check if value is a string
var isArr = isArray([1, 2, 3]); // Check if value is an array
var isObj = isObject({name: "Alice"}); // Check if value is an object
var type = typeOf(42); // Canonical tag ("int", "string", "dict", "object", "variant", "task", "null", ...)
var isInt = isTag(42, "int"); // true; isTag also accepts legacy names like "integer" during deprecation
13.16 Encoding and Decoding Functions
var encoded = base64Encode("Hello World"); // Base64 encode string
var decoded = base64Decode(encoded); // Base64 decode string
var urlEncoded = urlEncode("Hello World"); // URL encode string (returns "Hello%20World")
var urlDecoded = urlDecode(urlEncoded); // URL decode string
13.17 Hash Functions
var md5Hash = md5("Hello World"); // Calculate MD5 hash (returns hex string)
var sha256Hash = sha256("Hello World"); // Calculate SHA-256 hash (returns hex string)
- Both
md5andsha256return lowercase hexadecimal strings - MD5 produces 32-character hex strings
- SHA-256 produces 64-character hex strings
13.16.1 Password and JWT Security Functions
var passwordHash = hashPassword("my-password"); // PBKDF2-SHA256 hash
var isValid = verifyPassword("my-password", passwordHash); // true/false
var claims = {"sub": "user-123", "role": "admin"};
var token = createJwt(claims, "my-jwt-secret", 3600); // expires in 3600s
var token2 = createJwt(claims, "my-jwt-secret", {
"expiresInSeconds": 3600,
"issuer": "malda-core",
"audience": "malda-apps",
"notBeforeSeconds": 0
});
var verifiedClaims = verifyJwt(token2, "my-jwt-secret", {
"issuer": "malda-core",
"audience": "malda-apps"
});
print(verifiedClaims.sub);
var csrfToken = generateCsrfToken("csrf-secret", 3600);
var csrfOk = verifyCsrfToken(csrfToken, "csrf-secret"); // true/false
var setCookieHeader = createSecureCookie("session", "user-123", "cookie-secret");
// send with res.header("Set-Cookie", setCookieHeader) or use res.cookie(...)
var cookieValue = split(split(setCookieHeader, ";")[0], "=")[1];
var session = readSecureCookie(urlDecode(cookieValue), "cookie-secret");
hashPassword(password, iterations?)uses PBKDF2 with SHA-256 and random saltverifyPassword(password, passwordHash)performs constant-time comparisoncreateJwt(payload, secret, expiresInSeconds? | options?)signs HS256 tokens and addsiat; options may setexpiresInSeconds,issuer(iss),audience(aud), andnotBeforeSeconds(nbf)verifyJwt(token, secret, options?)validates signature,nbf,exp, and optional expectedissuer/audienceverifyJwtthrows standardized auth errors for missing, invalid, not-yet-valid, or expired tokens- In HTTP/REST handlers prefer
req.auth.authenticateBearerJwt(secret)orreq.auth.authenticateCookieJwt(cookieName, jwtSecret, cookieSecret?)— they verify the token and populatereq.authclaims/roles. Usereq.auth.requireRole/requirePermissionfor authorization.setVerifiedSubremains for ingress/gateway cases without a local JWT. generateCsrfToken(secret, ttlSeconds?)creates signed CSRF tokens for form and API mutation flowsverifyCsrfToken(token, secret)validates signature + expiration and returns booleancsrfField(secret, ttlSeconds?)returns a hidden_csrfinput HTML fragment for forms (token matchesenableCsrf)bindForm(body, fields)binds/validates form fields (name,required,trim,minLength/maxLength,pattern: "email") into{ ok, values, errors }formErrors(errors)renders an escaped HTML error listpageLayout(title, bodyHtml, options?)thin full-document HTML chrome for@PAGEstring apps (preferui.layoutfor rich layouts)createSecureCookie(name, value, secret, options?)returns a signedSet-Cookieheader string with secure defaultsreadSecureCookie(cookieValue, secret)verifies a signed cookie value and returns plaintext ornull
13.16.1a Background jobs (lightweight queue)
Short async units (email, webhooks) use a SQLite queue at ./.malda/jobs.db. This is separate from durable workflow processes.
var jobId = enqueueJob("mail", {"to": "user@example.com"}, {"maxAttempts": 3});
var job = claimJob("mail", "worker-1");
if (job != null) {
// ... do work with job.payload ...
completeJob(job.id, {"sent": true});
// or: failJob(job.id, "SMTP timeout", true);
}
var open = listJobs("mail", "pending", 20);
var one = getJob(jobId);
enqueueJob(queue, payload, options?)— options:runAt,maxAttempts,correlationIdclaimJob(queue, workerId?)— returns a running job ornullcompleteJob(jobId, result?)/failJob(jobId, error?, retry?)getJob(jobId)/listJobs(queue?, status?, limit?)
13.16.2 Request auth context (req.auth)
Both HttpServer and RestServer expose the same req.auth surface on each request:
- State:
verified,sub/subject,claims,roles,permissions,token - AuthN:
authenticateBearerJwt(secret),authenticateCookieJwt(cookieName, jwtSecret, cookieSecret?),setVerifiedSub(sub),setAnonymous()/clear() - AuthZ:
claim(name, default?),hasClaim,hasRole/requireRole,hasPermission/requirePermission,requireVerified()
function requireAuth(req, res, next) {
req.auth.authenticateBearerJwt(getEnv("MALDA_JWT_SECRET"));
next();
}
server.use(requireAuth, { "except": ["/api/health", "/metrics"] });
13.18 Range Generation
var range1 = range(5); // Generate [0, 1, 2, 3, 4]
var range2 = range(1, 10); // Generate [1, 2, 3, 4, 5, 6, 7, 8, 9]
var range3 = range(0, 10, 2); // Generate [0, 2, 4, 6, 8] (step of 2)
var range4 = range(10, 0, -1); // Generate [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] (negative step)
13.19 Error Handling Functions
exit(0); // Exit program with exit code 0 (success)
exit(1); // Exit program with exit code 1 (error)
error("Something went wrong"); // Throw runtime error with message
assert(x > 0, "x must be positive"); // Assert condition is true, throw error if false
assert(isValid, "Validation failed"); // Assert without custom message
exit(code)immediately terminates the program with the specified exit code (0 = success, non-zero = error)error(message)throws a runtime error that can be caught by error handling mechanismsassert(condition, message?)is useful for debugging and validation - throws an error if condition is false
13.19.1 result and option
Prefer these modules when a function should report success or absence without throwing. They return variants with tags Ok/Err and Some/None — the same shape as a type Result = Ok(value) | Err(message) declaration, but you do not need to declare the type. The module names are lowercase (result, option); a user-declared type Result is a different name.
Use try/catch for unexpected failures (see 8. Control Structures). Use result/option for expected outcomes in the return value.
function parseAge(raw) {
var n = toIntOrNull(raw);
if (n == null) {
return result.err("not an int");
}
return result.ok(n);
}
print(result.unwrapOr(parseAge("12"), 0));
print(result.isErr(parseAge("x")));
var present = option.some("hi");
var missing = option.none();
print(option.unwrapOr(present, "no"));
print(option.isNone(missing));
result.ok(value)/result.err(value)— construct anOkorErrvariantresult.isOk(r)/result.isErr(r)— tag testsresult.unwrapOr(r, fallback)— payload ofOk, otherwisefallbackresult.map(r, fn)— applyfnto anOkpayload; leaveErrunchangedresult.andThen(r, fn)— ifOk, callfn(payload)and return that Result; ifErr, skipfn.fnmust returnOk/Err(usemapto transform a bare payload)option.some(value)/option.none()— construct aSomeorNonevariantoption.isSome(o)/option.isNone(o)/option.unwrapOr(o, fallback)/option.map(o, fn)/option.andThen(o, fn)— the same pattern for optional values
function parseAge(raw) {
var n = toIntOrNull(raw);
if (n == null) {
return result.err("not an int");
}
return result.ok(n);
}
function doubleAge(n) {
return result.ok(n * 2);
}
print(result.unwrapOr(parseAge("12") |> result.andThen(doubleAge), 0));
print(result.isErr(parseAge("x") |> result.andThen(doubleAge)));
Do not treat type hints (var n: int = …) as runtime validation. For JSON-shaped payloads use schema and validate(). Tutorial: errors, Result/Option, and schema validate.
13.19.2 grounded.wrap
Retrieval citations (GraphMemory, files, tools) are not a match-visible value kind. Wrap a payload so provenance is a dict you can read:
var g = grounded.wrap("the sky is blue", [
{ "source": "wiki", "id": "p1", "span": "12-40" }
]);
print(g.value);
print(g.sourced);
print(g.citations[0].source);
grounded.wrap(value, citations?)— returns{ value, citations, sourced }.sourcedis true when the citation list is non-empty after normalization.- Each citation is
{ source, id?, span? }. A string citation becomes{ source }. There is no flatgrounded()alias. - GraphMemory opt-in ASK:
memory.ask(query, maxResults?, options?)(orquery(..., { grounded: true })) wraps hits with citations fromfilePath/source/nodeId. Plainquery()still returns an array. See 19. GraphMemory §19.3.15.
13.19.3 cap.fileRead
@effects("io") is a name allow-list. Pass an unforgeable token into a tool so the model cannot invent a path. Tokens are sealed host objects, not dicts — JSON and object literals cannot rehydrate one.
var notes = cap.fileRead("notes.md");
print(notes.kind);
print(cap.is(notes, "fileRead"));
var forged = false;
try {
cap.read({ "kind": "fileRead", "path": "notes.md" });
} catch (e) {
forged = true;
}
print(forged);
cap.fileRead(path)/cap.fileWrite(path)/cap.dirList(path)— mint a token withkindandpath. There is no flatcap()alias.cap.read(token)/cap.write(token, content)/cap.list(token)— consume a matching token only. Strings and{ kind, path }dicts throw.cap.is(value, kind?)— true only for a real token.cap.confine(token, relativePath)returns a narrower token of the same kind; paths outside the parent throw.io.readFile/io.writeFile/io.listDirectoryalso accept a matching token. Ordinary string paths still work.- Mark handlers that mint or consume tokens
@effects("cap")(or list both"io"and"cap"). JavaScript can mint /is/confine; file consume is host-only. - Example:
Examples/Tools/capability_tokens.malda.
13.20 Structured Task Planning
decomposeTask, executePlan, and createSubmitPlanTool live in 18. Agent Orchestration (§ 18.13). runProgram runs a closed api / program(ApiName) value with no further LLM calls — see 10. Prompts (§ 10.8 Closed APIs and Deterministic Programs).
13.21 Tool Creation Functions
Agent tool factories (createReadFileTool, createWriteFileTool, createReplaceInFileTool, createEditFileTool, createInsertAtLineTool, createGrepTool, createListDirectoryTool, createAskUserTool, createWebSearchTool, createGitStatusTool, createGitAddTool, createGitCommitTool, createGitLogTool, createGitDiffTool, createGitBranchTool, createGitCheckoutTool, createGitPushTool, createGitPullTool, createRunCommandTool, createRunMALDATool, createCompileMALDATool, createGetSymbolsTool, createGetParseErrorsTool, createSubmitPlanTool, createGlobTool, createCreateMcpAgentScriptTool) live in 18. Agent Orchestration (§ 18.6). createNativeCallback wraps a MALDA function as a .NET delegate — see 30. .NET Interop.
13.22 Durable Workflow Operations
Runtime, query, and control helpers (startWorkflow, getWorkflowStatus, getWorkflow, getWorkflowSteps, getWorkflowEvents, getWorkflowMetrics, listWorkflows, listWorkflowDeadLetters, requeueDeadLetter, runWorkflowInstance) live in 22. Durable Workflows.
13.23 Agent Runtime Logging
Diagnostic helpers (enableAgentVerboseLogging, setAgentVerbosePhase, setAgentStatusBanner, reportRalphStatus) live in 18. Agent Orchestration (§ 18.5 and 18.18 Ralph Wiggum). They affect presentation only and never change an agent's result.
13.24 Web UI Functions
Server component helpers (renderTemplate, componentFragment, componentLiveEmit, componentState*, onAgentProgress, clearAgentProgress) and ui.* controls live in 24. Web UI Server Components. Start from 23. Web UI Overview if you are choosing a UI model.
13.25 Optional packs (not in core)
Core BuiltInRegistry lists only open-source core symbols. Domain-specific builtins may ship in separately distributed packs; load them with loadNativeModule(...) and ship any required assemblies beside your app. Core does not auto-register pack globals.
See Also
- Appendix — Optional packs
- Input/Output — console, files, paths, environment, host I/O; prefer
io.* - Prompts —
runProgramand closedapi/program(ApiName) - Web UI Server Components — Server-side UI and component APIs
- Agent Orchestration — Tools, task plans, and agent logging
- Durable Workflows — Workflow runtime built-ins