MALDA™ Reference Manual

The AI-First Programming Language - Version 1.0.39

13. Built-in Functions

This chapter is the stdlib catalog: conversion, math, strings, files, JSON, dates, and error helpers. How-to for I/O, prompts, jobs, JWT, and UI lives in those chapters; this page keeps signatures and a numbered index.

First-read stop. Prefer namespaced calls. The rest of this chapter is the catalog. Course: Learn MALDA — After the core path.
io.print(math.sqrt(16));
io.print(str.upper("malda"));
io.print(toIntOr("", 1));

13.0 Chapter map

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

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

ModuleCovers
mathRounding, trigonometry, aggregates, random helpers, LLM math, linear algebra, and the constants math.PI, math.E, math.TAU, math.INF, math.NaN
nnNeural-net activations, local derivatives, dense / denseBackward, and the loss gradients mseGrad / softmaxGrad. Signatures and the layer model are 14. Neural Nets. No flat aliases
strCase, trimming, splitting and joining, padding, regex helpers, similarity, base64, md5 / sha256
ioprint, input, file and path helpers, glob, grep, environment variables, git helpers
pdfextractText — read text from a PDF file (digital text layer; no OCR)
docextractText — read text from a Word .docx (Open XML; not legacy .doc)
resultok, err, map, unwrapOr, isOk, isErr — see 13.19.1
optionsome, 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:

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.

Convention used in this manual: examples throughout the manual and in 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

Preferred spelling is math.*. Flat names and Math.* are deprecated aliases (see 13.2).

Interpreter, C# transpile, and JavaScript all run math.*. See the backend capability matrix.

print(math.abs(-5));
print(math.pow(2, 3));
ArgumentsReturnsNotes
math.abs(x)
1 argument—
math.acos(x)
1 argument—
math.anneal(initial, cost, neighbor, options?)
3-4 arguments: (initial, cost, neighbor, options?){ state, cost, steps }Metropolis search; cost/neighbor are unary lambdas (cooling may be a number or unary lambda); options: steps/temp/cooling/schedule/maximize/copy; uses math.random so math.seed pins it; WF1001 outside a workflow step
math.argmax(array)
1 argument: (array)—
math.argmin(array)
1 argument: (array)—
math.asin(x)
1 argument—
math.atan(x)
1 argument—
math.atan2(a, b)
2 arguments—
math.average(array)
1 argument: (array)—
math.ceil(x)
1 argument—returns a float even when whole-valued; integer sinks coerce whole floats; wrap with int() if you need an Integer-tagged value
math.clamp(x, lo, hi)
3 arguments—
math.cos(x)
1 argument—
math.degToRad(x)
1 argument—
math.dot(a, b)
2 arguments: (a, b)float1D vectors, same length
math.exp(x)
1 argument—
math.floor(x)
1 argument—returns a float even when whole-valued (print shows 1, not 1.0); integer sinks coerce whole floats, so str.repeat("-", math.floor(n)) works; fractional floats still fail
math.hypot(a, b)
2 arguments—
math.log(x)
1 argument—
math.log10(x)
1 argument—
math.log2(x)
1 argument—
math.logSumExp(array)
1 argument: (array)—
math.max(a, b)
2 arguments or 1 array—
math.matmul(a, b)
2 arguments: (a, b)array2D@2D, 2D@1D, or 1D@2D; inner dimensions must match
math.min(a, b)
2 arguments or 1 array—
math.pow(a, b)
2 arguments—
math.radToDeg(x)
1 argument—
math.randn(std?, mean?)
0-2 arguments: (std?, mean?)—
math.random()
0 arguments—float in [0.0, 1.0)
math.randomChoiceWeighted(weights)
1 argument: (weights)—
math.randomFloat(min, max)
2 arguments: (min, max)—min included, max excluded
math.randomInt(min, max)
2 arguments: (min, max)—min and max are BOTH included, unlike half-open ranges elsewhere; math.seed(n) pins the sequence
math.round(x)
1 argument—returns a float even when whole-valued; integer sinks coerce whole floats; wrap with int() if you need an Integer-tagged value
math.rsqrt(x)
1 argument—
math.seed(x)
1 argumentnullresets the one generator shared by random, randomInt, randomFloat, randn, randomChoiceWeighted and anneal
math.sigmoid(x)
1 argument: (x)—scalar or elementwise 1D/2D; clamps |x|>20
math.sign(x)
1 argument—
math.sin(x)
1 argument—
math.softmax(array, temperature?)
1-2 arguments: (array, temperature?)—
math.sqrt(x)
1 argument—returns a float even when whole-valued (sqrt(4) is 2.0); integer sinks coerce whole floats; wrap with int() if you need an Integer-tagged value
math.sum(array)
1 argument: (array)—
math.tan(x)
1 argument—
math.tanh(x)
1 argument: (x)—scalar or elementwise 1D/2D
math.transpose(matrix)
1 argument: (matrix)array2D nested array
math.trunc(x)
1 argument—
math.zeros(n, cols?)
1-2 arguments: (n, cols?)array1D math.zeros(n) or 2D math.zeros(rows, cols); each 2D row is a new array; cells are 0.0

math.max and math.min accept (a, b) or a non-empty numeric array. Aggregates are also methods: values.sum(), values.average(), values.min(), values.max(). Trigonometry is in radians; out-of-domain input is NaN, not an error. math.round uses banker's rounding.

math.zeros(n) / math.zeros(rows, cols)

Builds a 1D vector or a 2D nested array filled with 0.0. The two-argument form allocates a fresh row per row, so writing m[0][0] does not change other rows. Dimensions must be integers >= 0. Empty sizes are allowed: math.zeros(0) is [], and math.zeros(2, 0) is two empty rows.

var w = math.zeros(2);        // [0, 0]
var g = math.zeros(3, 4);     // 3 rows, 4 columns
g[0][0] = 1.0;                // other rows stay zero

Neural-net helpers

Linear algebra used by the offline AI_Theory track stays on math. Inner dimensions of math.matmul must match. Activations, local derivatives, a dense layer, and the signature table are 14. Neural Nets.

print(math.dot([1.0, 2.0], [3.0, 1.0]));

13.3.1 LLM-oriented Math Helpers (Reference)

See math.seed through math.anneal in the table. Invalid counts or types, empty arrays, a non-positive softmax temperature, or zero total weight throw. math.seed pins math.random, math.randomInt, math.randomFloat, math.randn, math.randomChoiceWeighted, and math.anneal.

13.3.2 Simulated annealing

math.anneal(initial, cost, neighbor, options?) runs Metropolis simulated annealing. cost and neighbor are unary lambdas (or named functions): cost returns a finite number to minimize, neighbor returns a candidate state. Optional options:

Returns { state, cost, steps }. Acceptance uses math.random(), so math.seed(n) makes a run reproducible. Like other RNG helpers, anneal is WF1001 outside a workflow step.

math.seed(1);
var result = math.anneal(0.0, x => x * x, x => x, { steps: 5 });
print(result.cost == 0.0);
print(result.steps);
math.seed(7);
var result = math.anneal(
    10.0,
    x => (x - 3.0) * (x - 3.0),
    x => x + math.randomFloat(-1.0, 1.0),
    { steps: 800, temp: 2.0, cooling: t => t * 0.995 }
);
print(result.state);
print(result.cost);

13.4 String Functions

Preferred spelling is str.*. The same names also work as methods on a string value ("hello".upper()). Flat globals are deprecated aliases (see 13.2).

Interpreter, C# transpile, and JavaScript all run str.*. See the backend capability matrix.

print(str.lower("HELLO"));
print(str.startsWith("Hello", "He"));
ArgumentsReturnsNotes
str.base64Decode(x)
1 argument—
str.base64Encode(x)
1 argument—
str.endsWith(str, suffix)
2 arguments: (str, suffix)—
str.extractNumbers(x)
1 argument—
str.includes(array, value)
2 arguments: (array, value)—
str.indexOf(string, string)
(string, string)—
str.join(array, separator?)
1-2 arguments: (array, separator?)—
str.length(x)
1 argument—accepts a string or an array
str.lower(x)
1 argument—
str.md5(x)
1 argument—
str.normalizeText(string, options?)
(string, options?)—
str.padEnd(str, length, padChar?)
2-3 arguments: (str, length, padChar?)—
str.padStart(str, length, padChar?)
2-3 arguments: (str, length, padChar?)—
str.regexFind(string, string)
(string, string)—
str.regexMatch(string, string)
(string, string)—
str.regexReplace(string, string, string)
(string, string, string)—
str.repeat(str, count)
2 arguments: (str, count)—count must be an integer or a whole-valued float; fractional floats are rejected
str.replace(string, string, string)
(string, string, string)—
str.sha256(x)
1 argument—
str.similarity(string, string, method?, options?)
(string, string, method?, options?)—
str.split(string, string?, bool?)
(string, string?, bool?)—
str.startsWith(str, prefix)
2 arguments: (str, prefix)—
str.substring(string, int, int)
(string, int, int)—
str.text(value)
1 argument: (value)string (never null)null → empty string (unlike string(null) → "null"); use at env/JSON/CLI boundaries
str.tokenize(string, options?)
(string, options?)—
str.tokenOverlap(string, string, options?)
(string, string, options?)—
str.trim(x)
1 argument—
str.trimText(value)
1 argument: (value)string (never null)null-safe trim: str.trim(str.text(value))
str.upper(x)
1 argument—

str.substring(text, startIndex, length) — the third argument is a count, not an end index. str.text(value) maps null to "" (unlike string(null) → "null"). str.trimText(value) is str.trim(str.text(value)). Use those at env / JSON / CLI boundaries. str.repeat rejects a fractional count.

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 the first argument.

print("hello".upper());                 // HELLO
print("HELLO".lower());                 // hello
var s = "Hello";
print(s.substring(0, 3));               // Hel
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()) is a runtime error. Path helpers (io.pathJoin, io.isPathUnder, …) are in 13.8. ~/.malda helpers are in 13.5.

13.5 Environment and Host

How-to and the getEnv / str.trim footgun: 12.5 Environment and Host. Host-only (interpreter and C# transpile); JavaScript does not read the process environment or call Brave / webFetch. See the backend capability matrix.

ArgumentsReturnsNotes
getAssistantMemory(path?)
0-1 arguments: (path?)—
getCommandLineArgs()
0 arguments—
io.getEnv(x)
1 argumentstring, or null when the variable is not setunlike io.input (which returns empty string at EOF), missing variables yield null — prefer io.getEnvOr or str.trimText before string sinks
io.getEnvOr(name, default?)
1-2 arguments: (name, default?)string (never null)never null; missing variables yield default (empty string when omitted) — preferred before str.trim
getHostPlatform()
0 arguments—
getMaldaConfig()
0 arguments—
getMaldaHome()
0 arguments—
getProgramDirectory()
0 arguments—
getSkillNames()
0 arguments—
io.hasEnv(x)
1 argument—
httpAuthToken
request and optional options object—
httpBearerToken(request)
1 argument: (request)—
httpCookieToken
request, cookieName, optional cookieSecret—
loadSkill(name)
1 argument: (name)—
loadSkillsFromDir(skillsPath?)
0-1 arguments: (skillsPath?)—
webFetch(urlOrToken, pathOrMaxBytes?, maxBytes?, timeoutMs?)
1-4 arguments: (urlOrToken, pathOrMaxBytes?, maxBytes?, timeoutMs?)—
webSearch(query, apiKey?)
at least 1 string argument: (query, apiKey?)—

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"
});

Wire these into handlers with req.auth — see 13.25 and 29.6.2.

13.5.4 webFetch(url, maxBytes?, timeoutMs?)

Signature catalog for fetching an http:// or https:// URL on the host path used by httpGet. How-to, caps, and the return shape: 12.9 Fetching URLs. Typed REST calls: 30. REST Web Client. The agent factory is createWebFetchTool.

13.6 Array Utility Functions

math.sum / math.average / math.min / math.max are in 13.3 and also work as array methods. The rows below are the array-only helpers. Interpreter, C# transpile, and JavaScript all run these.

print(str.join(reverse([1, 2, 3, 4, 5]), ", "));
print(includes([1, 2, 3], 3));
ArgumentsReturnsNotes
str.includes(array, value)
2 arguments: (array, value)—
str.join(array, separator?)
1-2 arguments: (array, separator?)—
reverse(x)
1 argument—
sort(array, compareFn?)
1-2 arguments: (array, compareFn?)—
toCsv(rows, columns?, options?)
1-3 arguments: (rows, columns?, options?)—

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

Catalog of JSON / schema helpers. toJSON, parseJSON, validate, and asVariant run on interpreter, C# transpile, and JavaScript. evalPrompt is host-only (prompts). See the backend capability matrix.

ArgumentsReturnsNotes
asVariant(typeName, value)
2 arguments: (typeName, value)variantthrows if typeName is not a sum type or the tagged JSON is invalid; already-a-variant is idempotent; validate() does not coerce
evalPrompt(prompt, fixture, typeName?)
2-3 arguments: (prompt, fixture, typeName?){ ok, data } | { ok: false, error }no LLM; same extract/validate/coerce path as await; {ok,data} or {ok:false,error}; data is a variant for sum types; instance.eval(fixture) is the same helper
parseJson(value, schemaRef) and optional options object. For a plain JSON reader use parseJSON(text)
2 arguments (value, schemaRef) and optional options object. For a plain JSON reader use parseJSON(text)—schema-validating parser for LLM output, NOT a plain JSON reader
parseJSON(the JSON string). For schema-validated LLM JSON use parseJson(value, schemaRef)
1 argument (the JSON string). For schema-validated LLM JSON use parseJson(value, schemaRef)—plain JSON text to a value; note that parseJson with a lowercase s is a different built-in
toJSON(x)
1 argument—
validate(schema, value)
2 arguments: (schema, value)—
var jsonStr = toJSON(obj);  // Convert object to JSON string
var obj = parseJSON('{"name":"Alice","age":30}');  // Parse JSON string to object

toJSON writes dicts, arrays, and the public instance fields of a class (including a primary constructor). Methods and private fields are omitted. A cycle throws. parseJSON always returns a dict — it does not reconstruct the class. Build a new instance yourself if you need methods again.

class Point(x, y);
var d = parseJSON(toJSON(new Point(3, 4)));
print(d.x);
print(d.y);

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.

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 asVariant("Intent", dict) or await prompt … -> Intent when you need a variant for match. The agent factory is createValidateJsonTool (no working directory; parallel-safe); it returns the same { ok, data } / { ok: false, error } object.

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);
Not to be confused with: memory.validate() on a GraphMemory instance, which checks graph integrity rather than a schema. The two share a name but are unrelated.

13.7.1.1 asVariant(typeName, value)

Turns a tagged dict into a sum-type variant so match can bind constructors. validate("Intent", dict) never does this. An already-built variant is returned as-is when its tag belongs to the type. Mismatch (unknown type name, object schema, bad tag, typed payload that fails JSON Schema) throws — unlike validate.

type Intent = Search(query: string) | Buy(sku: string, qty: int) | Help();
var tagged = dict { "tag": "Buy", "sku": "SKU-9", "qty": 2 };
var checked = validate("Intent", tagged);
var label = match asVariant("Intent", checked.data) {
    case Search(q): "search " + q;
    case Buy(sku, qty): "buy " + sku + " x " + qty;
    case Help(): "help";
};
print(label);

See Examples/Basics/as_variant.malda and docs/llm/few-shot/25_as_variant.malda.

13.7.1.2 evalPrompt(prompt, fixture, typeName?)

Offline fixture in/out on a PromptInstance. Does not call an LLM, consume @budget, or run a gather tool round. The fixture is a dict/object or an LLM-shaped JSON string (markdown fences and a surrounding { … } extract the same way await does). The result shape matches validate:

The type comes from the instance’s declared -> Type (instance.returnType), including Mode C gather: instances that have not attached response_format yet. Pass optional typeName to override. instance.eval(fixture, typeName?) is the same helper. Pipe-friendly: p |> evalPrompt(fixture).

schema Card {
    name: string;
}

prompt extract(raw) -> Card {
    user: raw;
}

var p = extract("Ada Lovelace");
var checked = evalPrompt(p, dict { "name": "Ada" });
if (checked.ok) {
    print(checked.data.name);
}
type Intent = Search(query: string) | Buy(sku: string, qty: int) | Help();
prompt parseUtterance(text) -> Intent {
    user: text;
}
var checked = evalPrompt(parseUtterance("buy"), dict { "tag": "Buy", "sku": "SKU-9", "qty": 2 });
var label = match checked.data {
    case Search(q): "search " + q;
    case Buy(sku, qty): "buy " + sku + " x " + qty;
    case Help(): "help";
};
print(label);

See Examples/Prompts/eval_prompt.malda and docs/llm/few-shot/27_eval_prompt.malda.

13.7.2 AI Pipeline Functions

How-to, worked pipes, and the signature table live in 10.9.1 AI pipeline helpers. Vector index + asRetriever: 16. VectorDB. Offline fixtures: 13.7.1.2 evalPrompt.

Catalog names: loadDocuments, splitDocuments, indexInto, formatRetrievedDocs, composePipe, parallelRun, mergeRetrievedDocs, withExamples, evalPrompt, runPrompt, parseJson.

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. File I/O is host-only (interpreter and C# transpile); JavaScript has io.print / io.input / JSON, not disk files. See the backend capability matrix.

ArgumentsReturnsNotes
io.copyFile(src, dest)
2 arguments: (src, dest)booleanbinary-safe overwrite; returns false on I/O failure; rejects embed: src and dest; does not create parent directories
io.deleteFile(x)
1 argument—
editFile(string, array)
(string, array)—
io.embeddedFolderRoot(alias)
1 argument: (alias)—
io.ensureDir(x)
1 argument—
extractDocxText(path)
1 argument: (path)—
extractPdfText(path, password?)
1-2 arguments: (path, password?)—
io.getDirectoryName(x)
1 argument—
io.getFileName(x)
1 argument—
io.glob(pattern, dirPath?, ...)
at least 1 argument: (pattern, dirPath?, ...)—
io.grep(pattern, filePath, ...)
at least 2 arguments: (pattern, filePath, ...)—
io.hasDirectory(x)
1 argument—
io.hasEmbeddedFolder(alias)
1 argument: (alias)—
io.hasFile(x)
1 argument—
insertAtLine(filePath, lineNumber, content, ...)
at least 3 arguments: (filePath, lineNumber, content, ...)—
io.isPathUnder(root, path)
2 arguments: (root, path)—
io.listDirectory(x)
1 argument—
io.pathExists(x)
1 argument—
io.pathGetExtension(x)
1 argument—
io.pathJoin
at least 1 argument—
io.pathNormalize(x)
1 argument—
io.readFile(string, int?, int?)
(string, int?, int?)—
io.readFileBase64(x)
1 argument—
io.readTextFileLines(x)
1 argument—
io.replaceInFile(string, string, string, int?)
(string, string, string, int?)—
io.writeFile(a, b)
2 arguments—
io.writeFileBase64(path, base64Content)
(path, base64Content)—
io.writePng(path, width, height, pixels)
(path, width, height, pixels)—
io.readPng(path)
1 argument—

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

ReturnsBehavior
pdf.extractText(path, password?)
stringExtracts 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)
stringExtracts 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 nullReads the file as UTF-8 and splits it into lines. Returns null when the file is missing or cannot be read.
deleteFile(path)
booleanDeletes the file. Returns true when the file was deleted or was already absent; false on an empty path or an I/O failure.
copyFile(src, dest)
booleanCopies the file as bytes (overwrites dest). Returns false on I/O failure. Rejects embed: source and dest. Does not create parent directories. Prefer io.copyFile.
insertAtLine(path, lineNumber, content, insertAfter?)
booleanInserts content (which may span several lines) at a 1-indexed line. Returns false if the file does not exist.
readFileBase64(path)
string, or nullReads the file as bytes and returns base64. Returns null when the file is missing.
writeFileBase64(path, base64Content)
booleanDecodes base64 and writes the bytes. Returns false when the input is not valid base64 or the write fails.
io.writePng(path, width, height, pixels)
booleanWrites an 8-bit RGBA PNG. pixels is a flat array of length width * height * 4 (R, G, B, A). Channels are rounded to the nearest integer and clamped to 0–255. Returns false on I/O failure. Rejects embed: paths. Throws when the size is not positive, the image is larger than 16 megapixels, the array length does not match, or a channel is not a number.
io.readPng(path)
object, or nullReads an 8-bit non-interlaced PNG (grayscale, gray+alpha, RGB, or RGBA) and returns { width, height, pixels } with a flat RGBA array. Returns null when the file is missing or is not a decodable PNG of that kind. Indexed, 16-bit, and interlaced images return null.
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);

var px = [255, 0, 0, 255];
io.writePng("pixel.png", 1, 1, px);
var image = io.readPng("pixel.png");

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.

Failure style: readTextFileLines, deleteFile, insertAtLine, the base64 helpers, and io.readPng / io.writePng 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 (io.writePng also raises when the pixel buffer does not match width and height). 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, io.writePng / io.readPng, pdf.extractText / extractPdfText, and doc.extractText / extractDocxText are supported by the C# transpiler. The JavaScript backend does not implement io.writePng or io.readPng.

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?)
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?)
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");
Errors are returned as strings: when the path does not exist, or a regular expression is invalid, 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 }
        // mode is interpreter (default), transpile (C#), or js (browser). game.*/dom.*/three.* need js.
        var gameJs = compileMALDA("game.malda", "game.js", "js");

13.11.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, imports, 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. Each import has file?, resolvedPath?, package?, alias?; unresolved modules are not flagged here (use checkMalda, whose malda-import warning names the missing path). 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.imports, sym.parseErrors

13.11.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 []

13.11.3 checkMalda(sourceOrFilePath, typeMode?, workingDir?)

Diagnoses MALDA code with the same LanguageService diagnostics as malda check --json (parser, types, schema/sum-type names, interpolation). Does not execute the program. Accepts a file path or inline source (same path heuristic as getParseErrors). Optional typeMode is default (IDE: type mismatches are errors), strict (full CLI suite), or lenient (type mismatches as warnings). Returns { ok, executed: false, file, errorCount, warningCount, infoCount, error?, diagnostics }. Each diagnostic has severity, code, message, file?, line, column (1-based), length, hint?, suggestedFix?. The agent factory is createCheckMaldaTool.

var report = checkMalda("var x = 1;");
print(report.ok);          // true
var typed = checkMalda("var n: int = \"abc\";", "lenient");
print(typed.ok);           // true (mismatch is a warning)
Command Execution Safety: The runCommand function includes comprehensive safety checks:

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);
        }
    }
});
Markup and Line Endings:
Progress API:
Where Spectre.Console Renders:

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
Date/Time Format:

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)
Reproducible Randomness:

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)
Hash Functions:

Password hashes, JWT, CSRF, and signed cookies are not digest helpers — see 13.25.

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
Error Handling:

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));
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);

13.19.3 cap.fileRead

This subsection is the signature catalog. If you have not used tokens before, start with the how-to in 12.6 Capability tokens — why they exist, the key analogy, cap.confine, and the host-mint pattern for tools.

A token is a sealed host object with kind and path (and name for an MCP tool). JSON and object literals cannot rehydrate one. @effects("io") only names the effect; it does not bind a path, URL, tool, or argv.

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);

13.19.4 expect

Throws like assert when the condition is false. Used in suite cases; malda eval runs those cases. validate still returns { ok, error }. See 24.1.

expect(checked.ok);
expect(n > 0, "n must be positive");

13.19.5 stream

Yields an array of { text } chunks, or schema-aware partials when a registered schema name is passed. LlamaCpp is buffered, not live tokens. Iterate with for await. See 24.8.

var chunks = stream("hello world from malda");

13.19.6 race / firstOk

race is the first completed branch. firstOk is the first branch that is not a Timeout variant. all waits for every branch and puts AgentError.Upstream in failed slots. See 24.4.

race(taskA, taskB);
firstOk(taskA, taskB);

13.19.7 trace.span / trace.journal / trace.lastUsage

In-process run journal: prompt, tool, cap, hop, and workflow-step events. .usage on a prompt result is metadata (own key wins). See 24.3.

trace.span("name", () => { });
var events = trace.journal();
var spend = trace.lastUsage();

13.19.8 AgentError

Built-in sum type attached as agentError beside the string error. Throws still throw. validate mismatch → SchemaMismatch. See 24.7.

AgentError = Refused(reason) | Unparsable(raw, attempts) | SchemaMismatch(schema, error)
           | BudgetExceeded(kind, limit) | ToolDenied(tool, reason) | Timeout(ms)
           | Upstream(status, body)

13.20 Structured Task Planning

decomposeTask, executePlan, createSubmitPlanTool, createUpdatePlanTool, and createMarkStepTool live in 19. Agent Orchestration (§ 19.13). agents.define / agents.team bind role specs to a directed graph; executePlan(plan, team) honors step.role and declared hops, branches reject hops on the predecessor approved verdict, and accepts plan.think: false to stay offline — see § 19.17. team.handoff / team.review / team.reject / team.consult are typed hops and stay validate-only unless think is true. 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, createWebFetchTool, createGitStatusTool, createGitAddTool, createGitCommitTool, createGitLogTool, createGitDiffTool, createGitBranchTool, createGitCheckoutTool, createGitPushTool, createGitPullTool, createRunCommandTool, createRunMALDATool, createCompileMALDATool, createGetSymbolsTool, createGetParseErrorsTool, createCheckMaldaTool, createValidateJsonTool, createTestMaldaTool, createSubmitPlanTool, createUpdatePlanTool, createMarkStepTool, createGlobTool, createCreateMcpAgentScriptTool, createDeleteFileTool, createCopyFileTool, createEnsureDirTool) live in 19. Agent Orchestration (§ 19.6). createNativeCallback wraps a MALDA function as a .NET delegate — see 32. .NET Interop.

13.22 Durable Workflow Operations

Runtime, query, and control helpers (startWorkflow, getWorkflowStatus, getWorkflow, getWorkflowSteps, getWorkflowEvents, getWorkflowMetrics, listWorkflows, listWorkflowDeadLetters, requeueDeadLetter, runWorkflowInstance) live in 23. Durable Workflows.

13.23 Agent Runtime Logging

Diagnostic helpers (enableAgentVerboseLogging, setAgentVerbosePhase, setAgentStatusBanner, reportRalphStatus) live in 19. Agent Orchestration (§ 19.5 and 19.19 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, cancelThink) and ui.* controls live in 26. Web UI Server Components. Start from 25. Web UI Overview if you are choosing a UI model.

13.25 Password, JWT, and request auth

Signature how-to for HTTP lives in 29.16 Password, JWT, and cookie helpers. Request principal: 29.6.2 req.auth. Primers: password hashing, JWT, CSRF.

Catalog names: hashPassword, verifyPassword, createJwt, verifyJwt, generateCsrfToken, verifyCsrfToken, csrfField, createSecureCookie, readSecureCookie, httpBearerToken, httpCookieToken, httpAuthToken, bindForm, formErrors, pageLayout. Handler surface: req.auth.authenticateBearerJwt, authenticateCookieJwt, requireRole, requirePermission, setVerifiedSub.

13.26 Background jobs

Lightweight SQLite queue (enqueueJob, claimJob, completeJob, failJob, getJob, listJobs) — not a durable workflow. How-to: 23.11 Lightweight job queue.

13.27 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