# Builtin index

Every Mix builtin grouped by category, generated from the binary's own `mix builtins --json`. See the linked topical page for prose and examples; `mix what NAME` prints a one-line description of any single builtin (or keyword), and `mix help` prints a compact names-only summary.

For incremental HTTP responses, see [`http_stream`](http.md#response-streams-and-idle-timeouts):
a scoped line callback with early stop, independent idle and whole-call
timeouts, and partial-byte diagnostics. The same `idle_timeout` option is
available on `http_get`, `http_post` and `http_request`.

Some builtins are feature-gated on the `mixos-lib-mix` crate (`json`, `regex`, `toml`, `yaml`, `datetime`, `url`, `crypto`, `http`, `sqlite`, `archive`, `dkim`, `markdown`, `datastar`, `xml`, `mime`) so embedders can pull only what they need — the `mix` binary turns them all on.

## Machine-readable discovery (metadata_schema 1)

From 0.97.0, `required_capabilities` lists additional unconditional capability
classes beyond `capability`. File transfers use this to require filesystem
access even without an options map. Evaluator policy checks and `mix lint`
enforce the combined set; `conditional_capabilities` remains option-dependent.

Argument entries also carry `hint` (instructional text or null), including
encode-first guidance for file payloads; this is additive within metadata_schema 1.

Since 0.29.0 every builtin carries a structured contract — per-argument names/kinds/optionality, derived min/max arity, a return shape, effect flags, an operational-failure mode, and any conditional capabilities. The human signature shown by `mix builtins <name>` is derived from the same contract, so it can never drift from the machine metadata.

- `mix builtins --json` — the full table as a JSON array; each entry carries `metadata_schema` (1), `kind` (`builtin` or `statement` for print/eprint), `name`, `category`, `capability` (kebab class, or `statement`), `conditional_capabilities` (`[{option, capability}]`), `description`, `signature`, `arity` (`{min, max, exact}` — `max: null` = variadic; `exact` is normally `null`, but when a builtin's accepted argument counts are NOT a contiguous range it lists them exhaustively, e.g. `random` has `exact: [0, 2]` — an arity checker must use `exact` when present), `args` (`[{name, required, variadic, kind}]`), `returns`, `effects`, and `operational_failure`.
- `mix builtins --data` — the same logical array as strict-data Mix source (parse with `data_parse` / `load_data`); `null` becomes `nil`.
- Value shapes (`kind`/`returns`) are `{type: "any"|"nil"|"bool"|"number"|"string"|"bytes"|"buffer"|"function"}` scalars, `{type: "list", items: shape}`, `{type: "map", shape: name-or-null, fields: [...]}`, or `{any_of: [shapes...]}` unions.
- `effects` flags: `must_use` (discarding the result hides a failure — `run_rc`, `ssh_run`, `http_*`, ...), `blocking` (unbounded/external wait: process, network, stdin, sleep), `shell` (backed by `/bin/sh`), `mutates_args` (`push`, `buffer_push`, ...), `terminates` (`exit`, `panic`).
- `operational_failure`: how I/O-level failure is reported — `not-applicable` (pure), `raises` (catchable error), `returns-result` (encoded in the returned value, e.g. `ok:false` / `status:0` / exit code), `terminates`. Argument-validation errors always raise regardless.
- Arity in the contract is the documented surface; a few older builtins tolerate surplus arguments at runtime. `mix lint` checks calls against the contract, which is deliberately stricter.
- **Argument type gate and nil** (0.103.x): the evaluator checks argument types against the contract for the side-effect classes (fs/process/network/bus) in every mode, and for pure builtins under strict mode. A `nil` VALUE is checked like any other value — there is no blanket nil exemption, so `write_file(nil, "x")` and `mkdir(nil)` raise TYPE_MISMATCH instead of coercing nil into a literal `"nil"` path. An optional argument that intentionally treats an explicit `nil` as "omitted/default" declares it in the contract as `any_of(…, nil)` (e.g. `run_argv`/`exists`/`write_atomic`/`stat`/`walk` opts, `hash_file` algo, `bytes_to_string` opts, `normalize` form, `slice` end); that is the ONLY way a nil reaches the builtin. `any` args accept nil because they accept everything. A nil in a plain `string`/`number`/`map` slot raises in the same modes as any other wrong type.

> The tables below are generated: `docs/_build/gen-builtins-md.mix` writes
> one section per category, one row per entry of `mix builtins --json`, in
> the binary's order. `cargo test -p system --test man_pages` fails when the
> committed tables differ from the binary it built, so after adding or
> changing a builtin run
> `mix docs/_build/gen-builtins-md.mix --mix target/debug/mix`. Rows of kind
> `statement` (`print`, `eprint`, and the Bus forms `send`, `emit`, `on`,
> `reply`, ...) are keyword forms listed beside the builtins; see
> [bus](bus.md).

## string  — see [strings](strings.md)

  length          Length of a string (codepoints), list/map (elements), or bytes/buffer (bytes, v0.64.0)
  len             Alias for length()
  upper           Convert string to uppercase
  lower           Convert string to lowercase
  left            Return leftmost N characters
  right           Return rightmost N characters
  substr          Extract substring by codepoint position and length (splits emoji/combining; see grapheme_substr)
  pos             Find first position of needle in haystack (1-based, 0=not found — so `if pos(..)` reads correctly, since 0 is falsy). 0-based twin: index_of(), which takes its args the other way round and is NOT safe in a condition
  lastpos         Find last position of needle in haystack (1-based, 0=not found — safe in a condition, 0 is falsy). 0-based twin: last_index_of(), which takes its args the other way round
  strip           Remove leading/trailing whitespace, or codepoints in charset: strip(s[, charset]) (0.63.0 — the 2nd arg was silently IGNORED before)
  trim            Alias for strip(): trim(s[, charset]) — charset is a SET of codepoints to strip from both ends (0.63.0; was silently ignored). One-sided: ltrim/rtrim
  replace         Replace all occurrences of old with new in string
  replace_must    replace() that REFUSES a no-op: raises NEEDLE_ABSENT when old does not occur, and NEEDLE_COUNT when {count: n} is given and the occurrence count differs. Optional {path} names the file in the message. The form to use in a read_file -> edit -> write_file chain (0.90.0)
  split           Split string into list by delimiter (default: space)
  join            Join list into string with delimiter (default: space)
  starts_with     Test if string starts with prefix
  ends_with       Test if string ends with suffix
  contains        Test if string/list contains a value, or a bytes/buffer contains a byte needle (needle: bytes/buffer/string/byte number, non-empty; v0.70.0) — the correct yes/no test, and what to use instead of a bare index_of() in a condition
  repeat          Repeat string N times
  lpad            Left-pad string to width (codepoint count; see lpad_w for display cells). Optional 3rd arg is the fill character, default space: lpad(s, 12, "0") (v0.54.0)
  rpad            Right-pad string to width (codepoint count; see rpad_w for display cells). Optional 3rd arg is the fill character, default space (v0.54.0)
  lpad_w          Left-pad to width in terminal display CELLS (UAX #11; CJK/emoji=2) — aligns wide-char columns. Optional 3rd arg is the fill character (must be 1 cell wide), default space (v0.54.0)
  rpad_w          Right-pad to width in terminal display CELLS (UAX #11; CJK/emoji=2) — aligns wide-char columns. Optional 3rd arg is the fill character (must be 1 cell wide), default space (v0.54.0)
  reverse         Reverse a string (by codepoint; splits emoji — see grapheme_reverse), list, or bytes/buffer (byte-wise → a new value-semantic bytes, v0.70.0)
  words           Count whitespace-delimited words in string
  word            Extract Nth word from string (1-based)
  ord             Unicode codepoint of the FIRST character: ord("A") -> 65, ord("é") -> 233. Empty string raises. Inverse: chr()
  chr             The 1-character string for a Unicode codepoint: chr(65) -> "A", chr(10084) -> "❤". Surrogates (D800-DFFF) and >0x10FFFF raise, same rule as \u{...}. Inverse: ord()
  normalize       Unicode normalisation (UAX #15): normalize(s[, form]) with form "NFC" (default), "NFD", "NFKC" or "NFKD" (case-insensitive; nil selects NFC; anything else raises VALUE_ERROR). Makes canonically-equivalent text compare equal: a decomposed e + combining acute (macOS filenames, NFD) equals the precomposed é after normalize(); NFKC also folds compatibility forms (fullwidth letters, ligatures: normalize("ﬁ", "NFKC") -> "fi"). Emoji and ZWJ sequences pass through unchanged (v0.92.0)
  mix_tokens      How Mix itself tokenises Mix source, for tools that read .mix files: mix_tokens(source[, {comments: bool}]) -> [{kind, text, line, col}] from the real lexer, in source order; nothing is run. kind: number, string (a quoted literal), word (a bare word), interp_string, heredoc, variable, command_sub, keyword, operator, punct, newline, and comment (only with comments:true; # and -- comments). text is the exact source span (a heredoc includes its body and terminator); line and col are 1-based, col in characters. Newlines inside (), [] and {} are not tokens. Source that does not lex raises MIX_SOURCE_LEX with details {line, col} (v0.117.0)
  before          Text before the FIRST delim: before(s, delim) -> string | nil (nil when delim absent; "" is a real result — delim at the start). Empty delim raises
  after           Text after the FIRST delim: after(s, delim) -> string | nil (nil when delim absent; "" when delim at the end). Empty delim raises. Want a default? `after($s, "=") or ""`
  before_last     Text before the LAST delim -> string | nil (nil when absent). Empty delim raises
  after_last      Text after the LAST delim -> string | nil (nil when absent) — basename/extension: after_last(path, "/"), after_last(name, "."). Empty delim raises
  split_once      Split at the FIRST delim: split_once(s, delim) -> [head, tail] | nil (nil when absent — never a 1-element list). Empty delim raises
  rsplit_once     Split at the LAST delim -> [head, tail] | nil (nil when absent). Empty delim raises
  between         Text after the first a and before the NEXT b: between(s, a, b) -> string | nil (nil if either marker absent, in that order). Empty a or b raises
  strip_prefix    s without a leading p, else s UNCHANGED (never nil — "nothing to strip" is an answer). Empty p -> unchanged. Kills the starts_with+substr idiom
  strip_suffix    s without a trailing x, else s UNCHANGED (never nil). Empty x -> unchanged
  replace_first   Replace the FIRST occurrence of old; old absent -> s unchanged. Empty old mirrors replace(): inserts new at the start (replace_first("ab", "", "X") is "Xab")
  count_of        Non-overlapping occurrences of needle in s; 0 for an empty needle. (The HOF count(list, pred) is a different builtin)
  ltrim           Strip leading whitespace, or leading codepoints in charset: ltrim(s[, charset]) — PHP-style charset is a SET of codepoints, not a prefix string
  rtrim           Strip trailing whitespace, or trailing codepoints in charset: rtrim(s[, charset])
  lines           Split into lines: \n-separated, ONE trailing \r stripped per line (CRLF and LF both work; a lone \r is not a terminator), exactly one trailing empty element dropped (the final newline). lines("") -> []; "a\n\n" -> ["a", ""]. Native since 0.63.0 (was a prelude fn that kept \r and the trailing "")
  fields          awk-style fields: split on whitespace RUNS, no empties; fields("") -> []. 0-based access fields(s)[2]; the 1-based single-field form is word(s, n)
  chars           Codepoints as 1-char strings (grapheme_* builtins exist for clusters). Native since 0.63.0 (was a prelude fn)
  last_index_of   0-based codepoint index of the LAST occurrence in a string, or last index of a value in a list; -1 if absent. The 0-based twin of lastpos() (args reversed). List search compares with == — SCALAR elements only, exactly like index_of (a map/list element never matches; deep_eq is the structural comparison). ⚠ Like index_of, NEVER bare in a condition: -1 is truthy, 0 is falsy
  template        Substitute single-brace {key} placeholders in a string from a map
  word_wrap       Wrap text to a column width (codepoint budget; see word_wrap_w for display cells)
  word_wrap_w     Wrap text to a column width in terminal display CELLS (UAX #11; CJK/emoji=2)
  markdown_escape Escape markdown metacharacters in a string
  markdown        Render CommonMark + GFM markdown (tables, strikethrough, task lists, footnotes) to HTML; raw HTML is escaped and unsafe URL schemes neutralised (requires markdown feature)
  html_escape     Escape & < > " ' for HTML element text + quoted attribute values (not JS/CSS/URL/srcdoc contexts)
  sanitize        Make untrusted bytes safe for one-line diagnostics: collapse line breaks (incl. U+2028/9) to spaces, replace C0/C1 controls and Trojan-Source bidi/zero-width chars with '?'
  re_match        Subject-first regex test: re_match(s, pattern) -> bool, true if pattern matches anywhere in s
  re_find         All matches as {match, start, end[, groups]} maps with CODEPOINT offsets (compose with substr/slice/index_of; the deleted legacy regex_find answered in UTF-8 BYTE offsets). [] when none
  re_replace      Replace ALL matches: re_replace(s, pattern, replacement) — subject FIRST; $1/${name} backrefs in replacement
  re_replace_must re_replace() that REFUSES a no-op: raises NEEDLE_ABSENT when the pattern does not match, and NEEDLE_COUNT when {count: n} is given and the match count differs. Optional {path} names the file in the message (0.90.0)
  re_split        Split s on each match of pattern (subject first)
  grep_lines      Lines of text matching pattern (subject first; regex when enabled, else substring) — the line filter (its pattern-first predecessor grep() was deleted in release B)
  csv_parse       Parse CSV string into a list of header-keyed row maps. delim is exactly ONE ASCII byte (default ","; empty/multi-byte/non-string/nil and NUL/CR/LF/quote raise TYPE_MISMATCH — never a silent default or truncation)
  ini_parse       Parse INI string into nested map of sections
  xml_parse       Parse a strict-XML string (or bytes, e.g. an HTTP body) into a Value tree (requires xml feature). Default simple mode is the SOAP/RSS consumer shape: {RootName: …} with namespace prefixes stripped, attributes as @name keys, repeated sibling elements collapsed to a list, a leaf element's text as its value, mixed text under #text, xmlns declarations dropped. Pass {mode:"tree"} for full fidelity: nodes are {name, attrs, children} with prefixes + xmlns preserved and text children as plain strings. Strict XML only — real-world HTML is tag soup and will NOT parse.
  url_parse       Parse URL into {scheme, host, port, path, query, fragment}
  url_decode      Percent-decode a URL/form-encoded string ('+' → space)
  url_encode      Percent-encode a string for use in a URL/form body
  rfc2047_decode  Decode RFC 2047 encoded-words in a mail header value (=?charset?B/Q?data?=) to a plain string. Honours the charset token (utf-8/us-ascii/iso-8859-1; anything else falls back to UTF-8-lossy), joins adjacent encoded-words at the BYTE level per §6.2 so a character split across two words survives, and passes malformed words through literally rather than losing the header. Accepts string/bytes/buffer (v0.67.0)
  rfc2047_encode  Encode a header value as RFC 2047 encoded-words in UTF-8, or return it UNCHANGED when it is already plain ASCII with no "=?" (§5: encode only when needed). Optional {encoding: "B"|"Q"}, default B. Words are kept within the §2 75-character limit and split on CHARACTER boundaries so each stays independently decodable (v0.67.0)
  parse_query     Parse a k=v&k2=v2 query/form string into a map (url-decoded, last-wins)
  parse_form      Parse an x-www-form-urlencoded body into a map (alias of parse_query)
  byte_length     Length of a string in raw UTF-8 bytes (the pre-0.8.0 length() value for strings)
  byte_pos        Byte offset of needle in haystack (1-based, 0=not found) — byte twin of pos(), 0-based twin byte_index_of(). Safe in a condition (0 is falsy)
  byte_lastpos    Last byte offset of needle in haystack (1-based, 0=not found) — byte twin of lastpos()
  byte_index_of   Byte offset of needle in string (0-based, -1=not found) — byte twin of string index_of(), 1-based twin byte_pos(). ⚠ NEVER use bare in a condition: -1 is truthy, 0 is falsy (MIX-W2305)
  grapheme_count  Count grapheme clusters (user-perceived chars: emoji/flags/combining count as 1)
  grapheme_substr Substring by grapheme cluster position and length (won't split emoji/combining marks)
  grapheme_reverse Reverse a string by grapheme cluster (emoji/combining-safe, unlike reverse())
  display_width   Terminal display width in cells (UAX #11; CJK/emoji=2, combining=0, East-Asian-ambiguous=1)

## type  — see [numbers](numbers.md)

  deep_eq         Structural equality for any two values: maps compare by key set + deep_eq values (insertion order IGNORED), lists elementwise in order, scalars as ==. The answer `==` cannot give for maps/lists — since v0.68.0 `==`/`!=` RAISES when both sides are a map or list, and names this builtin. Caveats, inherited from ==: a FUNCTION value is never equal (even to itself — a callback-bearing map is not deep_eq its own copy) and Buffer-vs-Bytes is false (freeze() first). Raises past 512 nesting levels
  type            Return type name: string, number, bool, list, map, nil
  to_number       Convert value to number (nil if not numeric)
  to_string       Convert value to its string representation
  is_number       Test if value is numeric or a numeric string
  is_empty        Test if string/list/map is empty, or value is nil ("0" is NOT empty)
  has_builtin     Does THIS mix have the named builtin? has_builtin(name) -> bool. `mix builtins NAME` exits 0 for any name and cannot answer this; use for feature gates and compat shims: `if not has_builtin("ws_connect") then die "needs mix >= 0.74" end`. A feature-gated name absent from this build still reads true (the binary knows it, and calling raises 'requires the X feature') (v0.78.0)
  mix_version     The language runtime version as structured data: {major, minor, patch, string} — so a version gate never parses --version text (v0.78.0)

## math  — see [math](math.md)

  round           Round to nearest integer, half away from zero; round(x, n) to n decimal places (n<0 rounds to tens/hundreds) (v0.19.0)
  floor           Round down toward -inf; floor(x, n) to n decimal places (v0.19.0)
  ceil            Round up toward +inf; ceil(x, n) to n decimal places (v0.19.0)
  trunc           Truncate toward zero (drop the fraction); trunc(x, n) to n decimal places (v0.19.0)
  abs             Absolute value (v0.19.0)
  sign            Sign of x: -1, 0, or 1 (±0→0, NaN→NaN) (v0.19.0)
  band            Bitwise AND of two integers. Both arguments must be exact integers within ±2^53 (the range f64 represents without loss); a fraction, an infinity, a NaN or an out-of-range magnitude raises rather than silently truncating. Chiefly for permission bits: band(stat(p)["perm"], 0o111) != 0 asks whether any execute bit is set (v0.46.0)
  bor             Bitwise OR of two integers; same exact-integer domain as band (v0.46.0)
  bxor            Bitwise exclusive-OR of two integers; same exact-integer domain as band (v0.46.0)
  bnot            Bitwise NOT (one's complement) over 64-bit two's complement: bnot(0) is -1. Same exact-integer domain as band (v0.46.0)
  bshl            Shift left by n bits (n in 0..63). Raises rather than wrapping if the result leaves the exact-integer range (v0.46.0)
  bshr            Arithmetic shift right by n bits (n in 0..63); the sign bit is replicated, so bshr(-8, 1) is -4 (v0.46.0)
  sqrt            Square root (negative→NaN) (v0.19.0)
  cbrt            Cube root (defined for negatives) (v0.19.0)
  pow             Raise to a power: pow(base, exp) = base^exp (v0.19.0)
  exp             e raised to the x (v0.19.0)
  ln              Natural logarithm, base e (ln(0)→-inf, ln(neg)→NaN) (v0.19.0)
  log10           Base-10 logarithm (v0.19.0)
  log2            Base-2 logarithm (v0.19.0)
  log             Logarithm in an arbitrary base: log(x, base) (v0.19.0)
  min             Smallest of the number arguments, or of a single list argument: min(a, b, …) | min(list). Lexicographic when all args are strings; NaN-skipping (v0.19.0)
  max             Largest of the number arguments, or of a single list argument: max(a, b, …) | max(list). Lexicographic when all args are strings; NaN-skipping (v0.19.0)
  clamp           Constrain a number to a range: clamp(x, lo, hi) (errors if lo > hi) (v0.19.0)
  hypot           Euclidean distance sqrt(x²+y²) computed without intermediate overflow: hypot(x, y) (v0.19.0)
  sin             Sine of x in radians (v0.19.0)
  cos             Cosine of x in radians (v0.19.0)
  tan             Tangent of x in radians (v0.19.0)
  asin            Arcsine in radians (domain [-1, 1], else NaN) (v0.19.0)
  acos            Arccosine in radians (domain [-1, 1], else NaN) (v0.19.0)
  atan            Arctangent in radians (v0.19.0)
  atan2           Angle in radians of the point (x, y): atan2(y, x) (v0.19.0)
  pi              The constant π (v0.19.0)
  e               Euler's number e (v0.19.0)
  random          random() -> float in [0,1); random(min, max) -> integer in [min, max] inclusive (v0.23.0)

## list  — see [collections](collections.md)

  push            Append value to end of list (mutates)
  pop             Remove and return last element of list (mutates)
  shift           Remove and return first element of list (mutates)
  sort            Return sorted copy of list (all-number lists sort numerically; else lexicographic)
  index_of        Find 0-based index of value in a list, of a needle substring in a string (codepoint-based), or of a byte needle in a bytes/buffer (byte offset; needle: bytes/buffer/string/byte number, non-empty; v0.70.0); -1 if absent. 1-based twin: pos() (args reversed). ⚠ NEVER use bare in a condition — -1 (absent) is TRUTHY and 0 (first position) is FALSY, so both answers invert; use contains() for yes/no or compare >= 0 (MIX-W2305)
  unique          Return list with duplicates removed
  range           Generate list of numbers from start to end with optional step. Bounds/step must be whole numbers within i64 — fractional or oversized values raise VALUE_OUT_OF_RANGE instead of silently saturating (strict since v0.59.0)
  flat            Flatten nested lists into a single list
  concat          Concatenate 2+ lists into one new list (one level; each arg must be a list)
  slice           Sub-sequence [start, end): negative indices and out-of-range clamp, a reversed range is empty (v0.2.0). Slices a list (elements), string (codepoints), or bytes/buffer (bytes → a new value-semantic bytes, v0.64.0)
  take            First N items of a list (negative N = last N) (v0.2.0); also string (codepoints) and bytes/buffer (bytes → a new value-semantic bytes, v0.70.0)
  drop            Skip first N items of a list (negative N = drop last N) (v0.2.0); also string (codepoints) and bytes/buffer (bytes → a new value-semantic bytes, v0.70.0)
  zip             Pair two lists element-wise into [a, b] tuples (v0.2.0)

## map  — see [collections](collections.md)

  keys            Return list of map keys
  values          Return list of map values
  has_key         Test if map contains a key
  merge           Merge two maps (second wins on conflicts)
  delete          Return map with key removed

## buffer  — see [buffer](buffer.md)

  buffer          Create a reference-semantic MUTABLE byte buffer (the escape hatch from value semantics for large binary/audio/video). buffer() or buffer(nil) empty; buffer(n) n zero bytes; buffer(string) UTF-8; buffer(bytes|buffer) independent copy; buffer([items]) flat splice of int 0-255 / string / bytes / buffer. Append with buffer_push (O(1) amortized, aliases share); freeze() to a value-semantic bytes (v0.26.0)
  buffer_push     Append bytes to a buffer IN PLACE (reference-semantic: every alias sees the growth). Each item is an int 0-255, string (UTF-8), bytes, or buffer. Self-append-safe (v0.26.0)
  buffer_get      Byte at 0-based index i as a number 0-255, or nil if out of range (v0.26.0)
  buffer_set      Write byte (0-255) at 0-based index i, in place; errors if i is out of range — grow with buffer_push first (v0.26.0)
  freeze          Snapshot a buffer to a value-semantic bytes (a copy of the current content) — the bridge into write_file/hash/base64/http (v0.26.0)

## io  — see [io](io.md)

  read_file       Read entire file contents as string
  fs_watch        Register Linux inotify watch; returns evaluator-owned opaque handle. Delivers fs.changed via $event.args; bounded, overflow requires rescan; no polling fallback
  fs_unwatch      Cancel watch and pending changes; wake fs_wait with FS_WATCH_CANCELLED
  fs_wait         Suspend until a filesystem batch; cancellation-safe; refused in serve and expression modes
  dir_open        Open a retained native directory root; evaluator-owned numeric handle. Refuses symlink components. Linux openat2 required; no fallback (v0.108.0)
  dir_rename      Move a regular file or directory between relative paths beneath a retained root, atomically refusing overwrite. Landlock ABI 2 and erratum 3 required. Refuses symlink sources and escaping parents. Root pathname checked before operation; retained inode remains the containment boundary during concurrent root moves (v0.108.0)
  dir_close       Close an evaluator-owned retained directory root; invalid or closed handles raise (v0.108.0)
  read_file_bytes Read file contents as raw bytes. Optional 2nd arg caps the read: read_file_bytes(path, 8192) reads at most 8192 bytes (header-sniffing without slurping a huge file) (v0.3.1; cap v0.17.1)
  read_lines      Read file as a list of lines (trailing newline stripped, empty last line dropped) (v0.2.3)
  load_data       Read + parse a strict-data .mix file (bare-key `k: v`, the zones.mix/conf.mix form) into a Value — the non-executing twin of source/include, for substrate-internal data that must NOT run as code (v0.9.0)
  write_file      Write a string, bytes or buffer to file (creates/overwrites); bytes/buffer are written verbatim, a string as UTF-8. Nothing else is coerced — nil/map/list/function/number/bool raise TYPE_MISMATCH before the file is opened (encode with json_encode/data_encode/to_string first)
  write_new       Atomically create a new file with mode. write_new(path, content, 0o600) — mode as a value (octal literal) or octal string "0600"; fails if path exists; mode applied at creation (no umask race). content is a string, bytes or buffer (nothing else is coerced — wrong types raise TYPE_MISMATCH before the O_EXCL open)
  write_atomic    Replace or create a file so every reader and every crash sees the old complete file or the new complete file, never a partial one: write_atomic(path, data[, {durability, mode, max_bytes}]). data is a string, bytes or buffer (nothing else is coerced). A temp is claimed O_EXCL beside the target (same filesystem), written, optionally synced, and renamed over the target; any failure before the rename removes the temp and leaves the target untouched. durability "none" (default: atomic, NOT durable across power loss) | "file" (fsync the file before the rename) | "full" (also fsync the directory after it). An existing target keeps its mode and owner (raises rather than silently change the owner); a new file gets 0o666 & ~umask; mode sets it exactly. A symlink path replaces the file it names and keeps the link. max_bytes raises WRITE_TOO_LARGE before touching disk. A killed process can leave a hidden .NAME.mixtmp-* temp beside the target, never a partial target
  append_file     Append a string, bytes or buffer to file (created if missing); bytes/buffer append verbatim, a string as UTF-8. Nothing else is coerced — nil/map/list/function/number/bool raise TYPE_MISMATCH before the file is opened
  exists          Test if path exists. FOLLOWS symlinks by default, so a dangling link reads as absent — that is the right answer for "can I open something here" and the wrong one for "is this name taken". exists(path, {follow_symlinks: false}) is the lstat form and sees the link itself (v0.39.0). opts may be nil, like being omitted.
  access          Ask the kernel whether this process can access path using its effective uid/gid: mode is a non-empty, duplicate-free string of r/w/x/f letters (f = existence and is redundant when combined). Follows symlinks. Unlike inspecting stat().perm, this honours POSIX ACLs. Ordinary absence/denial returns false; malformed input or an unexpected syscall failure raises (v0.45.0).
  is_dir          Test if path is a directory
  is_file         Test if path is a regular file
  realpath        Canonicalise a path: resolve every symlink + `.`/`..` to the absolute real path (like `readlink -f` / realpath(3)). The path MUST exist. realpath(path) -> string | nil (nil ONLY when a component is missing; a permission/IO/symlink-loop/non-UTF-8 failure RAISES — v0.103.14). NORMALISATION ONLY, not a race-free authorization primitive: canonicalise-then-use is not atomic, so for an exec/open safety check, exec/open the RETURNED canonical path (which has no symlinks to re-traverse), not the original (v0.31.2)
  glob            List files matching a glob pattern (supports ** globstar in v0.2.1)
  ls              List directory entries
  mkdir           Create directory: mkdir(path[, {parents}]). parents defaults to true (create_dir_all). {parents: false} creates only the final component and fails if the parent is missing — the form to use when the parent was placed deliberately and re-creating it would hide its removal (v0.42.0)
  flock           Take a process-held advisory file lock: flock(path[, {shared, wait, create}]) -> bool. Exclusive and non-blocking by default; contention returns false, genuine filesystem errors raise. wait is seconds (0 = do not wait). A shared lock opens an existing file read-only, so it needs no write access; an exclusive one opens read-write. A missing file is created (0644) unless create:false, which raises LOCK_FILE_MISSING (v0.117.0). Repeated acquisition of the same canonical path by this process is idempotent-true (v0.43.0)
  funlock         Release and close this process's advisory lock for path. Returns true when held, false when not held (v0.43.0)
  fcntl_lock      Take a POSIX record lock over the whole file: fcntl_lock(path[, {shared, wait, create}]) -> bool — the fcntl(2) lock namespace C daemons use for pidfiles/lockfiles, which flock(2) locks never see (Linux keeps the two families separate). Contract-identical to flock: exclusive + non-blocking default, contention false, real errors raise, shared opens an existing file read-only, create:false refuses a missing one, per-process idempotent-true by canonical path. Implemented as open-file-description locks (F_OFD_SETLK): they conflict with other processes' traditional fcntl records, and survive this process opening/closing the same path elsewhere — a read_file of the locked path cannot drop them (v0.71.0)
  fcntl_unlock    Release and close this process's POSIX record lock for path. true when held, false when not (v0.71.0)
  copy            Copy a single file: copy(src, dst). Overwrites dst; preserves the source permission bits. Use copy_tree for a directory (v0.22.0).
  copy_tree       Recursively copy a directory: copy_tree(src, dst). Creates dst, copies files (perms preserved) and symlinks (as symlinks); merges into an existing dst (v0.22.0).
  symlink         Create a symbolic link: symlink(target, linkpath) — symlink(2), arguments in symlink(2) order (target first, the link to create second). `target` is stored verbatim and is NOT resolved or validated: a relative target resolves against the link's own directory, and creating a dangling link is legal. Raises EEXIST if linkpath already exists. Read the other way with read_link() (v0.38.0).
  read_link       Read a symbolic link's target: read_link(path) -> string — readlink(2), returning the target EXACTLY as stored (possibly relative, possibly dangling), which is what distinguishes it from realpath()'s full resolution. Raises EINVAL when path is not a symlink; test first with stat(path, {follow_symlinks: false}).is_symlink (v0.38.0).
  rename          Rename/move a path within one filesystem: rename(src, dst) — rename(2), so replacing an existing dst is ATOMIC (a concurrent reader sees either the old file or the new one, never a partial write). This is the primitive for a safe in-place update: write a temp file beside the target, then rename over it. Raises EXDEV across filesystems (copy + remove instead) and ENOENT when src is missing (v0.37.0).
  remove          Remove a single file/symlink: remove(path). No-op if already gone (rm -f). Errors if path is a directory — use remove_dir (v0.22.0).
  remove_dir      Recursively remove a directory and its contents: remove_dir(path) (rm -rf). No-op if already gone (v0.22.0).
  chmod           Set file/directory permissions. chmod(path, 0o755) — mode as a VALUE (use an octal literal) or an octal string "0755" (v0.11.0: a number is now the value, not its decimal digits read as octal)
  fsync           Make a file, a directory or a whole tree durable: fsync(path[, {recursive}]) -> number of inodes synced. A file is fsync(2)ed; a directory is opened and fsynced, which persists the entries created, renamed or removed in it; recursive:true syncs every regular file and directory beneath (children first, symlinks never followed, their entries persisted by their directory), then the directory itself. The path itself follows a symlink. Failures raise FSYNC_FAILED with details.path naming what could not be synced (v0.117.0)
  chown           Set file owner/group by numeric uid/gid: chown(path, 1000, 1000). Follows symlinks by default; chown(path, uid, gid, {follow_symlinks:false}) changes a symlink itself (lchown, v0.117.0). Numeric only (no name resolution) (v0.17.1)
  mime_type       The type of a file from the freedesktop shared-mime-info database, as the desktop names it (requires mime feature): mime_type(path[, {content}]) -> {mime, by, uncertain, exists, parents}. Globs first, magic to settle a missing or ambiguous glob, then a text check (the GLib order). by is stat|glob|magic|content|fallback; parents lists every supertype nearest first, ending text/plain (for text/*) and application/octet-stream. {content:false} never opens the file. A missing path is typed by name with exists:false; an unreadable file by name, uncertain. Follows symlinks (v0.113.0)
  stat            Stat a path → map {uid, gid, nlink, size, mode, perm, ino, dev, ctime, mtime, atime, ctime_nsec, mtime_nsec, atime_nsec, is_file, is_dir, is_symlink}. ino/dev are STRINGS (u64, exceed f64 exact range); mode is full st_mode, perm = mode & 0o7777; *time are epoch seconds (f64) and *_nsec the sub-second part 0..=999999999 (v0.44.0) — compare the PAIR to see a same-second rewrite. Follows symlinks by default; stat(path, {follow_symlinks:false}) is lstat (v0.17.1)
  line_count      Count lines in a file by streaming — never loads the whole file (byte-oriented, so it works on non-UTF-8 files too) (streams since v0.28.1)
  head            First N lines of a file as a list (default 10) — streams and stops after N lines, never reads the rest (the no-slurp twin of take(read_lines(p), n)) (v0.28.1)
  tail            Last N lines of a file as a list (default 10) — reads backwards in blocks from EOF, never slurps the whole file (the no-slurp twin of take(read_lines(p), -n)) (v0.28.1)
  basename        Return the filename component of a path
  dirname         Return the directory component of a path
  extname         Return the file extension (including the leading dot)
  path_join       Join path components with the native separator
  path_parts      Decompose a path into {dir, base, stem, ext} (v0.2.1)
  walk            Recursive directory walk: walk(dir, {max_depth, follow_symlinks, include_dirs, strict}); invalid max_depth raises instead of becoming unlimited (strict since v0.55.0). Unreadable directories and unstat-able entries are skipped unless strict: true, which raises WALK_UNREADABLE (details.path names the first one) so a gate can tell no matches from could not look
  readline        Read a line from stdin (optional prompt argument)
  read_stdin      Read all of stdin to EOF as a string (for pipe/hook input). STRICT UTF-8 — binary stdin raises; use read_stdin_bytes for that
  read_stdin_bytes Read all of stdin to EOF as raw bytes — the binary twin of read_stdin, which refuses invalid UTF-8. Optional arg caps the read: read_stdin_bytes(8192) reads at most 8192 bytes, the same cap contract as read_file_bytes (v0.65.0)
  tty_mode        Put the controlling terminal into raw or cooked mode: tty_mode("raw") disables canonical buffering, echo and signal generation (a lone ESC arrives as one byte — the keystroke-recorder primitive), tty_mode("cooked") restores the saved termios. The original termios is restored on process exit if the caller never returns to cooked (v0.103.9)
  stdin_copy      Copy stdin to a file, flushing every chunk, until EOF — the incremental twin of read_stdin_bytes, so a recorder killed mid-stream keeps the bytes it already read. Pair with tty_mode("raw") to capture keystrokes (v0.103.9)
  sqlopen         Open a SQLite database and return a handle: sqlopen(path[, mode]). mode "ro" (default) is read-only and the file must exist (SQL_NO_DATABASE otherwise); "rw" or "rwc" opens read-write and creates a missing file, in WAL mode with a 5 s busy timeout. ":memory:" is a private in-memory database. Any other mode raises. See mix man sqlopen
  tar_list        List a tar archive (zstd default, gzip or none codec) WITHOUT extracting: streaming entries {name,size,mode,uid,gid,kind,mtime}; the compressed stream is drained to EOF so the frame checksum is verified
  tar_unpack      Safely unpack a tar archive into dest (which must not exist, in a parent no other user can write unless sticky): every member is validated (no absolute/.. paths, a leading ./ accepted, no device/fifo, symlink targets contained relative to the link's own directory and never through another symlink, no extraction through a created symlink, hardlinks only to earlier files), entries land in a private staging dir held by descriptor and renamed into place (never replacing dest) only after the stream verifies to EOF — non-zero data after the tar end is refused (one tar; one zstd frame, gzip members concatenate); PAX global headers count as metadata. opts: codec (zstd default), numeric_owner (default true for root only), xattrs (default true: user.* only), keep_special_bits (default false strips suid/sgid and security.capability), privileged_xattrs (default false: trusted.*, ACLs, other security.*), max_entries, max_bytes, max_name, max_stream_bytes (bounds the decoded stream, longname/PAX buffers included), max_xattr_bytes (16 MiB). Unapplied owners are listed in the receipt's warnings, and their special bits dropped
  tar_pack        Pack a source DIRECTORY into a new archive at path (deterministic sorted walk, numeric owner/mtime/mode, security.capability captured as a SCHILY.xattr PAX record with keep_special_bits; refuses device/fifo members, an output inside the source, and a file that changes size while packed). opts: codec (zstd default), level (zstd 1..=22 default 7, gzip clamps to 9), keep_special_bits (default false strips suid/sgid)
  sqlexec         Execute SQL on a SQLite handle, return result rows
  sqlclose        Close a SQLite database handle
  write_stdout    Write values to fd 1 AS THEY ARE — no trailing newline, no separator, flushed. bytes/buffer go out verbatim; every other value renders exactly as print() renders it. Never re-opens a path, so it works when fd 1 belongs to another user (the sieve-filter case). A failed write RAISES (catchable): IO_BROKEN_PIPE when the consumer went away, else IO_WRITE_FAILED — print raises the same way since 0.99.0 (B9)
  write_stderr    Write values to fd 2 as they are — the stderr twin of write_stdout, same contract (v0.65.0)
  print_raw       ALIAS of write_stdout — identical contract, the spelling for `print` without the trailing newline (v0.65.0)
  eprint_raw      ALIAS of write_stderr — identical contract, the spelling for `eprint` without the trailing newline (v0.65.0)
  print           Print values to stdout with newline (statement, not a builtin call); bare `print` emits a blank line
  eprint          Print values to stderr with newline (statement, not a builtin call); bare `eprint` emits a blank line

## system  — see [system](system.md)

  env             Get environment variable value ("" if unset); env(name, default) returns default when unset or empty
  time            Return current Unix timestamp as float
  monotonic       Return CLOCK_MONOTONIC seconds as a float — the kernel monotonic clock (the one compositor FRAME_TRACE start_us/end_us stamp), never stepped by NTP or wall-clock adjustment, so it never goes backwards and differences are true elapsed intervals. The epoch is unspecified (on Linux it counts from boot); use time() for calendar timestamps, this for measuring and for correlating with compositor traces
  pid             Return current process ID
  uid             Effective user id of this process (geteuid) — normally the id a file access is checked against (Linux checks fsuid, which tracks euid unless setfsuid(2) is called; no Mix script can call it, though an embedder can), so it is the one to compare a stat() map's `uid` against when deciding whether a path is yours (v0.41.0)
  gid             Effective group id of this process (getegid) — the companion to uid(), for comparing against a stat() map's `gid`; same fsgid caveat, and it answers only whether a file's group is the EFFECTIVE one, so use groups() to decide which permission class applies (v0.41.0)
  groups          Every group id this process is in — the getgroups(2) supplementary set plus the effective gid, sorted. This is what decides whether the kernel applies a file's GROUP or OTHER permission bits: gid() alone cannot answer it for a file grouped under one of your other groups (v0.42.0)
  args            Return list of script arguments
  getopt          Parse args against a spec map: getopt(args(), {all:{short:"a"}, out:{short:"o", arg:true}}) -> {opts, rest, errors}. opts has every declared option (flag->bool, value->string|nil); rest=positionals (incl. post `--`); errors=collected unknown-option/missing-value strings ([]=clean). Forms: --long, -s, --k=v, --k v, -s v, -- terminator. Minimal: no bundling/abbrev (v0.12.0)
  exit            Exit with optional status code
  sleep           Sleep for N seconds (async)
  task_start      Start an in-process handler task; command must have an async handler. No Bus traffic. Requires the runner's LocalSet; drained on shutdown
  run             Run shell command via sh, return trimmed stdout as string. run(cmd, [{timeout: seconds}]) — 0 (default) = no deadline; a timed-out child is PG-killed and run dies (catchable)
  run_rc          Run shell command, return {rc, stdout, stderr, timed_out, interrupted} map. run_rc(cmd, [{timeout: seconds}]) — 0 (default) = no deadline; timeout → rc=-1 timed_out=true
  run_stream      Run an argv LIST directly (no sh), inheriting stdio so output streams live and the child can use the terminal (interactive when it has a pty, e.g. ssh -t); returns the exit code. run_stream(argv, [{env, clear_env, cwd}]) — same env/cwd semantics as run_argv, so an interactive child gets variables without an `env` prefix exposing them in its ps argv (v0.51.0). The run_argv-only opts (timeout, stdin, stdout, stderr, max_output, stream) are rejected by name: this runner blocks until the child exits and captures nothing
  run_argv        Run an argv list directly (no shell) with structured stdio routing and a whole-call deadline that starts before route opening. opts: timeout; grace (seconds: at the deadline SIGTERM the process group, wait up to grace for it, then SIGKILL — default 0 = SIGKILL at once; refused with timeout:0); stdin nil|string|bytes|buffer|{file}|{null:true}|{inherit:true} (only when mix's own stdin is not a terminal, else STDIN_TERMINAL — use run_stream); stdout capture|inherit|null|{file,append?,mode?}; stderr capture|inherit|null|stdout|{file,append?,mode?}; cwd/env/clear_env; max_output; stream. stdout/stderr default capture; output files default truncate, mode 0o600. Routed non-capture streams return "" with truncation false and are not capped. stderr:stdout merges into stdout. File-open failure or route-open deadline is a PROCESS_STDIO value and the child is not spawned. Captured output abandoned at a deadline is returned partially with its truncation flag true. stream:true + stdout:inherit and all bad options raise OPTION_INVALID before spawn. opts may be nil (defaults). Ordinary command/setup failure is encoded in the VALUE; timeout default 30s; max_output default 8 MiB per captured stream
  run_parallel    Run many argv jobs concurrently with a bounded worker pool: run_parallel(jobs[, {max, timeout}]) -> list of process_result maps in INPUT order. Each job is an argv list (like run_argv's first arg) OR a {argv, stdin, cwd, env, clear_env, stdout, stderr, max_output, timeout, grace} map mirroring run_argv's options. max bounds concurrency (default 8, hard-capped at 256 live workers — excess jobs still run, drained by index); a top-level timeout (seconds) overrides every job's own. A job may NOT disable its deadline (timeout: 0 is refused) — one hung job would park the whole batch. Each result is EXACTLY run_argv's process_result map, so existing result-handling code ports unchanged; one job's ordinary failure (nonzero/timeout/spawn) is DATA in its map, never a raise. Process-level fan-out (std::thread over the run_argv engine), NOT in-language concurrency — the evaluator is single-threaded and Values never cross a thread; a job's `stream` flag is ignored (parallel tee would interleave). The killer use is ssh_mix fan-out: run_parallel of ssh argvs. A parse error in ANY job fails the whole call before spawning (v0.82.0)
  run_argv_must   Fail-fast run_argv with the same structured stdio opts: returns captured stdout unchanged when ok and no captured stream truncated ("" when stdout is routed), else raises PROCESS_EXIT_NONZERO / PROCESS_TIMEOUT / PROCESS_SIGNAL / PROCESS_INTERRUPTED / PROCESS_OUTPUT_LIMIT or the result's setup/lifecycle error_code (PROCESS_STDIO / PROCESS_SPAWN / PROCESS_IO / PROCESS_INTERNAL) with the complete result map in $err.details.result
  run_pipeline    Run one or more argv stages without a shell, connecting each stdout to the next stdin. Stage maps accept argv/cwd/env/clear_env/stderr, plus stdin on the first stage and stdout on the last, using run_argv's stdio grammar. Every route and pipe is prepared before any stage runs, so PIPELINE_STDIO means no stage ran. Returns a distinct pipeline_result with final stdout/exit fields and per-stage outcomes. One whole-call deadline starts before route opening; captured output abandoned at that deadline is partial with its truncation flag true. Non-final SIGPIPE is NOT accepted by default: any stage killed by a signal makes the pipeline not-ok, matching `set -o pipefail`. Pass allow_signal:true to accept a non-final SIGPIPE when every downstream stage succeeded (the `yes | head -1` idiom). Every stage carries status ok|exit_nonzero|signal|broken_pipe|timeout|interrupted|setup_error and broken_pipe (killed by SIGPIPE: its reader closed); the result carries status ok|exit_nonzero|signal|broken_pipe|timeout|interrupted|setup_error, failed_stage (the RIGHTMOST non-ok stage, pipefail's rule; nil when none) and a one-line human summary — gates branch on status, never on text. Ordinary failure is encoded in the VALUE — never raises
  run_pipeline_must Fail-fast run_pipeline twin: returns final stdout unchanged when the pipeline is ok and no captured output truncated; otherwise raises PIPELINE_* with the complete pipeline_result in $err.details.result
  spawn           Start a child and return its PID. String form uses a shell and optional stdout/stderr paths. Argv form runs directly with options: detach, die_with_parent, exit_event, tag, cwd, env, clear_env, stdout, stderr. exit_event:true (Linux pidfd) registers the sole reaper in this evaluator and emits proc.exited {pid,tag,exit_code,signal}; tag is a string up to 4096 bytes, default empty. Cannot detach a managed child. Managed children are killed and reaped when their evaluator retires, after handler drain; failed reload leaves old managed children intact. die_with_parent additionally arms kernel parent-death SIGKILL. Without exit_event, existing detached/owned/plain spawn semantics apply. Stdio defaults null, capture is refused; cwd/env/clear_env match run_argv. See system manual for lifetime rules
  kill            Send signal to process (default SIGTERM); returns false when the signal could not be delivered. Both arguments must be whole NUMBERS and neither is coerced — a bool/string pid raises TYPE_MISMATCH rather than becoming 0 (which signals this process's whole group), and an unrecognised signal raises rather than silently defaulting to SIGTERM (strict since v0.52.0)
  shell_quote     Single-quote-wrap a string for safe interpolation into a POSIX shell command
  sql_quote       Escape a string for SQL string literals: doubles ' and escapes \ (MySQL/MariaDB-safe — the documented target; also safe for SQLite, where a literal backslash arrives doubled — use sqlexec binds for exact bytes); NUL bytes stripped
  random_password Generate an alphanumeric password (default len 16, no O/o, guaranteed upper+lower+digit)
  ssh_run         Run a command on a remote host via ssh; returns {stdout, stderr, exit_code, ok, duration_ms, host, timed_out, interrupted, utf8_lossy, stdout_truncated, stderr_truncated}; max_output optionally caps local capture bytes per stream (omitted: unbounded; 0 is REJECTED — unlike run_argv, where 0 means unbounded — omit the key instead). A cap that cuts mid-UTF-8-sequence makes the lossy decode insert U+FFFD, so utf8_lossy: true beside stdout_truncated: true may be local truncation damage, not remote garbage. env values ship by default in a Mix driver to the remote mix binary (mix_bin opt, else local env MIX_REMOTE_BIN, else /opt/mixos/bin/mix)
  ssh_must        ssh_run wrapper: returns stdout on success, throws a Mix error otherwise
  ssh_mix         Run Mix source on a remote host: ships the source over ssh stdin into `<mix_bin> -`, bypassing ALL shell quoting. The remote binary is the mix_bin opt, else the local env var MIX_REMOTE_BIN, else /opt/mixos/bin/mix; it must be an absolute path or a bare name using only [A-Za-z0-9_./+-] (anything else raises OPTION_INVALID locally). ssh_mix(host, source, [opts]) -> same map as ssh_run; bindings maps valid Mix identifier names to strict-data-encoded values prepended as `$name` assignments, and decode:"data"|"json" adds a parsed `.value` from stdout. max_output caps local capture per stream (0 rejected; omit for unbounded); a truncated stdout REFUSES to decode (raises) — a truncated prefix can parse as a smaller, wrong value — so omit decode and inspect stdout/stdout_truncated to work with partial output. Accepts every ssh_run opt except stdin/env_transport. Remote command failure stays in the result value; invalid arguments/options raise locally. (v0.20.4)
  ssh_mix_many    ssh_mix on many hosts at once: ssh_mix_many(hosts, source[, opts]) -> map host -> ssh_result, keyed in INPUT order. Every host gets the same source, bindings, env and decode, and each result is EXACTLY ssh_mix's ssh_result map, so per-host handling code ports unchanged. opts = every ssh_mix opt plus max (concurrency, default 8, at most 256 live workers — run_parallel's numbers, its own loop). Options are validated once (even for an empty host list) and every host is checked before any ssh spawns; a wrong argument type raises TYPE_MISMATCH. After that nothing raises — one host's failure is DATA in its own map: unreachable, nonzero exit and timeout arrive as ok:false; a local spawn/pipe failure as ok:false with error_code (`PROCESS_SPAWN`, `PROCESS_STDIO`, …) and error; a decode refusal (truncated or unparseable stdout, where ssh_mix raises) as ok:false, decode_error and no value; a host never started because of Ctrl-C as ok:false, interrupted:true. hosts must be unique strings; timeout:0 is refused (one hung host would park the batch); there is no whole-call deadline
  send_mail       Send a plain-text email through the local MTA: send_mail({to, from, subject, body[, headers]}[, {host, sendmail, timeout, mix_bin}]) -> run_argv's process_result + message_id (+ host, only with the host opt). Renders an RFC 5322 message (From, To, Subject, Date, Message-ID, MIME-Version, text/plain utf-8) and pipes it to `sendmail -t -i -f <envelope>` on stdin — never a network SMTP client; ok means the MTA accepted it, not that it was delivered. to is a string or list of strings; Cc/Bcc go in headers. from is exactly one mailbox, addr or Name <addr> (a comment, a second mailbox or <> raises); its address is the envelope sender. Long headers are folded within 78 columns (an unbreakable run over 998 raises); a non-ASCII body or one with a line over 998 bytes goes quoted-printable, else 7bit. A non-ASCII subject is RFC 2047-encoded; every other header value must be ASCII, and CR/LF/NUL in any header raises. headers adds headers or replaces the generated Date/Message-ID/MIME-Version; From/To/Subject there raise (set them in msg), and so do Content-Type/Content-Transfer-Encoding (send_mail encodes the body itself, always text/plain utf-8). sendmail is found on PATH, then /usr/sbin/sendmail, /usr/lib/sendmail, unless the sendmail opt names it. host sends from that host via ssh_exec (remote default /usr/sbin/sendmail); mix_bin (host only) names the remote mix binary, as for ssh_mix. An MTA failure or missing sendmail is DATA (ok:false, exit_code, stderr, error_code); bad input raises before anything runs: OPTION_INVALID (msg fields, options), TYPE_MISMATCH (msg not a map, arity), or ssh_exec's own validation errors with host
  ssh_exec        Run an argv list DIRECTLY on a remote host via a strict-data driver and remote run_argv. Remote stdio allowlist: stdin nil|string|{file}|{null:true} (a stdin STRING is always data, as locally — there is no stdin "inherit" route on either side); stdout capture|null|{file}; stderr capture|null|stdout|{file}. File paths resolve remotely. stdout/stderr inherit and stream:true raise OPTION_INVALID locally before ssh because they would corrupt or bypass the result envelope. Binary stdin also raises locally. Transport/protocol failures and remote command failure are returned in the process_result plus host; a remote without run_argv returns SSH_REMOTE_UNSUPPORTED without running the command. The remote mix binary is the mix_bin opt (older name remote_mix), else local env MIX_REMOTE_BIN, else /opt/mixos/bin/mix
  process_alive   Test if a process exists (signal 0 check). EPERM counts as alive: existence does not imply permission to signal, including another user's process. pid must be a positive whole NUMBER; no coercion. Nonpositive, bool or string PIDs raise TYPE_MISMATCH. Reaps exited unmanaged children; controller-owned job and registered native-task PIDs use only signal 0 so their sole wait owner retains every status (zombies may briefly report alive).
  net_watch       Subscribe to Linux rtnetlink link/address changes; returns an evaluator-owned opaque handle. Delivers net.changed {watch, changes:[{kind:"link"|"addr", ifname, index, up, removed, operstate?, loopback?, wireless?, family?, address?, prefix?}], overflow, closed?} via $event.args; bursts coalesce per link/address, repeats that change nothing are dropped, overflow means re-read net_state(). opts {events: ["link","addr"]}. No polling fallback
  net_unwatch     Cancel a net_watch handle and its pending changes
  net_state       Snapshot of network links and addresses from an rtnetlink dump: {links:[{ifname, index, up, operstate?, loopback, wireless}], addresses:[{ifname, index, family, address, prefix}]}. up = operstate up, or IFF_UP+IFF_RUNNING when the driver reports unknown (lo, WireGuard)
  audio_watch     Subscribe to PipeWire (pulse server) change notices through one managed `pactl subscribe` child; returns an evaluator-owned opaque handle. Delivers audio.changed {watch, changes:[{facility, kind, index}], overflow, closed?} via $event.args; read the volume with audio_state() once per batch. closed {error_code:AUDIO_SOURCE_EXITED} when the server goes away. opts {facilities (default sink, source, server, card), runtime_dir}
  audio_unwatch   Cancel an audio_watch handle: kills and reaps its pactl child, drops pending changes
  audio_state     Default audio sink volume via one `wpctl get-volume @DEFAULT_AUDIO_SINK@` (2 s deadline): {ok, volume, level (0-100+), muted, reason?}. No default sink, a wpctl that is missing or cannot start, or a timeout is ok:false with a reason, never an error. opts {runtime_dir}
  panic           Abort via an uncatchable Rust panic (distinct from catchable die); the SPEC 18 §3.4 handler boundary isolates it in --serve mode
  raise           Raise a catchable structured error: raise(code, message[, details]) — code is UPPER_SNAKE (e.g. "VALIDATION_REQUIRED", stable identifiers, scripts may define their own); a non-string message is coerced to its string form; catch with `catch $msg, $err` and read $err.code / $err.details / $err.frames (v0.29.0)
  hostname        Return the system hostname
  cwd             Return current working directory
  chdir           Change current working directory
  platform        Return OS platform string (linux, macos, windows, etc.)
  script_path     The absolute, symlink-resolved path of the running ENTRY script, fixed when it starts: the same answer as realpath($0) at start, and a chdir() does not move it. nil under `mix -c`, in the REPL and for `mix -` (stdin). Always the entry script: a require()d module, even during its top-level init, gets the entry script's path, not its own (v0.111.0)
  script_version  The running entry script's provenance: {name, version, sha, sha256, modified, mix: {version, sha, dirty}} — `version` is the `-- version: X.Y.Z` header (nil when absent or malformed), `sha` the first 12 hex of the content SHA-256, `modified` the file mtime as RFC 3339 UTC (nil for `mix -`). Always the ENTRY script (a require()d module gets its caller's record); held per evaluator, so each --serve RELOAD generation answers for its own file. Returns nil in the REPL, under `mix -c`, and in embedders that install no record. The same facts `mix SCRIPT --version` prints, as data (v0.95.0)
  which           Locate an EXECUTABLE in PATH: a PATH entry is returned only if it is a regular file the kernel says this process may execute (faccessat2 X_OK, so POSIX ACLs count), never merely a file that exists, and never a directory. cmd must be a string and is not coerced. Returns nil when nothing on PATH is runnable under that name (executability enforced since v0.52.0)
  date_format     Format Unix timestamp with strftime pattern
  date_parse      Parse date string with strftime pattern into Unix timestamp
  now_iso         Current time as ISO 8601 string
  duration_format Format seconds as human-readable duration (e.g. "2h 15m")
  relative_time   Format timestamp as relative string (e.g. "3 hours ago")
  base64_encode   Encode string as base64
  base64_decode   Decode base64 string
  hash_blake3     BLAKE3 hash of a string/bytes/buffer → lowercase hex; pass {raw:true} for the raw digest as bytes (v0.66.0)
  hash_sha256     SHA-256 hash of a string/bytes/buffer → lowercase hex; pass {raw:true} for the raw 32 digest bytes (v0.66.0 — before that a second argument was silently IGNORED)
  hash_md5        MD5 hash of a string/bytes/buffer → lowercase hex; {raw:true} → bytes. ⚠ CRYPTOGRAPHICALLY BROKEN (collisions since 2004) — legacy interop only (Content-MD5, mail dedup keys, checksums against existing tools), NEVER a security decision; use hash_sha256/hash_blake3 for those (v0.66.0)
  hash_sha1       SHA-1 hash of a string/bytes/buffer → lowercase hex; {raw:true} → bytes. ⚠ CRYPTOGRAPHICALLY BROKEN (SHAttered, 2017) — legacy interop only (git object ids, older ETags/APIs), NEVER a security decision; use hash_sha256/hash_blake3 for those (v0.66.0)
  hmac_sha256     HMAC-SHA256 (RFC 2104) of a message with a secret key → lowercase hex; {raw:true} → the 32 MAC bytes (v0.66.0) — webhook signature verification (Stripe-Signature etc). Accepts string/bytes/buffer for both args (requires crypto feature)
  password_hash   Hash a password: password_hash(plaintext[, cost]) → bcrypt $2b$… string (cost 4-31, default 12; input over 72 bytes raises), or password_hash(plaintext, {scheme: "sha512-crypt"[, rounds]}) → $6$… for Dovecot passdbs (rounds 1000-999999999, default 5000; 16-char salt; default rounds emit the implicit glibc `$6$salt$hash` form, 120 chars with the {SHA512-CRYPT} prefix, while any other rounds value adds a `rounds=N$` field). Client-side hashing before writing maild.accounts.password over the Bus — a raw props.set stores the field verbatim (requires crypto feature; v0.71.0, sha512-crypt v0.102.6)
  password_verify Check a plaintext password against a hash: bcrypt (any $2a$/$2b$/$2y$ form) or SHA-crypt ($6$/$5$, incl. the Dovecot {SHA512-CRYPT} prefix) → bool. A malformed hash RAISES rather than answering false — a corrupt stored hash is a config fault, not a wrong password (requires crypto feature; v0.71.0, sha-crypt v0.102.6)
  constant_time_eq Timing-safe equality for secrets/MACs: compares full length with no early exit (plain == leaks a timing oracle). Use for webhook signature comparison. Accepts string/bytes/buffer
  jwt_rs256_sign  Sign JSON object claims with a PEM RSA private key using RS256; optional JSON object headers, alg pinned to RS256. Returns a compact JWT; crypto feature. No token exchange or expiry/audience policy
  hash_file       Streaming digest of a file, fixed 64 KiB working set whatever the size: hash_file(path[, "md5"|"sha1"|"sha256"|"blake3"|nil][, {raw:true}]) → lowercase hex, or bytes with {raw:true}. md5/sha1 added v0.66.0 and are BROKEN hashes for legacy interop only (v0.24.0)
  uuid            Generate a new random UUID v4 string
  dkim_keygen     Generate a DKIM keypair. dkim_keygen("rsa", [bits=2048]) or dkim_keygen("ed25519") → {algorithm, private_pem, public_b64, dns_txt_record}
  http_get        HTTP GET. http_get(url, [headers], [{timeout, ssl_verify, ca_file, ca_pem}] — timeout default 30, 0 disables; ssl_verify default true, false skips TLS cert/hostname checks like curl -k; ca_file/ca_pem ADD a private CA to the default roots — mutually exclusive with each other and with ssl_verify:false, 4 MiB cap, bad PEM raises HTTP_TLS, v0.29.0) → {status, body, bytes, headers, final_url, duration_ms, error_code, error} (headers lowercase-name→list; final_url after redirects; transport failure = status:0 + HTTP_* error_code; v0.30.0). `body` is the response decoded as UTF-8 (nil if not valid UTF-8); `bytes` is the raw byte buffer. Response bodies are capped at 64 MiB (over-cap → {status:0, error}).
  http_post       HTTP POST. http_post(url, body, [headers], [{timeout, ssl_verify, ca_file, ca_pem}]) → {status, body, bytes, headers, final_url, duration_ms, error_code, error} (headers lowercase-name→list; final_url after redirects; transport failure = status:0 + HTTP_* error_code; v0.30.0). Opts (incl. ssl_verify: false → skip TLS verification like curl -k) and `body`/`bytes` semantics (incl. the 64 MiB body cap) match http_get.
  http_request    HTTP any-verb. http_request(method, url, [body], [headers], [{timeout, ssl_verify, ca_file, ca_pem}]) → {status, body, bytes, headers, final_url, duration_ms, error_code, error} (headers lowercase-name→list; final_url after redirects; transport failure = status:0 + HTTP_* error_code; v0.30.0). Opts (incl. ssl_verify: false → skip TLS verification like curl -k) and `body`/`bytes` semantics (incl. the 64 MiB body cap) match http_get.
  http_post_multipart HTTP POST with a multipart/form-data body: http_post_multipart(url, fields, files, [headers], [opts]) → http_response map. `fields` is a map of string form fields; `files` is a map of field_name → {filename, content_type?, data: bytes|buffer} (raw binary payloads, the webhook/file-upload slot — v0.103.12). The boundary is generated, and the Content-Type header is set accordingly.
  http_put_file   Stream a regular file or inclusive range with exact Content-Length. Opts: method PUT/POST/PATCH (default PUT), range:{start,end}, headers, idle_timeout (seconds, default 30), deadline (seconds, default 0), ssl_verify, ca_file, ca_pem. Redirects disabled; 3xx returned. Deadline is cooperative and best-effort during blocking DNS/IO. Fixed 64 KiB transfer buffer; response capped at 64 MiB. Operational errors return status:0; invalid options raise. bytes_written counts source bytes consumed, size is window size, blake3 hashes that window (nil on failure). published is false (no local publication).
  http_get_file   Stream GET through a unique temp sibling and publish atomically. Opts: overwrite (default false), append (default false; requires expect_blake3 and matching 206 Content-Range), expect_blake3 (64 lowercase hex), max_bytes (final size), headers, idle_timeout (seconds, default 30), deadline (seconds, default 0), ssl_verify, ca_file, ca_pem. 200/206 require identity framing and Content-Length; missing length or encoded responses return HTTP_IDENTITY_FRAMING. Append copies and hashes the existing prefix. Redirects returned; error bodies never installed. No-replace is atomic. Deadline is cooperative and best-effort during blocking DNS/IO. bytes_written counts downloaded bytes, size includes prefix, blake3 hashes the final file. published records publication even if directory fsync fails. Operational errors return status:0; invalid options raise.
  bytes_len       Length of a Value::Bytes buffer in bytes (v0.3.1)
  string_to_bytes Convert a string to its UTF-8 byte representation (v0.3.1)
  bytes_to_string Convert a bytes buffer to a string; strict UTF-8, or pass {lossy:true} for a from_utf8_lossy decode (v0.17.2). Also accepts a Buffer.
  bytes_find      0-based byte offset of needle in a bytes/buffer value, -1 if absent; optional `from` (signed, clamped) starts the scan and the result stays ABSOLUTE. Needle: bytes/buffer/string/byte number 0-255, and must not be empty. ⚠ NEVER use bare in a condition: -1 is truthy, 0 is falsy (MIX-W2305) (v0.64.0)
  bytes_starts_with Test whether a bytes/buffer value starts with a prefix (bytes/buffer/string/byte number 0-255); an empty prefix is true (v0.64.0)
  bytes_ends_with Test whether a bytes/buffer value ends with a suffix (bytes/buffer/string/byte number 0-255); an empty suffix is true (v0.70.0)
  bytes_split     Split a bytes/buffer value on a separator (bytes/buffer/string/byte number 0-255) → list of bytes. Same piece rules as split(): absent separator → one whole piece, leading/trailing separator → empty piece. An EMPTY separator raises (v0.64.0)
  bytes_concat    Concatenate 1+ bytes/buffer/string values into one new bytes (a string joins as its own UTF-8). A list argument raises and names bytes_from (v0.64.0)
  bytes_from      Build bytes from a LIST, flat-splicing each item — int 0-255 = one byte, string = its UTF-8, bytes/buffer = its content (same item vocabulary as buffer([items])) (v0.64.0)
  bytes_to_hex    Lowercase hex of a bytes/buffer value, two chars per byte, no separator (v0.64.0)
  bytes_from_hex  Decode a hex string to bytes — strict: even length, [0-9a-fA-F] only, no separators or whitespace. Exact inverse of bytes_to_hex (v0.64.0)
  dns_query       Ask one DNS server one question and get the whole answer: dns_query(name, type[, {server, port, timeout, tcp, recurse}]) -> {ok, rcode, aa, ra, tc, answers, authority, additional, server, port, transport, duration_ms}; each record is {name, type, ttl, data}. type is A, AAAA, MX, TXT, SRV, NS, SOA, PTR, CNAME, CAA, ... (PTR of an IP address asks its reverse name). server defaults to the first resolv.conf nameserver, port 53, timeout 5 s, recurse true (the RD flag); tcp:true forces TCP and a truncated UDP answer is retried over TCP. The name is always fully qualified (no search list). Timeout, unreachable and malformed replies return {ok:false, error_code: DNS_TIMEOUT|DNS_UNREACHABLE|DNS_PROTOCOL|DNS_IO|DNS_SERVER, error}; bad arguments raise (v0.117.0)
  dns_lookup      Resolve a hostname to a list of IP address strings
  udp_send        Send ONE UDP datagram: udp_send(host, port, payload) -> bytes sent. Payload (string/bytes/buffer) goes out verbatim; host is resolved. Not a socket API — nothing to hold or close (v0.71.0)
  udp_recv        Receive ONE UDP datagram: udp_recv(port[, {timeout, host, max}]) -> {bytes, text, from_host, from_port}, or nil on timeout (an ordinary answer, not a fault). timeout seconds default 30, 0 = wait forever; host = bind address default 0.0.0.0; max caps the read (default 65535 = never truncates; a longer datagram truncates to max, recvfrom(2)'s own contract). text is the payload as UTF-8 or nil — bytes always carries the truth (v0.71.0)
  ws_connect      Open a websocket (ws:// or wss://): ws_connect(url[, {insecure, headers, timeout}]) -> numeric handle. insecure:true skips TLS cert verification (self-signed device endpoints — the LG SSAP case); headers adds handshake request headers; timeout seconds bounds connect AND handshake (default 30, must be positive). Requires ws feature (v0.74.0)
  ws_send         Send one websocket frame: text for a string payload, binary for bytes/buffer; flushed before returning. A closed connection raises and retires the handle (v0.74.0)
  ws_recv         Wait for the next DATA frame: ws_recv(handle[, timeout]) -> string (text frame) | bytes (binary frame) | nil on timeout (poll again). timeout seconds default 30, 0 = wait forever. Ping/pong handled internally. A peer close RAISES (catchable) and retires the handle — closed is not confusable with quiet. In a Class C async body, numeric ws_recv(handle[, timeout]) yields on native readiness; subscribed numeric handles refuse SOCKET_SUBSCRIBED. Source-id recv yields outside serve mode; serve mode refuses SOCKET_RECV_SERVE so the event pump cannot steal frames. nil on timeout keeps the connection usable; a terminal raises SOCKET_CLOSED (v0.74.0)
  ws_close        Close a websocket handle: true when it was live, false when unknown/already retired (never raises for the not-held case, like funlock) (v0.74.0)
  http_serve      BLOCKING static file server — the python -m http.server slot: http_serve(root[, {port, host, duration, index, listing, render_md, requests}]) -> requests served. GET/HEAD only (405 otherwise), NO TLS ever and NO dynamic handlers (both are webd's job). port 0 (default) binds ephemeral and PRINTS the URL; host defaults 127.0.0.1 (pass "0.0.0.0" to expose); duration 0 = until SIGINT; listing opts into directory indexes; render_md serves .md as HTML (markdown feature); spa (true=index, or a shell filename) answers an extensionless would-be-404 with that shell so a client-side router boots — for a single-shell SPA; clean_urls serves /foo.html for /foo (GitHub Pages parity — for a pre-rendered page-per-route site), tried before spa. Traversal-proof: every canonicalised path must stay under the canonicalised root (v0.75.0)
  http_recv       Accept ONE HTTP request, answer it, return it: http_recv(port[, {timeout, host, max, respond}]) -> {method, path, query, headers, body, bytes, from_host, from_port}, or nil on timeout. The OAuth-localhost-redirect / webhook-catch shape. respond: {status, body, content_type, headers} (default 200 "ok"); max caps the request body (default 1 MiB); host defaults 127.0.0.1 (v0.75.0)
  tcp_connect     Open a raw TCP connection: tcp_connect(host, port[, {timeout, tls, insecure}]) -> numeric handle. tls:true wraps in TLS (ring-pinned, webpki roots); insecure:true skips cert verification. The stream-socket primitive for a line/binary protocol (SMTP/redis/memcached probe, banner grab) UDP/WS/HTTP don't cover (v0.78.0)
  tcp_send        Send bytes on a TCP handle: tcp_send(h, payload[, {timeout}]) -> bytes sent (string/bytes/buffer, verbatim; flushed). Without timeout each write is bounded by the socket's 30 s write timeout, as before. With {timeout} (seconds, 0 = wait forever) one deadline bounds the WHOLE send however many partial writes it takes; on expiry it raises TCP_SEND_TIMEOUT (details {written, total}) and retires the handle, and bytes already written stay written. The timed wait honours SIGTERM and Ctrl-C. On a tcp_on handle the timeout is the receipt deadline (0 keeps the 30 s bound) (v0.78.0; timeout v0.112.1)
  tcp_recv        Read available bytes: tcp_recv(h[, {timeout, max}]) -> bytes (buffered bytes first, then one read of at most 256 KiB — poll again for more even when max is larger) | nil on timeout (poll again). Bytes not string — a stream has no frame boundary. A peer close RAISES and retires the handle. timeout default 30 (0=forever), max default 64 KiB. Numeric Class C recv yields on native readiness. Source-id recv yields outside serve; serve mode refuses SOCKET_RECV_SERVE and consumes frames through handlers. nil on timeout keeps the connection usable; terminal raises SOCKET_CLOSED (v0.78.0)
  tcp_recv_line   Read the next LINE: tcp_recv_line(h[, {timeout, max}]) -> string (LF + one trailing CR stripped) | nil on timeout. Buffers across reads; if `max` bytes accumulate with no newline the handle RAISES and RETIRES (a peer that never terminates a line — broken framing). For line protocols (SMTP/redis) so a caller need not hand-roll a \r\n scanner. On a unix_connect {frame:"nul"} handle a line is a NUL-terminated frame (no CR stripping). From v0.115.0 a line longer than max raises even when its terminator has arrived. Numeric Class C recv yields on native readiness. A line-mode source-id recv yields outside serve; serve mode refuses SOCKET_RECV_SERVE and uses event handlers. nil on timeout keeps the connection usable; terminal raises SOCKET_CLOSED (v0.78.0)
  ws_on           Subscribe a ws_connect handle to the event stream: ws_on(handle, command) -> source id (string). The connection MOVES to an evaluator-generation reader thread: ordered frames arrive as `command` events {watch, frame:{kind:"text"|"binary", data}} (binary data hex-encoded), a peer close as ONE terminal {watch, closed:{reason}} — then the source retires. ws_send on the moved handle routes to the owner and awaits its receipt; numeric ws_recv refuses. Serve handlers receive frames as events. The reader parks in poll(2) when idle (no timer). Overflow hard-closes the socket with exactly one terminal event, never a silent drop. ws_unwatch cancels, joins and emits NO terminal marker (v0.107.0)
  ws_unwatch      Cancel a ws_on subscription: ws_unwatch(source) -> nil. Cancels and joins the reader, drops queued frames and wakes a parked ws_recv with SOCKET_WATCH_HANDLE. Emits NO terminal event (explicit close — documented). Unknown or retired sources raise (v0.107.0)
  tcp_on          Subscribe a tcp_connect handle to the event stream: tcp_on(handle, command[, {frame:"line"|"bytes", max}]) -> source id (string). frame defaults to "bytes": ordered raw chunks of at most 64 KiB; frame:"line" splits on LF (one trailing CR stripped) with max capping the line length (default 65536) — a line over max hard-closes with one terminal event. On a unix_connect {frame:"nul"} handle, line frames end at NUL; from v0.115.0 a complete line over max also hard-closes. Same ownership, ordering, overflow and retirement rules as ws_on; tcp_recv consumes a bytes source, tcp_recv_line a line source, and a mismatched verb refuses (SOCKET_KIND). A tcp_listen LISTENER subscribes too (no options): each accepted connection arrives as {watch, accepted:{handle, peer:{host, port}}}, handle a plain connected handle; tcp_accept(source) takes the next one outside serve mode (v0.107.0; listeners v0.112.0)
  tcp_unwatch     Cancel a tcp_on subscription: tcp_unwatch(source) -> nil. Same contract as ws_unwatch (v0.107.0)
  tcp_close       Close a TCP handle or listener: true when live, false when unknown/already closed (never raises for that, like funlock) (v0.78.0)
  tcp_listen      Listen for TCP connections: tcp_listen(host, port[, {backlog}]) -> numeric listener handle (tcp_connect's handle space). host is required: "127.0.0.1" is the normal choice, and a non-loopback address ("0.0.0.0", a LAN IP) must be named explicitly. port 0 binds an ephemeral port (read it with tcp_local_addr); backlog defaults to 128 (1..4096). Owned by the evaluator generation. Raises TCP_LISTEN_ADDR_IN_USE, TCP_LISTEN_PERMISSION, TCP_LISTEN_ADDR_UNAVAILABLE, TCP_LISTEN_ADDRESS, TCP_LISTEN_ARGUMENT, TCP_HANDLE_LIMIT (v0.112.0)
  tcp_accept      Wait for one connection on a tcp_listen listener: tcp_accept(listener[, {timeout}]) -> numeric connected handle (use with tcp_send/tcp_recv/tcp_recv_line/tcp_on/tcp_close) | nil on timeout. timeout seconds default 30, 0 = wait forever. Numeric Class C accept yields on native readiness; a subscribed listener refuses SOCKET_SUBSCRIBED. Source-id accept (a tcp_on listener source) yields outside serve; serve mode refuses SOCKET_RECV_SERVE. Accepted handles belong to the evaluator generation (v0.112.0)
  tcp_local_addr  Local address of a TCP listener or connected handle: tcp_local_addr(handle) -> {host, port} — how a script that bound port 0 learns its port (v0.112.0)
  unix_connect    Open a unix-domain stream socket: unix_connect(path[, {timeout, frame}]) -> numeric handle in tcp_connect's handle space, so tcp_send, tcp_recv, tcp_recv_line, tcp_on and tcp_close take it (tcp_local_addr refuses: no TCP address). path is an absolute filesystem path (at most 107 bytes; abstract sockets are not offered). timeout (seconds, default 30) bounds the connect and each write; a listener with a full backlog fails at once (UNIX_CONNECT_BUSY) rather than block. frame:"nul" makes a line a NUL-terminated frame (Varlink, hostd): tcp_recv_line returns the next frame without its NUL and tcp_on {frame:"line"} delivers one per event; send the NUL yourself (tcp_send(h, json .. chr(0))). frame:"line" (default) keeps LF lines. Raises UNIX_CONNECT_NOT_FOUND, UNIX_CONNECT_PERMISSION, UNIX_CONNECT_REFUSED, UNIX_CONNECT_BUSY, UNIX_CONNECT_TIMEOUT, UNIX_CONNECT_ARGUMENT, UNIX_CONNECT (v0.115.0)
  help            Show Mix builtin help in the REPL
  project_info    Read-only workspace introspection: project_info() -> {root, main: {members: [crate names], exclude, toolchain}, desktop: bool} — the main workspace members (crates/* minus excludes), the pinned rust-toolchain channel, and whether the desktop workspace is present. For orchestration scripts, no ad-hoc TOML parsing (v0.103.15)
  require         Load a Mix module: evaluate the file once in an isolated scope, return its exports (map of top-level fns + $vars, or the file's top-level return value). Cached per canonical path; cycles error (v0.27.0)

## format  — see [strings](strings.md)

  fmt             printf-style format string → string. Specs: %s %d %f %.Nf %Nd %-Ns %0Nd %% (v0.2.0; %0Nd zero-pad v0.54.0 — numeric only, use lpad(s,n,"0") for strings). Dynamic width `*` takes the width from the next argument: %*s %-*s %*d %0*d %*f (v0.63.0; the width argument must be a non-negative integer). For byte-exact C-printf parity (%e %g %x, flags, glibc float rounding) use sprintf()
  sprintf         C-compatible printf: sprintf(fmt, ...) → string. Conversions %d %i %u %o %x %X %f %F %e %E %g %G %s %c %%; flags - + 0 # and space; width/precision incl. *; length modifiers parsed and ignored (integer conversions are 64-bit, so a negative %u/%x prints its 64-bit two's-complement). Float output matches glibc printf byte-for-byte (fixture-tested) — for emitting numbers a C/Rust consumer compares exactly. Divergences: %s pads by codepoints and %.Ns truncates to ≤N bytes without splitting a codepoint; %c takes a Unicode scalar (v0.71.0)
  printf          Formatted write to stdout (no trailing newline — include \n explicitly) (v0.2.0)
  eprintf         Formatted write to stderr (v0.2.0)
  format_bytes    Format byte count as human-readable size (e.g. "1.5 MB"); a non-numeric argument raises (strict since v0.55.0)
  format_number   Format number with thousands separators; non-numeric value/decimals arguments raise (strict since v0.55.0)

## json  — see [data](data.md)

  json_parse      Parse JSON string into Mix value
  json_encode     Encode Mix value as JSON string
  jq              Run a jq filter; filter MUST yield 0 (→nil) or 1 (→value) output, >1 raises. jq(value, filter)
  jq_all          Run a jq filter, collect ALL outputs as a list (the stream case). jq_all(value, filter)
  read_json       Read a single-record JSON file directly into a Mix value (v0.2.3)
  read_jsonl      Read a JSON-lines file — list of records, strict by default, {skip_errors: true} for lenient (v0.2.3)
  yaml_parse      Parse a YAML string into a Mix value (requires yaml feature; v0.71.0). Single document by default (0 docs → nil, >1 raises); pass {docs:true} for a list of every document. Anchors/aliases resolved; scalar mapping keys become string keys; a non-scalar key raises
  yaml_encode     Encode a Mix value as YAML (requires yaml feature; v0.71.0). No leading --- marker, trailing newline guaranteed; whole numbers emit as integers; nil/bool/number/string/list/map only — bytes, buffer or function values raise
  toml_parse      Parse TOML string into Mix map
  toml_encode     Encode Mix value as TOML. Raises TOML_UNREPRESENTABLE with {path,type} details for nil, function, bytes, or buffer values instead of silently replacing them with empty strings (strict since v0.55.0)
  data_parse      Parse a strict-data `.conf.mix` string into a Mix value (inverse of data_encode) (v0.3.2)
  data_encode     Encode a Mix value as a strict-data `.conf.mix` string with correct \$ / \~ / \\ escaping; round-trips through data_parse. data_encode(value, [pretty]) — truthy 2nd arg emits multi-line indented output (v0.3.2)

## validate  — see [data](data.md)

  require_key     Assert a map key is present with a non-nil value and return it; raises VALIDATION_REQUIRED with details {path, expected, actual_type} (v0.29.0)
  expect_type     Assert a value's type and return it: expect_type($v, "integer") — types: any nil bool number integer string bytes buffer list map function (integer = finite whole within ±2^53-1); raises VALIDATION_TYPE (v0.29.0)
  nonblank        Assert a string contains a non-whitespace character, return it UNTRIMMED; the optional label names the value in the error; raises VALIDATION_NONBLANK — the boundary guard against nil/"" flowing into hostnames and paths (v0.29.0)
  get_or          Map lookup with a default that covers BOTH an absent key and a nil value (the tolerant twin of require_key) (v0.29.0)
  validate        Validate a map against a field spec at a job/API boundary: validate($raw, {node: {type: "string", nonblank: true}, plan: {enum: ["gold", "silver"]}, vmid: {type: "integer", min: 100, max: 999999}, tags: {required: false, type: "list", items: {type: "string"}}, owner: {type: "map", schema: {name: {nonblank: true}}}}). Rules: required (default TRUE) / type (string or list of types) / nonblank / enum / min / max / min_length / max_length / items / schema. Returns the ORIGINAL map unchanged; optional absent-or-nil fields skip their rules; unknown INPUT fields pass through; unknown RULE keys raise VALIDATION_SPEC; violations raise VALIDATION_* with details {path, expected, actual_type} — paths like owner.name and tags[2] (v0.29.0)

## hof  — see [hof](hof.md)

  sort_by         Return list sorted ascending by key function (stable) (v0.2.0)
  filter          Return new list of items where predicate returns truthy (v0.2.0)
  map             Return new list of transform(item) results (v0.2.0)
  reduce          Fold list left with an explicit init: reduce($xs, $init, function($a, $b) = ...) (v0.2.0)
  any             Short-circuit: true if any item matches predicate (v0.2.0)
  all             Short-circuit: true if every item matches predicate (v0.2.0)
  count           Count items where predicate returns truthy (v0.2.0)
  min_by          Return the ITEM (not the key) with minimum key-function value (v0.2.0)
  max_by          Return the ITEM with maximum key-function value (v0.2.0)
  sum_by          Sum of key(item) across all items, returns number (v0.2.0)
  group_by        Map of stringified-key → list of items (first-seen key order) (v0.2.0)
  unique_by       Dedup list by key function, first occurrence wins (v0.2.0)

## bus  — see [bus](bus.md)

  bus_call        Call a host-injected Bus verb under delegated identity: bus_call(verb, args) → reply. The embedder bounds which verbs are reachable and injects the delegation envelope; the script names no host/peer/actor
  publish         One-call topic publish (0.63.0): publish(topic, body[, opts]) builds the SPEC-02 wire frame and sends it via noded topic.publish — no hand-built ---\n frames, no body=/name= header-route trap. body is the payload STRING (json_encode a map first); opts: {retain: bool, command: string (inner frame header override, defaults to topic), headers: map}. Sets $rc/$result like `send`; returns rc (0 = published)
  serve_name      The Bus service name this `mix --serve` citizen registered under — the `--name` value, else the script-stem derivation — or nil in a plain script or the REPL. Read it instead of hard-coding the name: a second instance started with `--name other` must publish `other`, not the first instance's name, in anything that routes replies or clicks back to it. `$me = serve_name() ?? "quoin-panel"` keeps a script runnable outside serve mode (v0.91.0)
  is_reload_candidate True only while a `--serve` hot-reload candidate's init body is executing (false during the initial boot, in a plain script, and in every committed generation). A loader branches on it: the candidate must prepare passive state only — no starts, no spawns, no stopping old behaviour, no persisted writes — because a failed candidate reverts to the old evaluator with its managed children intact, and the committed generation reaps the old children before its own `lifecycle.commit` handler starts anything. Commit-time work belongs in an `on lifecycle.commit` handler, which the runtime queues locally exactly once per committed swap
  send            Send a request to a Bus port: send PORT VERB [ARGS...]. Reply bands in $rc: 0 delivered+accepted; 1..9 delivered with a warning (still success); >=10 peer application error (kept in $rc, details in $reply); -1 transport failure; -2 per-send timeout; -3 Bus unavailable. $result holds the reply body
  emit            Fire-and-forget Bus message (no reply is waited for): emit PORT VERB [ARGS...]
  address         Set the default Bus target for a block: address PORT ... end (bare send lines inside go to PORT)
  on              Register a Bus handler: on VERB ... end. A serve citizen answers VERB calls; reply() sends the answer. Topic subscribers match on the inner command
  reply           Answer the in-flight request the serve pump is dispatching (only inside an on handler); payload becomes the caller's $result
  subscribe       Register interest in a Bus topic so deliveries reach a matching on handler: subscribe("topic.name")
  unsubscribe     Drop interest in a Bus topic: unsubscribe("topic.name")
  port_exists     True when a Bus port exists on the broker
  bus_reconnect   Reconnect the Bus broker session
  noded_register  Register this node with noded (identity/bootstrap)

## db  — see [capabilities](capabilities.md)

  db_query        Query the host-injected scoped DB: db_query(sql, [params]) → rows
  db_exec         Exec on the host-injected scoped DB: db_exec(sql, [params]) → {affected, last_insert_id}

## jmap  — see [capabilities](capabilities.md)

  jmap            Call the host-injected JMAP upstream: jmap(method, args) → result, or jmap([[method,args,callId],…]) → methodResponses
  jmap_upload     Upload bytes as a JMAP blob via the host-injected upstream: jmap_upload(body[, content_type]) → blobId (the compose half of the mail seam; Email/set create is blob-only)

## datastar  — see [datastar](datastar.md)

  ds_patch_elements Frame an HTML fragment as a Datastar patch-elements SSE event: ds_patch_elements(html, [{selector, mode, view_transition}]) → event string. mode=outer(default)/inner/remove/replace/prepend/append/before/after. Caller MUST html_escape() untrusted content first — this only frames (requires datastar feature) (v0.18.1)
  ds_patch_signals Frame a signal update as a Datastar patch-signals SSE event: ds_patch_signals(signals_map_or_json, [{only_if_missing}]) → event string. A map is JSON-encoded; a string is used verbatim (requires datastar feature) (v0.18.1)
  ds_sse          Assemble a text/event-stream response body from one event string or a list of them: ds_sse(event | [events]) → body. Pair with headers={"Content-Type":"text/event-stream"} (requires datastar feature) (v0.18.1)

## Prelude — Mix-defined helpers, not builtins

`mix help` also lists a small **prelude** (`sum`, `avg`): plain Mix functions auto-loaded from `std/prelude.mix` before every script and `~/.mixrc`. They are not builtins — `mix builtins` and `mix what` do not know them. A builtin always shadows a same-named Mix function, which is why the old prelude `min`/`max`/`abs`/`clamp` shims were retired when the native `math` category landed in v0.19.0, and why the `lines`/`chars`/`read_lines` shims went with the 0.63.0 native `lines`/`chars` (the `read_lines` builtin had shadowed its shim since v0.2.3).

## See also

- [overview](overview.md) · [keywords](keywords.md) · [the mix CLI](cli.md)
- `mix builtins [CATEGORY]` lists one category with one-line descriptions (`mix builtins` alone lists them all); `mix what NAME` describes one builtin or keyword; `mix help` prints the compact category / keyword / subcommand summary.
