statically typed · AOT compiled · self-hosting

The Ξ programming
language.

A language for building microservices and enterprise software — with dependency injection, function intent, and refined types as first-class citizens. Compiled to native binaries through C.

$ brew install code-by-sia/xi/xi
◇ self-hosting The compiler is written in Ξ and compiles its own source to a byte-identical fixpoint. The only non-Ξ code is a small C runtime.
The language

What makes Ξ different.

Ideas that usually live in frameworks and conventions are, in Ξ, features of the language itself.

01

Refined types

Constraints live in the type. Values are checked at construction, so a partially-valid instance can never exist.

Number where value >= 0
02

Function intent

Eight kinds — mapper, predicate, consumer, producer and more — make purity and effects syntactic. The compiler enforces them.

mapper · predicate · consumer
03

Dependency injection

Declare deps { } and the compiler wires it. No container, no registration, no reflection.

deps { logger: Logger } · how it works ↓
04

Guarded overloading

One name, many bodies — the first where guard that holds wins. It is exactly how std/web routing works.

where res.status == 200
05

Decision tables

Business rules as first-class DxT tables — alongside atoms, state machines, interrupts and pub/sub events.

DxT · atoms · machines ↓
06

Errors as values

T! result types, ok/err, and ? propagation. Failures are values you handle, not surprises.

let row = load(id)?
07

Concurrency

async spawns a worker and returns a Future immediately. await all joins them, in order.

await all jobs
08

No null

Absence is typed. Optionals (T?) unwrap with if let; empty gives the zero value. null does not exist.

if let row = find(7) { … }
09

Sum types & match

Algebraic types with payload-binding match — lowered to plain tagged unions.

match s { Circle c -> … }
10

Interrupts

Resumable conditions. A function signals and suspends; the caller decides — resume it or abandon it.

signal · recover · skip ↓
11

Typed events

Built-in pub/sub. Producers publish a DTO; listeners receive the typed value. No JSON inside the process.

publish · listener · Events.run ↓
12

Native output — and WASM

Compiles to a standalone binary through C — or to WebAssembly with --target wasm. No VM, no garbage collector.

xc app.xi → ./build/app
◇ the heart of Ξ

Dependency injection is the language.

Every serious codebase ends up bolting on an IoC container — a framework, annotations, a runtime registry. Ξ moves injection into the compiler: you declare what you need, and the wiring is derived from your code.

01

Declare, never construct

A class lists what it needs in a deps { } block. It never news up its own collaborators — constructor plumbing disappears from the codebase.

02

Discovery, not registration

Implementations are discovered and wired automatically at compile time. No container to configure, no annotations, no reflection — a missing dependency is a build error, not a runtime surprise.

03

Everything is injectable

The entry takes dependencies as parameters. Classes, listeners — even decision tables — declare deps. Lifetimes are explicit: singleton or transient.

04

bind is the override, not the rule

You only write bind to choose between implementations or swap in a test double. Zero bindings is the normal case.

checkout.xi XI

        
Machinery

Rules, state, and flow — built in.

Rules engines, Redux stores and statechart libraries are language constructs in Ξ. All three are values — and all three are injectable.

DxT · decision tables

Business rules as tables.

A decision is a function kind whose body is a set of when → result arms, read top to bottom — first match wins. The rule set your product owner writes on a whiteboard is the code.

when <cond> => <result> arms, with an else fallback
A declared hit policy — hit first: the first matching arm wins
A function kind — injectable, and arms can call predicates
quote.xi XI

          
Atoms · active-state stores

State without setters.

An atom holds an immutable state that can only change through transition reducers — Redux, built into the language instead of imported from npm.

Read with .current — the state is immutable, there are no setters
transition reducers take the state and return a new one — call them with just the extra args
.undo() / .canUndo() — history comes for free
cart.xi XI

          
Machines · finite state machines

State machines as values.

A machine declares named states, machine-wide data, and transitions with parameters. Machines are immutable — every transition returns a new value.

where guards and update clauses on every transition
Ask before you leap with .can(...)
An illegal move raises IllegalTransition — a resumable interrupt, not a crash
door.xi XI

          
Interrupts · resumable conditions

Errors you can resume.

A function signals a condition and suspends. The enclosing try/catch decides what happens next. Exceptions unwind — interrupts negotiate.

interrupt declares a typed condition with a payload
recover runs the restart and resumes at the signal point
skip abandons the suspended computation instead
calc.xi XI

          
Events · typed pub/sub

Publish values, not JSON.

Producers publish(topic, dto); a listener receives the typed value — zero serialization in process. Bind a transport to cross the network; producers and listeners never change.

The listener kind subscribes with on "topic" — each delivery resolves fresh deps
In-memory queue by default — drain with Events.run() or Events.runAsync()
Bind PublisherService / ConsumerService to go external
shop.xi XI

          
Batteries included

The framework is in the box.

A typed web framework, a test runner, configuration and C interop ship with the toolchain. Building a service needs no packages.

std/web

A web framework, not a dependency.

Implement WebRequestHandler and route by overloading handle with where guards. Params and bodies decode into your types; responses serialize themselves. HTTPS and HTTP/2 are opt-in flags.

users.xi XI

          
xt · testing

Tests live next to the code.

test blocks are excluded from normal builds and run with xt. Tests get dependencies injected, and module Test bindings swap in doubles — no mocking library.

calc_test.xi XI

          
Typed configuration

Config is an interface bound to a file: bind AppConfig -> readConfig("app.yaml"). YAML, JSON or XML — hot-reload included.

C interop

Port a C library by declaring it: an extern "C" block plus a link directive. The signatures are the binding.

Collections

List, Map, Set, Stack, Queue, SortedQueue — built-in generics, no imports.

Standard library

math · text · json · yaml · xml · crypto · fs · net · http · thread · process · time

The toolchain
xc app.xicompile to a native binary
xirun tool + interactive REPL
xt calc_test.xirun the tests
xi installfetch module dependencies
xi packpackage a library for others
loadtest --bench app.xiload & perf testing
xc --target wasmcompile to WebAssembly
xi updateself-update the toolchain
◇ showcase

eXstream — a music-streaming service built in Ξ: microservices behind an API gateway, JWT auth, a React front end, Docker deployment.

code-by-sia/eXstream ↗
Examples

A taste of Ξ.

{{ activeFilename }} XI
{{ activeLineNumbers }}

          
Getting started

Up and running in a minute.

On macOS (Apple Silicon & Intel) and Linux. You just need a C compiler on your PATH.

01

Install with Homebrew

Or grab a prebuilt tarball from the releases page and put its bin/ on your PATH.

$ brew install code-by-sia/xi/xi
02

Two tools, one toolchain

You get xc, the compiler, and xi, the run tool and REPL.

$ xc --version
$ xi repl
03

Write a program

Save a file with the .xi extension. Every program has an entry and a module.

04

Compile & run

One command compiles through C to a native binary and runs it.

$ xc greeting.xi && ./build/greeting
Playground

Try Ξ in the browser.

A simulated editor — pick an example, edit it, and run to see the compiler output.

console
// press Run to compile and execute