← back

0x0, Technically
Jun 21, 2026

Technically as I see it.

The language looks like a Lisp:

;;; A source contract plus a pure effect boundary.
( examples.add)

(ƒ add
  ( ( I64 I64 I64))
  (cap pure)
  (doc "Return the sum of two integers.")
  (a b)
  (+ a b))

(ƒ main
  ( ( Unit I64))
  (cap pure)
  (_)
  (add 20 22))

The colors here follow the same token families as the project's editor support: comments, strings, numbers, delimiters, keywords, constants, types, functions, and operators.

0x0 is a small symbolic functional kernel whose compiler is written in 0x0 from the beginning. The assembly seed is kept around as a recovery/audit path. The normal point of gravity is compiler/main.0x0.

The project:

compiler/main.0x0 -> stage1.oisa
stage1.oisa      -> stage2.oisa
stage2.oisa      -> stage3.oisa

stage2.oisa == stage3.oisa

That comparison is the self-hosting gate. If stage 2 and stage 3 disagree, the compiler is not actually preserving itself.

That is the part I like.

0x0 starts with the parts almost aggressively: bootstrap boundary, compiler succession, ABI notes, object metadata, linker diagnostics, release hashes, and compatibility gates.

A file is a sequence of parenthesized forms. (⊙ name) declares the module. (ƒ name ...) declares a function. declares a checked source contract. cap declares what kind of effects the function is allowed to reach. doc is source metadata for generated API docs. introduces local bindings. if and do are the control surface.

The current value world is:

The current builtin world is useful but still small: arithmetic, comparison, list operations, text operations, stdin/stdout, argv/env, file read/write, print, and panic.

The type checker rejects malformed function shapes, duplicate declarations, unbound symbols, call arity errors, builtin arity errors, obvious concrete type mismatches, bad if conditions when known, and pure/effect boundary violations.

Local packages are manifest and lockfile backed:

;;; Local package imports resolve through 0x0.lock.
( examples.core_data)
( "pkg:core-map")
( "pkg:core-json")
( "pkg:core-result")

(ƒ main
  ( ( Unit I64))
  (_)
  ( ((m (map-put (map-empty Unit) "base" 35))
      (base (option-value-or (map-get m "base") 0))
      (from-json (option-value-or (json-get-int "{\"n\":7}" "n") 0)))
    (+ base from-json)))

The package layer is a local manifest plus a checked lockfile. That is still useful because it gives imports a stable name before the project grows a registry around them.

The direct ELF ABI uses a payload plus a tag:

rax = value payload
r15 = value tag

0 = Unit / nil
1 = I64 or Bool
2 = NUL-terminated UTF-8 Text pointer
3 = cons/list pointer

Direct ELF output is Linux x86-64 today. It can emit integer/control-flow code, calls, recursion, locals, text operations, list operations, file/stdin/stdout operations, and compiler artifacts. There is also a C compatibility path, a GAS/object compatibility path, a direct object writer slice, an archive writer, a linker, and an optimizer with small verified passes.

It owns enough of the pipeline to make release engineering part of the language design:

So what is 0x0, technically?

It is a self-hosting language kernel where the compiler trust path is the main feature. It is a small source language wrapped around an auditable native toolchain experiment. It is not yet mature enough yet to be your batteries included app stack.

That is the kind of weird I respect.