Reference
Builtins index
A categorized map of the built-ins. The full signatures live on each topic page; the core ones are doctested here so this reference can't drift.
-- Doc reference: a few core builtins, doctested so the reference can't drift.
intent: "doc reference: core builtins"
print("upper(\"hi\") = " + upper("hi") + ", join([a,b],\"-\") = " + join(["a", "b"], "-"))
test "collections"
assert_eq(length([1, 2, 3]), 3)
assert(contains([1, 2, 3], 2))
assert_eq(slice([1, 2, 3, 4], 1, 3), [2, 3]) -- Python-style end-exclusive
assert_eq(keys({"a": 1, "b": 2}), ["a", "b"])
assert_eq(values({"a": 1, "b": 2}), [1, 2])
test "text"
assert_eq(upper("hi"), "HI")
assert_eq(trim(" x "), "x")
assert_eq(split("a,b,c", ","), ["a", "b", "c"])
assert_eq(join(["a", "b"], "-"), "a-b")
assert(starts_with("hello", "he"))
test "intentional ops"
assert_eq(apply((n) => n * 2, [1, 2, 3]), [2, 4, 6])
assert_eq(where([1, 2, 3, 4], (n) => n > 2), [3, 4])
assert_eq(reduce([1, 2, 3], (a, b) => a + b, 0), 6)
test "intentional ops accept both orders (fn-first and list-first)"
assert_eq(apply([1, 2, 3], (n) => n * 2), [2, 4, 6]) -- list-first also works
assert_eq(where((n) => n > 2, [1, 2, 3, 4]), [3, 4]) -- fn-first also works
assert_eq(reduce((a, b) => a + b, [1, 2, 3], 10), 16) -- extra args stay at the end
test "unique and index_of"
assert_eq(unique([3, 1, 3, 2, 1]), [3, 1, 2]) -- first-appearance order
assert_eq(index_of([10, 20, 30], 20), 1) -- by item
assert_eq(index_of([1, 2, 3], (n) => n > 1), 1) -- by predicate
assert_eq(index_of([1, 2], 9), nothing) -- absent → nothing, not -1
assert_eq(index_of("héllo", "llo"), 2) -- on text: the character position
test "reverse and split(text, \"\") (engine v0.6.20+)"
assert_eq(reverse([1, 2, 3]), [3, 2, 1]) -- a NEW list; the original is untouched
assert_eq(reverse("abc"), "cba") -- text too (by Unicode scalar)
assert_eq(split("abc", ""), ["a", "b", "c"]) -- empty separator → the characters
assert_eq(split("", ""), [])
test "renamed in v0.6.29: the new names (the old ones are deprecated aliases until v1.0)"
assert_eq(replace("a-b-c", "-", "+"), "a+b+c") -- was replace_text
assert_eq(regex_find_all("a1b2", "[0-9]"), ["1", "2"]) -- was find_all
assert_eq(regex_replace("a1b2", "[0-9]", "#"), "a#b#") -- was replace_re
assert_eq(fold_text("Continúa"), "continua") -- was fold
assert_eq(identity(2), array([[1, 0], [0, 1]])) -- was eye
-- regex_capture (was capture) is ALWAYS a list, or nothing
assert_eq(regex_capture("2026-09", "([0-9]+)-([0-9]+)"), ["2026", "09"]) -- the groups
assert_eq(regex_capture("hello world", "w[a-z]+"), ["world"]) -- no groups → [match]
assert_eq(regex_capture("abc", "[0-9]+"), nothing)
-- hmac (was hmac_sha256) returns BYTES; hmac_sha256 returned hex text
let mac be hmac("data", "key")
assert_eq(type_of(mac), "bytes")
assert_eq(hex(mac), "0x" + decode(mac, "hex"))
test "maps and lists: get, items, merge, remove, insert, sort desc (v0.6.29+)"
assert_eq(get({"a": 1}, "b", 0), 0) -- Python's d.get(k, default)
assert_eq(get({"a": 1}, "b"), nothing)
assert_eq(get([1, 2, 3], -1), 3) -- lists too; negative from the end
assert_eq(items({"x": 1}), [{"key": "x", "value": 1}])
assert_eq(merge({"a": 1, "b": 2}, {"b": 3, "c": 4}), {"a": 1, "b": 3, "c": 4}) -- rightmost wins
assert_eq(remove({"a": 1, "b": 2}, "a"), {"b": 2}) -- a NEW map
assert_eq(insert([1, 2, 3], 1, 9), [1, 9, 2, 3])
assert_eq(sort([3, 1, 2], desc = true), [3, 2, 1])
assert_eq(sort_by([{"n": 1}, {"n": 2}], (r) => r.n, desc = true), [{"n": 2}, {"n": 1}])
test "type predicates and exact integers (v0.6.29+)"
assert(is_integer(1) and not is_integer(1.0))
assert(is_text("a") and is_list([]) and is_map({}))
assert_eq(int("ff", base = 16), 255) -- the base goes by name
assert_eq(int("abc", fallback = 7), 7) -- so does the fallback
assert_error(() => int("ff", 16)) -- 2..36 in second place: ambiguous → error
assert_eq(hex(7960), "0x1f18")
assert_eq(int("0x1f18"), 7960)
assert_eq(7 // 2, 3) -- floor division
assert_eq(-2 ** 2, -4) -- ** binds tighter than unary minus
test "strict arity (v0.6.29+): extra or missing arguments are errors"
task one(a)
give a
task two(a, b)
give a
assert_error(() => append([1], 2, 3)) -- was: the 3 silently dropped
assert_error(() => one(1, 2))
assert_error(() => two(1)) -- was: b arrived as nothing
test "text + nothing is an error; fmt is strict; a template hole takes any value"
assert_eq("n=" + 1, "n=1") -- text + number still joins
assert_error(() => "n=" + nothing)
assert_error(() => "xs=" + [1, 2])
assert_eq(`xs={[1, 2]} n={nothing}`, "xs=[1, 2] n=nothing")
assert_error(() => fmt("{a} {b}", {"a": 1})) -- a {name} without a value
assert_eq(fmt("^[0-9]{3}-{n}$", {"n": 1}), "^[0-9]{3}-1$") -- not a name → stays literal
assert_eq(text(["1", 1]), "[\"1\", 1]") -- text inside a list is shown quoted
test "lists and maps are values (v0.6.29+): a task gives back what it changes"
let xs be [1, 2]
let ys be xs
set ys[0] to 9
assert_eq(xs, [1, 2]) -- only ys changed
task mark(cfg)
set cfg["seen"] to true
give cfg
let c be {"seen": false}
mark(c)
assert_eq(c["seen"], false) -- the task changed its own copy
set c to mark(c)
assert_eq(c["seen"], true) -- the change leaves with `give`
test "tables and statistics (v0.6.29+)"
let rows be [{"region": "n", "amount": 1}, {"region": "s", "amount": 2}, {"region": "n", "amount": 3}]
let groups be group_by(rows, "region") -- [{key, items}], first-appearance order
assert_eq(groups[0].key, "n")
assert_eq(length(groups[0].items), 2)
assert_eq(summarize(rows, "region", {"total": sum_of("amount")}), [{"region": "n", "total": 4}, {"region": "s", "total": 2}])
assert_eq(count_by(["x", "y", "x"]), [{"key": "x", "count": 2}, {"key": "y", "count": 1}])
assert_eq(mean([1, nothing, 3]), 2.0) -- reductions skip nothing
assert(std([1, 2, 3, 4]) > std([1, 2, 3, 4], ddof = 0)) -- sample by default, like pandas
test "dates, seeded randomness, Parquet and JSON Lines (v0.6.29+)"
assert_eq(add_days(date("2026-09-24"), 7), date("2026-10-01"))
assert_eq(type_of(datetime("2026-09-24T10:00:00Z")), "datetime")
assert_eq(in_units(duration(hours = 1, minutes = 30), "minutes"), 90.0)
assert_eq(rng(42)(), 0.7739560485559633) -- numpy.random.default_rng(42).random()
let rows be [{"a": 1, "day": date("2026-09-24")}]
assert_eq(parquet_read(parquet_write(rows)), rows)
assert_eq(jsonl_decode(jsonl_encode([{"a": 1}])), [{"a": 1}])
test "EVM names (v0.6.29+): pure helpers under the evm_/abi_ prefixes"
assert_eq(abi_event_topic("Transfer(address,address,uint256)"), "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef")
assert_eq(evm_create_address("0x0000000000000000000000000000000000000001", 0), "0x522B3294E6d06aA25Ad0f1B8891242E335D3B459")
test "steps() counts executed statements — deterministic, no capability (engine v0.6.20+)"
let before be steps()
each i in range(100)
let x be i
assert(steps() - before > 100)
test "program & subprocess: args() and self_path() (no capability)"
assert_eq(type_of(args()), "list") -- the program's argv (empty under `synsema test`)
assert_eq(type_of(self_path()), "text") -- this executable's path
assert(length(self_path()) > 0)Renamed in v0.6.29§
v0.6.29 fixed the names once, before v1.0. The old name is a deprecated alias: it still runs, a program that uses one prints a single warning on stderr when it loads (also for a module loaded with use, v0.6.30+), synsema check flags every use, and it goes away in v1.0. Write the new name — and read the "meaning" column, because three of them do not return the same thing:
| Old | New | Meaning |
|---|---|---|
replace_text | replace | same |
find_all | regex_find_all | same |
replace_re | regex_replace | same |
capture | regex_capture | changed: always a list — the groups, or [match] when the pattern has none — or nothing. The old capture returned the bare match text without groups, and still does |
fold | fold_text | same (lowercase + strip accents; not Python's casefold) |
eye | identity | same (numeric arrays) |
hmac_sha256(data, key) → hex text | hmac(data, key, algo?) → bytes | changed: hex(mac) shows it as "0x…", decode(mac, "hex") gives the old bare hex |
eth_rpc, eth_nonce, eth_balance, eth_gas_price, eth_chain_id, eth_estimate_gas, eth_call, eth_fee_history | evm_rpc, evm_nonce, evm_balance, evm_gas_price, evm_chain_id, evm_estimate_gas, evm_call, evm_fee_history | same. The JSON-RPC method names you pass to evm_rpc stay "eth_call", "eth_getLogs", … |
eth_send_raw, eth_receipt, eth_wait_receipt, eth_address | evm_send, evm_receipt, evm_wait, evm_address | same |
tx_eip1559, tx_eip1559_raw | evm_tx, evm_tx_raw | same; contract creation is the new evm_tx_create, and evm_tx without to is an error that points there |
solana_message (builds) | solana_tx(params) | the name solana_tx changed meaning: it now BUILDS the message |
solana_tx(message, signatures) (assembles) | solana_tx_raw(message, signatures) | the old two-argument solana_tx call is an error that points to solana_tx_raw |
solana_confirm | solana_wait | same |
algorand_tx_encode (bytes to sign) | algorand_tx(txn) | the name algorand_tx changed meaning: it now returns the bytes to sign |
algorand_tx(txn, sig) (signed) | algorand_tx_raw(txn, sig) | the old two-argument algorand_tx call is an error that points to algorand_tx_raw |
algo_address | algorand_address | same |
Unchanged on purpose: matches, find_first, read_file(path, line, limit). Blockchain follows <family>_<action> (Bitcoin already did: btc_tx/btc_tx_raw/btc_send/btc_wait).
Rules every builtin follows (v0.6.29+)§
- Strict arity. A builtin given more than its maximum is an error (`append() takes at most 2
arguments, got 3); before, the extras were dropped in silence (trim(s, "x") ignored the "x"). A task or lambda you call with a missing argument (task 'f' is missing argument 'b') or an extra one (task 'f' takes 1 argument, got 3) is an error too. Builtins take arguments by position, except the documented named forms (sort/sort_by desc = true, int base = / fallback =, std/var ddof =, recall(from = …), random_normal(g, mean =, std =), duration(hours = …), …). Callbacks that a builtin or the host calls (apply, where, reduce`, route handlers, cron) still receive what they get.
- Lists and maps are values. A builtin never changes the list or map you pass it:
append,
insert, merge, remove, sort, reverse return a new one (and set xs to append(xs, v) is O(1), it writes in place when nobody else holds the list). A task that sets inside a map it received changes its own copy — give it back. Shared state stays explicit: blackboard, memory, bus, state_* — see Multi-agent and Memory & state.
- Text +
nothing/list/map/bytes/task is an error (`Cannot add text and nothing — convert it on
purpose); text + number/bool still joins. A template hole takes any value: xs={xs} n={nothing} → xs=[1, 2] n=nothing. join(xs, sep)` refuses the same items.
fmtis strict: a{name}with no value in the map is an error ({{name}}for a literal
brace); braces that do not surround a name — JSON, CSS, regex quantifiers such as {3} — stay literal.
- Inside a list or map, text is shown quoted:
print(["1", 1])→["1", 1]; a top-level
print("x") is unchanged.
By category§
- Core / conversion:
print,eprint(v0.6.42+: likeprint, to stderr),exit(code?)(v0.6.42+: ends asynsema runwith that code;trydoes not catch it; v0.6.45+: also aserveprogram before it listens — see CLI),length,text,number(always a float; an integer text beyond ±2⁵³ is an error that namesint),int(x)(exact, any size;int(text, base = 16),int(x, fallback = 0)— an integer 2..36 as the second positional argument is an error, because it reads as a base to a Python eye and as a fallback to the engine),hex(x)(an integer →"0x1f18", bytes → every byte),decimal,float,type_of(also"date","datetime","duration"), predicatesis_integer(is_integer(1.0)isfalse),is_text,is_list,is_map(v0.6.29+),is_bytes,is_decimal,is_complex,is_array,is_missing. - Collections:
length,contains,slice,keys,values,items(v0.6.29+:[{key, value}, …]),get(map, key, default?)(v0.6.29+: Python'sd.get; alsoget(list, i, default)),merge(a, b, …)(v0.6.29+: a new map, the rightmost value wins),remove(map, key)(v0.6.29+: a new map),append,insert(list, i, item)(v0.6.29+; out of range is an error, Python clamps),range(integer arguments only),sort(list, desc = true)andsort_by(list, key, desc = true)(a total, stable order —nothingand NaN last, mixed incomparable types an error),apply,where,reduce,find_first,every,some,collect,count_where,flatten,chunk(an integer size),zip_with,reverse(engine v0.6.20+: a new list in reverse order; on text, the characters reversed),unique(dedupe, first-appearance order, structural equality),index_of(0-based index of item or predicate match; absent →nothing, not -1; on text, the character position, v0.6.29+).enumerate(list)→[{index, item}, …]for indexed loops (language and templates). Operators (v0.6.29+):x in xs/x not in xs, negative indexesxs[-1], one characters[0]; an index must be an integer (xs[1.7]is an error,xs[1.0]is fine). The intentional ops that take a callable accept both orders —apply(fn, list)andapply(list, fn)read equally well; two tasks or two lists where one-and-one is expected is an explicit error. v0.6.46+:enumeratealso takes an array and walks its first axis (eachitema number for 1-D, the row for 2-D+; a 0-d array is an error). - Text:
upper,lower,fold_text(wasfold),trim,starts_with,ends_with,split(split(t, "")→ the characters, v0.6.20+),join,replace(wasreplace_text),index_of,min/maxon text,text,fmt(strict, see above),strip_ansi(engine v0.6.8+: terminal output → plain text; CSI/OSC/charset escapes and control bytes removed,\rredraws keep the last frame). - Regex (pure):
matches(a full match),regex_find_all(wasfind_all),regex_capture(wascapture— always a list ornothing),regex_replace(wasreplace_re). - Numbers / math:
+ - * / %and floor division//(exact for integers of any size; float//and%are CPython's),-2 2is-4,|>passes the value as the first argument of a call step; literals0x1f18,0o17,0b101,1_000,1e-9; constantspi/tau/e/inf/nan;abs,sign,min,max,clamp,sqrt,cbrt,hypot,pow,exp,ln,log10,log2,log_base,floor,ceil,round,trunc(exact integers, also from a decimal),round_to(a float's real binary value, like Python:round_to(2.675, 2)is2.67; decimals round half to even),sin/cos/tan/asin/acos/atan/atan2,radians/degrees,sinh/cosh/tanh/asinh/acosh/atanh,gcd,lcm,factorial,is_nan/is_infinite/is_finite,gamma/lgamma/erf/erfc/beta;decimal(arbitrary precision since v0.6.29;decimal("1.5e-3")with an exponent, v0.6.30+; a decimal compared with a float is an error),complex/real/imag/conj/arg; arraysarray,arange,linspace,zeros,ones,identity(waseye),full,reshape,shape,ndim,size,transpose,trace,dot(two vectors only, v0.6.29+),norm,matmul(matrices),solve,det,inv,eig,svd,concat,stack,cumsum,diff,argmin,argmax;bytes_to_int,int_to_bytes,int_to_bytes_le— see Bytes, math & arrays. - Bytes / crypto:
bytes,decode(encodings:utf8,hex,base64,base64url,base58,base32),sha256,sha512,hmac(data, key, algo?)→ bytes (washmac_sha256, which returned hex text;data/keytext, bytes — raw since v0.6.44 — or a secret),verify_hmac,constant_time_eq,basic(user, secret)/oauth_basic(client_id, secret)(v0.6.44+, HTTP Basic as a secret),xor_bytes(a, b)(v0.6.44+, same length); bits on 64-bit integers (v0.6.44+):bit_and,bit_or,bit_xor,bit_not,shl,shr; ECDH / HKDF / AES-GCM (engine v0.6.20+ — see Bytes, math & arrays):ecdh_keypair(curve)(require random),ecdh_shared_secret,ecdh_public(private, curve)(v0.6.42+), curves"P-256","P-521"and"X25519"(v0.6.42+),hkdf_sha256,aes_gcm_encrypt,aes_gcm_decrypt. - Web auth (engine v0.5.5+ — see Login & sessions):
password_hash,password_verify,jwt_sign(HS256; RS256/ES256 with a PEM secret viaopts.alg/opts.kid, v0.6.20+),jwt_verify(HS256),rsa_sign_sha256/rsa_verify_sha256,ecdsa_p256_sign/ecdsa_p256_verify(v0.6.20+),totp,totp_verify(pure);random_bytes,token(require random); responseswith_header,set_cookie,clear_cookie;request.cookies; 2-paramauth withtask. - Web Push (engine v0.6.15+ — see Your app on the phone):
push_vapid_keys()→{public, private}(require random; the private key comes back as asecretlabelledvapid_private);push_send(subscription, payload, opts)→{status, ok, gone, retry_after, body}(require net("<host of the endpoint>")—fcm.googleapis.comandjmt17.google.com(Chrome uses either),*.notify.windows.com,updates.push.services.mozilla.com,web.push.apple.com;opts.vapid = {public, private: secret, subject}required,ttl,urgency,topic,timeout; payload text / map→JSON / bytes /nothing, ≤ 3993 bytes;goneon 404/410). RFC 8291aes128gcm+ RFC 8292 VAPID, no provider needed; not in the wasm profile. - Agent identity & auth (engine v0.5.6+ — see Agent identity): capability tokens
captoken_mint,captoken_attenuate(offline, no key),captoken_verify,captoken_allows(pure); signed requestshttp_sign(require sign("KEY")+ audit) andhttp_signature_verify(pure,opts.algmandatory); third-party OIDCoidc_verify(iss+audmandatory; JWKS needsrequire net(host));mtls_identity(cert, key, opts?)withopts.hostsscoping (require file.read); per-identity metering:spend_total(unit, identity?), identity-scoped rate limits andSYNSEMA_SPEND_CEILING_PER_IDENTITY="agent=UNIT:max"(any unit — no currency is privileged); discovery at/.well-known/synsema-auth. - Passkeys,
did:key, signed documents, receipts (engine v0.6.28+ — see Agent identity):webauthn_register/webauthn_verify(pure; attestation ignored on purpose;nothingon any failure);canonical_json(RFC 8785);did_key_encode/did_key_decode/did_key_document;document_sign/document_verify(W3C Data Integrity,eddsa-jcs-2022withrequire sign("KEY"),ecdsa-jcs-2019);receipt/receipt_verify(a Verifiable Credential derived from the audit);jwt_signwithalg: "EdDSA"andjwt_verify(token, {"did": …}); the signed Agent Card at/.well-known/agent-card.json(SYNSEMA_IDENTITY_KEY). - Time:
now,sleep(the only two that read the clock and needrequire time);format_time,parse_time,date_parts(pure since v0.6.29). - Dates, instants and durations (v0.6.29+, pure — see Time & random): the types
date,datetime(an IANA zone, DST-correct, or a fixed offset such as+05:30) andduration, with arithmetic and comparison;add_days,add_months,truncate,date_range,to_timezone,timestamp,in_units,parse_date,parse_datetime(%Zaccepts onlyUTC/GMTsince v0.6.30 — use%zor pass the zone; a date-only format is midnight). JSON and CSV write them as ISO 8601. - Random:
random,random_int(random,random_bytesandtokenneedrequire random— OS entropy). Seeded, pure (v0.6.29+, the same numbers as numpy'sdefault_rng, allowed under--deterministic):rng(seed)→ a generatorg(g()/random(g)),random_int(g, lo, hi),random_normal(g, mean =, std =),shuffle(g, xs),choice(g, xs),sample(g, xs, n),rng_spawn(g, n)— see Time & random. - Cron:
cron_every,cron_after,cron_cancel,cron_list,cron_status;cron_every(expr, task, {"tz": "America/Santiago"})runs in an IANA zone across clock changes (v0.6.30+) — see Cron. - JSON:
json_encode,json_decode;json_for_script(same JSON with</>/&escaped\u00XX— the safe way to embed data in an inline<script>); XML / TOML (v0.6.20+):xml_parse(xmltodict convention),toml_parse,toml_encode— see JSON, XML & TOML. v0.6.46+:json_encode/jsonl_encode/json_for_script(andcsv_encode) of asecretare an error that names where it is — it was"[redacted]"(see Secrets). - JSON Lines, CSV, Parquet (pure; the file I/O is
read_file/read_file_bytes/write_filewith their own capability):jsonl_encode,jsonl_decode(v0.6.29+);json_decode(text, allow_nan = true)reads theNaN/Infinitythatjson_encodewrites (an error by default), andjson_encoderefuses a task or a generator inside the value (v0.6.30+);csv_parse(text, opts?)({"types": {col: "int"|"float"|"decimal"|"text"|"bool"|"date"|"datetime"}},{"missing": ["NA", …]}; an empty field isnothingsince v0.6.29),csv_encode(rows, opts?)({"missing": "NA"},{"escape_formulas": true});parquet_read(bytes, opts?)({"max_cells": n, "max_bytes": n}),parquet_write(rows, opts?)({"compression": "snappy"|"zstd"|"gzip"|"lz4"|"none"}; writes the Arrow schema, so pandas and polars read durations and zoned datetimes with their types, v0.6.30+; not in the wasm build); v0.6.45+:parquet_read(bytes, {"columns": […], "row_groups": […], "limit": n})reads a part (the limits count only what is read) andparquet_info(bytes)→{rows, columns: [{name, type}], row_groups: [{rows, bytes}]}without reading the data (native only);gzip(data)→ bytes (deterministic: no name or time in the header) andgunzip(bytes, {"max_bytes": n})→ bytes (concatenated members; by default it refuses more than the larger of 256 MiB and 64 × the input —decode(…, "utf8")for text) — see JSON, XML & TOML and Data analysis. v0.6.46+:parquet_scan(path, opts?)reads a part straight from the disk — the footer and only the pages asked for (columns,row_groups,limit, the same checks asparquet_read); it needsfile.readand is a lineage input with the path (see Data analysis). - Tables — data analysis (v0.6.29+, pure; a table is a list of maps — see Data analysis):
summarize(rows, by, aggs)with the aggregatessum_of,mean_of,min_of,max_of,median_of,quantile_of,first_of,n_unique_of,count();group_by(rows, key)→[{key, items}](changed in v0.6.29: it returned a map keyed by text);count_by;join(left, right, on, how?)(inner/left/right/outer/semi/anti— with 2 argumentsjoinis still the text join);pivot(rows, index, columns, values, agg?); missing datais_missing,fill_missing,drop_missing,fill_nan,count(present values),count_missing. A column name that no row has is an error. - Statistics:
sum,mean,median,mode,quantile(values, q),percentile,histogram,stdandvar(sample statistics since v0.6.29,ddof = 1like pandas —std(xs, ddof = 0)for the population figure;synsema checkflags each call until v1.0),corr,cov,lstsq,polyfit,polyval. Every reduction skipsnothingand propagates NaN;axis =on arrays. - Lineage (v0.6.29+): the engine records every input the program reads — files, HTTP, SQL/Mongo/Redis,
recall, chain nodes, processes, model answers — with its sha256;lineage()lists it andreceipt()publishes it asinputs— see Observability and Agent identity. Since v0.6.46receipt()also lists what the run wrote asoutputs(eachwrite_file/append_file/edit_file/zip_extract/tar_extractwith path and sha256), and underserveboth lists are the request's (see Observability). - Charts:
chart_svg(v0.6.45+:{"x_axis": {"angle", "every", "format"}}on bar/line/area/heatmap/boxplot/waterfall);chart(negotiated content node);svg_to_png(svg, opts?)/svg_to_pdf(svg, opts?)— PNG optswidth,height,scale,background,max_pixels; PDF optswidth,height; bothfonts(v0.6.20+,file.readper font file; v0.6.45+: fallback per glyph, at most 16 fonts / 64 faces) andmax_text_chars(v0.6.45+, default 16 384 characters per<text>);qr_matrix(data, {ecc, version})→ rows of 0/1 andqr_svg(data, {ecc, version, module, margin, dark, light})→ SVG text (v0.6.45+, pure, ISO/IEC 18004) — see CSV, stats & charts. - I/O (capability-gated):
read_file,write_file,append_file,edit_file(needsfile.readas well asfile.write, v0.6.45+),file_exists,file_info,list_dir(each entry hasis_link, v0.6.45+),grep(on a folder it needsfile.read("<folder>/**"), v0.6.45+),read_file_bytes(read_file,read_file_bytesandedit_filesay why a file cannot be read, v0.6.45+:File not foundis only for what does not exist — see Errors); v0.6.20+:delete_file,delete_dir(file.write, on every path removed),cwd()(file.read(".")), archiveszip_create,zip_extract,tar_create,tar_extract(native only;file.writeon every path written),bundle:/disk:prefixes on reads — see Files & I/O. - HTTP:
http,http_get,http_post,http_put,http_delete,fetch(v0.6.20+: a map/list body goes out as JSON with itsContent-Type, and the response carriesjson);http_bytes(the exact bytes:{status, ok, bytes, headers}),multipart_encode(pure). v0.6.45+: everyhttp*builtin takes named arguments (http_get(url, headers = …, query = …, timeout = …),http(method = …, url = …, body = …)), and the positionalfetch(url, method, …)is deprecated (gone in v1). Pure helpers (v0.6.45+):header(r, name)(a response header regardless of case; a response or a map of headers),url_encode(text)/url_decode(text)(RFC 3986, strict,+is not a space),html_select(html, css)→[{tag, attrs, text, html}],html_text(html),html_unescape(text)(WHATWG parsing; the result keeps the input's labels) — see HTTP client. v0.6.46+:form = {…}sends anapplication/x-www-form-urlencodedbody (http,http_bytes,http_post,http_put,fetch); a secret bound to the host (require secret("K") for net("h")) may go in the URL, the query, the body or the form; a wildcardnetreaches only public addresses; redirects are never followed — see HTTP client. - WebSocket:
ws_connect,ws_send,ws_recv,ws_close, plus multiplexing/resiliencews_select,ws_select_all,ws_broadcast,ws_status,ws_stats(all gated bynet).ws_connectopts:subprotocols,max_queue,max_queue_bytes,on_full,reconnect({max_retries, backoff, backoff_max, on_reconnect}),keepalive({interval, timeout}). - Blockchain (pure):
keccak256,sha512_256,secp256k1_verify/recover/pubkey(secp256k1_recoveraccepts v = 27/28),ed25519_verify/pubkey,evm_address(waseth_address; also from 20 raw bytes),rlp_encode/decode,abi_encode/decode/selector(abi_encode(types, values)without a selector for constructor arguments),abi_event_topic,abi_decode_log,eip191_digest,eip712_digest, the EVM buildersevm_tx/evm_tx_raw(weretx_eip1559/tx_eip1559_raw;evm_tx_rawrecomputes the digest and refuses a map edited afterevm_tx),evm_tx_create(contract deployment, v0.6.29+),evm_create_address,evm_create2_address,evm_signature(v = 27/28 for wallets andecrecover),solana_tx(builds the message — wassolana_message),solana_tx_raw(assembles the signed transaction),solana_pda,spl_ata,spl_transfer_data,spl_transfer_checked_data,algorand_tx(the bytes to sign — wasalgorand_tx_encode),algorand_tx_raw(the signed transaction),algorand_address(wasalgo_address),bytes_to_int,int_to_bytes,int_to_bytes_le— see Blockchain. - Blockchain (gated):
secp256k1_sign/ed25519_sign/schnorr_sign(require sign);mnemonic_generate,mnemonic_to_seed,hd_derive,algorand_mnemonic,keystore_import/keystore_export,wif_import(require wallet). - Bitcoin (pure):
hash160,btc_address,btc_address_decode,btc_script,btc_txid,schnorr_verify,schnorr_pubkey,btc_tx,btc_tx_raw,psbt_encode,psbt_decode,psbt_finalize. - Bitcoin (read side, gated by
net):btc_utxos,btc_balance,btc_fee_estimates,btc_send,btc_wait,btc_rpc. - Blockchain read side (gated by
net, like HTTP):evm_rpc,evm_nonce,evm_balance,evm_gas_price,evm_chain_id,evm_estimate_gas(url, tx, block?),evm_call,evm_fee_history(url, blocks?, percentiles?, newest?),evm_send,evm_receipt,evm_wait, and new in v0.6.29evm_block_number,evm_logs(events; decode them withabi_decode_log);solana_rpc,solana_latest_blockhash,solana_balance,solana_send,solana_wait(wassolana_confirm),spl_balance;algorand_params,algorand_account,algorand_send,algorand_wait. Theeth_*names of v0.6.28 are deprecated aliases (table above). - DB:
db_open,db_close,sql,sql_exec,sql_batch,sql_tables,paged;mongo_find,mongo_find_one,mongo_insert,mongo_insert_many,mongo_update,mongo_delete,mongo_count,mongo_aggregate,mongo_collections;redis_get/set/del/exists/mget/mset/keys/type,redis_incr/decr/incrby,redis_expire/ttl/persist,redis_hget/hset/hdel/hgetall/hincrby,redis_lpush/rpush/lpop/rpop/lrange/llen,redis_sadd/srem/smembers/sismember,redis_lock/unlock— see SQL, Mongo & Redis. - Serve — responses, content, state:
ok,created,not_found,fail,html,respond,redirect,binary,render,with_header,set_cookie,clear_cookie; content nodespage,heading,prose,list,ordered_list,link,image,section,code,raw,content,chart; shared statestate_set,state_get,state_incr,state_delete,state_all, and the atomicstate_merge(key, map)→ the merged map andstate_cas(key, expected, new)→ bool (v0.6.45+);openapi_json()(v0.6.20+: the published OpenAPI document as text — underserveonly) — see HTTP server. - Agentic apps (engine v0.6.7+ — see Agentic apps): one wait
select(targets, timeout?); raw TCPtcp_connect(host, port, opts?)(gated bynet("host:port")),tcp_send,tcp_recv,tcp_close,tcp_statsand in-memory byte pipespipe(opts?),pipe_send,pipe_recv,pipe_close(v0.6.42+, both inselect); v0.6.45+:tcp_write(conn, data)/pipe_write(end, data)take what fits right now and return how many bytes they took, never waiting (0= full right now;tcp_send/pipe_sendstay all-or-timeout),pipe_stats(end)→{queued_in, queued_out, status}, and a peer reset arrives as{type: "close"}instead of an error; live processesproc_spawn,proc_recv,proc_select,proc_send,proc_close_stdin,proc_resize(v0.6.8+, pty only),proc_status,proc_kill,proc_wait,proc_stats,proc_close(gated byexec, likerun;proc_spawn(…, {"pty": true})from v0.6.8; kill reaches the whole process tree and{"process_group": false}detaches on purpose, v0.6.9+); file-watchwatch,watch_recv,watch_stats,watch_close(v0.6.9+, gated byfile.readlikelist_dir; polling with a snapshot, same events on every OS); the program's own terminalterm_open,term_recv,term_size,term_write,term_stats,term_close(v0.6.11+, gated bystdin; raw mode, every key as an event, inselect;term_openisnothingwithout a TTY); event busbus_publish,bus_subscribe,bus_recv,bus_unsubscribe,bus_topics(no capability); agent controlagents,agent_stop; thesocketbinding of aroute … socketblock is a WebSocket handle for thews_*family. - Program & subprocess (engine v0.6.14+):
steps()→ statements executed so far (v0.6.20+; deterministic, no capability — see Observability);args()→ the program's own argv (what follows--insynsema run, or the whole argv of asynsema buildbinary) — no capability (it's input the caller typed);self_path()→ this executable's path, exactly as the OS gives it (pass it torun/proc_spawn— theexecscope matches byte-for-byte) — no capability;platform()→{os, arch}(v0.6.18+:"windows"/"macos"/"linux"and other names as Rust reports them;"x86_64"/"aarch64";"wasm"/"wasm32"in the browser build) — no capability, the same answer under--sandboxand--profile pure(a fact of the binary, likeargs());shutdown(reason?)(v0.6.18+) → asks the running server for its ordered drain and exit 0 — from a route, a socket, a cron job or an agent; idempotent; an error underrunand before anything listens; asecretreason is refused; no capability — see Your app on the desktop;run_program(source, opts)—require sandbox_run— runs another Synsema program in a child process under a ceiling that is the intersection with the parent's, itsenv/cwd/timeoutits own and its audit returned as a value — see Running Synsema under a ceiling. - LLM / tools:
llm_available,llm_usage(tokens consumed by this process;0offline — see LLM primitives),llm_step,call,call_tool. v0.6.46+:tool_spec(task, describe)builds thellm_stepcatalog entry from a task's signature ({name, describe, params: ["a: number", …], optional}), andcall/call_toolcheck typed parameters (task f(a: number, b: text = "x")) strictly, without converting — see Tool calling. - Judge (System One, v0.6.25+): the
judgeblock is syntax, not a builtin (see Judge); its introspection isjudge_available()(a provider is wired),judge_usage()(input tokens consumed by this process; output is free),judge_model()(the versioned model id that answered the last block, ornothing). No gate. - Money / spend ledger (
require spend("UNIT")— see Capabilities):spend(amount, unit, reason)→ the unit's accumulated total (audited inspend.log, host ceilingSYNSEMA_SPEND_CEILING);spend_total(unit)→ the process total, no capability. - Memory / progress / rules (the whole family needs
require memory("name")— see Memory & state):remember,recall,forget_memory,memory_summary,create_progress,start_step,complete_step,fail_step,resume_point,progress_display,progress_percent,add_rule,check_rules,get_rules. - Confidential computing (engine v0.6.24+ — see Labels and Attestation): labels
private,declassify,label_of,is_private(under--labels, always on withserve --attestedand inside a guest); attestationattest,attest_key(require attest),attestation_document,attestation_key(the identity of aserve --attested; the key is sealed —revealrefuses it),attestation_verify(pure,opts.nowmandatory);groth16_verify(Groth16 over BN254, snarkjs JSON as it is); deterministic differential-privacy noiselaplace_noise,gaussian_noise(same seed → same noise, so repeating a query cannot average it away). Total variants for untrusted input, which is how you validate without raising when an error would itself be a bit:json_decode(x, default),number(x, default),aes_gcm_decrypt(k, n, ct, aad, default),decimal,float,toml_parse,abi_decode,bech32_decode,rlp_decode. v0.6.46+:declassifyandprivatecan only be called by their name; with labels,declassifyis a capability the host ceiling bounds (--cap-set declassify=<principal>); private data reaches a model only withrequire llm("P")+ the host'sllm=P@<provider>;read_line's prompt is a public sink; a sealed receipt for an auditor (--auditor) letsreveal/signrun in a private branch — see Labels and Observability. - Secrets:
secret,as_secret,bearer,reveal. v0.6.46+: a secret bound to the hosts it may reach,require secret("K") for net("api.example.com"), goes in a URL, a query, a JSON body or a form (an unbound one only in a header); what the server echoes back is masked as[secret K]— see Secrets. - Responses (serve):
ok,created,fail,not_found,respond,redirect,render,content,paged;form of request(parsed urlencoded/multipart form body, file uploads as exact bytes). - Errors:
raise,assert,assert_eq,assert_ne,assert_error.