Documentation menu
Built-ins

Built-in Namespaces

Serez Code ships with built-in namespaces available everywhere without imports. OS/hardware namespaces (Terminal, OS, Env, Time, System) require explicit permission declarations.

Math

All math functions are called as Math.functionName(args):

out Math.PI    // → 3.141592653589793
out Math.E     // → 2.718281828459045

// Rounding
out Math.floor(3.9)    // → 3
out Math.ceil(3.1)     // → 4
out Math.round(3.5)    // → 4
out Math.trunc(-3.9)   // → -3  (toward zero)

// Basic
out Math.abs(-7)       // → 7
out Math.sqrt(16.0)    // → 4.0
out Math.pow(2.0, 10.0)  // → 1024.0

// Min / max / clamp
out Math.min(3, 1, 4, 1, 5)    // → 1
out Math.max(3, 1, 4, 1, 5)    // → 5
out Math.clamp(15, 0, 10)      // → 10

// Logarithms
out Math.log(Math.E)   // → 1.0
out Math.log2(8.0)     // → 3.0
out Math.log10(1000.0) // → 3.0

// Random — decimal in [0, 1)
out Math.random()

Trigonometry

All trig functions use radians:

out Math.sin(Math.PI / 2.0)   // → 1.0
out Math.cos(0.0)              // → 1.0
out Math.tan(Math.PI / 4.0)   // → ~1.0

out Math.atan2(1.0, 1.0)      // → 0.785...  (π/4)

// Degrees → radians helper
let deg = 90.0
let rad = deg * Math.PI / 180.0
out Math.sin(rad)   // → 1.0

File I/O

Read and write files with the File namespace:

// Write a file (creates it if it doesn't exist, overwrites if it does)
File.write("data.txt", "Hello, world!")

// Check if it exists
out File.exists("data.txt")   // → true

// Read the whole file as a string
let content = File.read("data.txt")
out content   // → Hello, world!

// Create an empty file (no-op if it already exists)
File.create("log.txt")

Binary files

// Read raw bytes — returns [int] where each value is 0-255
let bytes = File.read_asBinary("image.png")
out bytes.length   // number of bytes

// Write raw bytes
File.write_asBinary("copy.png", bytes)

Extended file system methods

// List directory contents
let entries = File.listDir("./src")
out entries   // → [main.sz, utils.sz, ...]

// Create a directory (including parent dirs)
File.mkdir("output/logs")

// File metadata
let stat = File.stat("data.txt")
out stat.size      // → bytes
out stat.isDir     // → false
out stat.modified  // → Unix ms timestamp

// Rename / move (requires unsafe)
unsafe {
    File.rename("old.txt", "new.txt")
}

// Delete file or directory (requires unsafe)
unsafe {
    File.delete("temp_dir")
}

Practical example — save and load JSON data

let data <string, any> = (
    {"name", "Sergio"},
    {"score", 42},
    {"active", true}
)

// Save
File.write("save.json", JSON.stringify(data))

// Load
let loaded = JSON.parse(File.read("save.json"))
out loaded["name"]   // → Sergio

JSON

Serialize any value to JSON and parse it back:

// Stringify — works with any value
out JSON.stringify(42)          // → "42"
out JSON.stringify(true)        // → "true"
out JSON.stringify([1, 2, 3])   // → "[1,2,3]"

let user <string, any> = ({"name", "Sergio"}, {"age", 28})
out JSON.stringify(user)
// → {"name":"Sergio","age":28}

// Parse — returns the equivalent Serez value
let json = '{"x": 10, "y": 20}'
let obj = JSON.parse(json)
out obj["x"]   // → 10

// Round-trip
let original = [1, "hello", true, null]
let json_str = JSON.stringify(original)
let parsed   = JSON.parse(json_str)
out parsed[1]   // → hello

Use JSON.pretty(value, [indent]) for indented, human-readable output — great for inspecting a fetch response in the console. The indent (spaces per level) defaults to 2; an indent of 0 falls back to compact. If the value is a raw JSON string (such as a fetch body), it is parsed first and then re-indented.

native fn string fetch(string url)

let body = fetch("https://api.example.com/data")

// Pretty-print the raw response body (2-space indent by default)
out JSON.pretty(body)
// → {
//     "name": "Sergio",
//     "age": 28
//   }

out JSON.pretty(body, 4)   // 4-space indent

// Works on structured values too
out JSON.pretty(user)

Networking (fetch)

fetch is a general-purpose HTTP client. Declare it once as a native fn, then call it. Only http:// and https:// URLs are allowed, and URLs/headers with control characters are rejected (CRLF / header-injection safe).

native fn string fetch(string url)

let body = fetch("https://pokeapi.co/api/v2/pokemon/ditto")
out JSON.pretty(body)   // pretty-print the JSON response

Signature: fetch(url, [method], [body], [options]). Arguments after the url are sniffed by type — the first string is the method, the second is the body, and a dict is the options.

Default headers: fetch always sends User-Agent: Serez-Code/<version> unless you set your own (without it, some CDNs/WAFs reply 503). When a body is sent it also defaults Content-Type: application/json unless you set one. Any caller-provided header wins.

// POST with a JSON body (build it with JSON.stringify — no raw braces)
let payload <string, any> = ({"name", "serez"}, {"stars", 10})
let res = fetch("https://example.com/api", "POST", JSON.stringify(payload))

// Custom headers (override the default User-Agent, add auth, ...)
let headers <string, string> = ({"Authorization", "Bearer TOKEN"}, {"User-Agent", "my-app/1.0"})
let opts <string, any> = ({"headers", headers}, {"timeout", 10})
let r = fetch("https://example.com/api", opts)

Options dict (a <string, any> dict): headers (a <string, string> dict), timeout (seconds, default 60), full(return a structured response and don't throw on HTTP status), and binary (return the body as a byte array [int] for images/zips/PDFs).

native fn any fetch(string url, any options)

// full mode → { status, ok, statusText, headers, body }, never throws on status
let opts <string, any> = ({"full", true})
let r = fetch("https://pokeapi.co/api/v2/pokemon/ditto", opts)
if (r["ok"] == true) {
    out "status " + r["status"]    // 200
    out JSON.pretty(r["body"])     // headers keyed by lowercased name; missing key → null
}

Default mode (no full) returns the body string and throws on status ≥ 400 (the response body is embedded in the error), so wrap calls in try / catch:

try {
    let body = fetch("https://pokeapi.co/api/v2/pokemon/ditto")
    out body.length()
} catch (e) {
    out "request failed: " + e
}

Socket (TCP & WebSocket)

Raw TCP client/server sockets over the standard library, plus RFC 6455 WebSocket text frames. These are the low-level networking primitives — for a full HTTP/WebSocket server with routing, use the serez-http package. Requires the Socket permission — declare it in your serez.json or at the top of your script:

// serez.json
{ "permissions": ["Socket"] }
// or inline
use permissions { Socket }

TCP client

use permissions { Socket }

// Connect, send a request, read the reply
let sock = Socket.connect("example.com", 80)   // → socket id (int)
Socket.send(sock, "GET / HTTP/1.0\r\nHost: example.com\r\n\r\n")
let reply = Socket.recv(sock, 4096)            // read up to 4096 bytes → string
out reply
Socket.close(sock)

TCP server

use permissions { Socket }

// Listen, accept a connection, echo a message back
let server = Socket.listen(8080)   // → listener id (int)
let conn   = Socket.accept(server) // blocks until a client connects → socket id
let msg    = Socket.recv(conn, 1024)
Socket.send(conn, "echo: " + msg)
Socket.close(conn)
Socket.close(server)

WebSocket frames

After a connection is established, exchange WebSocket text frames. recvWsFrame returns the decoded payload, or nullon a close frame / end of connection. Frames larger than 16 MiB are rejected (DoS-safe).

Socket.sendWsFrame(conn, "ping")        // encode + send a text frame → null
let frame = Socket.recvWsFrame(conn)    // → text payload, or null on close
if (frame != null) {
    out "received: " + frame
}
MethodReturnsDescription
Socket.connect(host, port)intOpen a TCP connection → socket id
Socket.send(id, data)intSend a string → bytes written
Socket.recv(id, max_bytes)stringRead up to max_bytes
Socket.listen(port)intBind + listen → listener id
Socket.accept(listener_id)intAccept a connection (blocks) → socket id
Socket.close(id)nullClose a socket or listener
Socket.sendWsFrame(id, data)nullSend a WebSocket text frame
Socket.recvWsFrame(id)string | nullRead one WebSocket text frame

Permissions

OS/hardware namespaces are sandboxed by default. Grant access with a three-level permission model:

// Level 1 — serez.json (project-wide)
// { "permissions": ["Terminal", "OS", "Env"] }

// Level 2 — file-level
use permissions { OS, Time }

// Level 3 — operation-level (unsafe required for destructive ops)
unsafe {
    OS.exec("git", ["status"])
    File.delete("temp.txt")
}

Terminal

Interact with the terminal emulator — keyboard, mouse, cursor, raw mode. Requires use permissions { Terminal }.

use permissions { Terminal }

// Terminal size
let size = Terminal.getSize()
out "Cols: {size[0]}, Rows: {size[1]}"

// Clear screen and move cursor
Terminal.clear()
Terminal.setCursor(0, 0)

// Write raw byte to stdout (e.g. ANSI ESC = 27)
Terminal.writeByte(27)

// Raw mode + keyboard + mouse (all require unsafe)
unsafe {
    Terminal.setRawMode(true)
    Terminal.enableMouse(true)

    let evt = Terminal.readEvent()
    if (evt.type == "key") {
        out "Key: {evt.code}"         // "a", "Enter", "Esc", "F1", ...
        out "Mods: {evt.modifiers}"   // ["ctrl"], ["shift"], ...
    } else if (evt.type == "mouse") {
        out "Mouse {evt.kind} at {evt.col},{evt.row}"
        out "Button: {evt.button}"    // "left", "right", "middle"
    } else if (evt.type == "resize") {
        out "New size: {evt.cols}x{evt.rows}"
    }

    Terminal.enableMouse(false)
    Terminal.setRawMode(false)
}

Autodiff

Reverse-mode automatic differentiation tape. Record operations, run backward, retrieve gradients. All tensor operations performed while the tape is active are tracked automatically.

Tape control

Autodiff.tape()            // start recording
Autodiff.backward(loss)    // backpropagate from scalar tensor
Autodiff.gradient(tensor)  // retrieve gradient tensor
Autodiff.clear()           // clear tape and gradients
Autodiff.isRecording()     // → bool

Weight initialization

// Xavier (Glorot) — good for tanh / sigmoid
let w = Autodiff.xavierUniform([fan_in, fan_out])
let w = Autodiff.xavierNormal([fan_in, fan_out])

// He — good for ReLU networks
let w = Autodiff.heUniform([fan_in, fan_out])
let w = Autodiff.heNormal([fan_in, fan_out])

Optimizers

All optimizer steps are pure functions — they return updated parameters without modifying the tape.

// Adam — returns [new_param, new_m, new_v]
let result = Autodiff.adamStep(param, grad, m, v, step, lr)
let result = Autodiff.adamStep(param, grad, m, v, step, lr, beta1, beta2, eps)

// AdamW — Adam with decoupled weight decay
let result = Autodiff.adamwStep(param, grad, m, v, step, lr, wd)

// SGD with momentum — returns [new_param, new_velocity]
let result = Autodiff.sgdStep(param, grad, velocity, lr)
let result = Autodiff.sgdStep(param, grad, velocity, lr, momentum, weight_decay)

// RMSprop — returns [new_param, new_sq_avg]
let result = Autodiff.rmspropStep(param, grad, sq_avg, lr)
let result = Autodiff.rmspropStep(param, grad, sq_avg, lr, alpha, eps)

// Usage pattern:
let w = Autodiff.heNormal([128, 64])
let m = Tensor.zeros([128, 64])
let v = Tensor.zeros([128, 64])
let step = 0

// Training loop:
step++
Autodiff.tape()
let loss = Autodiff.mseLoss(w.matmul(x), target)
Autodiff.backward(loss)
let grad = Autodiff.gradient(w)
let res = Autodiff.adamStep(w, grad, m, v, step, 0.001)
w = res[0]; m = res[1]; v = res[2]

Loss functions

// All loss functions are tracked on the tape
let loss = Autodiff.mseLoss(pred, target)          // Mean Squared Error
let loss = Autodiff.maeLoss(pred, target)          // Mean Absolute Error
let loss = Autodiff.bceLoss(pred, target)          // Binary Cross-Entropy (probs in [0,1])
let loss = Autodiff.crossEntropyLoss(logits, idx)  // Cross-Entropy (raw logits + class indices)

Layers

// BatchNorm — normalizes [N, C] tensor per feature
let out = Autodiff.batchNorm(x, gamma, beta, training)
let out = Autodiff.batchNorm(x, gamma, beta, training, eps)

// Dropout — zeros random activations during training
let out = Autodiff.dropout(x, p)               // p = drop probability
let out = Autodiff.dropout(x, p, training)     // training=false → no-op

// Embedding — lookup rows from weight matrix
// indices: Array of int or integer Tensor
// weight:  [vocab_size, emb_dim] Tensor
// returns: [seq_len, emb_dim] Tensor
let out = Autodiff.embedding(indices, weight)

Gradient utilities

// Clip a single gradient tensor by norm
let clipped = Autodiff.clipGrad(grad, max_norm)

// Clip an array of gradients by global norm
let clipped = Autodiff.clipGradNorm([g1, g2, g3], max_norm)

// Detach a tensor from the tape (stop gradient flow)
let detached = Autodiff.stopGrad(tensor)
let detached = Autodiff.detach(tensor)

Weight persistence

// Save an array of tensors to a .szw binary file
Autodiff.saveWeights("model.szw", [w1, b1, w2, b2])

// Load tensors back — returns Array in same order
let weights = Autodiff.loadWeights("model.szw")
let w1 = weights[0]
let b1 = weights[1]

Tensor

Multi-dimensional arrays with automatic differentiation support. All operations are tracked when a tape is active.

Creation

Tensor.zeros([rows, cols])
Tensor.ones([rows, cols])
Tensor.eye(n)                            // identity matrix
Tensor.from([[1.0, 2.0], [3.0, 4.0]])    // from a (nested) array
Random.normalTensor([rows, cols], 0.0, 0.1)  // gaussian-filled

Shape manipulation

t.shape()        // → [rows, cols, ...]
t.ndim()         // → number of dimensions
t.size()         // → total number of elements
t.reshape([2,3]) // reshape (same total elements)
t.flatten()      // → 1D tensor
t.transpose()    // 2D transpose
t.permute([0,2,1])   // N-D generalized transpose
t.unsqueeze(dim)     // insert size-1 dim at position
t.squeeze()          // remove all size-1 dims
t.squeeze(dim)       // remove specific size-1 dim

Math operations

// Element-wise (all tracked)
t.add(other)   t.sub(other)   t.mul(other)   t.div(other)
t.neg()        t.abs()        t.sqrt()       t.exp()
t.log()        t.pow(exp)     t.scale(s)
t.sign()       t.reciprocal()
t.sin()        t.cos()
t.round()      t.floor()      t.ceil()
t.clamp(min, max)
t.maximum(other)   t.minimum(other)

// Matrix operations (tracked)
t.dot(other)        // 1D dot product
t.matmul(other)     // 2D matrix multiply
t.outer(other)      // outer product
t.bmm(other)        // batch matmul [B,N,M] @ [B,M,K] → [B,N,K]

// Reductions
t.sum()   t.mean()   t.max()   t.min()
t.sumAxis(axis)     t.meanAxis(axis)
t.reduceSum(axis)   t.reduceMean(axis)   t.reduceMax(axis)
t.variance()        t.std()
t.cumsum()          t.norm(order)

// N-D broadcasting
t.broadcastTo([shape])             // expand to target shape
t.broadcastAdd(bias)               // 2D + 1D (tracked)
t.broadcastAddNd(other)            // N-D broadcast add
t.broadcastMulNd(other)            // N-D broadcast multiply

Activation functions (all tracked)

t.relu()
t.sigmoid()
t.tanh()
t.softmax()
t.gelu()
t.leaky_relu(alpha)
t.elu(alpha)           // ELU (alpha default 1.0)
t.swish()              // swish(x) = x * sigmoid(x)
t.silu()               // alias for swish
t.mish()               // mish(x) = x * tanh(softplus(x))
t.softplus()           // log(1 + exp(x))
t.hardsigmoid()        // clamp((x+3)/6, 0, 1)
t.hardswish()          // x * hardsigmoid(x)

Convolution & pooling (all tracked)

// Input shape: [N, H, W, C_in]
// Weights shape: [C_in * kernel^2, C_out]
t.conv2d(weights, bias, kernel, stride)
t.max_pool2d(kernel, stride)
t.avg_pool2d(kernel, stride)   // average pooling

Recurrent layers (all tracked)

// LSTM — input [seq_len, input_size], returns [1, hidden_size]
t.lstm(wx, wh, b, h0, c0)

// GRU — input [seq_len, input_size], returns [1, hidden_size]
t.gru(wx, wh, b, h0)

// Multi-head attention — input [seq_len, d_model]
t.mha(wq, wk, wv, wo, n_heads)

// Layer normalization — tracked
t.layer_norm(gamma, beta, eps)

Utilities

t.toArray()          // convert to serez array
t.toString()         // human-readable string
t.get(i, j)          // element access
t.set(i, j, val)     // element mutation
t.slice(start, end)  // flat slice
t.concat(other, axis)
t.argmax()   t.argmin()
t.stopGrad() // alias: t.detach() — detach from tape

GPU

CPU-backed compute buffers with a GPU-shaped API. Buffers are flat decimal arrays; the create / upload / dispatch / readback / free pattern mirrors real GPU compute so a future backend can swap in actual GPU calls. Buffers are not garbage-collected — free them with GPU.freeBuffer when done. No permission declaration is required.

// Upload data, run element-wise + reduction, read back
let src     = GPU.createBufferFromArray([1.0, 2.0, 3.0, 4.0])  // → buffer id
let doubled = GPU.map(src, x => x * 2.0)            // element-wise → new buffer
let sum     = GPU.reduce(src, (acc, x) => acc + x, 0.0)   // → 10.0
let product = GPU.reduce(src, (acc, x) => acc * x, 1.0)   // → 24.0

// Linear algebra
let d = GPU.dot(src, doubled)        // dot product → decimal
let r = GPU.axpy(2.0, src, doubled)  // 2*src + doubled → new buffer

// Matrix multiply: [2×2] @ [2×2]
let I = GPU.createBufferFromArray([1.0, 0.0, 0.0, 1.0])
let M = GPU.createBufferFromArray([5.0, 6.0, 7.0, 8.0])
let C = GPU.matmul(I, 2, 2, M, 2, 2)
out GPU.readBuffer(C)   // → [5.0, 6.0, 7.0, 8.0]

// Always free buffers you created
GPU.freeBuffer(src)
GPU.freeBuffer(doubled)
MethodReturnsDescription
GPU.createBuffer(size)intAllocate a zero-filled buffer → id
GPU.createBufferFromArray(arr)intAllocate from a Serez array → id
GPU.readBuffer(id)[decimal]Copy a buffer back to a Serez array
GPU.freeBuffer(id)nullRelease a buffer
GPU.fill(id, value)nullSet every element to value
GPU.size(id)intNumber of elements
GPU.map(id, fn)intElement-wise fn → new buffer
GPU.reduce(id, fn, initial)decimalFold over the buffer
GPU.dot(id_a, id_b)decimalDot product of two buffers
GPU.axpy(alpha, id_x, id_y)intalpha*x + y → new buffer
GPU.matmul(id_a, ra, ca, id_b, rb, cb)intMatrix multiply → new buffer

OS

Process and operating system information. Requires use permissions { OS }.

use permissions { OS }

out OS.platform()   // → "windows" | "linux" | "macos"
out OS.pid()        // → current process ID

// Execute external command (requires unsafe)
let result = null
unsafe {
    result = OS.exec("git", ["log", "--oneline", "-5"])
}
out result.stdout   // command output
out result.code     // exit code (0 = success)

// Kill a process by PID (requires unsafe)
unsafe {
    OS.kill(1234)
}

Env

Environment variables and command-line arguments. Requires use permissions { Env }.

use permissions { Env }

out Env.get("HOME")     // → "/Users/sergio" or null if not set
out Env.get("PATH")     // → full PATH string

let args = Env.args()   // command-line args including program name
out args.length

// Set env var (requires unsafe — not thread-safe)
unsafe {
    Env.set("MY_VAR", "hello")
}
out Env.get("MY_VAR")   // → hello

Time

Timestamps and sleep. Requires use permissions { Time }.

use permissions { Time }

let t1 = Time.now()   // Unix timestamp in milliseconds
Time.sleep(500)       // pause 500ms
let t2 = Time.now()
out t2 - t1           // → ~500

DateTime

Immutable calendar date/time. DateTime.now() / utcNow() read the clock and require use permissions { Time }; from() / fromEpoch() and every field/arithmetic/format operation are pure and need no permission.

let d = DateTime.from(2026, 1, 31, 9, 30, 0)

// fields act as ints, but carry immutable add/reduce/remove
out d.day + 5            // 36
out d.month.add(1)       // 2026-02-28T09:30:00  (day clamped to month end)
out d.day.reduce(20)     // 2026-01-11T09:30:00

// formatting (moment.js-style; [text] is literal)
out d.format("YYYY-MM-DD HH:mm")   // 2026-01-31 09:30
out d.format("D/M/YYYY h:mm A")    // 31/1/2026 9:30 AM
out d.weekday                       // 6  (1=Mon … 7=Sun)

// object-destructuring exposes calendar fields as ints
const {day, month, year} = DateTime.from(2026, 6, 20)
out year + "-" + month + "-" + day  // 2026-6-20

Members: fields year month day hour minute second ms (each a DateField with .add/.reduce/.remove(n)), read-only weekday dayOfYear daysInMonth, and format(p) toString() iso() timestamp() isLeapYear() isUtc(). Two dates compare by instant.

System

Read-only system information. Requires use permissions { System }.

use permissions { System }

out System.cpuCount()      // → 15  (logical cores)
out System.totalMemory()   // → 34279034880  (bytes)
out System.freeMemory()    // → 13000000000  (bytes)
out System.hostname()      // → "DESKTOP-XYZ"
out System.uptime()        // → 168517  (seconds since boot)

Task (Concurrencia)

Execute background scripts in native threads to prevent blocking the main thread (highly critical to keep GUI apps running smoothly). Requires use permissions { Task }.

use permissions { Task, Time }

// 1. Spawns the worker script in the background
let taskId = Task.run("worker.sz", "Serez Developer")

// 2. Poll for completion (non-blocking)
while (!Task.isDone(taskId)) {
    Time.sleep(10)
}

// 3. Retrieve the final result
let result = Task.poll(taskId)
out result

Inside the worker script (e.g. worker.sz), use Task.message() to retrieve the input argument, and Task.reply(result) to return the response and terminate the worker:

// worker.sz
use permissions { Task }

let input = Task.message()
let response = "Hello, " + input
Task.reply(response)
MethodReturnsDescription
Task.run(script_path, arg)intSpawns a background worker thread → task id
Task.message()string(Worker only) Retrieves the input argument
Task.reply(result)null(Worker only) Sends the result and terminates the worker
Task.isDone(id)boolChecks if the task has finished or failed
Task.poll(id)string | nullReturns the result if finished, null if running, or error message

Media (Audio)

Play and control audio files (WAV, MP3, FLAC, Vorbis) asynchronously.Requires use permissions { Media }.

use permissions { Media, Time }

// Play audio asynchronously (returns an audio instance id)
let audioId = Media.playSound("sound.mp3")

// Control volume (scale: 0 to 200, representing 0% to 200%)
Media.setVolume(audioId, 150)

// Check if playing
if (Media.isPlaying(audioId)) {
    out "Audio is playing!"
}

// Pause, resume or stop
Media.pause(audioId)
Time.sleep(1000)
Media.resume(audioId)

// Stop a specific instance or stop all audio
Media.stop(audioId)
Media.stopAll()

Audio operations can throw catchable errors: IOError if the file is missing, or MediaError if the format is invalid or no audio device is found. Permission denial is fatal (sec_media_no_permission).

MethodReturnsDescription
Media.playSound(path)intStarts playing a sound file asynchronously → audio id
Media.stop(id)nullStops the specified audio instance
Media.stopAll()nullStops all playing audio instances
Media.pause(id)nullPauses the specified audio instance
Media.resume(id)nullResumes the specified paused audio instance
Media.setVolume(id, volume)nullSets the volume of the audio instance (0 to 200)
Media.isPlaying(id)boolChecks if the specified audio instance is currently playing
Media.playingCount()intReturns the total number of playing audio instances