OmniFlux Programming Language Reference Manual ๐
Welcome to the official reference manual for OmniFlux, a minimalist, self-healing backend programming language designed to run with zero compile-time friction.
OmniFlux code compiles directly into optimized, production-ready backend code.
1. Syntax & Core
1.1 Comments ๐ฌ
OmniFlux supports multiple comment styles with a clear distinction to give you flexibility:
Intent & Documentation Comments (
#): Comments starting with#are used to describe your intent, write explanations, or guide the compiler in building your application. These comments are preserved in the final output.# Calculate user rating based on historyTemporary & Code Comments (
//and/* ... */): Double-slash comments (//) and block comments (/* ... */) are used for local draft notes or to temporarily disable code blocks. They are completely ignored and stripped out during compilation.// var old_score = 0[!TIP] Nested block comments are fully supported! Unlike many other languages, OmniFlux allows you to nest block comments (
/* ... /* ... */ ... */) to any depth. You can safely comment out large chunks of code that already contain block comments without breaking the build.
1.2 Variables
- Block-scoped variables: Declared with
varorconstto scope variables to their local block. - Global variables: Prefixed with
$(e.g.$app_name). These are globally accessible across all included files. - Semicolons: Semicolons are optional. The compiler automatically inserts them where appropriate in the target output.
- Type Inspection (
describe): OmniFlux is dynamically typed. To inspect the type of any variable or expression at runtime, use thedescribekeyword. It returns a string representing the type (e.g.,"string","number","boolean","array","null","undefined","function", or"object"):
Note that uninitialized and non-existent variables returnvar v = [1, 2, 3] var type_name = describe v # Returns "array""undefined"underdescribe.
$app_name = "OmniFlux App" # Global variable
var local_counter = 1 // Block-scoped local variable
1.3 Tasks (Functions)
Tasks (or functions) in OmniFlux are declared using the define task syntax. There are two simple variations:
Standard task definition:
define task calculate(a, b) { return a + b }Natural English task definition:
define task calculate with a, b { return a + b }Default Parameter Values: OmniFlux supports default values for parameters in both syntaxes. If an argument is omitted when calling the task, the default value is used:
# Standard syntax with default values define task greet(name = "Guest", greeting = "Hello") { print(greeting + ", " + name) } # Natural English syntax with default values define task create_user with username, role = "user", active = true { print("User: " + username + " (Role: " + role + ", Active: " + active + ")") }Async Execution & Non-Blocking (
background): By default, all tasks and async bindings in OmniFlux are automatically awaited when calledโyou never writeawaitin OmniFlux.If you want a task to execute in a non-blocking/asynchronous way (so it runs in the background and returns immediately), prepend the call with the keyword
background:# Runs in the background (non-blocking) background log_event("Service started")Task Invocation (Calling Tasks): OmniFlux supports multiple natural ways to call (invoke) tasks:
Natural Call with Parameters (
with): You can call a task using thewithkeyword followed by arguments:greet_user with "Charlie", 30[!NOTE] Syntax Design: Natural parameter calls using
withare designed to be written on a single physical line for a clean, sentence-like reading flow. If you prefer to format and split arguments across multiple lines for better layout structure, use standard parenthesized calls:greet_user( "Charlie", 30 )Standard Call with Parameters: Traditional call syntax with parentheses is also supported:
greet_user("Charlie", 30)Call without Parameters (Parentheses-free): To invoke a task that takes no arguments, you can write its name directly without parentheses:
sayHello(Writing
sayHello()is also valid).Function Pointers & References (
refandcall): To get a reference to the task itself (e.g., to pass it as a callback or store it in a variable) without executing it immediately, prefix the task name withref:var callback = ref sayHelloTo execute a task reference (callback) dynamically, you can use the
callkeyword:# Call without parameters call callback # Call with parameters var greet_callback = ref greet_user call greet_callback with "Dave", 35(Using traditional parentheses like
callback()orcallback("Dave", 35)is also supported).
1.4 Printing to the Screen ๐บ
OmniFlux provides built-in options for outputting text to the screen:
print(...): Prints the given message to the console, automatically appending a trailing newline.
It also natively supports format strings:print("Hello, World!") print("User score is " + score)print("User %s has score %d", username, score)printf(format, ...args): Similar to C'sprintf, this function formats a string and prints it to the console without automatically appending a trailing newline.printf("Processing: %d%% completed\r", percent)
Supported format specifiers include:
%s: String (supports precision truncation, e.g.,%.3s)%d,%i: Integer (supports padding width and leading zeros, e.g.,%02d,%5d)%f: Float (supports width and decimal precision, e.g.,%.2f,%06.2f)%j: JSON serialization of objects%%: A single percent sign (%)
1.4.1 Structured Logging System ๐ชต
OmniFlux provides a production-grade, zero-friction structured logging utility. It supports procedural logging, structured context, and environment-based configuration.
log(message, level?, context?): Generic logging helper. Thelevelis optional (defaults to"warn"). Thecontextis optional and can be a data object or anErrorobject. Iflevelis not a string or a valid level name, it is treated as thecontextparameter, defaulting the level to"warn".log_debug(message, context?)/logdebug: Log a message with debug level.log_info(message, context?)/loginfo: Log a message with info level.log_warn(message, context?)/logwarn: Log a message with warn level.log_error(message, context?)/logerror: Log a message with error level.log_fatal(message, context?)/logfatal: Log a message with fatal level.
Configuration & Behavior
The logging system reads the following environment variables (which can be configured externally or dynamically using setenv):
LOG_LEVEL: Filters out logs below the configured level (hierarchy:debug<info<warn<error<fatal). Defaults to"info".LOG_FORMAT: Controls log serialization format:"text"(default for TTY consoles): Logs are printed with local timestamps and color-coded level tags, with thecontextJSON appended to the end of the line. If the context is anErrorobject, a readable multi-line stack trace is printed."json"(default when stdout is redirected/non-TTY): Logs are structured as single-line JSON objects, containingtimestamp,level,message, andcontext/errorproperties.
LOG_FILE: If set, copies the formatted logs directly to the specified file path. In"text"format, ANSI color escape codes are automatically stripped from file writes to keep log files clean.
# Enable text format and debug logs
setenv("LOG_FORMAT", "text")
setenv("LOG_LEVEL", "debug")
log_info("Application starting")
log_debug("Loading database connection pool", { "poolSize": 10 })
define task trigger_error() {
var x = null
var y = x.foo
} on error (err) {
log_error("Failed to query database", err)
}
1.5 Input & CLI Arguments ๐ฅ
OmniFlux provides simple tools to read input and arguments when building command line interfaces:
input(prompt): Prints an optional prompt message and blocks execution synchronously, waiting for user input in the terminal. When the user presses Enter, it returns the input as a string (with the trailing newline stripped).var username = input("Enter username: ") print("Hello, %s!", username)read_char(): Synchronously reads a single keypress from standard input without waiting for Enter. Returns the captured character as a string. If the user presses Ctrl+C, it terminates the script immediately with a standard SIGINT code (130).print("Press any key to continue...") var key = read_char() print("You pressed: %s", key)$args: A globally available array that contains all CLI arguments passed to the script (excluding the compiler/node command and the script file name itself).if len($args) > 0 { print("First CLI argument: %s", $args[0]) }getenv(name): Retrieves the value of the environment variablenamefrom the host system. Returnsnullif the variable is not set.var path = getenv("PATH") print("System PATH: %s", path)setenv(name, value): Sets the environment variablenameto the givenvalue(which is cast to a string).setenv("PORT", 8080)exit(code): Terminates the current process immediately with the specified integer exitcode(defaults to0).exit(1)
1.6 AI Directives (Interactive Code Completion) ๐ค
OmniFlux features a unique AI-assisted compilation pipeline. You can guide the AI to write entire blocks of code for you on demand using two simple mechanisms:
Line-level Directives (
>>>): To ask the AI to generate a block of code directly, start a new line with>>>followed by your request in English:on start { >>> print a list of numbers from 1 to 5 }This will trigger the AI compiler to generate the requested OmniFlux code. Crucially, the AI compiler will write the generated code directly back into your original
.ofsource file, replacing the>>>directive. The generated block will be cleanly commented so you can review exactly what was written:on start { # === AI Generated Code Start === # Request: print a list of numbers from 1 to 5 for i of range(1, 6) { print(i) } # === AI Generated Code End === }[!IMPORTANT] The
>>>marker must be the first non-whitespace character on the line (meaning only indentation spaces/tabs can precede it). This prevents any collisions with standard operators in the middle of expressions.Programmatic Directives (
aiandtodo): You can also write AI directives using theai("...")ortodo("...")functions inside your code. The AI compiler will resolve them and replace them with the actual generated code:on start { ai("read config.json and print its contents") }
2. Control Flow & Conditionals
OmniFlux provides simple structures for making decisions and handling execution flow.
2.1 Conditionals (if and switch)
Making Decisions with if / else
Use if, else if, and else to execute code based on conditions. Parentheses around conditions are optional.
var score = 85
if score >= 90 {
print("Excellent!")
} else if score >= 70 {
print("Good job!")
} else {
print("Keep trying!")
}
Multi-way Branching with switch
When you need to compare a variable against multiple values, a switch statement is cleaner than multiple if conditions.
var role = "admin"
switch role {
case "admin":
print("Welcome, Administrator!")
break
case "editor":
print("Welcome, Editor!")
break
default:
print("Welcome, User!")
}
2.2 Loops
Loops are used to execute a block of code multiple times. OmniFlux provides two simple loop constructs:
The for Loop (Iterating over Lists)
Used to step through items in an array or list. The loop variable (like fruit in the example below) is created automatically for you without needing the var keyword.
var fruits = ["apple", "banana", "cherry"]
for fruit of fruits {
print("I like " + fruit)
}
The while Loop (Iterating with Conditions)
Repeats a block of code as long as a specific condition remains true. This is also perfect for counter-based loops.
var count = 1
while count <= 5 {
print("Count is " + count)
count = count + 1
}
2.3 Delayed Execution (wait)
Allows delaying execution without blocking.
on start {
print("Initializing...")
wait 2 seconds
print("Ready!")
}
2.4 Periodic Execution (every)
Runs a code block periodically.
every 5 minutes {
clean_expired_sessions()
}
2.5 Execution Profiling Block (timer)
Measures the execution time of a block of code in seconds with high precision. Can be assigned to a variable, or used on its own (in which case it automatically logs the duration to the console).
# 1. Assign elapsed time to a variable
var elapsed = timer {
wait 0.15 second
}
print("Process took: %f seconds", elapsed)
# 2. Benchmark code block directly (auto-logs duration)
timer {
var hash = sha256("benchmark_text")
}
2.5 Lifecycle Hooks & Execution Order
[!WARNING] Root-Level Execution & Order of Operations: Any code written at the root level (outside of any function or
onblock) executes immediately when the file is loaded. However, if root-level code contains asynchronous operations (likewait), the order of operations cannot be guaranteed. Subsequent synchronous lines will continue executing while the asynchronous task runs in the background. Always place your main execution logic insideon startor functions to ensure predictable, sequential execution.
OmniFlux provides several lifecycle hooks to manage application state and events cleanly:
on start { ... }Executes immediately when the application starts. This is the main entry point of your program.on shutdown { ... }Guaranteed to run when the application terminates gracefully (e.g. when receiving a stop signal or system exit). Use this to close database connections or save final state.on error (err) { ... }A global error hook that catches any unexpected runtime errors or background failures, preventing the application from crashing silently.on request (req, res) { ... }A global middleware event hook that runs on every incoming HTTP request, prior to specific route matching.Parameters & Structure:
req(Request Object): An object containing the incoming HTTP request details:req.method: The HTTP verb (e.g.,"GET","POST").req.path/req.url: The request URL path (e.g.,"/dashboard").req.query: A JSON object of query parameters (e.g.,req.query.id).req.body: A JSON object containing parsed POST/PUT request body parameters.req.headers: An object containing the request headers (e.g.,req.headers["user-agent"]).
res(Response Object): An object used to manipulate and send the HTTP response:res.status(code): Sets the HTTP status code (e.g.,res.status(403)).res.send(html_or_text): Sends raw HTML or plain text content.res.json(object): Serializes and sends a JSON object.res.redirect(url): Redirects the client to another URL.res.setHeader(name, value): Sets an HTTP response header.
Execution Lifecycle:
If
on requestsends a response to the client (e.g., callingres.send(...)orrespond with ...), the request execution stops immediately, and the matched route handler (likeGET "/users") will not be executed. If no response is sent, the server automatically passes control to the matching route handler (next()).This hook is ideal for global tasks like request logging, CORS headers, API authentication checks, or rate limiting.
2.6 Local Error Handling (on error) ๐ก๏ธ
To keep your code simple, readable, and free of nested boilerplate (like the try-catch blocks found in other languages), OmniFlux provides a clean, flat syntax to handle errors locally.
You can attach an on error (err) block directly to the closing brace of any Route Handler or Task:
1. Route-Level Error Handling
When attached to a route handler, any network, database, or runtime error thrown inside the route will immediately divert execution to your error handler. This allows you to respond to the client with a custom status and message:
POST "/v1/chat/completions" (req, res) {
# If networkpost fails (e.g. network timeout), execution jumps straight to the on error block
var response = networkpost("https://api.provider.com/v1/chat", req.body, {
"Authorization": "Bearer key"
})
respond json response
} on error (err) {
# Respond gracefully without crashing the server
respond status 502 and json {
"error": "Failed to reach AI provider",
"details": err.message
}
}
2. Task-Level Error Handling
Similarly, you can attach an on error block to task definitions:
define task load_config(path) {
var content = fileread(path)
return JSON.parse(content)
} on error (err) {
print("Failed to load config: %s", err.message)
return { "status": "fallback_default" }
}
3. Default Compiler Protection
If you do not specify an on error block:
- For Route Handlers: The compiler automatically wraps the handler in a default safety net. If an unhandled error occurs, it prints the error to the console and responds to the client with a
500 Internal Server Error(preventing the server from crashing or leaving the connection hanging). - For Tasks: Unhandled errors are caught and re-thrown so they can bubble up to the caller or route handler.
4. Call-Level Error Handling
You can also catch errors on a specific function call or statement using on error (err) on the same line. This is perfect for capturing exceptions from library calls (like standard library tasks) and supplying a default/fallback value:
[!NOTE] Syntax Design: The start of the call-level
on error (err) {block must be placed on the same physical line as the target statement or function call. This design choice prevents ambiguity, clearly distinguishing local statement-level fallbacks from global process-wideon errorlifecycle hooks.
- Single-line statement fallback:
var data = fileread("config.json") on error (err) { data = "{}" } - Multi-line statement fallback:
var content = fileread("config.json") on error (err) { print("Warning: could not read config: %s", err.message) content = "{}" }
5. Programmatic Error Information (error_info)
When handling errors locally using an on error (err) block, you can get detailed information about where the error occurred in your OmniFlux code using the built-in function error_info(err) (alias errorinfo):
error_info(err): Parses the stack trace oferrand returns an object containing:file: The name of the original OmniFlux file where the error occurred.line: The line number in the original OmniFlux file.message: The error message.
Example:
define task run_process() {
var list = null
var first = list[0] # This will throw a runtime error
} on error (err) {
var info = error_info(err)
print("Error on line %d of %s: %s", info.line, info.file, info.message)
}
3. Web Server & Routing
OmniFlux has built-in primitives for setting up web servers and HTTP routing.
3.1 Initializing Server
listen on port 3000
3.2 Route Handlers & Responses
Define route handlers to respond to HTTP requests. The syntax specifies the HTTP method (like GET or POST), the URL path, and a block containing the response:
GET "/users" (req, res) {
# Send a JSON response with status code
respond with status 200 and json { "status": "ok" }
}
Procedural Response Primitives
OmniFlux provides simple, procedural statements for sending HTTP responses, fully hiding Node.js/Express objects. The keyword with is optional in all respond statements:
JSON Responses:
respond json { "status": "ok" }(orrespond with json ...)respond status 200 and json { "status": "ok" }
HTML & Text Responses:
respond html "<h1>Welcome</h1>"respond status 404 and html "<h1>Not Found</h1>"respond text "Hello World"respond status 200 and text "Hello World"
File Responses (for sending local files):
respond file "/path/to/file.png"respond status 200 and file "/path/to/file.png"
Paths can be absolute or relative. Relative paths are always resolved relative to the working directory at server startup โ not at request time โ making them safe when deployed under process managers like Phusion Passenger.
Redirects:
redirect to "/login"redirect to "/login" with status 301(for permanent redirects)
Template Responses (renders and sends HTML templates):
respond template("views/index.html", { "title": "Home" })(Parenthesized syntax)respond status 200 and template("views/index.html")respond template "views/index.html" { "title": "Home" }(Natural block syntax; the separating comma between path and object is optional and automatically completed by the compiler if omitted).respond with template "views/index.html", { "title": "Home" }
The template engine reads the
.htmlfile and processes{{ variable }}interpolation and@if/@else/@forcontrol blocks. It also recursively resolves@include("path/to/partial.html")directives. Likerespond file, all paths are resolved relative to the startup working directory, ensuring correct behavior under Passenger.
Deployment Note (Apache + Phusion Passenger): When running an OmniFlux server behind Apache with Passenger, Apache's document root is typically set to the
public/directory. This means any static assets placed inpublic/(CSS, images, JS) are served directly by Apache and never reach the OmniFlux application. This is more efficient than serving them through Node.js. Dynamic routes (GET "/",POST "/api/...", etc.) are transparently proxied by Passenger to the OmniFlux process.[!IMPORTANT] Static Asset URL Conventions: Because Apache/Passenger sets
public/as the web Document Root, all HTML references to static assets (images, CSS, JS) must be written relative to the domain root without the/public/prefix:
- Correct:
<link rel="stylesheet" href="/style.css">,<img src="/logo.png">- Incorrect:
<link rel="stylesheet" href="/public/style.css">,<img src="/public/logo.png">Writing/public/...in HTML templates will fail in production deployment under Passenger.[!NOTE] Static
index.htmlPrecedence & Routing: Web servers (Apache/Nginx/Passenger) automatically check forpublic/index.htmlfirst when handling root requests (GET "/").
- For Dynamic OmniFlux Applications (using
GET "/"inmain.of): If a staticindex.htmlexists inpublic/, web servers will serve it directly, bypassing OmniFlux dynamic template rendering (main.of). For dynamic applications, store template files inviews/(e.g.views/index.of.html) rather thanpublic/index.html.- For Pure Static Sites / Front-End SPAs: Placing
index.htmlinsidepublic/is standard and will be served directly by the web server as the entry point.To serve static assets when running standalone (without Apache), use the single-line
servedirective:serve "public"This directive instructs the OmniFlux engine to automatically serve all static files inside
public/transparently.Alternatively, you can define a custom wildcard route:
GET "/public/*file" (req, res) { var file_path = req.params.file.join("/") respond with file "public/" + file_path }This route is harmlessly ignored under Apache, since Apache intercepts those requests first.
4. Native Bindings
OmniFlux provides native bindings to common backend services, making setups extremely fast:
- Databases (Local JSON DB): Built-in NoSQL document store functions (
dbinsert,dbselect,dbupdate,dbdelete) that save to a localdb.jsonfile. Runs in memory for maximum read speed. - Caching:
cacheset(key, value, ttl)andcacheget(key)(backed by Redis). - File I/O: Core file system operations:
fileread(path): Reads file contents as a UTF-8 string.filewrite(path, data): Writes data (string or object) to a file.fileexists(path): Returnstrueif the file or directory exists,falseotherwise.fileappend(path, data): Appends data (string or object) to the end of a file.fprint(path, format, ...args): Formats a string (using the same format specifiers asprint) and appends it to the end of a file, automatically appending a trailing newline.fprintf(path, format, ...args): Formats a string and appends it to the end of a file without automatically appending a trailing newline.filedelete(path): Deletes the specified file.filecopy(src, dest): Copies a file fromsrctodest.filerename(src, dest): Renames or moves a file fromsrctodest.dirlist(path): Lists the contents of a directory (returns an array of strings).dircreate(path): Creates a directory recursively (including any missing parent directories).scriptdir(): Returns the absolute path of the directory containing the currently running script.filestat(path): Returns an object containing file metadata:{ size, isdirectory, isfile, createdat, modifiedat }.
- Strings & Text Processing:
len(val): Returns the length of an array or string.keys(obj): Returns an array of the keys (property names) of the given object/dictionary.strsplit(str, sep): Splits a string into an array of substrings using the specified separator (supports string or regex separators).match(str, regex): Matchesstragainst a regular expression. Returnstrueon success,falseon failure. If the regex contains capture groups (parentheses) and matches, it returns an array of the captured values.strtrim(str, side): Removes whitespace.sideis optional and can be"both"(default),"left", or"right".strsub(str, start, length): Extracts a substring starting at indexstartwith optionallength.strindexof(str, search): Returns the position of the first occurrence ofsearch, or-1if not found.strlastindexof(str, search): Returns the position of the last occurrence ofsearch, or-1if not found.strrepeat(str, n): Repeats the stringntimes.strreplace(str, search, replacement): Replaces occurrences ofsearch(string or regex) withreplacement. If a string is passed assearch, all occurrences are replaced.strupper(str): Converts the string to uppercase.strlower(str): Converts the string to lowercase.
- Arrays & Lists: Procedural array operations:
arraypush(arr, item): Appends an item to the end of the array.arrayunshift(arr, item): Prepends an item to the beginning of the array.arraypop(arr): Removes and returns the last item of the array.arrayshift(arr): Removes and returns the first item of the array.arraycontains(arr, item): Returnstrueif the item is present in the array,falseotherwise.arrayjoin(arr, sep): Joins array elements into a string separated bysep.arrayslice(arr, start, end): Returns a slice of the array fromstart(inclusive) toend(exclusive).arrayreverse(arr): Returns a new array with elements in reversed order.arraysort(arr, compareFn?): Returns a new array with elements sorted. If a customcompareFnis provided (using therefkeyword to pass it by reference, e.g.arraysort(arr, ref my_compare)), it will use it to sort the elements (the callback should return-1,0, or1).arraymap(arr, task): Maps elements using an async callback task.arrayfilter(arr, task): Filters elements using an async callback task.arrayfind(arr, task): Finds the first matching element using an async callback task.
- Path Utilities: Cross-platform path handling helpers:
pathjoin(...paths): Joins multiple path segments together, normalizing directory separators.pathjoin("src", "utils", "parser.of") # Returns "src/utils/parser.of"pathresolve(base, relative?): Resolves a relative path (or sequence of paths) into an absolute path. Ifrelativeis omitted, resolvesbaseagainst the current working directory.pathresolve("/home/user", "docs") # Returns "/home/user/docs" pathresolve("/home/user/docs", "../") # Returns "/home/user"pathdirname(filepath): Returns the directory portion of a file path.pathdirname("/src/utils/parser.of") # Returns "/src/utils"pathbasename(filepath): Returns the last segment of a path (usually the filename).pathbasename("/src/utils/parser.of") # Returns "parser.of"pathextension(filepath): Returns the file extension (including the dot).pathextension("/src/utils/parser.of") # Returns ".of"pathisabsolute(filepath): Returnstrueif the path is absolute, orfalseif it is relative.pathisabsolute("/src/main.of") # Returns true pathisabsolute("main.of") # Returns false
- Date & Time: Procedural time and date components:
time(): Returns the current Unix timestamp in seconds.microtime(getAsFloat?)(alsomicro_time): Returns the current Unix timestamp as a high-precision float in seconds (default) or a PHP-style string ifgetAsFloatisfalse. Useful for performance profiling.dateyear(ts): Returns the year of the given Unix timestampts(or the current year iftsis not provided).datemonth(ts): Returns the month (1-12) of the given Unix timestampts.dateday(ts): Returns the day of the month (1-31) of the given Unix timestampts.datehour(ts): Returns the hour (0-23) of the given Unix timestampts.dateminute(ts): Returns the minute (0-59) of the given Unix timestampts.datesecond(ts): Returns the second (0-59) of the given Unix timestampts.dateweekday(ts, format?): Returns the day of the week for the given Unix timestampts(or the current day iftsis not provided). Theformatparameter is optional and defaults to"number"(returning0-6where Sunday is0). Alternatively, passing"short"or"text"returns a 3-letter day abbreviation (e.g.,"Sun","Mon").
- Cryptography & Encryption: Secure hashing helpers:
sha256(text): Returns the SHA-256 hexadecimal hash string of the input text. Useful for secure password hashing.
- Web & HTTP Utilities: Native HTTP helpers:
getcookie(req, name): Extracts and returns the value of the cookienamefrom the incoming requestreq. Returnsnullif not found.setcookie(res, name, value, options?): Sets a cookie on the outgoing responsereswith the specifiednameandvalue. The optionaloptionsobject supports standard cookie attributes (such ashttpOnly,secure,maxAge,path, etc.). Note: Because cookies are sent in HTTP headers, this must be called before sending any response body (like HTML or JSON) to the client.
- JSON Utilities:
jsonparse(str)/jsondecode(str): Parses a JSON string and returns the resulting object or array. Returnsnullif the string is not valid JSON. (jsondecodeis an alias โ choose whichever reads more naturally alongsidejsonencode.)var data = jsondecode(fileread("settings.json")) print(data.name)jsonencode(val, pretty?): Serializes an object or array into a JSON string. The optionalprettyparameter (defaultfalse) formats the output with indentation when set totrue.filewrite("settings.json", jsonencode(data, true))
- Template Engine: HTML template rendering and layout generation:
(For the dedicated, complete guide with function calls, syntax warnings, and
of-targetSPA interceptors, see TemplateEngine.md)template(source, context): Parses, compiles, and renders an HTML template. Automatically detects ifsourceis a file path (loading it from disk) or a raw HTML string. Supports:- Dynamic Expressions:
{{ variable }}or{{ user.name }} - Control Flow Directives:
@if (cond) { ... },@else if (cond2) { ... },@else { ... },@for (item of list) { ... }, and@} - Static Inclusions:
@include("templates/header.html") - SPA Interceptors (
of-target): Automatically injects a lightweight client-side script before</body>to intercept links and forms withof-target="selector", enabling flicker-free SPA updates and server-driven script execution.
- Dynamic Expressions:
[!WARNING] Template Control Flow Syntax Rules: In OmniFlux templates,
@elseand@else ifdirectives automatically emit the closing brace}for the preceding@ifblock. DO NOT place@}before@elseor@else if(e.g. writing@} else {or@} @else {is invalid and will cause duplicate closing brace syntax errors}} else {, resulting in a<!-- Template Error -->blank screen).Correct Control Flow Structure:
@if (isLoggedIn) { <p>Welcome {{ name }}</p> @else if (isGuest) { <p>Welcome Guest</p> @else { <p>Please log in</p> @}
Complete Real-World HTML Template Example (views/index.of.html)
<!DOCTYPE html>
<html lang="he" dir="rtl">
<head>
<meta charset="UTF-8">
<title>{{ title }}</title>
<link rel="stylesheet" href="/style.css">
</head>
<body>
<!-- 1. Include header partial -->
@include("views/partials/header.html")
<main class="container">
<h1>{{ title }}</h1>
<!-- 2. Conditional rendering with @if / @else if / @else -->
@if (user.role == "admin") {
<div class="badge badge-admin">ืื ืื ืืขืจืืช</div>
<p>ืฉืืื {{ user.name }}, ืืฉ ืื ืืจืฉืืืช ื ืืืื ืืืืืช.</p>
@else if (user.role == "editor") {
<div class="badge badge-editor">ืขืืจื ืชืืื</div>
<p>ืฉืืื {{ user.name }}, ืืืคืฉืจืืชื ืืขืจืื ืืืืขืืืช ืชืื ืื.</p>
@else {
<div class="badge badge-user">ืืฉืชืืฉ ืจืืื</div>
<p>ืฉืืื {{ user.name }}, ืืจืื ืืื ืืืขืจืืช.</p>
@}
<!-- 3. SPA Form Submission using of-target attribute -->
<section class="card">
<h2>ืืืคืืฉ ืืืฆืจืื (ืกืจืืงื ืืกืื ืืจืื ืืช ืืื ืจืขื ืื ืืฃ)</h2>
<form action="/api/search" method="POST" of-target="#resultsContainer">
<div class="form-group">
<label for="query">ืืืืช ืืืคืืฉ:</label>
<input type="text" id="query" name="query" placeholder="ืืื ืืืืช ืืืคืืฉ...">
</div>
<button type="submit" class="btn">ืืคืฉ ืืืฆืจืื</button>
</form>
</section>
<!-- 4. Dynamic List Iteration with @for -->
<section class="card" id="resultsContainer">
<h2>ืชืืฆืืืช ืืืคืืฉ</h2>
@if (hasProducts) {
<ul class="products-list">
@for (prod of products) {
<li>
<strong>{{ prod.name }}</strong> - {{ prod.price }} โช
<!-- SPA Link using of-target attribute -->
<a href="/product/{{ prod.id }}" of-target="#productDetail" class="btn-sm">ืคืจืืื</a>
</li>
@}
</ul>
@else {
<p class="muted">ืืจื ื ืืฆืื ืืืฆืจืื ืืชืฆืืื</p>
@}
</section>
<div id="productDetail"></div>
</main>
</body>
</html>
SPA Interceptors & Partial Updates (of-target) โก
OmniFlux provides built-in Single Page Application (SPA) functionality without requiring client-side frameworks like React or Angular.
When template() renders an HTML template containing a </body> tag, OmniFlux automatically injects a lightweight client-side script that intercepts HTML <form> submissions and <a> link clicks containing the of-target attribute.
How of-target Works:
Form Interceptor (
<form action="..." method="POST" of-target="#targetSelector">):- Intercepts the standard browser form
submitevent. - Prevents full page reload (
e.preventDefault()). - Sends an asynchronous HTTP request (
fetch) with the form'sFormData. - Replaces the inner HTML of the target element (
document.querySelector(targetSelector).innerHTML = htmlResult). - Automatically executes any inline
<script>tags inside the returned HTML content.
- Intercepts the standard browser form
Link Interceptor (
<a href="..." of-target="#targetSelector">):- Intercepts the browser
clickevent on<a>tags containingof-target. - Prevents full page navigation.
- Fetches the target URL asynchronously.
- Injects the server response directly into the specified target selector.
- Intercepts the browser
Example Usage:
<!-- Form submission that updates only #invoicesContainer -->
<form action="/api/scan" method="POST" of-target="#invoicesContainer">
<input type="date" name="startDate">
<button type="submit">ืืฆืข ืกืจืืงื</button>
</form>
<!-- Container element updated asynchronously by the form submission -->
<div id="invoicesContainer">
<!-- Server-rendered partial HTML will be injected here -->
</div>
- Error & Diagnostic Utilities:
error_info(err)(aliaserrorinfo): Returns an object containing original OmniFlux file and line details for a given error object:{ file, line, message }.
4.1 Local JSON Database ๐๏ธ
OmniFlux includes a built-in, zero-setup database that stores your data in a local file (db.json). It runs entirely in memory for lightning-fast reads, making it perfect for blogs, catalogs, and basic websites.
Database Location & Production Environment Config (DB_FILE)
By default, the database is stored in a file named db.json in the current working directory (CWD) from which the process was started.
[!WARNING] Security Best Practice: Never store the database file (
db.json) inside a public directory served by web servers like Apache or Nginx (e.g.public/,www/, orpublic_html/). Doing so allows anyone to download your entire database directly via a browser. Always configureDB_FILEto point to a secure, non-public directory (like/var/lib/omniflux/db.jsonor a folder outside of your web root).
If your application is deployed to a production environment where the code directory is write-protected, you can easily configure the database file location by setting the DB_FILE environment variable:
# Run the server with the database file saved in a secure, writable directory
DB_FILE=/var/lib/omniflux/db.json ./omniflux server/proxy.of
Programmatic Database Path (dbsetfile / db_set_file)
You can also change the database file path directly within your code using the built-in function dbsetfile(path) (alias: db_set_file(path)). This is useful if you want to determine the path dynamically or read it from a custom config file:
# Set a custom database location programmatically
dbsetfile("/var/lib/omniflux/db.json")
# Any subsequent database calls will read/write to this file
dbinsert("logs", { event: "startup", time: time() })
Core Concepts for Beginners
- Collection: Think of this as a category or a folder of records. For example,
"users"or"posts". Each collection contains a list of individual items. - Document: A single record in a collection, represented as an object with key-value pairs (like
{ "name": "Alice", "role": "admin" }). - Filter: A simple object used to search for matching records. For example, passing
{ "role": "admin" }will find only those records where the role is"admin". Passing an empty filter{}ornullwill retrieve everything.
1. Inserting Data (dbinsert)
Adds a new item to a collection. It automatically generates a unique id for the record if you don't provide one.
# Save a new user to the "users" collection
var new_user = dbinsert("users", { name: "Alice", email: "alice@example.com", age: 30 })
# The returned object contains the auto-generated unique ID
print("New user created with ID: %s", new_user.id)
2. Querying & Finding Data (dbselect)
Retrieves records matching a filter. It always returns an array (a list) of items.
# Find all users who are admins (using a filter)
var admins = dbselect("users", { role: "admin" })
# Loop through the list to print names
for (var admin of admins) {
print("Admin: %s", admin.name)
}
# Find a single user by ID
var results = dbselect("users", { id: "mqrlgor5eywc" })
if len(results) > 0 {
var user = results[0]
print("Found user: %s", user.name)
}
# Retrieve everything in the collection (no filter)
var all_users = dbselect("users")
3. Updating Data (dbupdate)
Modifies existing records in a collection matching a filter. Returns the number of updated items.
# Update age for the user with a specific ID
var updated_count = dbupdate("users", { id: "mqrlgor5eywc" }, { age: 31 })
print("Updated %d users.", updated_count)
4. Deleting Data (dbdelete)
Removes matching records from a collection. Returns the number of deleted items.
# Delete all users who are under 18
var deleted_count = dbdelete("users", { age: 17 })
print("Deleted %d users.", deleted_count)
5. Compiler CLI Options ๐ ๏ธ
The omniflux command line tool provides options to control how your code is compiled and executed:
omniflux <filename>: Compiles and runs the specified file.--compile-only(or--no-run): Compiles the code to JavaScript without running the output file.--strict(or--no-llm): Disables the AI self-healing fallback. If the local compiler encounters syntax it doesn't recognize or if there is a syntax error, the compilation fails immediately and displays the errors. This is ideal for offline development and CI/CD pipelines.--verbose(or-v): Prints detailed usage statistics when communicating with the AI backend, such as the exact model used, request duration, input tokens, output tokens, and reasoning tokens.--watch(or-w): Watches for file changes in the input file or any of its dependencies and automatically recompiles and restarts.--force(or-f): Forces compilation and rebuild of the target and its dependencies even if they are already up-to-date.
6. Direct Node.js / JavaScript Integration (@{ ... @}) โก
OmniFlux is designed to keep development simple and clean. However, when you need direct access to the Node.js ecosystem, npm modules, or raw JavaScript APIs, you can write JavaScript code directly inside an escape block using the @{ and @} markers.
How it works
- Everything written between
@{and@}is copied verbatim (exactly as written) to the output JavaScript file. - The OmniFlux compiler does not parse or validate the contents of the block, meaning you can write complex JavaScript syntax (loops, objects, async code) without triggering compiler warnings.
- You can access and return variables defined in the surrounding OmniFlux code.
1. Reading a file using Node's standard fs library
define task read_config_file {
# Escape to Node.js to read a file using the native fs module
@{
const fs = require('fs');
const data = fs.readFileSync('config.json', 'utf8');
return JSON.parse(data);
@}
}
2. Performing native JavaScript calculations or operations
define task get_js_time {
@{
return new Date().toISOString();
@}
}
3. Error Handling and Line Mapping
If an error occurs inside your @{ ... @} block at runtime, the OmniFlux runtime automatically catches the error and maps the line number back to the exact line in your .of source file, making debugging extremely easy!
7. Standard Libraries & Inclusions (include) ๐ฆ
OmniFlux allows modularizing your code using the include directive. The standard library (stdlib/) contains pre-built tasks for common activities.
The include Directive
To import another file's variables and tasks into your script, use include followed by the relative path of the file:
include "stdlib/datetime.of"
include "stdlib/network.of"
include "stdlib/system.of"
7.1 Date & Time Library (stdlib/datetime.of)
Provides simplified tasks for reading and formatting dates:
datetime_now(): Returns the current Unix timestamp.datetime_format(timestamp, format_string): Formats a Unix timestamp. Supported tokens areYYYY(year),MM(month),DD(day),HH(hour),mm(minute), andss(seconds).datetimeparse(date_string)/datetime_parse(date_string): Parses a date string (e.g."YYYY-MM-DD","YYYY-MM-DD HH:mm:ss", or any other standard format) and returns its Unix timestamp in seconds. Returns0if the string is empty or invalid.
include "stdlib/datetime.of"
on start {
var now = datetime_now()
var pretty_date = datetime_format(now, "YYYY-MM-DD HH:mm:ss")
print("Current time: %s", pretty_date)
var ts = datetimeparse("2026-07-07 12:00:00")
print("Parsed timestamp: %d", ts)
}
7.2 Network Library (stdlib/network.of)
Provides tasks for sending HTTP requests and talking to public APIs:
networkget(url): Performs an HTTP GET request to the specified URL. Automatically parses and returns JSON if the response is JSON, otherwise returns plain text.networkpost(url, data): Performs an HTTP POST request to the specified URL, sending the data payload (either an object or a raw string).uploadfile(req, dest_dir): Parses a multipart/form-data request, saving uploaded files todest_dirwith unique filenames, and populatesreq.files(metadata array),req.file(shortcut to first file), andreq.body(text fields).
include "stdlib/network.of"
POST "/upload" (req, res) {
var ok = uploadfile(req, scriptdir() + "/uploads")
if ok {
respond json { "success": true, "files": req.files }
} else {
respond status 500 and json { "success": false }
}
}
7.3 System Commands Library (stdlib/system.of)
Provides tasks for executing and managing processes in the host OS shell:
system(command, args?): Runs a command in the shell. Ifargs(an array of strings) is specified, it runs the command with those arguments for command-injection safety. Inherits stdin, and returns its full captured output (stdout and stderr merged) as a string.exec(command, args?): Runs a command in the shell. Ifargs(an array of strings) is specified, it runs the command with those arguments for command-injection safety. Inherits stdin/stdout/stderr for full interactivity, and returns its exit status code (0 for success, non-zero for failure).spawn(command, args): Spawns an asynchronous child process with the given arguments array, registering it in the internal process registry, and returning its process ID (PID).pterminate(pid, signal): Sends a termination signal to the specified PID. Returnstrueon success,falseon failure. Common signals include:"SIGTERM"(Default): Request graceful termination. The program is asked to stop and has a chance to clean up."SIGKILL": Force immediate shutdown. The program is killed instantly by the operating system (cannot be blocked or clean up)."SIGINT": Interrupt from keyboard (equivalent to pressingCtrl+C).
pwait(pid): Waits for the process with the given PID to finish and returns its exit code (returns null if external process).pstatus(pid): Returns1if the process with the given PID is running, and0if finished or non-existent.
include "stdlib/system.of"
on start {
# 1. Run a command and capture output
var folder_contents = system("ls -la")
print("Files:\n%s", folder_contents)
# 2. Run a command and check success status
var status = exec("git status")
if status == 0 {
print("Git command completed successfully!")
} else {
print("Git command failed with status code: %d", status)
}
# 3. Spawn a background process, check status, wait, and terminate it
var pid = spawn("node", ["server.js"])
print("Spawned process with PID: %d", pid)
var is_running = pstatus(pid)
print("Is running: %d", is_running)
wait 2000
var success = pterminate(pid, "SIGTERM")
print("Process termination result: %s", success)
var exit_code = pwait(pid)
print("Process exited with code: %s", exit_code)
}
7.4 Cryptography & Encoding Library (stdlib/encrypt.of)
Provides tasks for secure hashing, symmetric encryption, and Base64 conversion:
encrypt(text, key): Encryptstextusing thekeyvia the secure AES-256-CBC algorithm. Generates a unique, random initialization vector (IV) for each call to ensure identical inputs result in different ciphertexts, and returns the result packed asiv:ciphertext.decrypt(encryptedText, key): DecryptsencryptedText(in theiv:ciphertextformat) using the providedkey. Returns the original decrypted string, ornullif decryption fails (e.g., due to an incorrect key or corrupted input).base64_encode(text)(aliasesbase64encode,encodebase64): Takes a string and returns its Base64 encoded representation (UTF-8 safe).base64_decode(text)(aliasesbase64decode,decodebase64): Takes a Base64 string and decodes it back to its original UTF-8 string format.
[!TIP] Interoperability with Browser JavaScript: Because OmniFlux uses standard UTF-8 bytes for Base64 encoding/decoding, you can easily decode and encode these values in your client-side JavaScript (browser-side) in a single line using the built-in browser functions
escape/unescape:// Decode Base64 string (including Hebrew/UTF-8) in browser JS: const decoded = decodeURIComponent(escape(atob(base64Str))); // Encode string to Base64 (including Hebrew/UTF-8) in browser JS: const encoded = btoa(unescape(encodeURIComponent(str)));
include "stdlib/encrypt.of"
on start {
# 1. Base64 encoding and decoding
var original = "Hello World!"
var encoded = base64_encode(original)
print("Encoded: %s (expected: SGVsbG8gV29ybGQh)", encoded)
var decoded = base64_decode(encoded)
print("Decoded: %s (expected: Hello World!)", decoded)
# 2. Symmetric AES-256-CBC encryption
var key = "secret_passphrase"
var encrypted = encrypt(original, key)
print("Encrypted payload: %s", encrypted)
var decrypted = decrypt(encrypted, key)
print("Decrypted payload: %s", decrypted)
}
7.5 MySQL Database Library (stdlib/mysql.of)
Provides tasks for connecting to and interacting with MySQL databases:
mysqlconnect(config)(aliasmysql_connect): Initializes a MySQL connection pool using the provided configuration object or connection string.mysqlquery(query, params?)(aliasmysql_query): Executes a parameterized SQL query on the database using prepared statements and returns the results.mysqlclose()(aliasmysql_close): Closes the MySQL connection pool.
[!IMPORTANT] Dependency Requirement: Under the hood, this library uses the
mysql2package. To ensure a zero-setup experience, the library will automatically detect ifmysql2is missing and install it vianpmon the first run.If you prefer to install it manually in your project directory beforehand, you can run:
npm install mysql2
include "stdlib/mysql.of"
define task run_db_query() {
var db_config = {
host: "127.0.0.1",
user: "root",
password: "secret_password",
database: "production_db"
}
print("Connecting to MySQL...")
mysqlconnect(db_config)
print("Fetching active users...")
var users = mysqlquery("SELECT id, username FROM users WHERE status = ?", ["active"])
for user of users {
print("- User: %s (ID: %s)", user.username, user.id)
}
mysqlclose()
} on error (err) {
print("Database error: %s", err.message)
}
on start {
run_db_query()
}
7.6 Internationalization Library (stdlib/i18n.of)
Provides tasks for dynamic internationalization (i18n) and translation management using the native built-in database:
i18n_init(primary_lang): Initializes the translation system with the specified primary language (e.g.,"he"). Loads all existing translations from the built-in database (omniflux_translationscollection) into the in-memory cache.i18n_set_lang(lang): Sets the active language for the current context (e.g.,"en").i18n_update(key, translation): Dynamically adds or updates a translation for the given key in the built-in database and runtime cache.i18n_delete(key): Deletes the translation key and its values from the built-in database and runtime cache.i18n_scan(source_or_file, mode): Scans the provided OmniFlux code string or file path for_("...")calls. Returns an array of objects{ key, translation }based on the filter mode ("all","missing", or"translated").i18n_load(filename): Loads a simple pipe-separated (|) translation text file, callingi18n_updateori18n_deletein the built-in database based on the file content._(key, ...params): Translates the given key based on the active language. Supports%sand%dformat placeholder replacements. Automatically performs background auto-discovery/insertion of new translation keys into the database.
include "stdlib/i18n.of"
define task run_i18n_demo() {
# 1. Initialize i18n (Primary Language: "he")
i18n_init("he")
# 2. Load translations from a text file (using simple " | " format)
# The file "translations.txt" has lines like:
# ืฉืืื %s | Hello %s
# ืฉืืืจื | Save
i18n_load("translations.txt")
# 3. Use the translation helper task
print(_("ืฉืืืจื")) # Prints "ืฉืืืจื" (since language is primary "he")
# Change language to secondary "en"
i18n_set_lang("en")
print(_("ืฉืืืจื")) # Prints "Save"
print(_("ืฉืืื %s", "ืืืจื")) # Prints "Hello ืืืจื"
}
on start {
run_i18n_demo()
}
8. Using NPM Packages ๐ฆ
OmniFlux runs on top of the Node.js runtime and utilizes esbuild for its compilation and bundling steps. This makes it incredibly easy to use any package from the npm registry directly in your OmniFlux code!
How to Install and Require Packages
- Initialize a Node.js project if your directory does not have a
package.jsonfile yet. This ensures npm packages are installed locally in your project folder (undernode_modules/) rather than inherited from a parent directory:npm init -y - Install the package in your project directory:
npm install package-name - Require the package in your OmniFlux code using the built-in
require()function:var pkg = require("package-name") - Compilation & Bundling: When you compile your application, the compiler automatically bundles the required npm package code into your final standalone binary. You do not need
node_modulesat runtime!
Example 1: Rendering Markdown with marked
This example shows how to install and use the marked library to parse Markdown text into HTML.
Installation:
npm install marked
Code (render_md.of):
on start {
# Import the marked library
var marked = require("marked")
var markdown = "# OmniFlux Guide\n\nOmniFlux is a *minimalist* language."
# Parse Markdown text to HTML
var html = marked.parse(markdown)
print("Parsed HTML output:\n%s", html)
}
Example 2: Generating Unique IDs with uuid
This example shows how to install and use the uuid library to generate cryptographically strong unique identifiers.
Installation:
npm install uuid
Code (generate_id.of):
on start {
# Import the uuid library
var uuid = require("uuid")
# Generate a random UUID
var new_id = uuid.v4()
print("Generated Unique ID: %s", new_id)
}
OmniFlux