← 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.