A programming language where humans and AI reason together about programs.
R7RS Scheme · LLVM bitcode · fully self-hosted
The problem with vibe coding isn’t the vibe — it’s the code.
When you ask a model to generate code in a language that resists clean abstraction, you get code that resists understanding. Not because the model failed, but because the language offers no tools for transparency. The generated code is opaque by nature: you can read it, but you cannot reason about it without re-deriving every implicit assumption the language makes.
Scheme is different. Its macro system makes program structure explicit — any expression can be mechanically expanded to a small set of well-understood primitives. There is no hidden compiler magic, no implicit transformation you have to take on faith. Vibe coding with Scheme is a more powerful experience because the language itself is designed for the kind of transparency that human–AI collaboration demands.
R7RS Small Scheme via macro expansion.
Every language feature that can be a macro must be a macro.
Only an irreducible set of primitive forms (define, lambda,
if, set!, quote, define-syntax)
are implemented natively. Everything else expands to those primitives through
well-defined, inspectable transformations.
Binding registry with human-language descriptions. Every binding in a Vibe program — every function, variable, macro, and type — is paired with a plain-language description of what it does. An LLM introspects a program by combining macro expansion (to see structure) with registry lookup (to see meaning). No “trust the code” — understand the code.
Together, these goals close the loop: macros make programs structurally transparent; the registry makes them semantically transparent. Structure all the way down, meaning all the way up.
User Programs ───────────────────────────────────── Standard Library (R7RS 6.x) ───────────────────────────────────── Derived Forms via Macros let, cond, and, or, begin, do, ... ───────────────────────────────────── Primitive Forms define, lambda, if, set!, quote ───────────────────────────────────── Kernel DSL (llvm:*) llvm:define-function, llvm:call, ... ───────────────────────────────────── LLVM Bitcode ───────────────────────────────────── Native Machine Code
Each layer is built entirely from the layer below it. The kernel DSL is the trusted core — the only code that must be understood by reading its implementation rather than its expansion. Everything above is transparent by construction.
Scheme today:
define (variables and procedures, with docstrings, mutual recursion and forward
references), if, set!, quote (interned symbols, cached list
literals), and calls to runtime builtins — enough to compile
(define (fib n) …) (exit (fib 10)). These are a
lowering pass, not a second language tier: Scheme S-expressions are rewritten
into llvm:* S-expressions in the same representation, and
--emit-lowered prints exactly what the code generator consumes.
There are no local variables yet — let and friends reduce to
lambda, which is Milestone 2.
Performance:
the compiler links the runtime's IR into your module and runs the LLVM pass pipeline
(-O2 by default), so the explicit boxing that makes lowered output readable
costs nothing in the final binary. Naive fib(36) runs in 0.03s against C
-O2's 0.02s on the same machine — down from 0.39s before the pipeline
existed. That comparison flatters Vibe while Milestone 1 arithmetic skips type checks; a
real numeric tower will reopen part of the gap.
Macro expander today:
syntax-rules with optional literals, multiple clauses,
top-level install-after-expand (e.g. prelude define-vibe-syntax),
nested list subpatterns, and final ... (ellipsis) in patterns and templates.
The kernel prepends shared helpers in macros.vibe: AST access (vibe:ast-ref / vibe:ast-addr),
list construction (vibe:ast-list), null/empty predicates, vibe:node-kind? (including quote wrappers),
lexer token and character literals (vibe:token-lit, vibe:char-eq?, vibe:char-digit?),
and C-style i32 truthiness helpers (vibe:i32-one?, etc.). Large codegen dispatch is still mostly explicit;
further line-count wins now need language features rather than macros — the kernel's 247
hand-encoded byte-array constants, for instance, were removed by teaching
llvm:define-constant to take a string literal, something
syntax-rules cannot do.
Bootstrap seeds are versioned on GitHub Releases; the default seed matches the expander capabilities needed for current main.
Full hygiene and non-final ellipsis patterns are still planned. Hygiene is scheduled
before the derived-form layer, since let, do and
cond's => are exactly the binding macros it protects (see design docs).
vibe_kernel binaries (./build.sh release-seed)