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:

1.2 Variables

$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:

1.4 Printing to the Screen ๐Ÿ“บ

OmniFlux provides built-in options for outputting text to the screen:

Supported format specifiers include:

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.

Configuration & Behavior

The logging system reads the following environment variables (which can be configured externally or dynamically using setenv):

# 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:

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:


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 on block) executes immediately when the file is loaded. However, if root-level code contains asynchronous operations (like wait), 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 inside on start or functions to ensure predictable, sequential execution.

OmniFlux provides several lifecycle hooks to manage application state and events cleanly:

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:

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-wide on error lifecycle hooks.

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):

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:

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 in public/ (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.html Precedence & Routing: Web servers (Apache/Nginx/Passenger) automatically check for public/index.html first when handling root requests (GET "/").

  • For Dynamic OmniFlux Applications (using GET "/" in main.of): If a static index.html exists in public/, web servers will serve it directly, bypassing OmniFlux dynamic template rendering (main.of). For dynamic applications, store template files in views/ (e.g. views/index.of.html) rather than public/index.html.
  • For Pure Static Sites / Front-End SPAs: Placing index.html inside public/ 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 serve directive:

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:

[!WARNING] Template Control Flow Syntax Rules: In OmniFlux templates, @else and @else if directives automatically emit the closing brace } for the preceding @if block. DO NOT place @} before @else or @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:
  1. Form Interceptor (<form action="..." method="POST" of-target="#targetSelector">):

    • Intercepts the standard browser form submit event.
    • Prevents full page reload (e.preventDefault()).
    • Sends an asynchronous HTTP request (fetch) with the form's FormData.
    • Replaces the inner HTML of the target element (document.querySelector(targetSelector).innerHTML = htmlResult).
    • Automatically executes any inline <script> tags inside the returned HTML content.
  2. Link Interceptor (<a href="..." of-target="#targetSelector">):

    • Intercepts the browser click event on <a> tags containing of-target.
    • Prevents full page navigation.
    • Fetches the target URL asynchronously.
    • Injects the server response directly into the specified target selector.
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>

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/, or public_html/). Doing so allows anyone to download your entire database directly via a browser. Always configure DB_FILE to point to a secure, non-public directory (like /var/lib/omniflux/db.json or 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

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:


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

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:

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:

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:

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:

[!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:

[!IMPORTANT] Dependency Requirement: Under the hood, this library uses the mysql2 package. To ensure a zero-setup experience, the library will automatically detect if mysql2 is missing and install it via npm on 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:

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

  1. Initialize a Node.js project if your directory does not have a package.json file yet. This ensures npm packages are installed locally in your project folder (under node_modules/) rather than inherited from a parent directory:
    npm init -y
    
  2. Install the package in your project directory:
    npm install package-name
    
  3. Require the package in your OmniFlux code using the built-in require() function:
    var pkg = require("package-name")
    
  4. 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_modules at 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)
}