p.enthalabs

GitHub - angeldevmobile/Orion: A backend and automation language compiled to bytecode in Rust. One binary, 58 built-in modules, no runtime to install.

Orion is a programming language for backend work and automation. Clean syntax, optional typing, native OOP, 58 built-in modules and a full pipeline written in Rust.

> Built by **Angel Zapata** · 2025-2026

> **Note on naming.** Orion is written in English: keywords (`fn`, `return`, `if`, `while`, `shape`, `serve`) and the standard library alike, so `db.insert`, `cache.set` and `validate.required` are the canonical names. Orion was designed by a Spanish-speaking developer, and the Spanish names that came first still work as **deprecated aliases**: `db.insertar` runs today and will keep running for the rest of 0.1.x, but it is scheduled for removal. Write `db.insert` in new code. See `SPEC.md` section 11.

- * *

Demo

[](https://github.com/angeldevmobile/Orion#demo) ![Image 1: Demo - Terminal](https://github.com/angeldevmobile/Orion/blob/master/assets/demo_terminal.jpeg)

``` -- demo/demo_ventas_q1.orx - 70 lines · 16 ms use "excel" as excel

full_data = excel.join(sellers, budgets, "region", "left") pivot = excel.pivot(full_data, "region", "producto", "venta")

excel.write_multi("sales_report.xlsx", { "Summary": summary, "By Region": by_region, "Top 10": top_10, "Pivot": pivot }) ```

``` ╔══════════════════════════════════════════════╗ ║ Q1 2026 Results ║ ╠══════════════════════════════════════════════╣ ║ Total sellers : 20 ║ ║ Total sales : USD 1487000 ║ ║ Overall attainment : 100.2% ║ ║ Largest sale : USD 110000 ║ ╠══════════════════════════════════════════════╣ ║ → demo/reporte_analisis.xlsx (5 sheets) ║ ║ → demo/reporte_detalle.xlsx (styled) ║ ╚══════════════════════════════════════════════╝ [Orion] 15.978 ms ```

![Image 2: Demo - Excel Output](https://github.com/angeldevmobile/Orion/blob/master/assets/demo_excel.jpeg)

- * *

Philosophy

[](https://github.com/angeldevmobile/Orion#philosophy)

- **No boilerplate** - code reads like pseudocode. One task, five lines at most.

- **Built for real work** - APIs, automation, data pipelines.

- **Modern** - OOP, type hints, string interpolation, async/await, regex, and AI as a language keyword.

- **Fast** - the whole pipeline is Rust: lexer → parser → type checker → codegen → VM. Loading and aggregating 500k CSV rows is **2× faster than Python at the same memory** (reproducible benchmark).

- **Safe** - parameterized queries, validation at the boundary, native crypto.

- * *

Installation

[](https://github.com/angeldevmobile/Orion#installation)

Prebuilt binary (recommended)

[](https://github.com/angeldevmobile/Orion#prebuilt-binary-recommended) Download the executable for your platform from the latest release. It is a single file, with no runtime and no dependencies.

| Platform | File | | --- | --- | | Windows x64 | `orion-win32-x64.exe` | | Linux x64 | `orion-linux-x64` | | macOS Apple Silicon | `orion-darwin-arm64` |

Linux / macOS - rename, make executable, put it on the PATH

chmod +x orion-linux-x64 sudo mv orion-linux-x64 /usr/local/bin/orion

orion file.orx

On Windows, rename the `.exe` to `orion.exe` and add it to your `PATH`.

VS Code extension

[](https://github.com/angeldevmobile/Orion#vs-code-extension) Install it from the Marketplace: **Orion Language**.

The extension downloads the compiler the first time you open a `.orx` file, taking it from the latest release and storing it in VS Code's global storage. If `orion` is already on your `PATH`, it uses that one instead.

Build from source

[](https://github.com/angeldevmobile/Orion#build-from-source)

cargo build --release --manifest-path orion-vm/Cargo.toml ./orion-vm/target/release/orion file.orx

- * *

Quick start

[](https://github.com/angeldevmobile/Orion#quick-start) Create a file called `hello.orx` and run it:

``` name = "Orion" version = 1

show "Hello from ${name} v${version}"

-- Ranges are half-open: 1..5 covers 1, 2, 3 and 4. for i in 1..5 { show " line ${i}" } ```

orion hello.orx

``` Hello from Orion v1 line 1 line 2 line 3 line 4 [Orion] 1.346 ms ```

Or run the full demo:

orion demo/demo_ventas_q1.orx

- * *

Syntax

[](https://github.com/angeldevmobile/Orion#syntax)

Variables and types

[](https://github.com/angeldevmobile/Orion#variables-and-types)

``` -- Variables name = "Orion" age = 25 active = yes

-- Constants const PI = 3.14159

-- Optional type hints city: string = "Monterrey" version: int = 1

-- Printing values show name show "Hello " + name show "Version ${version} of ${name}" -- interpolation

-- Escape sequences path = "C:\\users\\documents" line = "name\tsurname\nage" pattern = "\\d{4}-\\d{2}-\\d{2}" -- regex: \d{4}-\d{2}-\d{2} ```

Data types

[](https://github.com/angeldevmobile/Orion#data-types) | Type | Example | Description | | --- | --- | --- | | `int` | `42`, `0xFF`, `0b1010` | 64-bit integer, hex and binary literals | | `float` | `3.14`, `1.5e-3` | Decimal, scientific notation | | `string` | `"hi"`, `r"raw"`, `"""multi"""` | Text with `${var}` interpolation | | `bool` | `yes` / `no` | Boolean | | `list` | `[1, 2, 3]` | Dynamic array | | `dict` | `{"k": "v"}` | Hash map | | `null` | `null` | Explicit null | | shape | `Person("Ana", 30)` | Shape instance (object) |

Control flow

[](https://github.com/angeldevmobile/Orion#control-flow)

``` -- if / else if / else — the middle branch is two tokens, `else if`. -- There is no `elsif` keyword. if age >= 18 { show "Adult" } else if age >= 13 { show "Teenager" } else { show "Child" }

-- while i = 0 while i < 5 { show i i += 1 }

-- for over a range — half-open: 1..10 covers 1 through 9 for x in 1..10 { show x }

-- for over a collection for n in ["Ana", "Luis", "Eva"] { show n }

-- match is a statement, not an expression: each arm is `pattern { block }`, -- with no `=>` arrow, and the whole thing cannot be assigned to a variable. match value { 1 { show "one" } 2 { show "two" } _ { show "other" } }

-- break / continue for i in 1..100 { if i == 10 { break } if i % 2 == 0 { continue } show i } ```

Functions

[](https://github.com/angeldevmobile/Orion#functions)

``` -- Plain function fn greet(name) { return "Hello " + name }

-- With type hints fn add(a: int, b: int) -> int { return a + b }

-- Lambda double = fn(x) { x * 2 } show double(21) -- 42

-- Async async fn fetch(url) { resp = net.get(url) return resp.body } data = await fetch("https://api.example.com") ```

OOP - shapes

[](https://github.com/angeldevmobile/Orion#oop---shapes)

``` shape Person { name: string = "" age: int = 0

on_create(n: string, a: int) { name = n age = a }

act greet() { show "Hi, I'm " + name }

act birthday() { age += 1 } }

p = Person("Gabriel", 25) p.greet() p.birthday() show p.age -- 26

if p is Person { show "It is a Person" }

-- Composition with `using` shape Animal { name: string = "" act speak() { show name + " speaks" } }

shape Dog { using Animal breed: string = "" on_create(n, b) { name = n breed = b } act fetch_ball() { show name + " fetches the ball!" } }

d = Dog("Rex", "Labrador") d.speak() d.fetch_ball() ```

Error handling

[](https://github.com/angeldevmobile/Orion#error-handling)

``` attempt { result = divide(10, 0) show result } handle err { show "Error: " + err } ```

Native HTTP server

[](https://github.com/angeldevmobile/Orion#native-http-server) `serve` is a language statement: it takes a port and a handler function. The handler receives the request and returns a dict with `status` and `body`.

``` use "db"

db.exec("app.db", "CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT)")

fn router(req) { if req["path"] == "/ping" { return { "status": 200, "body": "pong" } }

if req["path"] == "/users" { if req["method"] == "GET" { return { "status": 200, "body": db.query("app.db", "SELECT * FROM users") } } if req["method"] == "POST" { db.insert("app.db", "INSERT INTO users (name) VALUES (?)", [req["body"]]) return { "status": 201, "body": { "ok": yes, "message": "Created" } } } }

return { "status": 404, "body": "not found" } }

serve 8080 router ```

**Automatic JSON.** When `body` is a dict or a list, Orion serializes it and responds with `application/json`. A string body goes out as `text/plain`. An explicit `content_type` always wins.

``` return { "status": 200, "body": {"ok": yes, "total": 3} } -- → application/json · {"ok":true,"total":3}

return { "status": 200, "body": "pong" } -- → text/plain · pong ```

For declarative routing with `:id` parameters and wildcards, use the `router` module and pass its dispatcher to `serve`.

Native AI - `think`, `learn`, `sense`

[](https://github.com/angeldevmobile/Orion#native-ai---think-learn-sense) These call an external provider and need an API key. See the `llm` module for explicit provider and model selection.

``` -- No module, no import: AI as a native statement think "Summarize this text in 3 bullet points: " + content

-- The ai module for higher-level operations use "ai" as ai

category = ai.classify(email.text, ["spam", "work", "personal"]) -- Module functions take positional arguments only. Named arguments (`x = 1`) -- work on functions you define, not on module methods. summary = ai.summarize(document) translated = ai.translate(text, "english") sentiment = ai.sentiment(review) -- "positivo" / "negativo" / "neutro" ```

Pipe operator

[](https://github.com/angeldevmobile/Orion#pipe-operator) `|>` feeds the value on its left in as the **first** argument of the call on its right. It is parser sugar: the result is the same `Call` you would have written by hand, so the VM, the JIT and the type checker see nothing new.

``` result = data |> filter_by("active", yes) |> sort_by("date", "desc") |> top(10)

-- Equivalent to: result = top(sort_by(filter_by(data, "active", yes), "date", "desc"), 10) ```

The right side can be a function name, a call, a method, or a lambda:

``` [1, 2, 3] |> len -- 3 5 |> double -- calls double(5) 5 |> add(10) -- calls add(5, 10) " hi " |> trim |> upper -- "HI" 3 |> (n) => n + 100 -- 103 ```

Precedence sits between comparison and arithmetic, so both of these read the way they look, without parentheses:

``` a + b |> f -- f(a + b) x |> len > 3 -- (x |> len) > 3 ```

Concurrency

[](https://github.com/angeldevmobile/Orion#concurrency)

``` -- Spawn (fire and forget) spawn long_running_job()

-- Async/await async fn process(item) { return item * 2 } result = await process(21) ```

- * *

Standard library - a tour with examples

[](https://github.com/angeldevmobile/Orion#standard-library---a-tour-with-examples)

Data and files

[](https://github.com/angeldevmobile/Orion#data-and-files)

``` use "fs" use "csv" use "json" use "excel" use "table" use "regex" as re ```

#### `fs` - file system

[](https://github.com/angeldevmobile/Orion#fs---file-system)

``` content = fs.read("config.toml") fs.write("output.json", data) files = fs.ls("data/") fs.copy("a.txt", "backup/a.txt") fs.mkdir("reports/2026") info = fs.info("file.txt") -- {size, modified, is_file} ```

#### `csv` - tabular data

[](https://github.com/angeldevmobile/Orion#csv---tabular-data)

``` data = csv.read("sales.csv") north = csv.filter(data, "region", "North") stats = csv.stats(data, "sale") -- {sum, avg, min, max} sorted = csv.sort(data, "sale", "desc") csv.write("report.csv", data) ```

#### `json` - JSON serialization

[](https://github.com/angeldevmobile/Orion#json---json-serialization)

``` obj = json.parse(text) txt = json.forge_pretty(obj) data = json.absorb("config.json") json.emit("output.json", data) val = json.trace(obj, "user.profile.name") ```

#### `excel` - spreadsheets

[](https://github.com/angeldevmobile/Orion#excel---spreadsheets)

``` sheets = excel.sheets("report.xlsx") data = excel.read("data.xlsx", "Sales") excel.write("output.xlsx", data, "Report 2026") ```

#### `table` - data analysis

[](https://github.com/angeldevmobile/Orion#table---data-analysis)

``` t = table.load("data.csv") -- auto-detects CSV / Excel / JSON table.peek(t, 5) -- pretty-prints the first 5 rows table.schema(t) -- column types table.profile(t) -- full statistics

t2 = table.filter(t, "active", yes) t3 = table.keep(t, ["name", "sale", "region"]) t4 = table.sort(t, "sale") t5 = table.join(t, t2, "id") ```

#### `regex` - regular expressions

[](https://github.com/angeldevmobile/Orion#regex---regular-expressions)

``` use "regex" as re

valid = re.is_match("user@example.com", "^[\\w.]+@[\\w]+\\.[\\w]+$") nums = re.find_all(text, "\\d+") clean = re.replace(dirty, "\\s+", " ") parts = re.groups("2026-05-08", "(\\d{4})-(\\d{2})-(\\d{2})") words = re.split(line, "[,;]+") ```

Network and server

[](https://github.com/angeldevmobile/Orion#network-and-server)

``` use "net" use "env" ```

#### `net` - HTTP client

[](https://github.com/angeldevmobile/Orion#net---http-client)

``` resp = net.get("https://api.github.com/users/octocat") data = net.post("https://api.com/data", {token: key, id: 1}) net.download("https://example.com/file.zip", "local/file.zip") ip = net.resolve("example.com") ping = net.pulse("example.com", 443) -- {alive, latency_ms} ```

#### `env` - configuration

[](https://github.com/angeldevmobile/Orion#env---configuration)

``` port = env.pull("PORT", 8080) mode = env.pull("MODE", "production") config = env.load(".env") ```

Utilities

[](https://github.com/angeldevmobile/Orion#utilities)

``` use "strings" use "datetime" use "random" use "process" use "log" ```

#### `strings`

[](https://github.com/angeldevmobile/Orion#strings)

``` upper = strings.upper("hi") parts = strings.split("a,b,c", ",") joined = strings.join(list, " - ") ok = strings.contains(text, "orion") b64 = strings.encode_base64(data) ```

#### `datetime`

[](https://github.com/angeldevmobile/Orion#datetime)

``` now = datetime.now() today = datetime.today() ts = datetime.timestamp() parts = datetime.parts(now) -- {year, month, day, hour, ...} tomorrow = datetime.add_days(today, 1) diff = datetime.diff_days("2026-01-01", "2026-12-31") day = datetime.weekday(today) -- "Thursday" ```

#### `random`

[](https://github.com/angeldevmobile/Orion#random)

``` n = random.int(1, 100) elem = random.choice(["red", "green", "blue"]) id = random.uuidv4() mix = random.shuffle([1, 2, 3, 4, 5]) ```

#### `process`

[](https://github.com/angeldevmobile/Orion#process)

``` res = process.execute("git status") show res.out process.background("server.exe") exists = process.check_dependency("ffmpeg") ```

Security and cryptography

[](https://github.com/angeldevmobile/Orion#security-and-cryptography)

``` use "crypto" ```

``` hash = crypto.sha256("sensitive data") token = crypto.token(32) id = crypto.uuid()

-- Password hashing h = crypto.hash(password) ok = crypto.verify_hash(password, h)

-- HMAC signing signature = crypto.sign(data, secret) valid = crypto.verify(data, signature, secret)

-- Symmetric encryption encrypted = crypto.encrypt(data, key) plain = crypto.decrypt(encrypted.cipher, encrypted.key) ```

AI and vision

[](https://github.com/angeldevmobile/Orion#ai-and-vision) `ai` and `insight` call an external provider and need an API key. `vision.ocr` runs locally with embedded models.

``` use "ai" use "vision" use "insight" ```

``` -- ai summary = ai.summarize(text) category = ai.classify(email, ["spam", "work", "personal"]) code = ai.code("function that sorts a list of dicts by date") sentiment = ai.sentiment(review) translated = ai.translate(text, "english") extracted = ai.extract(invoice, ["number", "date", "total"])

-- vision info = vision.info("photo.jpg") -- {width, height} vision.resize("photo.jpg", 800, 600, "thumb.jpg") vision.grayscale("photo.jpg", "gray.jpg") b64 = vision.to_base64("photo.jpg")

-- insight (AI over documents) analysis = insight.analyze("contract.png", "What is the expiry date?") ```

Scientific and simulation

[](https://github.com/angeldevmobile/Orion#scientific-and-simulation)

``` use "matrix" use "quantum" use "cosmos" ```

``` -- matrix - numerical linear algebra (nalgebra engine from 32×32 up: -- BLAS-style multiply, LU with pivoting; 512×512 in tens of ms) A = [[1,2],[3,4]] det = matrix.det(A) inv = matrix.inverse(A) x = matrix.solve([[1,1],[1,-1]], [3, 1]) -- linear systems via LU e = matrix.eig([[2,1],[1,2]]) -- eigenvalues: [1.0, 3.0] s = matrix.svd(A) -- {u, s, vt} r = matrix.rank([[1,2],[2,4]]) -- 1 (numerical rank)

-- quantum - a real CIRCUIT simulator (up to 24 qubits, O(2^n) gates -- parallelized; phase matters, so Grover works in plain Orion) c = quantum.circuit(2) quantum.h(c, 0) -- Hadamard on qubit 0 quantum.cnot(c, 0, 1) -- a Bell pair you build yourself quantum.rx(c, 0, 3.14159) -- parametric rotations (rx/ry/rz/phase) quantum.ugate(c, 0, [[0,1],[1,0]]) -- your own 2×2 gate (unitarity checked) show quantum.probs(c) -- {"00": 0.5, "11": 0.5} m = quantum.sample(c, 1000) -- Born rule, no collapse b = quantum.collapse(c, 0) -- measures one qubit and COLLAPSES the state -- Full Grover in demo/demo_grover.orx (P=0.945 exactly) and an animated -- Bloch sphere with real physics in demo/demo_bloch_anim.orx

-- cosmos - N-body simulation u = cosmos.create(5) u = cosmos.run(u, 100) -- cosmos.run(universe, steps?, dt?) show cosmos.summary(u) ```

- * *

The CLI

[](https://github.com/angeldevmobile/Orion#the-cli)

Run

orion file.orx

Interactive REPL

orion

New project scaffold

orion new my-api

Check syntax

orion check main.orx

Check static types

orion check main.orx --types

Hot reload on save

orion watch main.orx

Benchmark

orion bench main.orx --runs=20

Auto-discovered tests (test_*.orx)

orion test orion test tests/

Environment diagnostics

orion doctor

REPL

[](https://github.com/angeldevmobile/Orion#repl)

``` orion> 2 + 3 5 orion> name = "Orion" orion> "Hello " + name "Hello Orion" orion> fn double(x) { return x * 2 } orion> double(21) 42 orion> :vars ← show live variables orion> :fns ← show defined functions orion> :clear ← reset the state orion> :exit ← quit ```

What `orion new` generates

[](https://github.com/angeldevmobile/Orion#what-orion-new-generates)

``` my-api/ ├── main.orx ← a working backend server ├── orion.json ← project manifest ├── .env.example ├── .gitignore ├── lib/ │ └── utils.orx └── test/ └── test_routes.orx ```

- * *

Architecture

[](https://github.com/angeldevmobile/Orion#architecture)

Orion is **not a tree-walking interpreter** - that legacy was removed. It is a bytecode compiler with **three execution backends** that share one frontend and produce identical results, verified by differential tests. Around 13,600 lines of core Rust plus 58 native modules.

``` file.orx │ ▼ lexer.rs ← tokenization (UTF-8, ${} interpolation, escapes) │ ▼ parser.rs ← recursive descent AST │ ▼ typechecker.rs ← type checking (on by default; opt out with --no-typecheck) │ ▼ codegen.rs ← AST → bytecode │ ▼ bytecode │ ├──► vm.rs ← bytecode VM (default). Native Rust, no GIL. │ ├──► jit/ (--jit) ← JIT to machine code via Cranelift. │ Falls back to the VM automatically when an │ instruction is not yet supported in the JIT. │ └──► aot.rs (--build) ← AOT compilation to a standalone native binary. ```

Runtime subsystems shared by all three backends:

- **Mark-and-sweep GC** (`gc.rs`) - collects reference cycles; both _mark_ and _drop_ are iterative, so nesting depth is unbounded.

- **Checked arithmetic** - integer overflow is an explicit error, never a silent wrap.

- **Concurrency** - `spawn`/`await` on a cached thread pool (`task_pool.rs`), `chan` channels and thread-safe shared state (the `state` module).

- **DAP debugger** (`dap.rs`) - real breakpoints, stepping and watches from VS Code.

**No Python. No external runtime. A single executable.**

- * *

Performance - measured, not promised

[](https://github.com/angeldevmobile/Orion#performance---measured-not-promised)

Reproducible benchmark in `bench/`, one command: `bench\run_all.ps1`. Same task in both languages: load 500k CSV rows into typed columns, then `sum` and `mean`. The numeric results match **digit for digit**, so the benchmark doubles as a cross-language correctness test.

| Pipeline (500k rows × 4 cols) | Time | Peak RAM | | --- | --- | --- | | Python 3.13 (csv stdlib, in C) | 516 ms | 105 MB | | **Orion `frame.open` CSV** | **264 ms** | **104 MB** | | **Orion `frame.open` .odf** | **88 ms** | **73 MB** |

- **CSV: 2× faster than Python at the same memory** - columnar loading in Rust; cells go straight into a per-column `Vec`, and text columns are moved without reallocating.

- **.odf (Orion's own binary format): about 6× faster** - no text parsing at all, numbers are read as raw bytes.

- **At 5M rows**: 46% less peak RAM on load, plus data-parallel aggregations via rayon (`sum/std/min/max` use every core from 1M elements up).

- **And in 3× fewer lines**: Python's ~15 lines of manual loop and typing become 5 lines of Orion, since `frame.open` infers types and layout on its own.

Beyond throughput, the runtime is hardened for large data: structures nested 200k+ levels deep and reference cycles (`push(a, a)`) neither crash nor leak. The GC collects them and the VM returns every byte on exit, verified with LeakSanitizer in CI.

- * *

VS Code extension

[](https://github.com/angeldevmobile/Orion#vs-code-extension-1) ![Image 3: VS Code Extension](https://github.com/angeldevmobile/Orion/blob/master/assets/demo_vscode.jpeg)

- Full syntax highlighting

- IntelliSense through an integrated LSP

- Real compiler diagnostics as you type

- Code lenses: `▶ Run` plus complexity metrics

- Watch mode with output in a panel

- Visual shape diagram

- Route explorer with a built-in REST client

- Test explorer that discovers `test_*.orx`

- Import graph

- DAP debugger

- Integrated REPL

- **On-demand compiler** - if `orion` is not on your `PATH`, the extension downloads it from the latest release and keeps it up to date. Still zero-config, without inflating the `.vsix`.

- * *

Runtime status

[](https://github.com/angeldevmobile/Orion#runtime-status) | Component | Status | Technology | | --- | --- | --- | | Lexer + escape sequences | ✅ Complete | Rust | | Parser | ✅ Complete | Rust | | Type checker | ✅ Complete | Rust | | Bytecode compiler | ✅ Complete | Rust | | VM (execution) | ✅ Complete | Rust | | OOP (shape, act, using, is) | ✅ Complete | Rust | | Optional type hints | ✅ Complete | Rust | | Error handling (attempt/handle) | ✅ Complete | Rust | | Async / await | ✅ Complete | Rust | | Interactive REPL | ✅ Complete | Rust | | Native HTTP server | ✅ Complete | Rust | | Native AI (think/learn/sense) | ✅ Complete | Rust | | Errors with spans and visual context | ✅ Complete | Rust | | Interactive debugger (breakpoints, step, watches) | ✅ Complete | Rust | | DAP - Debug Adapter Protocol (VS Code) | ✅ Complete | Rust | | LSP - real-time diagnostics | ✅ Complete | Rust | | JIT - Cranelift (I/O, modules, OOP) | ✅ Complete | Cranelift | | AOT - standalone native executable (needs a C toolchain: MSVC Build Tools, or MinGW/gcc on the PATH) | ✅ Complete | Cranelift | | FFI - external native libraries | ✅ Complete | libloading | | Package manager (add/remove/list/search/publish) | ✅ Complete | Rust | | Official registry on GitHub | ✅ Complete | GitHub API | | Mark-and-sweep GC (cycles; iterative mark and drop, unbounded depth) | ✅ Complete | Rust | | Zero leaks on exit (verified with LeakSanitizer in CI) | ✅ Complete | Rust + ASan | | Reproducible benchmark vs Python (`bench/`) | ✅ Complete | PowerShell + Python | | Standard library modules | ✅ 58 modules (875 functions) | Rust | | Cloud native (S3 / SSH / Docker) | ✅ Complete | Rust | | Full CLI | ✅ Complete | Rust | | VS Code extension (published on the Marketplace) | ✅ Complete | TypeScript |

- * *

Full standard library (58 modules)

[](https://github.com/angeldevmobile/Orion#full-standard-library-58-modules)

Core

[](https://github.com/angeldevmobile/Orion#core) `fs``json``strings``datetime``random``regex``env``process``crypto``term`

System

[](https://github.com/angeldevmobile/Orion#system) `log``config``secret``zip``stream``crypto2``state`

Network and web

[](https://github.com/angeldevmobile/Orion#network-and-web) `net``ws``serve``router``middleware``sse``proto`

Backend

[](https://github.com/angeldevmobile/Orion#backend) `db``auth``cache``mail``validate`

Automation

[](https://github.com/angeldevmobile/Orion#automation) `tarea``cola``watch`

Data and science

[](https://github.com/angeldevmobile/Orion#data-and-science) `csv``excel``excel_f``table``frame``serie``stat``matrix``search`

Utilities

[](https://github.com/angeldevmobile/Orion#utilities-1) `template``formato``grafo``pdf`

Native AI (block C)

[](https://github.com/angeldevmobile/Orion#native-ai-block-c) `llm``embed``vector``ai`

Interfaces

[](https://github.com/angeldevmobile/Orion#interfaces) `gui``tui`

Advanced

[](https://github.com/angeldevmobile/Orion#advanced) `vision``insight``quantum``cosmos``timewarp`

Cloud native (block E)

[](https://github.com/angeldevmobile/Orion#cloud-native-block-e) `s3``ssh``docker`

- * *

Ecosystem

[](https://github.com/angeldevmobile/Orion#ecosystem) > Orion does not copy Python. Each module is designed for a simple, fast API that needs no configuration.

Where Orion differs from Python

[](https://github.com/angeldevmobile/Orion#where-orion-differs-from-python) | | Python | Orion | | --- | --- | --- | | Speed | slower (GIL) | native Rust + JIT | | Startup | 150-400 ms | < 1 ms | | Built-in AI | pip install | standard library | | Native compilation | no | `orion --build` | | Package manager | pip | `orion --add` | | API design | 1990s legacy | designed from scratch |

- * *

Block D - System ✅

[](https://github.com/angeldevmobile/Orion#block-d---system-) _The base of any real application._

| # | Module | Description | Rust crate | Status | | --- | --- | --- | --- | --- | | 1 | `use "zip"` | Compress and extract gzip, zip, tar | `flate2` + `zip` | ✅ Complete | | 2 | `use "secret"` | Read `.env`, safe secrets with validation | native | ✅ Complete | | 3 | `use "log"` | Structured logging with levels, colors, timers and files | native | ✅ Complete | | 4 | `use "config"` | Load TOML / JSON as typed configuration | `toml` | ✅ Complete | | 5 | `use "crypto2"` | AES-256-GCM, RSA, signing and verification | `aes-gcm` + `rsa` | ✅ Complete | | 6 | `use "stream"` | Data pipelines: filter, pluck, sum, avg, unique, flatten | native | ✅ Complete |

``` -- log - structured logging with tags, timers and dividers use "log"

log.divider("start") log.info("Server starting on port 8080", "startup") log.timer("db") log.info("Connecting to the database...", "DB") log.ok("Connection established", "DB") log.elapsed("db", "connection") -- OK [db] connection completed in 12ms log.warn("Token expiring soon", "auth") log.err("User not found", "auth") log.level("debug") -- enable debug messages log.debug("Request: GET /api/v1/users", "net") log.divider()

-- config - load TOML / JSON as typed configuration use "config"

cfg = config.load("orion.toml") port = config.get(cfg, "server.port") cfg2 = config.merge(cfg, "local.toml") -- local.toml overrides

-- secret - safe secrets from .env use "secret"

secret.load(".env") db_url = secret.require("DATABASE_URL") -- clear error if missing api_key = secret.get("API_KEY", "dev") show secret.mask(api_key) -- "sk***y"

-- zip - compress and extract use "zip"

zip.compress("src/", "release.zip") -- compresses a whole folder n = zip.decompress("release.zip", "out/") entries = zip.list("release.zip") -- [{name, size, is_dir}, ...] zip.gzip("data.csv", "data.csv.gz") zip.gunzip("data.csv.gz", "data.csv")

-- stream - data pipelines with no dependencies use "stream" as st

users = [ {"name": "Ana", "active": yes, "sale": 4200}, {"name": "Luis", "active": no, "sale": 1800}, {"name": "Eva", "active": yes, "sale": 3100} ]

active = st.where_(users, "active", yes) names = st.pluck(active, "name") -- ["Ana", "Eva"] total = st.sum(st.pluck(active, "sale")) -- 7300 top3 = st.take(st.reverse(st.range(1, 100)), 3) -- [99, 98, 97]

-- crypto2 - AES-256-GCM and RSA use "crypto2"

-- AES-256-GCM (authenticated symmetric encryption) encrypted = crypto2.aes_encrypt("sensitive data", "my-secret-key") plain = crypto2.aes_decrypt(encrypted, "my-secret-key")

-- RSA (asymmetric encryption + digital signature) keys = crypto2.rsa_keygen() -- {public_key, private_key} c = crypto2.rsa_encrypt("message", keys.public_key) m = crypto2.rsa_decrypt(c, keys.private_key) signature = crypto2.rsa_sign("contract", keys.private_key) valid = crypto2.rsa_verify("contract", signature, keys.public_key) -- yes ```

- * *

Block B - Modern web ✅

[](https://github.com/angeldevmobile/Orion#block-b---modern-web-) _Beyond the basic `serve`: middleware, advanced routing, modern protocols._

| # | Module | Description | Rust crate | Status | | --- | --- | --- | --- | --- | | 7 | `use "router"` | Declarative routing with `:id` parameters and `*` wildcards | native | ✅ Complete | | 8 | `use "middleware"` | Rate limiting, CORS, logging, JWT auth in a chain | native | ✅ Complete | | 9 | `use "sse"` | Server-Sent Events for real-time HTTP streaming | native | ✅ Complete | | 10 | `use "proto"` | MessagePack binary serialization, more compact than JSON | native | ✅ Complete |

``` -- router + serve together - the full combination use "router" use "middleware"

limiter = middleware.rate_limit(100, 60) -- 100 req / 60 s

-- Handlers are NAMED functions: you pass the function NAME to the -- router as a string, not a lambda. serve runs each request in its -- own VM and looks handlers up by name, so an anonymous lambda -- cannot be dispatched. fn mw_global(req) { if not middleware.check_rate(limiter, req["path"]) { return {"status": 429, "body": "Too Many Requests"} } return null -- null = continue to the handler }

fn view_user(req) { return {"status": 200, "body": "User: " + req["params"]["id"]} }

fn create_user(req) { return {"status": 201, "body": req["body"]} }

fn view_file(req) { return {"status": 200, "body": "File: " + req["params"]["rest"]} }

fn fallback(req) { return {"status": 404, "body": "not found"} }

r = router.new() router.use_middleware(r, "mw_global") router.get(r, "/users/:id", "view_user") router.post(r, "/users", "create_user") router.get(r, "/files/*rest", "view_file") router.attach(r) -- activates the router for the next serve

-- The router dispatches automatically; `fallback` handles anything that -- does not match. `serve` always takes a port plus a handler function. serve 8080 fallback

-- router.match() can also be used manually. `match` is a keyword, so the -- result cannot be bound to a variable of that name. hit = router.match(r, "GET", "/users/42") -- {method: GET, path: /users/42, params: {id: 42}, handler: view_user}

show router.routes(r) -- lists every registered route

-- middleware - rate limiting, CORS, JWT auth use "middleware"

limiter = middleware.rate_limit(100, 60) -- 100 req / 60 s ok = middleware.check_rate(limiter, "192.168.1.1") -- yes / no

cors_headers = middleware.cors("https://myapp.com", "GET, POST", "Authorization") result = middleware.auth_bearer(token, "my-secret") -- {valid: yes, sub: "user123", payload: {rol: "admin", exp: 1800000000}}

middleware.log_req("GET", "/api/users", 200, 12) -- 14:32:01 GET /api/users 200 12ms

-- sse - Server-Sent Events use "sse"

headers = sse.headers() -- {Content-Type: "text/event-stream", ...} ev = sse.event("test message") -- "data: test message\n\n" ev = sse.named("update", "new data") -- "event: update\ndata: new data\n\n" ev = sse.json_event("users", [{name: "Ana"}]) ev = sse.retry(3000) -- "retry: 3000\n\n" ev = sse.keep_alive() -- ": keep-alive\n\n"

-- proto - MessagePack binary serialization use "proto"

data = {name: "Ana", age: 25, active: yes} bytes = proto.encode(data) -- list of ints (bytes) b64 = proto.encode_b64(data) -- base64 string show proto.size(data) -- size in bytes (smaller than JSON) show proto.json_size(data) -- size as JSON, for comparison

restored = proto.decode(bytes) restored = proto.decode_b64(b64) ```

- * *

Block C - Native AI ✅

[](https://github.com/angeldevmobile/Orion#block-c---native-ai-) _First-class AI, without pip and without configuration. These modules call external providers and need an API key._

| # | Module | Description | Rust crate | Status | | --- | --- | --- | --- | --- | | 11 | `use "llm"` | One-line calls to OpenAI / Anthropic / Ollama / Gemini | `ureq` | ✅ Complete | | 12 | `use "embed"` | Text embeddings, cosine similarity, semantic search | native math | ✅ Complete | | 13 | `use "vector"` | In-memory vector database with cosine similarity | native | ✅ Complete |

> **Separation of concerns:** > > > * `ai.*` → high level, no model choice (summarize, classify, sentiment, translate) > * `llm.*` → direct model control (query with an explicit provider, multi-turn chat) > * `embed.*` → vectors only (text → embedding, similarity, semantic search)

``` use "llm" use "embed" -- alias de "embeddings" use "vector"

-- Multi-provider: claude, gpt, gemini, ollama answer = llm.query("gpt-4o", "Summarize this contract in 3 points: " + contract) answer = llm.query("claude-sonnet-4-6", prompt) answer = llm.query("ollama:llama3", prompt) answer = llm.query("gemini-2.0-flash", prompt) answer = llm.query("auto", prompt) -- detects the configured provider

-- With a system prompt r = llm.query_with("gpt-4o", question, "You are a legal expert.")

-- Multi-turn chat msgs = [ {"role": "user", "content": "Hi"}, {"role": "assistant", "content": "Hello!"}, {"role": "user", "content": "What is 2+2?"} ] r = llm.chat("claude-haiku-4-5-20251001", msgs)

-- Embeddings vec = llm.embed("text-embedding-3-small", text) -- List<float>

-- Semantic search over a small corpus (no vector DB) results = embed.search("When was it founded?", documents, 3) -- → [{text: "...", score: 0.91, index: 4}, ...]

-- Cosine similarity between two vectors sim = embed.similarity(emb1, emb2) -- 0.0 .. 1.0 dist = embed.distance(emb1, emb2) norm = embed.normalize(emb1)

-- In-memory vector database db = vector.new() for doc in corpus { v = embed.text(doc.text) vector.add(db, doc.id, v, doc.title) } query_vec = embed.text("When was the company founded?") results = vector.search(db, query_vec, 5) -- → [{id: "doc-12", score: 0.934, metadata: "History"}, ...] vector.save(db, "corpus.vdb.json") -- persist to JSON db2 = vector.load("corpus.vdb.json") -- load back

-- Available providers show llm.providers() -- ["anthropic", "openai", "gemini", "ollama"] show llm.models() -- ["claude-haiku-4-5-20251001", "gpt-4o", "ollama:llama3:latest", ...] ```

- * *

Block A - Modern data

[](https://github.com/angeldevmobile/Orion#block-a---modern-data) _A pandas replacement: faster, simpler API, no heavy dependencies._

| # | Module | Description | Implementation | Status | | --- | --- | --- | --- | --- | | 14 | `use "table"` / `use "df"` | Row-oriented dataframes: load, filter, group, join, forecast | native Vec | ✅ Complete | | 15 | `use "frame"` | **Columnar** dataframes: far less RAM, chunk streaming, scan without loading | columnar Vec | ✅ Complete | | 16 | `use "stat"` | Statistics: mean, std, percentile, correlation, regression, z-score, histogram | native Vec | ✅ Complete | | 17 | `use "serie"` | Time series: moving_avg, diff, pct_change, forecast, trend, smooth | native Vec | ✅ Complete | | 18 | `use "search"` | Fast search across TXT/CSV/Excel/dirs - streaming, regex, context, multi-column | native BufReader | ✅ Complete |

> No polars, no ndarray, no heavy dependencies. The split: `table` for quick exploration, `frame` for production and large volumes.

#### Which one to use

[](https://github.com/angeldevmobile/Orion#which-one-to-use) | Volume | Module | Why | | --- | --- | --- | | < 50K rows | `table` | Richer API, exploration, built-in AI | | 50K - 5M rows | `frame` | Columnar, far less RAM, operations straight on `Vec<f64>` | | > 5M rows | `frame.each_chunk` / `frame.scan_stats` | Never loads everything, processes in blocks | | Searching files | `search` | Streaming, stops at the first match, multi-file |

``` use "table" -- or: use "df"

-- Load: auto-detects CSV / Excel / JSON t = table.load("sales.csv") table.peek(t, 5) -- prints the first 5 rows table.schema(t) -- column types table.profile(t) -- full statistics

-- Filter, select, sort north = table.where(t, "region == 'North' && active == yes") top10 = table.top(t, "sale", 10) t2 = table.keep(t, ["name", "region", "sale"]) t3 = table.sort(t, "sale", "desc")

-- Computed column t4 = table.add(t, "total", "sale * 1.19")

-- Aggregation by_region = table.group(t, "region", "sale", "sum") stats = table.stats(t, "sale") -- {min, max, avg, std, p25, median, p75}

-- Combine joined = table.join(t, t2, "id") all = table.concat(t, t2)

-- Analytics pred = table.forecast(t, "sale", 5) -- linear projection outliers = table.anomalies(t, "sale") -- IQR outliers corr = table.correlate(t, "age", "sale") -- Pearson ranked = table.rank(t, "sale") -- adds _rank and _pct mavg = table.moving_avg(t, "sale", 3) -- moving average

-- Save: format auto-detected from the extension table.save(t, "report.csv") table.save(t, "report.xlsx") table.save(t, "report.json")

-- AI integration (calls an external provider) table.describe_ai(t) -- AI-generated description resp = table.ask(t, "Which region sells most in summer?") ```

#### `frame` - columnar dataframes for large volumes

[](https://github.com/angeldevmobile/Orion#frame---columnar-dataframes-for-large-volumes)

``` use "frame"

-- Direct columnar load, without materializing rows: 2× faster than the -- Python standard library at the same memory - measured in bench/ -- (500k and 5M rows). open() auto-detects the format: CSV, or the .odf -- binary format, which is about 6× faster. f = frame.open("sales_1M.csv") frame.schema(f) -- inferred column types frame.peek(f, 5) -- pretty table without loading everything frame.size(f) -- {rows: 1000000, cols: 8}

-- Stats straight on Vec<f64> - no hash lookups; from 1M elements up they -- use every core (rayon) frame.mean(f, "sale") frame.stats(f, "sale") -- {count, mean, std, min, p25, median, p75, max}

-- Filter, select, sort north = frame.where_(f, "region", "North") top = frame.sort(f, "sale", "desc") simple = frame.keep(f, ["name", "region", "sale"])

-- Columnar aggregation by_region = frame.group(f, "region", "sale", "sum")

-- Large files: process in 10K chunks without loading everything chunks = frame.each_chunk("sales_100M.csv", 10000) for chunk in chunks { stats = frame.stats(chunk, "sale") show "Chunk mean: ${stats.mean}" }

-- Full scan of one column without loading the file stats = frame.scan_stats("sales_100M.csv", "sale") -- → {count, mean, std, min, max, sum} - iterates only that column ```

#### `search` - fast search in any file

[](https://github.com/angeldevmobile/Orion#search---fast-search-in-any-file)

``` use "search"

-- TXT / LOG - streaming, never loads everything into RAM errors = search.text("app.log", "ERROR") -- → [{line: 42, content: "ERROR: connection refused"}, ...]

-- Regex with captured groups dates = search.regex("file.txt", "(\\d{4}-\\d{2}-\\d{2})") -- → [{line, content, matches: ["2026-05-15"]}, ...]

-- CSV - search by column without loading the file customers = search.csv("customers.csv", "city", "Monterrey") -- → [{name: "Ana", city: "Monterrey", ...}, ...]

-- CSV - search across several columns hits = search.columns("products.csv", ["name", "description"], "orion")

-- Excel - search a whole sheet rows = search.excel("report.xlsx", "pending") rows = search.excel("report.xlsx", "North", "Q1 Sales") -- specific sheet

-- Type auto-detected from the extension result = search.in_file("data.csv", "Ana") -- CSV result = search.in_file("notes.txt", "urgent") -- text result = search.in_file("base.xlsx", "error") -- Excel

-- Count without materializing (very fast on large files) n = search.count("logs/app.log", "CRITICAL")

-- First match, then stop (ideal for verification) first = search.first("customers.csv", "Ana García")

-- Search every file in a directory hits = search.in_dir("logs/", "timeout") -- all files hits = search.in_dir("data/", "North", "csv") -- only .csv

-- Context - N lines before and after (like grep -C) ctx = search.context("deploy.log", "FAILED", 3) -- → [{line, content, before: [...], after: [...]}] ```

- * *

Block E - Cloud native ✅

[](https://github.com/angeldevmobile/Orion#block-e---cloud-native-) _No pip, no npm. Cloud as part of the standard library._

| # | Module | Description | Rust crate | Status | | --- | --- | --- | --- | --- | | 18 | `use "s3"` | Upload and download files to S3 / R2 / MinIO | `ureq` + AWS Sig V4 | ✅ Complete | | 19 | `use "ssh"` | Run remote commands over SSH, plus SCP | `ssh2` | ✅ Complete | | 20 | `use "docker"` | Control Docker containers through the REST API | `ureq` | ✅ Complete |

``` -- s3 - works with AWS S3, Cloudflare R2 and MinIO use "s3"

s3.config("https://s3.amazonaws.com", env.pull("AWS_KEY"), env.pull("AWS_SECRET"), "us-east-1")

-- Upload a file r = s3.upload("my-bucket", "backups/report.csv", "report.csv") show r.url -- https://s3.amazonaws.com/my-bucket/backups/report.csv

-- Download a file s3.download("my-bucket", "backups/report.csv", "local/report.csv")

-- List objects files = s3.list("my-bucket", "backups/") for f in files { show f.key + " " + f.size }

-- Check existence and delete if s3.exists("my-bucket", "backups/old.csv") { s3.delete("my-bucket", "backups/old.csv") }

-- MinIO / R2 - same API, different endpoint s3.config("http://localhost:9000", "minio", "minio123", "us-east-1") s3.upload("data", "file.json", "output.json")

-- Cloudflare R2 s3.config("https://<account>.r2.cloudflarestorage.com", env.pull("R2_KEY"), env.pull("R2_SECRET"), "auto")

-- ssh - remote connection with a password or a key use "ssh"

-- Password s = ssh.connect("192.168.1.10", 22, "deploy", "secret")

-- Private key s = ssh.connect_key("server.com", 22, "ubuntu", "/home/user/.ssh/id_rsa")

-- Run commands r = ssh.exec(s, "df -h") show r.out -- disk usage show r.code -- 0 = success

r = ssh.exec(s, "systemctl status nginx") show r.out

-- Upload and download files (SCP) ssh.upload(s, "dist/app.tar.gz", "/opt/app/app.tar.gz") ssh.download(s, "/var/log/app.log", "logs/app.log")

-- Check the connection if ssh.test(s) { show "server reachable" }

ssh.close(s)

-- docker - control the daemon through the REST API use "docker"

-- Configure the endpoint (default: http://localhost:2375) docker.config("http://localhost:2375")

-- Check the daemon if docker.ping() { show "Docker is up" } show docker.version() -- {version, api_version, os, arch}

-- Containers cs = docker.containers() -- running only cs = docker.containers(yes) -- all, including stopped for c in cs { show c.name + " " + c.status }

-- Lifecycle docker.start("my-api") docker.stop("my-api", 10) -- 10s grace period docker.restart("my-api") docker.kill("my-api") docker.remove("my-api", yes) -- force=yes

-- Logs show docker.logs("my-api", 50) -- last 50 lines

-- Inspect info = docker.inspect("my-api") show info.State.Status

-- Launch a new container c = docker.run("nginx:latest", { name: "web", env: ["PORT=8080", "ENV=prod"], cmd: ["nginx", "-g", "daemon off;"] }) show "Started: " + c.id

-- Images imgs = docker.images() for i in imgs { show i.tags } docker.pull("redis:7")

-- Live metrics st = docker.stats("my-api") show "CPU: " + st.cpu_pct + "%" show "RAM: " + st.mem_usage + " / " + st.mem_limit ```

- * *

Implementation order

[](https://github.com/angeldevmobile/Orion#implementation-order)

``` Block D ✅ → Block B ✅ → Block C ✅ → Block A ✅ → Block E ✅ (base) (web) (AI) (table/df) (cloud) ```

- * *

Roadmap - Excel and automation

[](https://github.com/angeldevmobile/Orion#roadmap---excel-and-automation) > Orion does not copy pandas or openpyxl. Each feature has its own name, a cleaner API, and works with `|>`.

Current state of the `excel` module

[](https://github.com/angeldevmobile/Orion#current-state-of-the-excel-module)

``` use "excel" as excel

-- What already works today data = excel.read("sales.xlsx") data = excel.filter(data, "active", "==", yes) data = excel.group(data, "region", { "sales": "sum", "count": yes }) data = excel.sort(data, "region") -- single column data = excel.join(data, targets, "region") -- single key stats = excel.stats(data, "sales") excel.write_styled("report.xlsx", data, { titulo: "Q1", stripe: yes })

-- Data plus a chart in one file, in a single call excel.write_styled("report.xlsx", data, { titulo: "Q1 Sales Report", stripe: yes, freeze: yes, charts: [ { type: "bars", x: "region", y: "sales_sum", palette: "orion", style: "minimal", show_values: yes, sheet: "Chart" } ] }) ```

The nine designed features

[](https://github.com/angeldevmobile/Orion#the-nine-designed-features) Status below reflects what the compiler actually exposes, checked against `orion --builtins-json`.

| # | Feature | Pandas equivalent | Status | | --- | --- | --- | --- | | 1 | `compute` | `df["col"].apply(fn)` | Designed, not implemented | | 2 | `sort`, multi-column | `sort_values(["a","b"])` | ✅ Complete | | 3 | `group`, multi-agg | `groupby().agg({...})` | ✅ Complete | | 4 | `long` | `df.melt(...)` | ✅ Complete | | 5 | `dates` + `date_parts` | `pd.to_datetime(...)` | ✅ Complete | | 6 | `join`, multi-key | `merge(on=["a","b"])` | ✅ Complete | | 7 | `chart` | openpyxl charts | ✅ Complete | | 8 | `formula` | `ws["A1"] = "=SUM(...)"` | Partial: the `excel.f` builder exists, `excel.formula` does not | | 9 | `sheet` builder | openpyxl cell-level | ✅ Complete |

The sections below marked as not implemented describe the intended API, not current behaviour.

- * *

F-1 `compute` - computed columns

[](https://github.com/angeldevmobile/Orion#f-1-compute---computed-columns) The lambda receives the whole row, so fields can reference each other. Several columns in a single pass.

``` -- Two lambda forms exist: `params => body`, whose body may be an expression -- or a block, and `fn(params) { block }`. They do not mix: `fn row => ...` -- is a syntax error. `if` is a statement, not an expression, so a branching -- body needs a block with `return`. data = excel.compute(data, { "bonus": row => row["sales"] * 0.05, "tier": row => { if row["sales"] > 90000 { return "A" } if row["sales"] > 70000 { return "B" } return "C" }, "on_track": row => row["sales"] >= row["target"] }) ```

- * *

F-2 `sort` - multiple columns

[](https://github.com/angeldevmobile/Orion#f-2-sort---multiple-columns)

``` -- Explicit style data = excel.sort(data, [ { by: "region", dir: "asc" }, { by: "sales", dir: "desc" } ])

-- Short Orion style: + is ascending, - is descending data = excel.sort(data, "region+", "sales-", "name+") ```

- * *

F-3 `group` - several aggregations per field

[](https://github.com/angeldevmobile/Orion#f-3-group---several-aggregations-per-field)

``` by_region = excel.group(data, "region", { "sales": ["sum", "avg", "max", "min"], "months": ["avg"], "count": yes }) -- Produces: sales_sum, sales_avg, sales_max, sales_min, months_avg, count ```

Available functions: `sum``avg``max``min``count``first``last``std``median`

- * *

F-4 `long` - wide to long (unpivot)

[](https://github.com/angeldevmobile/Orion#f-4-long---wide-to-long-unpivot) Turns wide format into long format. A clear name: `long`, not `melt`.

``` -- Before (wide): region | CRM Pro | Analytics | Cloud -- After (long): region | product | sales

-- excel.long(data, keep, var, val) — positional, like every module function long_data = excel.long(wide_data, ["region", "seller"], "product", "sales") ```

- * *

F-5 `dates` and `date_parts`

[](https://github.com/angeldevmobile/Orion#f-5-dates-and-date_parts) Integrated with the `datetime` module.

``` data = excel.dates(data, "sale_date", "DD/MM/YYYY") data = excel.date_parts(data, "sale_date", ["year", "month", "quarter", "weekday"]) data = excel.group(data, "quarter", { "sales": ["sum", "avg"] }) ```

Formats: `"DD/MM/YYYY"``"MM/DD/YYYY"``"YYYY-MM-DD"``"auto"`

Parts: `"year"``"month"``"day"``"quarter"``"weekday"``"week"``"hour"`

- * *

F-6 `join` - multiple keys

[](https://github.com/angeldevmobile/Orion#f-6-join---multiple-keys)

``` -- Single key (unchanged) data = excel.join(sellers, targets, "region", "left")

-- Multiple keys data = excel.join(sellers, targets, ["region", "product"], "left") ```

- * *

F-7 `chart` - declarative charts in Excel

[](https://github.com/angeldevmobile/Orion#f-7-chart---declarative-charts-in-excel) No intermediate objects, no manual series. One call.

``` excel.chart("report.xlsx", by_region, { type: "bars", x: "region", y: "sales_sum", sheet: "Charts" })

-- Multiple series excel.chart("report.xlsx", by_month, { type: "lines", x: "month", y: ["sales_sum", "target_sum"], }) ```

Types: `"bars"``"stacked_bars"``"lines"``"area"``"pie"``"scatter"`

- * *

F-8 `formula` - live formulas in Excel

[](https://github.com/angeldevmobile/Orion#f-8-formula---live-formulas-in-excel) Orion does not expose raw Excel formula strings. Instead there is a builder with clear names. Columns marked as formulas stay live in the file and recalculate when opened in Excel.

``` f = excel.f

excel.write_styled("report.xlsx", data, { formulas: { "bonus": f.pct("sales", 5), "total": f.sum("sales"), "rank": f.rank("sales", "desc"), "ratio": f.ratio("sales", "target") } }) ```

Functions: `f.sum``f.avg``f.pct``f.ratio``f.rank``f.cumulative``f.if_`

- * *

F-9 `sheet` - full cell-by-cell control

[](https://github.com/angeldevmobile/Orion#f-9-sheet---full-cell-by-cell-control) A declarative builder. No manual cell iteration.

``` sheet = excel.sheet("Sales Report")

sheet.put("A1", "Q1 2026 - Sales Report", { bold: yes, size: 16, merge: "A1:F1" }) sheet.put("A2", "Generated: " + datetime.today(), { color: "#888888" }) sheet.data("A4", sellers, { header: yes, stripe: yes }) sheet.chart("H4", { type: "bars", x: "region", y: "sales", width: 400, height: 300 }) sheet.style("A4:F4", { bg: "#1B4F72", color: "#FFFFFF", bold: yes }) sheet.freeze("A5") sheet.autofilter("A4:F4")

excel.save(sheet, "custom_report.xlsx") ```

- * *

The full pipeline, in a single API

[](https://github.com/angeldevmobile/Orion#the-full-pipeline-in-a-single-api) `excel.compute` is not implemented yet, so it is left out of this example. Each step rebinds `data`; the same chain can be written with `|>`, since every `excel` function takes the table as its first argument.

``` use "excel" as excel

data = excel.read("sales_q1.xlsx") data = excel.filter(data, "active", "==", yes) data = excel.dates(data, "sale_date", "DD/MM/YYYY") data = excel.date_parts(data, "sale_date", ["month", "quarter"]) by_quarter = excel.group(data, "quarter", { "sales": ["sum", "avg"], "count": yes }) by_quarter = excel.sort(by_quarter, "quarter+")

excel.write_styled("q1_report.xlsx", by_quarter, { stripe: yes, freeze: yes, autofilter: yes })

excel.chart("q1_report.xlsx", by_quarter, { type: "bars", x: "quarter", y: "sales_sum", }) ```

Implementation order

[](https://github.com/angeldevmobile/Orion#implementation-order-1) | # | Feature | Impact | Estimated time | | --- | --- | --- | --- | | 1 | `compute` | Very high | 2-3h | | 2 | `sort`, multi-column | High | 1-2h | | 3 | `group`, multi-agg | High | 3-4h | | 4 | `join`, multi-key | Medium | 1-2h | | 5 | `dates` + `date_parts` | High | 3-4h | | 6 | `long` | Medium | 2-3h | | 7 | `chart` | Very high | 4-6h | | 8 | `formula` | Medium | 3-4h | | 9 | `sheet` builder | High | 6-8h |

- * *

Contributing

[](https://github.com/angeldevmobile/Ori