This is the opinionated document. 01-survey.md says what history taught; this one says what to
build and why, including the bets that could be wrong.
Every mainstream language was designed for a world where humans write all the code and the computer only executes it. Both assumptions are now false. Most new code will be written with or by AI models; most interesting programs will contain models (neural networks, LLM calls, probabilistic reasoning); and the hardware those programs run on is no longer “a CPU” but a zoo of CPUs, GPUs, NPUs and FPGAs. A language designed today should take all three as givens. Nobody has done that yet — Mojo took the hardware part, DSPy/BAML took the LLM part, Rust took safety — and all of them sit inside or beside Python. Lume’s bet is that one coherent language can cover the whole stack: the boot sector, the kernel, the database, the business app, the training loop, the inference kernel and the agent that orchestrates them — and that being designed for AI authorship is the thing that makes the whole-stack ambition feasible for the first time.
Every design decision below is scored against all four. That is the innovation: not any single feature, but refusing to sacrifice one audience for another.
Most “AI languages” mean “languages for writing AI”. The first and bigger opportunity is a language written by AI, verified by the compiler, reviewed by the human. Concretely:
a * b; dilemmas, no Python
print x legacy, no JS ASI). One canonical formatting. An LLM that emits Lume either parses or
gets an exact error location.requires/ensures, effects, exhaustive match, no null, no UB:
the categories of mistakes LLMs make most (off-by-one, wrong null handling, forgetting a case,
calling I/O where it shouldn’t) become compile errors. The compiler is the reviewer that never
tires.lume build --json yields machine-readable errors with
spans, expected/actual types, candidate fixes. The agent loop (write → compile → read errors →
fix) is a first-class workflow, with a lume agent mode exposing the compiler as a service
(parse, typecheck, query symbols, apply fix-its) over a protocol — LSP for machines.? or todo "reason" leave a hole; the program still typechecks and runs
(the hole panics or asks). An LLM can be asked to fill exactly that hole with the compiler
providing the expected type, in-scope values and the surrounding contracts. Program synthesis
becomes hole-filling under constraints (Hazel + Idris + Copilot).foo gained effect net” rather than 40 changed lines.spec block (contracts + examples + property tests) can exist before
the body. lume synth can ask a model to propose a body that satisfies the spec, and the test
runner + prover check it. The human writes what, the AI proposes how, the compiler judges.type Classifier = model
params: Params # a tree of tensors; serialisable; versioned
forward: fn(x: tensor[f32, batch, 3, 224, 224]) -> tensor[f32, batch, 1000]
model is a first-class type: it has typed parameters, a typed forward function, a schema, an
ONNX/safetensors import/export, and a version hash. You pass it to functions, store it in a
table, test it, ship it in a binary.grad, jvp, vjp, vmap, jit, shard are operators on functions (today shard is implemented (#239), jit specialises away the dispatch (#229), and grad covers + - * if and diagnoses other ops with [N0400] — see below), implemented as IR
transformations by the compiler (Jax’s design, Enzyme/Zygote’s implementation), not a library
with a tape. The design goal is that they work on any pure Lume function with tensor types, including loops and
branches; today symbolic autodiff differentiates only the + - * if fragment and rejects other operators at compile time with [N0400] (#184).tensor[f32, n, 3, h, w] with symbolic dimensions; mismatches are compile
errors; reshape/einsum are typed; broadcasting rules are in the type checker (Dex). The #1
bug class in ML code disappears.for batch in data: params -= lr * grad(loss)(params, batch). No
framework; the compiler lowers the gradient to CPU/GPU kernels through MLIR.kernel fn saxpy(a: f32, x: tensor[f32, n], y: mut tensor[f32, n])
for i in par 0..n # data-parallel; compiler maps to threads/warps/lanes
y[i] = a * x[i] + y[i]
kernel fn compiles to CPU SIMD, CUDA/ROCm/Metal/Vulkan compute, or WASM-SIMD from one source.@schedule(tile=(32,32), vectorize=8, unroll=4) or a
separate schedule for saxpy block. @autotune searches schedules at build time.tensor[f32, n] @gpu), movement is explicit (to(@gpu)), so the
compiler proves there are no accidental host↔device copies.fn coin(bias_prior: Beta) / {prob}
let p = sample bias_prior
observe flips ~ Bernoulli(p)
return p
let posterior = infer coin(Beta(1, 1)) with mcmc(steps = 10_000)
sample, observe, infer under a prob effect: generative models are ordinary functions;
inference algorithms are handlers of the effect (Church/Gen/Pyro, made first-class by the
effect system).rule blocks compiled to a Rete/Datalog engine over tables: business rules, authorisation,
program analysis, symbolic reasoning next to neural components (neuro-symbolic by
construction: a rule can call a model; a model’s output can be a fact).extern llm fn extract_invoice(text: str) -> Invoice / {net, llm}
"""Extract the invoice fields. Dates ISO-8601. Amounts as decimal."""
ensures result.total == result.items.sum(.amount)
Result.test llm extract_invoice with examples/*.txt expect …) and
optimised by the toolchain (DSPy’s compile-the-prompt idea) against the eval set.tables), typed
planning (llm fns), supervision (actors), and lume test evaluating it end to end.The dBase/Clipper/MUMPS inheritance, modernised:
record, table[T], index, relation, query in the core.persist table[Customer] customers at "data/customers"
gives a typed, ACID, crash-safe, concurrent store (an embedded engine in std.data; adapters for
PostgreSQL/SQLite/DuckDB map the same query syntax to their planners).decimal, date, time, duration, money[BRL] as proper types with units.@soa) so query over a million records is vectorised —
the table is the DataFrame, typed.versioned (append-only log + snapshots) — the model-training data
lineage problem and the audit problem solved by the same primitive.fn f() -> T / {io, alloc, net, async, prob, gpu, unsafe, interrupt, realtime, llm} — inferred,
shown at pub boundaries, enforced:
net cannot open a socket. The build
file grants capabilities per dependency (Deno/Austral). Supply-chain attacks become type errors.comptime-evaluable, differentiable,
provable.async is an effect handled by the runtime; sync code calls async
code; no .await noise, no two copies of every library (Koka/Effekt/OCaml 5).interrupt forbids blocking and allocation; realtime forbids unbounded
loops and allocation and lets lume prove compute worst-case execution time for the subset.rc[T]/arc[T]/cell[T] with literal syntax and good diagnostics; cycles detected
statically where possible, weak otherwise.@gc regions: a tracing collector for a region/type (not the whole program) for the
graph-shaped problems where ownership is the wrong tool (compilers, editors, GUI trees,
symbolic AI). Kernels and kernels’ users never pay for it because it does not exist unless
declared.Plus explicit allocators (Zig) everywhere in std, so the same std.collections works in a
kernel with a bump allocator and in a server with a general-purpose one.
lume build --target x86_64-freestanding → a kernel. --target riscv32-none → a microcontroller
firmware. --target wasm32 → a browser or edge function. --target cuda → a kernel for the GPU.
lume0 emit <file.lume> <file.lbe> → dense binary AST serialization (LBE, docs/09-lbe.md; see #206 for the target-triple matrix). Cross-compiling from any host (Zig).lume-os as the long-term proof and testbed: a capability-based microkernel written in Lume
where drivers are Lume platforms, user programs are Lume apps parametrised by the capabilities
they receive (Roc’s split), processes are software-isolated because the compiler proved them safe
(Singularity’s bet, without GC), and the shell is the Lume REPL with tables for the filesystem
and process list (query processes where cpu > 50%). Models run as first-class services
(std.os.model scheduler aware of GPUs).std.nn), an inference server,
and a spiking/neuromorphic simulation library (std.neuro: neurons as actors with logical time,
Lingua Franca style) — demonstrating that the same language expresses a backprop network and a
biologically-inspired one.lume-core: ~30 constructs, a formal semantics (mechanised in Lean), the thing the verifier,
the interpreter, the optimiser and the self-hosted compiler all agree on.query, model, kernel, rule, llm fn, string interpolation,
comprehensions, UFCS — is sugar defined by macros over the core, in the standard library,
readable by users. The language can grow without the core growing (Scheme/Racket’s lesson).Features are table stakes. These are the experience goals that decide whether people love it:
lume new, lume run, lume test, lume fmt, lume doc,
lume prove, lume bench, lume pkg, lume agent. No Makefiles, no CMake, no virtualenvs, no
webpack, no Dockerfiles for dev. Reproducible by default (content-addressed store).null, no data races, no supply-chain surprises, no
silent float money. A Lume program that compiles has a meaning.| Bet | Risk | Fallback |
|---|---|---|
| Indentation syntax for a systems language | Macro-heavy or generated code may prefer braces; copy-paste hazards | Grammar accepts an explicit-brace form that the formatter normalises; both are the same AST |
| Region inference removes most lifetime annotations | Inference may be slow or produce confusing errors on hard cases | Fall back to Rust-style explicit annotations in those functions only; errors suggest them |
| Effects with inference stay ergonomic | Effect rows can get noisy in higher-order code | Effect aliases (/ {io} expands to a named set), inference hides them unless pub |
| MLIR as the main backend | Heavy dependency, slow builds | Cranelift tier for debug/REPL; LLVM-only build option; MLIR only for kernel/tensor paths at first |
@gc regions won’t fragment the ecosystem |
Two memory models in one language has hurt D and Nim | Regions are per-type and never cross a pub API without being visible in the type; std is GC-free |
| LLM calls as language features age badly | Model APIs change monthly | The core only knows “an extern function with schema-driven decoding and an effect”; providers are stdlib handlers, replaceable |
| The whole-stack ambition is too big | Scope creep kills languages | Phases (see roadmap): the core language + tooling must be excellent alone before model/kernel/llm ship; each is a macro library over the core, so they can lag without blocking |
“Lume” — light in Portuguese/Galician; short; .lume files; lumec compiler; lume tool. If a
collision appears (there is a small JS library and a LaTeX package with the name), alternatives
with the same feel: Lúmen, Faro (lighthouse), Ígnis, Aurea, Omega (the author’s
brand). Decide before the first public release, not before.
No Rust, no third language in the loop. The bootstrap strategy is the classic one, chosen so that Lume owns itself as early as possible:
lume0: a disposable interpreter for lume-core + the minimal surface syntax,
written in portable C (no dependencies, builds with any C compiler on any machine, including a
future bare-metal port). It exists only to run Stage 1 once. It is deliberately small (~5–8k
lines), unoptimised, and frozen after Stage 1 runs.lumec written in Lume: the real compiler (parser, type checker, effects,
ownership, Cranelift/LLVM/MLIR backends through a C ABI) written in Lume, interpreted by
lume0 to compile itself the first time. From then on lumec compiles lumec. Stage 0 is kept
in the repository only as the reproducibility root (the “trusting trust” defence: anyone can
rebuild Lume from C).lumec is self-hosted, the language evolves through its own
tooling: proposals are Lume programs that use lume agent (the compiler as a service) to
transform the compiler’s own source, the standard library, or the spec; every proposal must pass
the spec’s conformance suite, the self-build (lumec builds lumec builds lumec — three
stages bit-identical), the verified-core proofs, and the benchmark gates. AI models write
proposals; the gates decide; humans set direction and veto. lume evolve is the command; the
editions mechanism keeps old code compiling. See 04-roadmap.md §Stage 2 for the governance.Order of work:
lume-core (the ~30-construct typed IR) and the Stage 0 interpreter in C.lumec is
written in Lume.table/query (the data story is Lume’s most visible
differentiator), comptime + macros (unlocks everything else as libraries), tensors/grad
(the AI story), freestanding + a toy kernel (the OS story), and lume evolve.