Official documentation
The Fogu language
Fogu (.fg files) is a small, predictable scripting language, dynamically typed with optional type
annotations, built for automation, infrastructure, systems integration and small services.
The reference implementation is written in Rust and ships an interpreter, a JIT compiler (Cranelift), a REPL,
a CLI, a package manager and standalone executables.
Simple
A small grammar, optional semicolons, no implicit coercions.
Predictable
Errors are values, lexical scope, no hoisting, names and types checked before running.
Practical
HTTP, TCP/UDP, SQL, key-value, cron and events in the standard library.
Installation
Requires Rust (2024 edition) and git on the PATH (for packages).
First steps
Variables and types
let creates a mutable variable; const an immutable binding (the referenced object may
still change). Scope is lexical, each { } block creates a new scope and there is no hoisting.
Declaring the same name twice in the same scope is an error.
Conversions and truthiness
- There are no implicit coercions:
"10" + 2is an error. Useint("10"),float(10),str(10). - The only automatic promotion is
int → floatin arithmetic:1 + 2.5 == 3.5. - Only
falseandnilare falsy;0,"",[]and{}are truthy. ==compares lists and maps by structure; structs by identity (or with theirequalsmethod).
Type annotations
Annotations are optional. They are checked at runtime (parameters on entry, return values on
exit, let/const on assignment) and unknown type names are rejected before the program runs.
Annotated numeric functions are still compiled by the JIT.
Built-in type names: int float str bool nil duration list map tuple fn chan error any, plus struct
and interface names. error also accepts nil. Generic arguments such as list<int>
document the intent; only the outer kind is checked.
Strings and template strings
Template strings use backticks and interpolate any expression with ${...}. They may span several lines.
str methods: split upper lower trim replace starts_with ends_with repeat lines chars slice.
Durations
Literals with a unit (ns us ms s m h d, decimals allowed) create duration values, stored in
nanoseconds. They are accepted by time.delay, time.sleep, cron.every and timeout.
Fields: ns, us, ms (int) and seconds, minutes, hours (float).
Operators
| Precedence (high → low) | Meaning |
|---|---|
() [] . ?. | call, index, field, optional access |
! - <- | negation, unary minus, channel receive |
** | power (right-associative) |
* / % · + - | checked arithmetic (overflow and division by zero are errors) |
< <= > >= · == != | comparison |
&& · || ?? | logical; a ?? b returns b if a is nil |
.. | half-open range [a, b) |
= += -= *= /= %= | assignment (also to fields and indices) |
Control flow
No parentheses around conditions. match is an expression, with literal patterns, |
alternatives, bindings with guards and the _ wildcard. A match must be
exhaustive: without a _ (or plain name) arm it is rejected before the program runs.
Functions
Functions are first-class values with closures. There are three forms: declaration, anonymous function and arrow function. Parameters may have default values (which may use earlier parameters) and the last one may be variadic. Functions and structs may be generic; type parameters are erased at runtime.
Missing arguments are nil (or their default value); passing too many is an error, except for
variadic functions.
Lists and maps
- Lists:
push pop shift unshift insert remove first last contains index_of join reverse slice concat sort map filter each find any all reduce - Maps:
keys values entries has get set remove merge - All of them work as methods (
xs.push(1)) or as functions (push(xs, 1)).
Errors as values
There is no try/catch. A function returns value, error; the ? operator returns
the error to the caller. An error has message, cause and trace.
? may only be used in functions whose declared return type includes error (or that are not
annotated).
The operational errors of native functions (a file that does not open, a refused connection,
invalid SQL or JSON) are error values too. Programming errors (for example, an argument of the wrong
type) stop the program.
const [a, b] = f() destructures lists. If a native function returns a list
(for example json.parse("[1, 2]") or db.query(...)), use ? instead of destructuring.
panic("msg") signals an unrecoverable failure. In an fg task it does not stop the other
tasks, unless the program runs with --strict.
Structs, interfaces and composition
There is no inheritance: reuse comes from embed. The constructor is called new and methods
reach the instance through this. Structs compare by identity, unless they define equals.
Interfaces are structural: any struct (or map of functions) with the required methods satisfies
them, without declaring it.
Modules and visibility
Each file is a module, evaluated only once. Use export to export functions, let/const,
structs and interfaces. Names starting with _ are private to the module: they cannot be
imported, read through module._x, or used as fields or methods of a struct outside the module where it
was declared.
Concurrency: fg, chan, select
fg starts a cooperative task (not an OS thread). Buffered or unbuffered channels connect tasks;
select waits for the first ready case (choosing randomly among ready ones) and timeout(d)
returns a channel that receives a value after d. The runtime detects deadlocks.
Standard library
Modules are imported with import name from "fogu:name" (or by name: import { parse } from "fogu:json"). Each section below lists every function with its parameters and return value, and shows an example with its real output (the examples are run when this page is generated).
| Core | fogu:math fogu:json fogu:time fogu:system fogu:fs fogu:path fogu:process fogu:sync fogu:test fogu:log fogu:regex fogu:crypto |
| Data formats | fogu:csv fogu:excel fogu:yaml fogu:toml fogu:xml |
| Storage | fogu:kv fogu:sql fogu:orm fogu:redis fogu:s3 fogu:scylla |
| Web & network | fogu:http fogu:web fogu:jwt fogu:websocket fogu:net |
| Messaging & events | fogu:nats fogu:rabbitmq fogu:mqtt fogu:fogumq fogu:events fogu:cron |
| Integrations | fogu:mail fogu:ai fogu:ssh fogu:shell fogu:ffi fogu:playbook |
Conventions
Errors are values. Operational failures — a missing file, a refused connection, a server error, malformed input — come back as an error value: handle them with ? (propagate) or const [value, err] = f(). Programming mistakes — a wrong argument type, an unknown option — stop the program with a message. Options are passed as a last map argument: f(x, { timeout: 5s }). Durations accept a duration literal (500ms, 2s, 1h) or an int number of milliseconds. Network operations wait cooperatively: other fg tasks keep running while one waits.
Global functions
Available everywhere, without an import.
| Function | Returns | Description |
|---|---|---|
print(...values) | nil | Writes the values separated by spaces and a newline (Fogu.write writes without them). |
len(x) | int | Length of a str (characters), list, map or chan (queued items). |
typeof(x) | str | int float str bool nil list map fn duration chan error struct … |
str(x) | str | Text form of any value (the same text print shows). |
int(x) | int | From a float (truncates), a numeric str or a bool. Invalid text stops the program. |
float(x) | float | From an int or a numeric str. |
clock() | float | Seconds since the UNIX epoch, with fractions — use differences to measure time. |
error(message, cause?) | error | A new error value; err.message, err.cause. |
panic(...values) | — | Stops the program with a message (for impossible situations). |
timeout(d) | chan | A channel that receives once after d (use with select). |
close(ch) | nil | Closes a channel: receivers get nil once it is empty. |
Strings, lists and maps
Methods of the built-in values. Indexes start at 0; negative indexes count from the end in slice.
str
| Function | Returns | Description |
|---|---|---|
s.len() | int | Number of characters. |
s.upper() · s.lower() | str | Case conversion. |
s.trim() | str | Without leading and trailing whitespace. |
s.split(sep) | list | Parts between sep. |
s.lines() · s.chars() | list | Lines (without line endings) · single characters. |
s.contains(t) · s.starts_with(t) · s.ends_with(t) | bool | Substring tests. |
s.index_of(t) | int | Character index of the first t, or -1. |
s.replace(old, new) | str | Every old replaced. |
s.repeat(n) | str | s repeated n times. |
s.slice(start, end?) | str | Characters from start up to (not including) end. |
list
| Function | Returns | Description |
|---|---|---|
l.push(x) · l.pop() | nil · value | Add to / remove from the end. |
l.unshift(x) · l.shift() | nil · value | Add to / remove from the start. |
l.insert(i, x) · l.remove(i) | nil · value | At an index. |
l.first() · l.last() | value | nil when empty. |
l.contains(x) · l.index_of(x) | bool · int | Search by value. |
l.join(sep) | str | Items as text joined with sep. |
l.reverse() · l.sort(fn?) | list | New list; sort takes an optional comparator (a, b) => int. |
l.slice(start, end?) · l.concat(other) | list | Copies. |
l.map(fn) · l.filter(fn) · l.find(fn) | list · list · value | Functional helpers. |
l.any(fn) · l.all(fn) · l.each(fn) | bool · bool · nil | |
l.reduce(fn, initial) | value | fn(acc, item) over the items. |
l.clear() · l.len() | nil · int |
map
| Function | Returns | Description |
|---|---|---|
m.keys() · m.values() · m.entries() | list | Entries are [key, value] pairs. |
m.has(key) | bool | |
m.get(key, default?) | value | The value, or default (nil). |
m.set(key, value) · m[key] = value | nil | |
m.remove(key) | value | Removes and returns the value. |
m.merge(other) | map | A new map; other wins on equal keys. |
m.len() · m.clear() | int · nil |
The Fogu object
Runtime helpers available everywhere, without an import.
| Function | Returns | Description |
|---|---|---|
Fogu.version · Fogu.os | str | Fogu's version · windows, linux, macos… |
Fogu.env | map | Environment variables. |
Fogu.args | list | Arguments after the script name (fogu run app.fg a b). |
Fogu.file(path) | File | text() lines() json() write(s) append(s) exists() size() remove(), fields path name ext dir. |
Fogu.asset(path) | str | A project file: relative to the project root — and inside fogu build --compile executables, the extracted embedded files. |
Fogu.run(cmd, args?, opts?) | map | Runs a program → { ok, code, stdout, stderr } (see fogu:process). |
Fogu.glob(pattern) | list | Files matching *, ? and **. |
Fogu.hash(data, algo?) | str | Hex digest, sha256 (default) or sha512. |
Fogu.sql(url) | Database | Same as sql.open(url). |
Fogu.sleep(d) | nil | Waits (other tasks keep running). |
Fogu.write(...values) | nil | Like print, without spaces or newline (streaming output). |
Fogu.watch(path | [paths], { recursive = true, debounce = 50ms }) | Watcher · error | File system events: w.next(timeout?) → { kind, path, paths } (create modify remove rename), tryNext(), close(). |
Fogu.exit(code?) | — | Ends the program. |
Watching files — rebuild on every change:
fogu:math
| Function | Returns | Description |
|---|---|---|
math.PI · math.E | float | Constants. |
math.abs(x) | number | Absolute value (int stays int). |
math.sqrt(x) | float | Square root. |
math.pow(base, exp) | number | Power. |
math.floor(x) · math.ceil(x) | int | Rounding down / up. |
fogu:json
| Function | Returns | Description |
|---|---|---|
json.parse(text) | value · error | JSON text → maps, lists, str, int, float, bool, nil. Invalid JSON is an error value. |
json.stringify(value) | str | Compact JSON (map keys in order). |
fogu:time
| Function | Returns | Description |
|---|---|---|
time.now() | int | Milliseconds since the UNIX epoch. |
time.Date() | Date | The current instant (UTC). |
time.delay(d) · time.sleep(seconds) | nil | Waits; other fg tasks keep running. |
Date
| Function | Returns | Description |
|---|---|---|
d.year · d.month · d.day | int | Month 1–12. |
d.hour · d.minute · d.second · d.millis · d.weekday | int | Weekday 0 = Sunday. |
d.getTime() | int | Milliseconds since the epoch (also d.ms). |
d.toISOString() | str | 2026-10-10T12:00:00.000Z |
d.toString() | str | Human readable. |
d.addMs(ms) | nil | Moves the date by ms (in place). |
d.diff(other) | int | Milliseconds between the dates. |
getFullYear() getMonth() getDate() getDay() getHours() getMinutes() getSeconds() getMilliseconds() | int | JavaScript-style getters (month 0–11). |
fogu:system
| Function | Returns | Description |
|---|---|---|
system.args | list | Script arguments (fogu run app.fg a b → [a, b]). |
system.time() | float | Seconds since the epoch. |
system.exit(code) | — | Ends the program. |
system.info.os · .arch · .family | str | windows/linux/macos · x86_64/aarch64 · windows/unix. |
system.info.cores · .pid | int | Logical CPUs · process id. |
system.info.env(name) | str · nil | An environment variable. |
system.info.sleep_ms(ms) | nil | Blocks the whole program (prefer time.delay). |
fogu:fs
Files and folders. Failures (missing file, permission) are error values.
| Function | Returns | Description |
|---|---|---|
fs.readText(path) | str · error | Whole file as UTF-8 text. |
fs.readLines(path) | list · error | Lines without line endings. |
fs.writeText(path, text) | nil · error | Creates or replaces. |
fs.append(path, text) | nil · error | Adds to the end (creates the file). |
fs.exists(path) · fs.isFile(path) · fs.isDir(path) | bool | |
fs.mkdir(path) | nil · error | Creates the folder and its parents. |
fs.list(path) | list · error | Names inside a folder, sorted. |
fs.stat(path) | map · error | { size, isFile, isDir, modified } (modified: ms since the epoch). |
fs.copy(from, to) · fs.move(from, to) | nil · error | |
fs.remove(path) | nil · error | A file or an empty folder. |
fs.removeAll(path) | nil · error | A folder and everything inside. |
fs.glob(pattern) | list | Paths matching *, ?, **, sorted. |
fs.cwd() · fs.tempDir() | str | Working folder · system temp folder. |
fogu:path
| Function | Returns | Description |
|---|---|---|
path.join(...parts) | str | Joined with / and normalized. |
path.dirname(p) · path.basename(p) | str | Folder · last component. |
path.stem(p) · path.extname(p) | str | Name without extension · extension with the dot. |
path.normalize(p) | str | Resolves . and ... |
path.isAbsolute(p) | bool | |
path.absolute(p) | str | Absolute path from the working folder. |
path.sep | str | The system separator. |
fogu:process
A program that exits with a non-zero code is not an error: check ok and code. Not being able to start it is an error value. For pipes and Linux commands see fogu:shell.
| Function | Returns | Description |
|---|---|---|
process.run(cmd, args?, { cwd, env, input }) | map · error | { ok, code, stdout, stderr }. |
process.shell(command) | map | Through sh -c / cmd /C. |
process.env(name) · process.setEnv(name, value) | str · nil | |
process.cwd() · process.chdir(path) | str · nil | |
process.pid · process.os · process.arch · process.args | ||
process.exit(code) | — |
fogu:sync
Coordination of fg tasks. Waiting operations yield to the other tasks; waiting forever is reported as a deadlock.
| Function | Returns | Description |
|---|---|---|
sync.Mutex() | Mutex | lock() unlock() tryLock() → bool, field locked. |
sync.WaitGroup() | WaitGroup | add(n = 1) done() wait(), field count. |
sync.Once() | Once | do(fn) runs fn only the first time. |
sync.Atomic(value) | Atomic | get() set(v) add(n = 1) → new value, compareAndSwap(old, new) → bool. |
fogu:test
Used in *.test.fg files, run with fogu test. A test fails when an expectation fails, when it raises an error or returns an error value.
| Function | Returns | Description |
|---|---|---|
test(name, fn) | nil | Declares a test. |
skip(name, fn) | nil | A test that is reported but not run. |
expect(value) | Expectation | Then a matcher; .not negates it. |
toBe(x) · toEqual(x) | Equality (toEqual compares lists and maps deeply). | |
toBeTruthy() · toBeFalsy() · toBeNil() · toBeError() | ||
toBeType("int") · toContain(x) · toHaveLength(n) | ||
toBeGreaterThan(n) · toBeLessThan(n) · toBeCloseTo(x, eps?) |
fogu:log
Structured logs to stderr (default), stdout or a file. The level comes from FOGU_LOG (default info).
| Function | Returns | Description |
|---|---|---|
log.trace/debug/info/warn/error(message, fields?) | nil | fields: a map added as key=value (or JSON keys). |
log.setLevel(level) | nil | trace debug info warn error off. |
log.level() | str | Current level. |
log.setFormat("text" | "json") | nil | One line per entry. |
log.setOutput("stderr" | "stdout" | path) | nil · error | A file is appended to. |
log.setTime(bool) | nil | Show the time stamp (default true). |
log.child(fields) | Logger | A logger that adds fields to every line; same methods + child. |
fogu:regex
Rust regex syntax (linear time, no backtracking). Positions are character indexes. In Fogu strings write \\d for \d. An invalid pattern is an error value.
| Function | Returns | Description |
|---|---|---|
regex.compile(pattern, { ignoreCase, multiline, dotAll, verbose }) | Regex · error | |
re.test(text) | bool | Matches somewhere. |
re.matches(text) | bool | The whole text matches. |
re.find(text) | map · nil | { text, start, end, groups, named }. |
re.findAll(text) | list | Every match. |
re.replace(text, repl) · re.replaceAll(text, repl) | str | $1, ${name}, $$ in repl. |
re.split(text, limit?) | list | |
re.source · re.groups · re.names | Pattern · group count · group names. | |
regex.test/find/findAll/replace/replaceAll/split/matches(text, pattern, …) | One-off shortcuts. | |
regex.escape(text) | str | A literal pattern. |
fogu:crypto
| Function | Returns | Description |
|---|---|---|
crypto.hash(algo, data, { base64 }) | str | md5 sha1 sha256 sha384 sha512; hex by default. |
crypto.hmac(algo, key, data, { base64 }) | str | |
crypto.encrypt(data, key) | str | AES-256-GCM; key is a password (argon2id) or 64 hex chars. Base64 output with salt and nonce. |
crypto.decrypt(box, key, { bytes }) | str · error | Wrong key or altered data → error value. |
crypto.hashPassword(password) | str | argon2id PHC string, for storing passwords. |
crypto.verifyPassword(password, hash) | bool | |
crypto.randomBytes(n) · crypto.randomHex(n) | list · str | Secure random. |
crypto.randomInt(min, max) | int | Inclusive, unbiased. |
crypto.uuid() | str | Random UUID v4. |
crypto.base64(data, { url }) · crypto.fromBase64(text, { bytes }) | str | data: str or list of bytes. |
crypto.hex(data) · crypto.fromHex(text, { bytes }) | str | |
crypto.equal(a, b) | bool | Constant-time comparison. |
fogu:csv
Rows with a header become maps; cells are typed (42 → int, 3.5 → float, true → bool, empty → nil; codes like 007 stay text). The delimiter is guessed (, ; tab |).
| Function | Returns | Description |
|---|---|---|
csv.parse(text, { header = true, delimiter, types = true, trim }) | list · error | Maps (or lists without header). |
csv.stringify(rows, { header = true, delimiter = ",", columns }) | str | Rows: maps (a header line is written) or lists. |
csv.read(path, options?) · csv.write(path, rows, options?) | list · nil | The same, from/to a file. |
fogu:excel
Reads .xlsx .xlsm .xls .xlsb .ods; writes .xlsx (bold, frozen header row, column widths fitted). Dates become ISO text.
| Function | Returns | Description |
|---|---|---|
excel.read(path, { sheet, header = true }) | list · map · error | The first sheet (or sheet: name or index) as rows; sheet: "*" → { name: rows }. |
excel.sheets(path) | list · error | Sheet names. |
excel.write(path, rows | { Sheet: rows }, { header = true, columns }) | nil · error | One sheet per map key. |
fogu:yaml
| Function | Returns | Description |
|---|---|---|
yaml.parse(text) | value · error | |
yaml.parseAll(text) | list · error | Every document of a --- stream. |
yaml.stringify(value) | str | |
yaml.read(path) · yaml.write(path, value) | value · nil |
fogu:toml
Dates become text. TOML has no null: nil values are left out when writing; the top level must be a map.
| Function | Returns | Description |
|---|---|---|
toml.parse(text) | map · error | |
toml.stringify(map) | str | |
toml.read(path) · toml.write(path, map) | map · nil |
fogu:xml
An element is { name, attrs, children, text }; children holds elements (maps) and text (str); text joins the element's own text.
| Function | Returns | Description |
|---|---|---|
xml.parse(text, { whitespace }) | map · error | The root element. |
xml.stringify(element, { pretty = true, declaration = true }) | str | |
xml.read(path) · xml.write(path, element, options?) | map · nil |
fogu:kv
An embedded key-value store in a single file (redb, ACID). Values are any Fogu value (stored as JSON).
| Function | Returns | Description |
|---|---|---|
kv.open(path) | Store · error | Creates the file if needed. |
store.set(key, value) · store.get(key) | nil · value | get → nil when missing. |
store.has(key) · store.delete(key) | bool | |
store.keys() · store.len() · store.clear() | list · int · nil | |
store.path · store.close() | str · nil |
fogu:sql
SQLite, PostgreSQL and MySQL/MariaDB by URL: sqlite://app.db, sqlite::memory:, postgres://user:pass@host/db, mysql://user:pass@host/db. Parameters: ? (SQLite/MySQL) or $1 (PostgreSQL).
| Function | Returns | Description |
|---|---|---|
sql.open(url) | Database · error | |
db.run(sql, params?) | int · error | One statement with parameters; returns the affected rows (alias execute). |
db.query(sql, params?) | list · error | Rows as maps. |
db.one(sql, params?) | map · nil · error | The first row. |
db.exec(sql) | nil · error | Raw SQL without parameters — may hold several statements (migrations). |
db.begin() · db.commit() · db.rollback() | nil · error | Transactions. |
db.driver · db.url · db.close() |
fogu:orm
A Prisma-style ORM for SQLite, PostgreSQL and MySQL. Models are described in a map; migrate: "auto" creates tables (with foreign keys) and adds new columns. Each model is reached as db.<model in camelCase>. Relations load with one query per level.
Client and schema
| Function | Returns | Description |
|---|---|---|
create_client({ schema, migrate, log }) | Client · error | schema: { provider, url, models }; log: true prints every SQL statement. |
field: { type, primary, autoincrement, required, unique, defaultValue } | Types Int BigInt String Bool Float DateTime Json; defaults "now", "uuid" or a value. | |
relation: { model, kind, foreignKey, references } | one-to-many, many-to-one, one-to-one. | |
db.query(sql, params?) · db.execute(sql, params?) | list · int | Raw SQL. |
db.begin() · db.commit() · db.rollback() · db.migrate() · db.disconnect() |
Model methods
where: { field: value }, { field: { equals, not, in, notIn, lt, lte, gt, gte, contains, startsWith, endsWith, mode: "insensitive" } }, AND/OR/NOT, and nil for IS NULL. orderBy: { field: "asc" | "desc" } or a list of them.
| Function | Returns | Description |
|---|---|---|
create({ data, include, select }) | map | Missing required fields stop the program; a duplicate is an error value. |
createMany({ data: [...] }) | { count } | |
findMany({ where, select, include, orderBy, take, skip }) | list | |
findFirst(opts) · findUnique(opts) | map · nil | |
update({ where, data }) | map · error | data values may be { increment, decrement, multiply, divide, set }. |
updateMany({ where, data }) · deleteMany({ where }) | { count } | |
upsert({ where, create, update }) | map | |
delete({ where }) | map · error | The deleted record. |
count({ where }) | int |
fogu:redis
Redis, Valkey and KeyDB. Every Redis command is a method (r.lpush(…), r.xadd(…)) or goes through r.command("CMD", …); maps become field value pairs. Redis errors (WRONGTYPE, NOAUTH) are error values.
| Function | Returns | Description |
|---|---|---|
redis.connect(url | { host, port, username, password, db, tls, timeout, name }) | Redis · error | redis://[user:pass@]host[:port][/db], rediss:// for TLS, default $REDIS_URL. |
r.set(key, value, { ex, px, exat, nx, xx, keepTtl, get }) | bool · value | false when nx/xx prevented it. |
r.get(key) · r.del(keys) · r.incr(key) · r.expire(key, s) · r.ttl(key) | ||
r.hset(key, map) · r.hget(key, f) · r.hgetall(key) | int · str · map | |
r.zrange(key, start, stop, { withScores, rev, byScore }) | list | With scores: [{ member, score }]. |
r.setJson(key, value, opts?) · r.getJson(key) | bool · value | JSON values. |
r.pipeline([[cmd, …args], …]) | list | One round trip; a failed command is an error value in its place. |
r.transaction([...]) | list · error | MULTI … EXEC. |
r.subscribe(...channels) · r.psubscribe(...patterns) | Subscription | Its own connection: next(timeout?) → { channel, message, pattern? }, tryNext(), close(). |
r.publish(channel, message) | int | Receivers. |
r.close() | nil |
fogu:s3
AWS S3 and compatible storage (MinIO, Cloudflare R2, Backblaze B2, DigitalOcean Spaces, Wasabi) with AWS Signature V4. Credentials default to $AWS_ACCESS_KEY_ID, $AWS_SECRET_ACCESS_KEY, $AWS_REGION, $AWS_ENDPOINT_URL.
Every method also takes { bucket } in its options.
| Function | Returns | Description |
|---|---|---|
s3.connect({ endpoint, region, accessKey, secretKey, sessionToken, bucket, pathStyle, timeout }) | S3 | Path-style URLs when an endpoint is given. |
store.put(key, body, { contentType, metadata, cacheControl, acl }) | { etag } · error | body: str, list of bytes, or any value (JSON). |
store.upload(path, key?, opts?) | { etag } · error | A local file. |
store.get(key) · store.getBytes(key) · store.download(key, path) | str · list · nil | |
store.head(key) · store.exists(key) | map · nil · bool | { size, etag, contentType, lastModified, metadata }. |
store.list(prefix?, { delimiter, max }) | list | { key, size, etag, lastModified }; folders { key, dir: true }. |
store.copy(from, to, { fromBucket }) · store.delete(key | keys) | ||
store.presign(key, { method = "GET", expires = 1h }) | str | A temporary URL that needs no credentials. |
store.url(key) · store.withBucket(name) | str · S3 | |
store.createBucket(name?) · store.deleteBucket(name?) · store.listBuckets() |
fogu:scylla
ScyllaDB and Apache Cassandra (CQL). Statements with parameters are prepared once and cached; parameters are converted to the column types (collections, UDTs, uuid, timestamp…).
| Function | Returns | Description |
|---|---|---|
scylla.connect("host:port" | { hosts, keyspace, user, password, singleNode, addressMap }) | Scylla · error | addressMap translates addresses of nodes behind Docker/NAT. |
db.execute(cql, params?) | nil · error | |
db.query(cql, params?) | list · error | Rows as maps. |
db.one(cql, params?) | map · nil · error | |
db.use(keyspace) · db.close() |
fogu:http
A minimal HTTP server (one handler for every request) and an HTTP client. For routing, middleware, static files, uploads, SSE and WebSocket use fogu:web.
Client
| Function | Returns | Description |
|---|---|---|
http.get(url) · http.delete(url) | Response · error | Network failures are error values; HTTP 4xx/5xx are normal responses. |
http.post(url, body) · http.put(url, body) | Response · error | body: str, or a map sent as JSON. |
res.status · res.headers · res.body · res.json() |
Server
| Function | Returns | Description |
|---|---|---|
http.serve(port, fn(req)) | nil | Requests are handled while the program runs (e.g. in a while loop with time.delay). |
req.method · req.path · req.query · req.headers · req.body | query is the raw query string. | |
req.header(name) · req.json() · req.form() · req.bytes() | form(): urlencoded and multipart bodies. | |
http.text(body, opts?) · http.json(value, opts?) · http.html(body, opts?) | Response | opts: { status, headers }. |
fogu:web
A web framework: routes with parameters, middleware, static files and SPA builds, uploads, downloads, Server-Sent Events and WebSocket — on one port.
App
| Function | Returns | Description |
|---|---|---|
web.app() | App | Methods return the app, so calls can be chained. |
app.get/post/put/patch/delete/head/options/all(path, ...middlewares, handler) | App | /users/:id parameters, * wildcard. |
app.use(fn) · app.use(prefix, fn) | App | Middleware for every request, or under a path prefix. |
app.after((ctx, res) => …) | App | After the handler; returning a value replaces the response. |
app.onError((ctx, err) => response) | App | For runtime errors and returned error values (default: 500). |
app.static(dir) · app.static(prefix, dir, { spa, index, maxAge, dotfiles }) | App | Files served by the server thread: ETag/304, Cache-Control; spa: true serves index.html for unknown HTML routes (React, Vue, Svelte builds). |
app.ws(path, ...middlewares, (ws, ctx) => …, { protocols }) | App | WebSocket routes; the handler runs in its own task with a WebSocket. |
app.set(key, value) · app.store | App · map | Shared state (ctx.store). |
app.listen(port, { host = "127.0.0.1", maxBody = 10 MB, quiet }) | nil · error | Use host: "0.0.0.0" to accept other machines. |
app.handler() | fn | Calls the app without a network (tests): h({ method, path, headers, body }) → Response. |
app.routes() | list |
Context and responses
| Function | Returns | Description |
|---|---|---|
ctx.method · ctx.path · ctx.params · ctx.query · ctx.headers · ctx.body | query is a map; header names are lower case. | |
ctx.req.json() · ctx.req.form() · ctx.req.bytes() | form(): fields as str, files as UploadedFile. | |
ctx.set.status · ctx.set.headers | Adjust the final response from middleware or handlers. | |
ctx.store | map | The app's shared map. |
handler result | A str (text or HTML), any value (JSON), a response, or nil (204). | |
web.json/text/html(body, { status, headers }) | Response | |
web.redirect(url, status = 302) | Response | |
web.file(path, { download, contentType, status }) | Response · error | Sent by the server thread (binary safe). |
web.sse({ retry, headers }) | SseStream | Return it from the handler; send(data, { event, id }), comment(text), close(), field open. |
web.cors({ origin, methods, headers, credentials, maxAge }) | middleware | Answers preflight requests. |
web.logger() | middleware | GET /path 200 0.4ms. |
UploadedFile: filename, contentType, size, text(), bytes(), json(), save(path) | save("uploads/") keeps a sanitized file name. |
Without a network, through app.handler():
fogu:jwt
JSON Web Tokens with HMAC (HS256/HS384/HS512). A token that fails verification is an error value.
| Function | Returns | Description |
|---|---|---|
jwt.sign(payload, secret, { algorithm, expiresIn, notBefore, issuer, audience, subject, jwtid, header, noTimestamp }) | str | iat is added; durations or seconds for times. |
jwt.verify(token, secret, { algorithms, issuer, audience, subject, leeway, maxAge, ignoreExpiration }) | map · error | The claims. |
jwt.decode(token) | map · error | { header, payload } without verifying. |
jwt.middleware(secret, { property = "user", optional, …verify options }) | middleware | For fogu:web: Authorization: Bearer → ctx.user, otherwise 401. |
fogu:websocket
WebSocket client (ws://, wss://) and a standalone server. The same connection object is used by app.ws in fogu:web.
| Function | Returns | Description |
|---|---|---|
websocket.connect(url, { headers, protocols, timeout }) | WebSocket · error | A rejected handshake (401, 404…) is an error value. |
websocket.listen(port, { host }) | Server · error | port 0 picks a free port; server.accept(timeout?) → WebSocket, fields port url. |
ws.send(data) | nil · error | str → text frame, list of bytes → binary, other values → JSON text. |
ws.next(timeout?) | Message · nil | { type: "text" | "binary", data, bytes, size, json() }; nil on timeout or when closed. |
ws.tryNext() · ws.ping() · ws.close(code = 1000, reason) | ||
ws.open · ws.closeCode · ws.closeReason · ws.path · ws.url · ws.headers · ws.protocol |
fogu:net
TCP and UDP sockets. Data is text (UTF-8).
| Function | Returns | Description |
|---|---|---|
net.tcpListen("host:port") | Listener · error | accept() → Stream, setNonblocking(bool), close(). |
net.tcpConnect("host:port") | Stream · error | |
stream.write(text) · stream.writeLine(text) | nil · error | |
stream.read(n = 4096) · stream.readLine() · stream.readAll() | str · error | readLine without the newline; "" at the end. |
stream.setTimeout(ms) · stream.close() | ||
net.udpBind("host:port") | Socket · error | sendTo(addr, data), recvFrom() → { data, addr, len }, connect(addr), send(data), recv(), setTimeout(ms). |
net.resolve(host) | list · error | IP addresses. |
fogu:events
| Function | Returns | Description |
|---|---|---|
events.EventEmitter() | Emitter | |
e.on(event, fn) · e.once(event, fn) | nil | Listeners receive every emitted argument (declare them all). |
e.off(event, fn?) · e.removeAll(event?) | nil | |
e.emit(event, ...args) | bool | true when someone listened. |
e.listeners(event) · e.eventNames() · e.hasListeners(event) |
fogu:cron
Jobs run when the program calls cron.tick() (typically in its main loop).
| Function | Returns | Description |
|---|---|---|
cron.every(interval, fn) | nil | A job every interval (duration or ms). |
cron.schedule(expression, fn) | nil | 5-field cron expression ("*/5 * * * *"); an invalid one stops the program. |
cron.tick() | int | Runs the jobs that are due; returns how many ran. |
cron.list() | list | Job names (every(10ms), the cron expression…). |
cron.clear() | nil | Removes every job. |
fogu:nats
NATS core protocol plus JetStream (streams, acknowledged publishing, pull consumers).
| Function | Returns | Description |
|---|---|---|
nats.connect(url | { url, user, pass, token, name, timeout }) | Nats · error | nats://[user:pass@|token@]host:4222, default $NATS_URL. |
nc.publish(subject, data?, { headers, reply }) | nil · error | data: str, or any value as JSON. |
nc.subscribe(subject, { queue, max }) | Subscription | Wildcards * and >; queue groups split the messages. |
sub.next(timeout?) · sub.tryNext() · sub.unsubscribe() | Message · nil | |
nc.request(subject, data?, { timeout, headers }) | Message · error | No responders → error value. |
nc.flush() · nc.close() · nc.connected · nc.server | ||
msg.subject · .data · .headers · .reply · .json() · .respond(data) |
JetStream
| Function | Returns | Description |
|---|---|---|
nc.jetstream({ prefix, timeout }) | JetStream | |
js.addStream({ name, subjects, storage, max_msgs, max_age, … }) | map · error | NATS stream config (snake_case keys). |
js.updateStream(cfg) · js.streamInfo(name) · js.deleteStream(name) · js.purgeStream(name) | ||
js.publish(subject, data, { msgId, headers, timeout }) | { stream, seq, duplicate } | msgId deduplicates. |
js.consumer(stream, { durable, filter, ackWait, deliver, maxDeliver }) | Consumer · error | A durable pull consumer. |
consumer.fetch(batch = 1, expires = 5s) | list | Up to batch messages. |
msg.ack() · msg.nak(delay?) · msg.term() · msg.inProgress() | nil | msg.seq, msg.delivered, msg.stream. |
fogu:rabbitmq
RabbitMQ (AMQP 0-9-1). Publishing waits for the broker's confirmation. A channel closed by an error (for example declaring a queue with other options) is reopened on the next call.
| Function | Returns | Description |
|---|---|---|
rabbitmq.connect(url?) | RabbitMQ · error | amqp://user:pass@host:5672/vhost, default $AMQP_URL. |
mq.exchange(name, kind = "direct", { durable, autoDelete, internal, arguments }) | nil · error | direct fanout topic headers. |
mq.queue(name = "", { durable, exclusive, autoDelete, ttl, maxLength, deadLetter, passive }) | { name, messages, consumers } | "" gives a server-named queue. |
mq.bind(queue, exchange, key = "") · mq.unbind(…) | nil · error | |
mq.publish(exchange, key, data, { persistent, headers, contentType, correlationId, replyTo, messageId, expiration, priority, mandatory }) | nil · error | Maps are sent as JSON. |
mq.send(queue, data, opts?) | nil · error | Through the default exchange. |
mq.get(queue, { noAck }) | Message · nil | |
mq.consume(queue, { prefetch = 10, noAck, exclusive, tag }) | Consumer | next(timeout?), tryNext(), cancel(). |
msg.data · .json() · .routingKey · .exchange · .headers · .redelivered · … | Properties: contentType correlationId replyTo messageId type persistent. | |
msg.ack() · msg.nack({ requeue = true }) · msg.reject({ requeue }) | nil | |
mq.purge(queue) · mq.deleteQueue(name) · mq.deleteExchange(name) · mq.close() |
fogu:mqtt
MQTT 3.1.1 with automatic reconnection (subscriptions are restored).
| Function | Returns | Description |
|---|---|---|
mqtt.connect(url?, { clientId, username, password, keepAlive, clean = true, will, timeout }) | Mqtt · error | mqtt:// or mqtts://; will: { topic, payload, qos, retain }. |
m.publish(topic, data, { qos = 0, retain }) | nil · error | |
m.subscribe(filter | [filters], { qos }) · m.unsubscribe(…) | nil · error | + one level, # the rest. |
m.next(timeout?) · m.tryNext() | Message · nil | { topic, data, qos, retain, json(), matches(filter) }. |
m.connected · m.clientId · m.subscriptions · m.close() | ||
mqtt.matches(filter, topic) | bool |
fogu:fogumq
Client of the Fogu broker (binary protocol, JSON payloads): key/value store, channels, pub/sub, RPC and API keys. Methods that wait for the server let the other fg tasks run.
| Function | Returns | Description |
|---|---|---|
fogumq.connect("fogu://token@host:port", { timeout, requestTimeout }) | FoguMQ · error | Fields connected authenticated isRoot url; ping() close(). |
mq.kv.get(key) · set(key, value, ttl?) · del(key) · exists(key) · incr(key, n?) · decr(key, n?) | value · error | get gives nil for a missing key. |
mq.channel(name) | Channel | join(alias?) leave() send(data) members() list(). |
channel.onMessage() | Listener | next(timeout?) → { channel, data, ... }; tryNext() close(). |
channel.subscribe(topic) · channel.publish(topic, data) | Subscription · error | Topics live under the channel: name/topic. |
channel.act(method) | Service · error | next() → Request with method params reply(result) fail(msg). |
channel.call(method, params?, timeout?) | value · error | |
mq.apikeys.create(name, { channels, kv, topics, rpc }) · delete(id) · get(id) · list() | value · error | Root token only. |
fogu:bullmq
Job queues on Redis, wire-compatible with BullMQ for Node.js v5 (on the bullmq-rs crate): Fogu and Node producers and workers can share the same queues, and dashboards such as Bull Board see them. The worker owns locks, stalled-job recovery, retries with backoff, concurrency and rate limits; each job is handed to the program, which finishes it with complete or fail. Redis failures are error values.
Queue
| Function | Returns | Description |
|---|---|---|
bullmq.queue(name, { connection, prefix = "bull" }) | BullQueue · error | connection is a redis:// / rediss:// URL (default $REDIS_URL or redis://127.0.0.1:6379). |
q.add(name, data, opts?) | job · error | Options: delay attempts backoff: { type: "fixed" | "exponential", delay, max } priority jobId ttl deduplication: { id, ttl }. |
q.addBulk([{ name, data, opts }]) | list · error | |
q.getJob(id) · q.getJobs(states, start = 0, end = -1, asc = false) | job | nil · list | A job: { id name data state timestamp attemptsMade progress processedOn finishedOn failedReason returnvalue opts }. |
q.counts() · q.count() | map · int | Per state: wait active delayed prioritized completed failed paused waiting-children. |
q.upsertJobScheduler(id, { every | pattern, tz, limit, immediately }, { name, data, opts }) | job · error | Repeatable jobs (cron pattern or every duration). |
q.removeJobScheduler(id) | bool · error | |
q.pause() · resume() · isPaused() · drain() · remove(id) · clean(grace, limit, state) · obliterate({ force }) · getJobLogs(id) |
Worker and events
Limitation: the worker of bullmq-rs publishes completed events with an empty return value; q.getJob(id).returnvalue has the value given to complete.
| Function | Returns | Description |
|---|---|---|
bullmq.worker(name, { connection, prefix, concurrency = 1, lockDuration, maxStalledCount, limiter: { max, duration } }) | BullWorker · error | |
w.next(timeout?) · w.tryNext() | BullJob | nil · error | Waits cooperatively (other fg tasks keep running); nil on timeout or after close(). |
job.complete(value?) · job.fail(reason) | nil | fail retries the job while attempts remain. A job dropped without an answer fails. |
job.progress(value) · job.log(text) | nil | Fields are those of the job map, plus done. |
w.pause() · w.resume() · w.close() · w.running · w.pending | ||
bullmq.events(name, { connection, prefix, lastEventId }) | BullEvents · error | next(timeout?) → { event, jobId, id, … } (added waiting active progress completed failed delayed stalled removed). |
fogu:mail
E-mail over SMTP (presets for Gmail, Outlook, Office 365, Yahoo, iCloud, Zoho, Fastmail, AOL, GMX, Amazon SES, Mailtrap, Mailpit) or the HTTP APIs of Resend, SendGrid, Mailgun, Postmark, Brevo, MailerSend and Mailjet. The console provider only prints (development and tests).
| Function | Returns | Description |
|---|---|---|
mail.connect({ provider, … } | url) | Mailer | No connection is made yet. |
SMTP: { provider: "gmail" | "smtp" | …, host, port, secure, user, password, region } | secure: tls (465), starttls (587), none; URLs smtp://user:pass@host:587, smtps://…. | |
APIs: { provider: "resend" | "sendgrid" | …, apiKey, domain, region, baseUrl } | apiKey defaults to $RESEND_API_KEY, $SENDGRID_API_KEY…; Mailgun needs domain, Mailjet apiSecret. | |
common: { from, timeout } | Default sender. | |
mailer.send(message) | { id, provider } · error | A rejected message, a bad address or a network failure is an error value. |
mailer.sendMany([messages]) | list · error | |
mailer.verify() | bool · error | SMTP: connects and authenticates. |
mailer.render(message) | str | The RFC 5322 text that SMTP would send. |
message: { from, to, cc, bcc, replyTo, subject, text, html, attachments, headers } | Addresses: "a@x.com", "Ana <a@x.com>", { name, email } or a list. | |
attachment: { filename, content | path, contentType, cid, encoding } | content: str or list of bytes; cid makes it inline (<img src="cid:logo">). |
fogu:ai
LLMs over HTTP: OpenAI-compatible APIs (OpenAI, Groq, OpenRouter, DeepSeek, Mistral, xAI, Together, Fireworks, Perplexity, Ollama, LM Studio), Anthropic and Google Gemini — chat, streaming, tools, agents, embeddings. Keys default to $OPENAI_API_KEY, $ANTHROPIC_API_KEY, $GEMINI_API_KEY…
Client
| Function | Returns | Description |
|---|---|---|
ai.client({ provider, model, apiKey, baseUrl, timeout, headers, maxTokens } | "provider/model") | AiClient | Provider compatible + baseUrl for any OpenAI-style server. |
client.chat(prompt | { messages, prompt, system, model, temperature, maxTokens, topP, stop, tools, toolChoice, json }) | map · error | { text, toolCalls, finishReason, usage: { inputTokens, outputTokens }, model, message }. |
client.stream(same) | AiStream · error | next(timeout?) → the next piece of text or nil at the end; collect() → like chat; fields text done result. |
client.models() | list · error | [{ id, name }]. |
client.embed(text | [texts], { model }) | list · error | Vectors (OpenAI-style and Gemini). |
message: { role: "system" | "user" | "assistant" | "tool", content, toolCalls, toolCallId, name } | result.message can be appended to continue the conversation. |
Tools and agents
A tool that returns an error value sends error: … back to the model, which can recover.
| Function | Returns | Description |
|---|---|---|
ai.tool(name, description, parameters, run?) | map | parameters is a JSON schema; also a plain map { name, description, parameters, run }. |
ai.agent({ client, model, instructions, tools, maxSteps = 10, temperature, maxTokens, memory, onStep }) | Agent | Tools need run(args). |
agent.run(input) | map · error | Calls the model and the tools until it answers: { text, steps, messages, usage, finishReason }. |
agent.reset() · agent.history | With memory: true the conversation continues across runs. |
fogu:ssh
Commands, file copies and tunnels over the system's OpenSSH client (key or password).
| Function | Returns | Description |
|---|---|---|
ssh.connect("user@host:port" | { host, user, port, key, password, strictHostKey, knownHosts, timeout, options }) | Ssh · error | Checks the connection; strictHostKey defaults to accept-new. |
s.run(command, { input }) | { ok, code, stdout, stderr } · error | A non-zero exit code is not an error. |
s.upload(local, remote) · s.download(remote, local) | nil · error | scp, folders included. |
s.forward(localPort | 0, host, port) | Tunnel · error | -L: a local port that reaches host:port through the server. |
s.reverse(remotePort, host, localPort) | Tunnel · error | -R: a port on the server that reaches a local service. |
tunnel.localPort · .remotePort · .alive() · .close() | ||
s.close() | nil |
fogu:shell
A small POSIX-style shell: pipes, && || ;, redirections (> >> < 2> 2>&1 &>), $VAR, $(…), quotes, globs and ~. The usual Linux commands are built in, so scripts behave the same on Windows: echo cat ls pwd cd mkdir rm cp mv touch grep head tail wc sort uniq cut tr tee basename dirname which env export true false exit sleep seq. Other commands run as programs.
| Function | Returns | Description |
|---|---|---|
shell.run(command, { cwd, env, input, native = true }) | { ok, code, stdout, stderr } | A non-zero exit is not an error; native: false uses system programs only. |
shell.exec(command, opts?) | same | Output goes to the terminal as it happens. |
shell.text(command, opts?) | str · error | stdout without the final newline; a failure is an error value. |
shell.lines(command, opts?) · shell.json(command, opts?) | list · value | |
shell.quote(text) | str | Safe to interpolate into a command. |
shell.cd(dir) · shell.cwd() | nil · str | The shell's own working folder. |
shell.which(program) · shell.builtins | str · list |
fogu:ffi
Calls functions of native libraries (C ABI): .dll, .so, .dylib. Unsafe by nature: a wrong signature can crash the program. Supported signatures: up to 4 arguments mixing integers and floats, or up to 8 integer/pointer arguments.
| Function | Returns | Description |
|---|---|---|
ffi.open(name) | Library · error | A path or a name ("user32" → user32.dll / libuser32.so); "c" and "m" are the C runtime and the math library. |
lib.func(symbol, [argTypes], returnType = "void") | fn · error | A Fogu function that calls the symbol. |
lib.has(symbol) · lib.name | bool · str | |
types | i8 i16 i32 i64 u8 u16 u32 u64 isize usize bool f64 ptr str buffer; results also f32 void. str passes a NUL-terminated copy; a str result reads a C string. | |
ffi.alloc(size) | Buffer | Memory for out-parameters: text() bytes(start?, len?) write(offset, str | bytes) i32/u32/i64/f64(offset), fields size address. |
ffi.types · ffi.suffix | list · str |
fogu:playbook
Configuration management in the style of Ansible: an inventory of hosts and playbooks of idempotent tasks, run over SSH (the system's OpenSSH client) or on the local machine (through fogu:shell, so it also works on Windows). Hosts run in parallel; the output and the PLAY RECAP follow Ansible's. From the command line: fogu play site.yml -i inventory.yml [--check] [-l hosts] [-t tags] [--skip-tags t] [-e key=value] [-f forks] [-v] (exit code 2 when a host failed or was unreachable).
Inventory
vars for every host; hosts: name → { host, port, user, key, password, become_password, connection: "local", …vars }; groups: name → list of hosts or { hosts, vars }. Patterns in hosts: — all, a host, a group, web:db, web:!web2.
Playbooks and tasks
Templates: {{ expr }} with variables (item, facts, inventory_hostname, groups, registered results), . [], + - * / % ~, comparisons, and or not in, is defined, and the filters default upper lower trim length join first last replace split int float string bool to_json basename dirname.
| Function | Returns | Description |
|---|---|---|
play: { name, hosts, vars, become, gather_facts = true, tags, tasks, handlers } | Facts: facts.os arch hostname distribution distribution_version pkg_mgr service_mgr user. | |
task keys: name, when, loop, register, notify, ignore_errors, changed_when, check_mode, become, tags | when is an expression; loop sets item; register keeps the result. | |
shell / command: "cmd" | { cmd, chdir, creates, removes, stdin } | Skipped in check mode (unless check_mode: false); { rc, stdout, stderr, stdout_lines }. | |
copy: { content | src, dest, mode } · template: { src, dest, mode } | Written only when the content or mode differs; template renders {{ }}. | |
file: { path, state: directory | absent | touch | file, mode } | ||
lineinfile: { path, line, regexp, state, create, mode } | Replaces the last line matching regexp, or appends. | |
package: { name, state: present | absent, update_cache, use } | apt, dnf, yum, zypper, apk, pacman (from the facts). | |
service: { name, state: started | stopped | restarted | reloaded, enabled } | systemd. | |
debug: { msg } | { var } · set_fact: { … } · fail: { msg } · wait_for: { port | path, host, timeout } |
From Fogu
| Function | Returns | Description |
|---|---|---|
playbook.run(plays | path, { inventory, vars, check, limit, tags, skipTags, forks, verbose, quiet }) | map · error | { ok, failed: [hosts], recap: { host: { ok, changed, unreachable, failed, skipped, ignored } } }. |
playbook.inventory(path | map) | map | The hosts and groups it describes. |
playbook.render(text, vars) | str · error | The template engine on its own. |
fogu:vm
Runs Fogu source code at run time, in the style of Node's node:vm. The code runs on the same interpreter, so its functions can be called from the program and vice versa. A new context only sees the global natives plus the keys of its sandbox map (it may still import modules); like node:vm, it is not a security boundary. The value of the last expression is returned; syntax, name, runtime and timeout errors come back as error values.
| Function | Returns | Description |
|---|---|---|
vm.runInNewContext(code, sandbox?, options?) | value · error | Options: { filename = "<vm>", timeout } or a filename. Variables the code declares are copied into the sandbox map. |
vm.createContext(sandbox?) · vm.isContext(x) | VmContext · bool | A context keeps its variables between runs: ctx.sandbox, ctx.name reads a variable, ctx.run(code, options?). |
vm.runInContext(code, ctx, options?) | value · error | Changes to the sandbox map are seen by the next run. |
vm.runInThisContext(code, options?) | value · error | Sees the program's globals; its declarations persist between calls. |
vm.Script(code, options?) | VmScript · error | Parsed once: runInContext(ctx) runInNewContext(sandbox?) runInThisContext(), fields source filename. |
vm.compileFunction(code, params = [], { context, filename }) | fn · error | A function whose body is code. |
timeout | A duration; loops and calls stop once it passes (script execution timed out after 50ms). The JIT is not used while it runs. |
fogu:cli
Terminal interaction: prompts (dialoguer), colors and terminal control (console), spinners and progress bars (indicatif), tables (comfy-table) and argument parsing (clap). Without a terminal on stdin (pipes, CI) the prompts read plain lines, so echo Ana | fogu app.fg works; spinners and bars draw on stderr, only on a terminal. Colors are off when stdout is not a terminal or NO_COLOR is set.
Prompts
| Function | Returns | Description |
|---|---|---|
cli.input(prompt, { default, allowEmpty, type: "str" | "int" | "float" }) | str | int | float · error | |
cli.password(prompt, { confirm: "Repeat password", allowEmpty }) | str · error | Hidden input. |
cli.confirm(prompt, { default }) | bool · error | |
cli.select(prompt, items, { default, fuzzy, index }) | value | nil · error | Items are strings or { label, value }; nil when cancelled with Esc; fuzzy filters while typing. |
cli.multiSelect(prompt, items, { defaults, index }) | list | nil · error | Without a terminal: names or numbers separated by commas. |
Styles, terminal, spinners and tables
| Function | Returns | Description |
|---|---|---|
cli.style(text, ...styles) | str | bold dim italic underline strike inverse, colors red green yellow blue magenta cyan white black gray, brightRed, backgrounds bgRed, 256 colors "208" / "bg208". |
cli.red(text) · green · yellow · blue · magenta · cyan · white · black · gray · bold · dim · italic · underline · strike · inverse | str | |
cli.colors(on?) · cli.stripAnsi(s) · cli.textWidth(s) · cli.link(text, url) | bool · str · int · str | colors(true) forces colors. |
cli.isTTY("stdin" | "stdout" | "stderr") · cli.size() | bool · { columns, rows } | nil | |
cli.clear() · clearLine() · hideCursor() · showCursor() · readKey() | readKey → a character or Enter Escape Backspace Tab ArrowUp ArrowDown ArrowLeft ArrowRight Home End PageUp PageDown Delete. | |
cli.spinner(text, { frames }) | Spinner | text(t) succeed(msg?) fail(msg?) warn(msg?) info(msg?) stop(). |
cli.progress(total, { message, prefix, template, chars }) | ProgressBar | inc(n = 1) set(n) length(n) message(m) println(line) finish(msg?), fields position length elapsed finished. Templates of indicatif. |
cli.table(rows, { headers, style: "rounded" | "utf8" | "ascii" | "markdown" | "none", align, width }) | str | Rows are lists or maps; numbers are right aligned. |
Arguments
| Function | Returns | Description |
|---|---|---|
cli.parse(spec, argv = Fogu.args, { exit = true }) | map · error | spec: { name, version, about, args: [...], commands: [{ name, about, args }], commandRequired }. --help and --version print and exit; a usage error prints and exits with 2, or is an error value with { exit: false }. |
arg: { name, type, short, long, help, positional, required, multiple, default, choices, env } | Types str int float bool count; multiple gives a list. A subcommand sets command and its values in args. |
Command line
fogu fmt indents with 4 spaces, normalizes the spacing around commas, colons, operators and braces,
keeps one blank line at most and never touches strings or comments. It checks that the formatted program has
exactly the same tokens before writing a file; --check lists the files that need formatting (exit 1).
| Option / variable | Effect |
|---|---|
--no-jit · FOGU_JIT=0 | interpreter only |
--jit-stats · --jit-debug · --jit-dump | statistics, what compiles/is rejected, Cranelift IR |
--strict | an error in an fg task terminates the process |
FOGU_HOME | base of the package store (default: ~/.fogu) |
NO_COLOR | disables colors |
FOGU_DOTENV=0 | do not load ./.env into Fogu.env/process.env (loaded by default; variables already set win) |
fogu init creates fogu.json (with start and dev scripts),
main.fg and a .gitignore.
Diagnostics
Undefined names, uses before declaration, unknown types, misplaced ? and non-exhaustive
match are detected before the program runs. Errors show a code, the position, an excerpt
and, when possible, a suggestion. fogu check also warns about unused local variables (prefix them with
_ to silence the warning).
| Code | Meaning |
|---|---|
E0001 · E0002 | lexical error · syntax error |
E0100 · E0101 | undefined variable · used before its declaration |
E0102 · E0103 · E0104 | redeclaration in the same scope · assignment to a const · private name |
E0200 · E0201 · E0202 | integer overflow · division by zero · index out of bounds |
E0203 · E0204 · E0205 | non-exhaustive match · value is not callable · stack overflow |
E0206 | ? outside a function, or in a function whose return type has no error |
E0207 · E0208 | type mismatch · unknown type |
E0300 | deadlock between tasks |
Testing
Tests live in *.test.fg files and use fogu:test. fogu test finds them
(under the current folder, or the given files and folders), runs each file in a fresh interpreter and exits
with 1 if a test fails. A test fails when an expectation fails, when it raises an error, or when it returns an
error value — so ? can be used inside tests.
Matchers: toBe, toEqual, toBeTruthy, toBeFalsy,
toBeNil, toBeError, toBeType("int"), toContain,
toHaveLength, toBeGreaterThan, toBeLessThan, toBeCloseTo(x, eps?)
— each can be negated with .not.
Packages
Packages come from git repositories, .tar.gz archives or local folders and live in a
global store (~/.fogu/fogu_modules/<name>@<commit>). fogu.lock pins the commit and the
sha256 checksum; install scripts are never run.
Standalone executables
fogu build --compile produces dist/<name> (.exe on Windows): a copy of the
Fogu runtime with the program appended — the entry file, every module it imports and the packages it uses. The
executable runs on machines without Fogu and passes every command-line argument to the program.
Files the program reads at runtime (a React build, templates, images…) are embedded with
"embed": ["dist", "templates/*.html"] in fogu.json or --embed <glob>. The program
finds them with Fogu.asset(path), which works the same when running from the sources:
On first run the bundle is extracted to <temp>/fogu-bundles/<hash>;
--target wasm is not supported yet.
JIT compiler
The interpreter is the semantic reference. The JIT (Cranelift) compiles hot numeric functions and loops
(int/float/bool, if, while, for a..b, match,
math.*, numeric type annotations); when something is not supported, the code keeps running in the
interpreter, with the same results and error messages.
| Benchmark (release) | Interpreter | JIT |
|---|---|---|
| fib(32) | 3.02 s | 0.025 s |
| 50M loop | 16.7 s | 0.069 s |
| mandelbrot | 3.5 s | 0.013 s |
Status and roadmap
The language is in development (before 1.0 there may be incompatible changes). It does not have
yet: permissions --allow-*, fogu audit, fogu publish,
static type inference, or the bytecode VM. The detailed status of every feature is in
CHECKLIST.md and the full specification in docs/spec.md.
The standard library reference on this page is generated by docs/tools/gen_reference.py, which runs
the examples to show their real output.
Fogu is distributed under the MIT license © 2026 Edmilson Soares.