Reference
Standard library
What ships with Lira today — the builtins always in scope, and the 21 importable std modules. Every signature here was read from the source, every example runs.
Lira draws a clear line between two kinds of functionality. Some functions
are VM builtins: implemented in the runtime and always in
scope, no import required. Everything else lives in std modules, written in Lira itself under stdlib/, and pulled in with
import std.X.
Builtins vs. stdlib
Builtins need no import. They cover I/O, the core array and
channel operations, file handles, JSON, and a handful of numeric and time
primitives:
-
I/O:
println,eprintln -
Arrays:
len,push,pop -
Channels & fibers:
chan,send,recv,close,spawn,select -
Files:
file_open,file_read,file_write,file_close -
JSON:
json_parse,json_stringify,json_pretty -
Numbers & time:
abs,sqrt,time_ms,sleep
// No import needed — these are VM builtins, always in scope.
fn main() {
// I/O
println("hello from a builtin")
// Collections: arrays are mutated in place by push/pop.
let xs = [1, 2, 3]
push(xs, 4)
println(len(xs)) // 4
println(pop(xs)) // 4
// Numbers
println(abs(-7)) // 7
println(sqrt(144.0)) // 12
// A timestamp, straight from the VM.
let t = time_ms()
println(t > 0) // true
}import std.core
fn main() {
// abs and clamp are methods on int.
println((-5).abs()) // 5
println((15).clamp(0, 10)) // 10
// min and max are free functions taking two ints.
println(min(3, 9)) // 3
println(max(3, 9)) // 9
}The 21 std modules at a glance
Every module below imports cleanly today. The pure ones are self-contained Lira you can read end to end (and the examples in this page run them); the I/O ones are thin wrappers around runtime builtins — file handles, sockets, the system clock, env vars — so they are documented by signature.
std.core
pure
std.math
pure
std.collections
pure
std.strings
pure
std.regex
pure
std.json
pure
std.url
pure
std.uuid
pure
std.hash
pure
std.time
pure
std.sync
pure
std.io
I/O
std.fs
I/O
std.os
I/O
std.env
I/O
std.path
I/O
std.http
I/O
std.net
I/O
std.test
I/O
std.log
I/O
std.random
I/O
Numbers & collections
core extends int with abs / clamp and adds min / max. math hangs single-argument operations off int and float and exposes multi-argument helpers as free functions. collections adds methods to typed arrays.
std.core
pure
int::abs() -> int int::clamp(min, max) -> int min(a: int, b: int) -> int max(a: int, b: int) -> int
std.math
pure
// constants (functions returning float)
math_pi() · math_e() · math_tau() · math_sqrt2() · math_ln2() · math_log10e()
// int methods
int::{sign, factorial, fibonacci, is_prime, is_even, is_odd}() -> ...
int::{is_power_of_two, square, cube, next_power_of_two, popcount}() -> int
int::{sum_to, sum_squares_to}() -> int · int::pow(exp) · int::mod_floor(div)
// float methods
float::{sign, square, cube, cbrt, sigmoid, relu}() -> float
float::{to_radians, to_degrees, wrap_angle, normalize_angle}() -> float
float::clamp(min, max) -> float
// free functions
lerp(a, b, t) · inverse_lerp(a, b, v) · smoothstep(e0, e1, x)
hypot(x, y) · distance(x1, y1, x2, y2) · distance3d(...)
gcd(a, b) · lcm(a, b) · binomial(n, k) · nthroot(x, n) · log(x, base)
min_float(a, b) · max_float(a, b) · approx_equal(a, b, eps)
map_range(v, in_min, in_max, out_min, out_max) · leaky_relu(x, alpha)
sec(x) · csc(x) · cot(x) · asinh(x) · acosh(x) · atanh(x)
std.collections
pure
// on [int]
[int]::{map_double, map_square, filter_positive, filter_even, filter_odd}() -> [int]
[int]::{sum, product, min, max, count, index_of}() -> int · [int]::average() -> float
[int]::{reverse, unique, sort, sort_desc}() -> [int]
[int]::{take(n), skip(n), slice(start, end), concat(other)} -> [int]
[int]::contains(value) -> bool · [int]::{all_truthy, any_truthy, none_truthy}() -> bool
[int]::repeat(value, n) -> [int] (static) · [[int]]::flatten() -> [int]
// on [float] — same reductions / transforms, plus filter_negative
// on [string]
[string]::{contains(v) -> bool, index_of(v) -> int, reverse() -> [string]}
// free generators
range(start, end) -> [int] · range_step(start, end, step) -> [int]
import std.math
fn main() {
// Methods on int.
println((5).factorial()) // 120
println((10).fibonacci()) // 55
println((17).is_prime()) // true
println((-4).sign()) // -1
// Methods on float.
println((180.0).to_radians()) // 3.14159...
// Free functions for multi-argument math.
println(gcd(48, 36)) // 12
println(lcm(4, 6)) // 12
println(lerp(0.0, 10.0, 0.5)) // 5
// Constants are functions.
println(math_pi()) // 3.141592653589793
}import std.collections
fn main() {
let xs = [5, 3, 8, 1, 3, 9]
// Reductions.
println(xs.sum()) // 29
println(xs.max()) // 9
println(xs.min()) // 1
// Transformations return new arrays.
println(xs.sort()) // [1, 3, 3, 5, 8, 9]
println(xs.unique().sort()) // [1, 3, 5, 8, 9]
println(xs.filter_even()) // [8]
// Search.
println(xs.contains(8)) // true
println(xs.index_of(8)) // 2
println(xs.count(3)) // 2
// Generators.
println(range(0, 5)) // [0, 1, 2, 3, 4]
}Text
strings extends the string type with methods, so you write name.to_upper() rather than to_upper(name). regex layers validators and extractors over the regex_* builtins.
std.strings
pure
string::{to_upper, to_lower, capitalize, title_case}() -> string
string::{trim, trim_start, trim_end, reverse}() -> string
string::char_at(i) -> string · string::char_code(i) -> int · string::substring(start, end)
string::{index_of, last_index_of}(substr) -> int · string::contains(substr) -> bool
string::{starts_with(prefix), ends_with(suffix)} -> bool
string::split(delim) -> [string] · string::{replace, replace_first}(old, new) -> string
string::repeat(count) -> string · string::{pad_start, pad_end}(length, pad) -> string
string::{is_empty, is_blank, is_numeric, is_alpha, is_alphanumeric}() -> bool
string::count(substr) -> int · string::word_count() -> int
// free functions
from_char_code(code) -> string · join(arr: [string], delim) -> string
std.regex
pure
is_email(text) · is_url(text) · is_phone(text) -> bool is_digits(text) · is_alpha(text) · is_alphanumeric(text) -> bool extract_numbers(text) -> [string] · extract_words(text) -> [string] remove_whitespace(text) -> string · normalize_whitespace(text) -> string
import std.strings
fn main() {
let title = " the lyre is tuned "
// Methods hang off the string type itself.
println(title.trim().title_case()) // The Lyre Is Tuned
let name = "lira"
println(name.to_upper()) // LIRA
println(name.capitalize()) // Lira
println(name.repeat(3)) // liralira lira -> liraliralira
println(name.starts_with("li")) // true
println(name.index_of("r")) // 2
// split returns [string]; join is a free function.
let parts = "a,b,c".split(",")
println(len(parts)) // 3
println(join(parts, " / ")) // a / b / c
}import std.regex
fn main() {
// Validators return bool.
println(is_email("ada@lira.dev")) // true
println(is_email("not-an-email")) // false
println(is_url("https://lira.dev")) // true
println(is_digits("12345")) // true
// Extractors return [string].
let nums = extract_numbers("order 42 ships in 3 days")
println(nums) // [42, 3]
let words = extract_words("two words")
println(len(words)) // 2
// Whitespace normalizers.
println(normalize_whitespace("a b c")) // a b c
}Data formats
json wraps the json_parse / json_stringify / json_pretty builtins with safe helpers. url, uuid and hash sit on their own runtime builtins.
std.json
pure
// VM builtins (no import) json_parse(text) · json_stringify(value) · json_pretty(value) // std.json helpers json_get(obj, key) · json_has(obj, key) -> bool · is_json_value(val) -> bool json_object() · json_array() · json_parse_safe(text)
std.url
pure
struct URL url_parse(str) -> URL · url_build(url: URL) -> string url_origin(url) · url_path_query(url) -> string url_is_absolute(s) · url_is_relative(s) · url_is_http(url) · url_is_https(url) · url_is_secure(url) -> bool query_parse(q) -> [string] · query_get(q, key) -> string · query_has(q, key) -> bool · query_build(pairs)
std.uuid
pure
uuid() · generate() · random() · time_ordered() -> string is_nil(uuid) -> bool · version(uuid) -> int
std.hash
pure
// builtins: md5 / sha1 / sha256 / sha512 verify_md5(input, expected) · verify_sha1(...) · verify_sha256(...) · verify_sha512(...) -> bool md5_salted(input, salt) -> string · sha256_salted(input, salt) -> string
import std.json
fn main() {
// json_parse / json_stringify are VM builtins; std.json adds helpers.
let text = "{\"name\": \"lira\", \"stars\": 7}"
let obj = json_parse(text)
// Index into the parsed object.
println(obj["name"]) // lira
println(obj["stars"]) // 7
// json_has is a std.json helper.
println(json_has(obj, "name")) // true
println(json_has(obj, "missing")) // false
// Round-trip back to a string.
let out = json_stringify(obj)
println(len(out) > 0) // true
}Time
time adds duration helpers to int (90.minutes() -> milliseconds) and a Timestamp struct with formatting, arithmetic, and comparison methods.
std.time
pure
int::{seconds, minutes, hours, days, weeks}() -> int (durations in ms)
struct Timestamp
timestamp_now() · timestamp_from_ms(ms) · timestamp_from_date(y, m, d)
timestamp_from_datetime(y, mo, d, h, mi, s) · timestamp_parse_iso(s) -> Timestamp
Timestamp::{to_iso, format(fmt), format_date, format_time, format_datetime, format_readable}() -> string
Timestamp::{add(ms), subtract(ms)} -> Timestamp · Timestamp::diff(other) -> int
Timestamp::{elapsed, elapsed_secs}() -> int
Timestamp::{is_before, is_after, is_past, is_future, is_today}() -> bool
Timestamp::{year, month, day, hour, minute, second}() -> int · Timestamp::components() -> [int]
today() · now_time() · now_iso() -> string · timezone_offset() -> int
import std.time
fn main() {
// int gains duration helpers: 90.minutes() -> milliseconds.
let ninety_min = (90).minutes()
println(ninety_min) // 5400000
// Build a fixed timestamp so output is deterministic.
let t = timestamp_from_datetime(2026, 6, 24, 9, 30, 0)
// Formatting methods on the Timestamp struct.
println(t.format_date()) // 2026-06-24
println(t.to_iso()) // 2026-06-24T09:30:00+00:00
// Arithmetic returns new timestamps; diff is in milliseconds.
let later = t.add(ninety_min)
println(later.format_time()) // 11:00:00
println(later.diff(t)) // 5400000
// Component accessors.
println(t.year()) // 2026
println(t.hour()) // 9
}Concurrency
sync gives you mutual exclusion and coordination built on the same channels and fibers covered in the concurrency guide. Because Lira has no RAII, locking is explicit: lock() takes the value out, unlock(v) puts one back; the with closure brackets that pair for you.
std.sync
pure
struct IntMutex · new_int_mutex(initial) -> IntMutex IntMutex::lock() -> int · IntMutex::unlock(value) · IntMutex::with(f: fn(int) -> int) struct StringMutex · new_string_mutex(initial) -> StringMutex (lock / unlock / with) struct WaitGroup · new_wait_group() -> WaitGroup · WaitGroup::done() · WaitGroup::wait(n) struct Semaphore · new_semaphore(n) -> Semaphore · Semaphore::acquire() · Semaphore::release()
import std.sync
// Each worker increments the shared counter once, then signals done.
fn worker(m: IntMutex, wg: WaitGroup) {
let v = m.lock()
m.unlock(v + 1)
wg.done()
}
fn main() {
let counter = new_int_mutex(0)
let wg = new_wait_group()
let n = 5
var i = 0
while i < n {
spawn worker(counter, wg)
i = i + 1
}
// Block until all n workers have finished.
wg.wait(n)
// No RAII in Lira, so locking is explicit: lock to read, unlock to release.
let total = counter.lock()
counter.unlock(total)
println(total) // 5
}System & I/O
Thin wrappers around runtime builtins: file handles, the system clock, the filesystem, and environment variables. Output depends on the host, so these are listed by signature.
std.io
I/O
print_str(s) · print_line(s) · print_fmt(template, values: [string]) debug(label, value: int) · assert(condition: bool, message) now_ms() -> int · delay(ms) · measure_time() -> int
std.fs
I/O
read_file(path) -> string · write_file(path, content) -> bool append_file(path, content) -> bool · exists(path) -> bool · size(path) -> int
std.os
I/O
walk(path) -> [string] · exists(path) -> bool home_dir() -> string · temp_dir() -> string
std.env
I/O
get_or(name, default) -> string · get_bool(name) -> bool is_ci() · is_debug() -> bool · user() · shell() -> string
std.path
I/O
dirname(p) · basename(p) · extension(p) · stem(p) · parent(p) · normalize(p) -> string is_absolute(p) · is_relative(p) · has_extension(p) · starts_with(p, pre) · ends_with(p, suf) -> bool with_extension(p, ext) -> string · components(p) -> [string] join(p1, p2) -> string · path_join(parts: [string]) -> string
Network
http and net wrap the runtime's HTTP and TCP builtins. They perform real I/O, so they are listed by signature.
std.http
I/O
get(url) · get_ok(url) -> string post_json(url, data) · post_form(url, data) · post_text(url, data) -> string is_success(status) · is_redirect(status) · is_client_error(status) · is_server_error(status) · is_error(status) -> bool
std.net
I/O
tcp_try_connect(host, port) -> int · is_connected(socket_id) -> bool tcp_write_line(socket_id, line) -> int · tcp_write_lines(socket_id, lines: [string]) -> int tcp_read_exact(socket_id, n) -> string · tcp_close_safe(socket_id) -> bool
Testing, logging & random
test is a stateless assertion toolkit, log a leveled logger, and random a generator over the random() builtin. random is pure-ish but nondeterministic, so it is listed by signature.
std.test
I/O
describe(name) · section(name) · test(name, passed) -> bool · run_test(name, passed) -> int summary(total, passed, failed) · skip(name, reason) · expect_fail(name, passed) -> bool assert(c) · assert_eq(a, b) · assert_eq_str(a, b) · assert_eq_float(a, b, eps) · assert_ne(a, b) assert_true(v) · assert_false(v) · assert_gt / gte / lt / lte(a, b) (+ _float variants) assert_between(v, min, max) · assert_contains(hay, needle) · assert_starts_with / ends_with assert_len(arr, n) · assert_empty(arr) · assert_array_contains(arr, v) · assert_null / not_null(v) count_passed(r) -> int · count_failed(r) -> int · all_passed(failed) -> bool
std.log
I/O
debug(msg) · info(msg) · warn(msg) · error(msg) · fatal(msg)
log(level, msg) · level_name(level) -> string · parse_level(name) -> int
log_kv(level, msg, k, v) · log_kv2(...) · log_kv3(...) · {debug,info,warn,error}_kv(msg, k, v)
log_timing(operation, start_ms) · log_timing_level(level, operation, start_ms)
std.random
I/O
random_bool() -> bool · random_range(min: float, max: float) -> float random_index(length) -> int · shuffle_int_array(arr) -> [int] random_digits(n) -> int · coin_flip() -> string · dice_roll() -> int · dice_roll_n(sides) -> int
Where to go next
Ready to put these to work? The
guide walks through your first program, types covers generics and optionals, patterns covers
matching and exhaustiveness, and concurrency goes
deep on fibers, channels, and select. The examples gallery shows whole programs that run.