Status & Roadmap
Lumina is a working language, not a finished one. The core pipeline (source to AST, HIR, MIR, LLVM IR, then JIT or native binary) is green, and every sample on these pages was run with the current compiler. Much of the language already works: the first half of this page lists what you can build on today, the second half what remains.
Status legend
Every open point on the other pages carries one of these tags, linked to its entry below. Anything without a tag works as described.
- implemented Built and working, with no known gap worth naming.
- mostly done Works for the common case. What remains is an edge case or polish, and the entry names it.
- in progress A documented behaviour is missing or works differently, and you can hit it on the main path. The entry says what.
- designed Designed, with nothing in the tree yet. A design that has been dropped keeps this tag and says what superseded it.
What works today
You can build real programs on all of this.
Language core
- implemented Structs with methods, enums with payloads, tuples and destructuring
- implemented Expression-bodied functions, closures, lambdas,
mapandfilter - implemented Template strings with interpolation
- implemented Const by default,
mutchecked at every scope (see Mutability) - implemented Generics compiled per type, with interface bounds and
implementsblocks (see Generics & Interfaces) - implemented Operator overloading with
@Operator - implemented Typed literals such as
42kmand#FF8800via@Literal - implemented Proxies with
@Forward: logging, caching, mocks and stubs - implemented String literals checked at compile time:
jsonand your own@StringDialectvalidators
Types and errors
- implemented
T?with??andif Some(x) = ... - implemented
T!Ewith?andFromconversion; a droppedResultis an error (E2100) - implemented Exhaustive
match(E2011), range and or-patterns - implemented Union types with narrowing
- implemented Contracts:
@Contract.requiresandensures, proven violations rejected (E4011), the rest checked at run time - implemented
panic(msg)with a clean exit that runs the function's@Deferblocks - implemented Reflection through
.reflect
See Errors & Types.
Memory and safety
- implemented Escape analysis to the stack, a generational, concurrently marking GC for the rest
- implemented GC fallbacks reported by
lumina build;--no-gcmakes them errors (E2052) - implemented
@Memory.noAlloc(E2051),@Memory.deterministicand@Memory.stack(E2053), checked transitively - implemented
@Memory.frozenstructs (E2030) - implemented Zero-copy
StringViewandBytesViewthat cannot outlive their source - implemented Moves for resources: use after
takeorsendis rejected (E5106, E5114) - implemented
@Zone(N)bump regions, with escapes to globals rejected (E4016) - implemented Capabilities:
@Capability,@Provide, OS-backed defaults, fakes in tests (see Capabilities) - implemented Algebraic effects with
handle ... with; an unhandled effect is an error (E9003)
See Memory.
Concurrency
- implemented Stackful coroutines,
spawnand explicitawait - implemented
Channel<T>andselectwith timeouts - implemented
Stream<T>,for awaitand generator streams - implemented Cancellation and deadlock detection
- implemented Work-stealing threads with
@Runtime(threads: N) - implemented Two tasks sharing a
mutarray or struct are rejected (E5114, use after send); consuming one through atakeparameter is E5106
See Async.
Tooling
- implemented
lumina run(JIT) andlumina build(native,-O,--release,--emit-llvm) - implemented
lumina verifyin tens of milliseconds - implemented
lumina lintandlumina fixwith--diff,--only,-nand--json - implemented
lumina explain,lumina help --searchandlumina agent-guide - implemented
lumina testwith-f,--watch,--integration,@Skip,@BeforeEach,@AfterEachand@Timeout - implemented
lumina format,expandandinteractive - implemented
lumina newwith app, library, wasm and agent templates - implemented Git packages pinned in
lumina.lock, with capability auditing and ed25519-signed publishing - implemented
lumina lspandlumina dap - implemented Compile errors show a
path:line:colheader, the offending source line with a caret underline, and anexplain:line - implemented
lumina verifyandlumina buildreject a call that leaves out a capability argument (E4008), reported at the call;lumina runprovides capabilities in script mode - implemented A wrong argument type is E4002 in every nested call, including inside a template string
- implemented A failed
assertreports the expression text and the actual and expected values - implemented Excessive expression depth is a located E1028 that counts only real nesting
See Tooling.
Interop and stdlib
- implemented C calls with
@ExternC, audited by@Trusted(W408) - implemented Strings, bytes, JSON, CSV, TOML, XML, crypto, randomness, collections
- implemented TCP with
peekand kernelspliceTo, on epoll and io_uring - implemented HTTP/1.1 servers, WebSocket and JSON-RPC modules
- implemented
@Cacheon free functions - implemented An MCP client
See Interop & Stdlib and Zero-Copy & Servers.
Agents
- implemented Model calls as a typed
Llmeffect, with test handlers that need no network - implemented Agent-written code run through the JIT:
Module.loadSource,module.call,Module.eval - implemented
@Sandboxfunctions andResourceLimitsfor CPU and memory - implemented
ScopedNetworkhost and port allowlists - implemented
runAgent, a tool registry, andrunAgentSeamedfor offline replay - implemented Claude Code skills for the language under
.claude/skills/<name>/(lumina-syntax,lumina-idiomatic,lumina-test)
See Built for Agents.
What remains
Each open point, with the concrete gap. The table is the summary; the entries below give the detail.
At a glance
| Point | Status | What remains |
|---|---|---|
| Stack safety | mostly done | async recursion on the host stack; advisory stack budget |
| Mutable references | mostly done | reassigning a whole struct parameter |
| Compile speed | mostly done | large programs not measured |
| String dialect | mostly done | user grammars, lazy templates |
| Coverage toolchain | mostly done | needs llvm-cov on PATH |
| Purity | in progress | built-ins such as println bypass the check |
| Optional chaining | in progress | a field read on T? is not rejected |
| Contracts | in progress | compound clauses, struct invariants |
| Function wrappers | in progress | @Logged, @Memoize, @Retry inert |
| Await elision | in progress | behind a flag, not the default |
| Preemptive scheduling | in progress | cooperative only |
| CPU-parallel tasks | in progress | opt-in thread count |
| Channel semantics | in progress | struct elements, closed-channel signals, rendezvous, send cases |
| Data-race checks | in progress | captured mut Integer silently copied |
| Move tracking | in progress | plain values usable after send |
| Frozen data | in progress | mutation via calls, collections, closures |
| Deep immutability | in progress | mutation through a mut alias |
| Sharing primitives | in progress | no Lumina type yet |
| Zones | in progress | silent overflow, no budgets |
| Tuple GC layout | in progress | mixed tuples across a GC cycle |
| GC compaction | in progress | behind an environment flag |
| Bounded generics in lambdas | in progress | interface call inside map crashes |
| Derive engine | in progress | derive() not wired |
| FFI gating | in progress | W407 is a warning |
| Regex | in progress | captures, counted quantifiers, replace |
| Runtime modules | in progress | ambient built-ins escape the grant |
| Sandbox tiers | in progress | Module.load, namespace @Sandbox import |
| Agent harness | in progress | runAgentWith untested |
| Approval gate | in progress | opt-in; no human-facing handler |
| Scoped network | in progress | redirects, wildcards, protocols, ambient bypass |
| Resource limits | in progress | memory-only limit can hang; no wall clock |
| Line numbers on every error | in progress | some codes lack a location |
| Help lines | in progress | generic per code |
| Quiet lints | in progress | false positives; exit status |
| Runtime crash location | in progress | no source location |
| Ambient I/O warning | in progress | built-ins still work without a capability |
| Library template hint | in progress | "Next steps" names a missing file |
| Inferred borrow checker | designed | escape placement in progress; checker is design |
| OS isolation | designed | Landlock, namespaces, hard stop |
| Fix interactive | designed | lumina fix -i not supported |
| Fuzz and Expect | designed | no generated input; @Expect inert |
| Panic boundaries | designed | no @PanicBoundary, no recover |
| Literal validation | designed | no compile-time literal checks |
| String template | designed | no StringTemplate type |
| One effect model | designed | separate systems today |
| Copy-on-write and reference counting | designed | superseded, not planned |
| Zero-copy layers | designed | AF_XDP, sendfile, UDP, stream interfaces |
| Non-Linux event backends | designed | kqueue, IOCP |
| HTTP framework | designed | router, middleware, TLS |
| Unsafe blocks | designed | @Trusted covers whole functions |
| Debug info | designed | -g keeps symbols only |
| MCP server | designed | client only |
| Type system extensions | designed | deferred by design |
| Self-hosting | designed | tools still in Rust |
Mostly done
Stack safety
mostly done Guard pages and stack canaries turn a stack overflow in main or a spawned task into a clean runtime error that suggests @Runtime(stackSize: N). Recursion warnings (W601) and stack estimation exist. Still open: async code that recurses on the host call stack is not intercepted, and the stack budget check (E5110) reports without blocking the build.
Mutable references
mostly done mut-as-reference (ownership phase P1) is on by default: field writes, scalars, String and arrays passed to a mut parameter reach the caller. Still open: reassigning a whole struct parameter (p = Point { ... }) does not reach the caller.
Compile speed
mostly done On small and mid-sized programs turnaround is in Go's range. Large programs have not been measured yet. Indicative wall-clock numbers, taken with a debug build of the compiler on a busy multi-core aarch64 machine (so they lean pessimistic):
| Step | Time |
|---|---|
lumina verify, small file | tens of milliseconds (rustc --emit=metadata on the equivalent Rust file: about a fifth of a second) |
lumina run (JIT), hello world | about 0.1–0.2 s |
lumina run (JIT), a mid-sized example program | about 1 s |
| Lumina warm incremental native build, small program | about 0.3–0.6 s |
Go go build, same programs | about 0.2–0.4 s |
rustc -O, no incremental cache, small programs | about 0.4–0.6 s |
| Cold Lumina build vs cold Go build (including its standard library) | about 6 s each |
On small programs Lumina is in the same range as Go, not measurably faster, and rustc is not slow there either.
String dialect
mostly done @StringDialect works: built-in dialects such as json are checked at compile time (E1112), and a @CompileTime validator defines your own. Still open: user-defined grammars and highlighting, and lazy templates, which need the StringTemplate type.
In progress
Purity
in progress Pure-by-default is the design. Full enforcement is an accepted transition (LANG-PURITY) still in progress: some built-in free functions, such as a bare println, still bypass the purity check.
Optional chaining
in progress ?. chaining is partial. Reading a field straight off a T? without unwrapping is not rejected yet: u = findUser(2) followed by u.name passes verify, and when u is None the program crashes with a segmentation fault.
Contracts
in progress @Contract.requires and @Contract.ensures work on parameters, functions and struct fields: a violation provable at compile time is E4011, the rest panic at run time. A compound clause such as a > 0 && a < 10 is not checked at run time, and a struct-level @Contract.invariant is accepted silently but never enforced.
Function wrappers
in progress @Cache works on free functions. @Logged, @Memoize and @Retry (outside tests) are accepted but have no observable effect. User annotations are an @Annotation interface plus an @AnnotationHandler, gated behind import from "lumina.meta". What remains is the transform dispatch: ctx.wrap and ctx.insertBefore rewriting is designed, and @! is validated but rewrites nothing. The old @Decorator marker is deprecated and its removal is tracked as part of this work. @Memoize under @Provide is a DI factory cache, not a function cache.
Await elision
in progress Explicit await is the default. Await elision (the colorless form) works behind lumina run --await-elision=on; making it the default needs deterministic ordering and async stack traces first. Overlapping un-awaited calls and spawning them automatically are further experimental switches.
Preemptive scheduling
in progress Tasks are cooperative, not preemptive. A loop that never awaits can starve its worker.
CPU-parallel tasks
in progress With @Runtime(threads: N) on main, spawned CPU-bound tasks run in parallel on a multi-threaded work-stealing runtime. Parallelism is opt-in: without a thread count the runtime stays on one thread unless tasks hand values to each other through channels, so CPU-bound tasks run one after another. The goal is a sensible default thread count so spawn uses all cores without an annotation. I/O-bound concurrency works either way.
Channel semantics
in progress for v in ch works for scalar elements but is broken for struct elements: a String field comes back as garbage. A receive on a closed channel returns -1, ambiguous with a real value (no v, ok form). A send on a closed channel returns -1 silently instead of failing loudly. Capacity-0 trySend buffers one item, so an unbuffered channel is not yet a true rendezvous. select has no send cases, and directional Sender<T>/Receiver<T> types are missing (ch.sender() is rejected with E6001).
Data-race checks
in progress Two tasks capturing the same mut array or struct are rejected (E5114, use after send), and consuming one through a take parameter is E5106, but a mut Integer captured by two task lambdas is silently copied, so their writes are lost without a diagnostic.
Move tracking
in progress Moves and use-after-move are checked for resources and take parameters; plain structs and arrays are copied, so using a value after sending it on a channel is accepted. Conditional (per-path) move tracking and move-on-mutable-capture are design.
Frozen data
in progress @Memory.frozen covers direct construction and frozen-typed parameters. Mutations through call results, collections and closures are not detected yet. Deep const is a conservative syntactic check.
Deep immutability
in progress Immutability is enforced on the binding. If two bindings refer to the same heap value, that value can still be mutated through a mut alias. Until deep immutability lands, use @Memory.frozen for data that must never change; ROADMAP.md tracks the remaining facets.
Sharing primitives
in progress Guarded<T>, Atomic<T> and Snapshot<T> are the designed way to share mutable state between tasks. Runtime support for guarded and snapshot values exists in runtime/src/, but no Lumina type exposes it yet.
Inferred borrow checker
designed Escape-driven stack-versus-reference placement (ownership phase P2) is in progress, and the inferred borrow and exclusivity checker (P3) is design.
Zones
in progress @Zone(N) works. When the region overflows, allocation falls back to the heap silently: there is no ZoneOutOfMemory, and the budget form @Zone(budget: .hard(5.mb)) does not parse. A zone struct passed as an argument only draws a warning (W302).
Tuple GC layout
in progress Tuples mixing references and values that survive a GC cycle are a known bug and need a per-slot-tagged layout.
GC compaction
in progress A handle table and sliding compaction exist, but only behind LUMINA_GC_HANDLES=1; the default path uses raw pointers.
Bounded generics in lambdas
in progress A lambda that calls an interface method on a bounded generic inside map (items.map(i => i.describe()) where items: Array<T>) fails at run time; a for loop works. A bounded generic function can also print a stray [codegen] debug: line to stderr during compilation; the program output is unaffected.
Derive engine
in progress .reflect metadata works on structs and enums. The implements-triggered derive() is not wired end to end.
FFI gating
in progress W407 (FFI without a capability) stays a warning in every mode. Making it an error for non-trusted code is a top roadmap item.
Regex
in progress Matching works. Capture groups, counted quantifiers and replace are missing.
Agents and sandboxing
Runtime modules
in progress Module.loadSource(src, caps:), module.call and Module.eval compile and run Lumina source at run time through the JIT. A module that names a capability it was not granted is refused at load time, but that check is a scan of the source text (src/runtime/capability_detection.rs), not the type system. Ambient built-ins such as read_file, write_file, exec, get_env_value, file_exists and the http_* functions still work inside a module granted nothing; closing this goes with the ambient I/O warning.
Sandbox tiers
in progress @Sandbox on a function works, and @Sandbox import { f } from "plugin" runs, without verified isolation. Module.load(path) does not exist (use Module.loadSource), and the namespace form @Sandbox import plugin from "plugin" fails. @Trusted (C bindings) and @FullAccess (view narrowing) are not sandbox tiers. Capability and limit gaps are under Runtime modules and Resource limits.
Agent harness
in progress stdlib/agent/ has runAgent, a tool registry, and runAgentSeamed, which replays scripted model replies without network access (examples/ai_effects/agent_e2e_flow.lumina). runAgentWith, which calls OpenAI or Anthropic with retry, budget and policy, has no tests yet and is limited by closure and capability gaps.
Approval gate
in progress The Approval effect and guardedAction in stdlib/ai/tool_effects.lumina work, and a missing handler is a compile error (E9003). The gate is opt-in: ambient built-ins bypass it, and no stdlib handler asks a human yet.
Scoped network
in progress ScopedNetwork.allow(hosts:, ports:) enforces its host and port allowlist, runs an SSRF check on every request, and is covered by tests/spec/34_sandbox/. Still missing: the protocols: argument is ignored, a wildcard host matches by substring, redirects are not re-checked against the allowlist, there is no rate limit, and ambient http_* built-ins bypass it.
Resource limits
in progress ResourceLimits runs each module call in a child process with memory and CPU rlimits; no root is needed. Hitting the CPU limit returns an unhelpful error, a memory-only limit can hang, and there is no wall-clock limit. The seccomp filter for the child exists on x86_64 only and is skipped silently elsewhere. cgroup v2 limits and timeouts (src/runtime/cgroup.rs, src/runtime/sandbox.rs) are used only by lumina test (@Timeout, --timeout), not by lumina run, the JIT or native binaries; without a delegated cgroup subtree they fall back silently.
OS isolation
designed Landlock, namespaces and selectable OS isolation levels for loaded modules, a wall-clock limit, and handle.kill() for a runaway call. Today a spawned module call can only be stopped cooperatively with handle.stop().
Toolchain and diagnostics
Issues hit while writing real tools in Lumina are also logged in docs/web/tools/FINDINGS.md.
Line numbers on every error
in progress Most errors carry a location. Some, including E9003, do not; in JSON their line is null. Others, such as E3009, put it only inside the message text.
Ambient I/O warning
in progress Calling an ambient I/O built-in (read_file, write_file, file_exists, list_directory, network_*, exec, getEnv, set_env_var, ...) draws warning W106 that names the capability call to use, for example read_file(path) becomes fs.read(path) with fs: FileSystem, and getEnv(key) becomes env.get(key) with env: Environment. It is a warning, not an error. Exempt: methods of structs that implement a covered capability, and functions marked @Allow("W106", "reason"), which silences W106 for that function only. @Trusted also silences it, but today a @Trusted marker on any function trusts the whole program, so every W106 in it goes quiet. Built-ins whose capability has no method yet draw no warning, and Clock, Random and print built-ins never do. Still open: the built-ins keep working without a capability, and their failure is a runtime error (E7014), not a type.
Help lines
in progress Codes, spans and lumina explain exist. The note: and help: lines are generic per code rather than specific to the mistake.
Quiet lints
in progress W120, W127 and W601 can fire on code that is fine, and lumina lint exits with status 1 even when every finding is only info.
Runtime crash location
in progress A runtime crash prints a long banner and a runtime stack trace instead of the program's own source location.
fix interactive
designed lumina fix -i (ask before each fix) is listed in --help but exits with "not supported yet". Preview with --diff and narrow with --only or -n instead.
Coverage toolchain
mostly done lumina test --coverage runs the tests, but the report needs an LLVM coverage toolchain (llvm-cov) on PATH; without one the report fails.
@Fuzz and @Expect
designed @Fuzz runs a test once, with no generated input. @Expect is accepted and has no effect. Relatedly, @Timeout limits CPU time, not wall-clock time.
Library template hint
in progress lumina new -t library creates src/lib.lumina, but its "Next steps" line says to run src/main.lumina, a file that template does not create.
Designed, not built
Panic boundaries
designed @PanicBoundary is rejected (E2001) and there is no recover: a panic always ends the program. Only the panicking function's @Defer blocks run; a caller's @Defer does not.
Literal validation
designed @Literal suffixes and prefixes work, but validating a literal at compile time does not: a @CompileTime fromLiteral that calls compileError fails (E6003, then E3002). Built-in literals such as 500ms and 2GB are plain integers (nanoseconds, bytes) and print as such.
String template
designed A StringTemplate type for lazy and callable templates. Backtick strings interpolate eagerly, and StringTemplate is an unknown type (E2007).
One effect model
designed Capabilities lowered to inferred effect rows, T!E as the Error effect, async as the Suspend effect, @Provide as the default handler. Today these are related but separate systems, and Language_Effects.md describes what is real.
Copy-on-write and reference counting
designed Superseded by the mut-as-reference ownership model, and not planned. Nothing is refcounted and no value is copied lazily. Pluggable, Lumina-authored GC selection is likewise design history; the GC is a fixed Rust runtime.
Zero-copy layers
designed AF_XDP kernel bypass, sendfile, UDP and Unix sockets, and PeekableStream/SpliceableStream interfaces with composable decorators. Today peek and spliceTo are methods on TcpSocket (see Zero-Copy & Servers).
Non-Linux event backends
designed kqueue (macOS) and IOCP (Windows). Networking runs on epoll and io_uring on Linux.
HTTP framework
designed A router, middleware and TLS in the standard library. Servers speak raw HTTP/1.1 today.
Unsafe blocks
designed unsafe blocks for local, auditable escapes. Today @Trusted marks a whole function.
Debug info
designed Source-level debug info (DWARF line tables) for Lumina code in native builds. -g currently keeps the symbol table only.
MCP server
designed An MCP server for the toolchain. An MCP client exists in stdlib/mcp/.
Type system extensions
designed Deferred by design: where clauses, variance, higher-kinded types, newtype, timeout expressions. where clauses already parse, but their constraints are not enforced; put bounds inline (<T implements X>).
Self-hosting
designed The formatter, explain and the warning system written in Lumina itself. Parser combinators and @StringDialect are already in place.
Where to get the real numbers
These pages deliberately carry no test counts or percentages, because those go stale with the next commit. The sources of truth live in the repository:
cargo run --bin lumina_analyzemeasures spec compliance and names the highest-leverage next goal.--transitionslists accepted language changes that are still pending.--gapslists confirmed bugs, each registered as a failing probe.FEATURE_STATUS.mdgives the per-area picture: what exists, what is partial, what is planned.ROADMAP.mdholds the priority ladder, the four learning tiers and the sequenced plan.cargo nextest run --no-fail-fastgives the test ground truth.
Where it is heading
The priority ladder in ROADMAP.md, roughly:
- Make "always async" true by default: stabilize await elision and add effect-inferred async.
- Harden stack safety so cooperative coroutines can compete with Go's scheduler.
- Close the FFI hole: W407 becomes an error for non-trusted code, and the stdlib's C bindings move behind capabilities.
- Developer experience: a quickstart path, better error text, more LSP code actions.
- Progressive disclosure: a T0 script tier with zero annotations, a T1 app tier built on five core annotations, and deeper power behind import walls you can grep for.
The guiding goal is TypeScript's ergonomics with Rust's correctness at native speed. Where today falls short of that, FEATURE_STATUS.md and ROADMAP.md say so plainly, and this page does the same.
Next: Overview