mcp server
lova-lang
Every language before it was built for humans to read and learn. LOVA is the first built for AI: programs are integer sequences — 64 one-byte operators, structured faults with repair hints, declared e
Set up
Runs on your computer. Pick your agent and operating system.
Before you start
- uv (`curl -LsSf https://astral.sh/uv/install.sh | sh`)
{
"mcpServers": {
"lova-lang": {
"command": "uvx",
"args": [
"lova-lang"
]
}
}
}same format Cursor, GitHub Copilot CLI, Junie, JetBrains AI Assistant, Augment (Auggie CLI), Factory Droid, Kiro, Devin CLI +12
Values in angle brackets are placeholders. Restart Claude Desktop after editing its config.Claude Desktop docs
README
synced Oct 21, 2026LOVA
English · 中文
A programming language built for AI to write, run and repair.
Site: npcnpc09.github.io/lova-lang — the language in one page, on a field of a quarter million particles (docs/).
Status: 1.0 — the language is complete, and initially usable.
All ten design axioms are realised inside the language and measured by
an experiment. The 64-operator table is spent (63 operators and END):
integers, lists, strings, closures, letrec, loops, error handling
that can catch and raise, programs as values with lineage, populations
that evolve, file / clock / network IO under declared capability
boundaries, and a persistent map. There is a compiler with five static
passes, a type-constrained generator, a standard library written in
LOVA, modules, a CLI, an MCP server for agents, and 1 116 tests. The
reference implementation is a stdlib-only Python interpreter; the
programs run on a native Rust runtime -- a bytecode VM at 10-12
million steps a second, checked against the interpreter step for step
on a golden set of 1 023 records -- which is the default, and the same
runtime loads into Godot 4 as an extension class, so a game's rules can
be LOVA under the engine's own picture. It has no floats, no namespaces
and no concurrency. The "What LOVA still cannot do" section below is
kept honest.
The one-paragraph pitch
Every programming language before it was built for humans -- to be learned by a human, read by a human, reviewed by a human. LOVA is the first built for AI.
LOVA has one goal: an AI uses it more conveniently than any other language. Not denser, not stranger: fewer attempts from writing to running, less context spent on each failure, no scaffolding needed to run the code safely, and code that can be reused, repaired and traced by the program that comes after it. The error model, the contracts, the declared effects, the lineage and the evolution machinery exist for that; the integer encoding underneath is the format and the identity of a program, not the point. AI is the first-class reader, writer, and executor -- and the people who work with it are the second.
Where it stands against that goal
The goal is measured by four numbers, on the same tasks in LOVA and in Python, with fresh model sessions. Where each one stands today:
| number | standing | evidence |
|---|---|---|
| 1. attempts from writing to running correctly | parity on most tasks; behind on search-heavy ones, and closing | Exp 17-20; Exp 31: a step trap now says how many steps the run needs -- 17/18 search faults fixed against 14/18 without it (pilot) |
| 2. context spent on each failure | parity on like failures | Exp 30: the fault is one line -- where, the span to patch, what is wrong -- 193 characters where the structured anomaly was 877; a wrong value 75 against Python's 71 |
| 3. scaffolding to run the code safely | won | a function call under a step budget and a capability boundary, against a subprocess with a timeout |
| 4. reusing, repairing, tracing | repair won at 110-160 lines; reuse and trace unproven | Exp 29 |
And one thing the numbers settled: a current model writes the tree and transcribes it, so the integer substrate is the program's storage, transport and identity -- not a way for a model to think (Exp 24). The language keeps what the numbers support and changes what they do not.
And because it is open source, the language is not anyone's to own. Anyone may extend it, change it, or rebuild it outright -- on the one test that decides everything here: does an AI get more done with it, and get it done more easily.
(defn square [n] (⊗ n n))
(square 7)
...is a Stage-1 projection. The program itself is an integer sequence;
the text is a pretty-printer over it. ⊗ is mul, defn desugars to
let + lambda, and the call desugars to apply — so what the
substrate stores is:
(let 0 (lambda 1 (mul (ref 1) (ref 1))) (apply (ref 0) 7))
Identifiers are interned to integer name ids at parse time and printed back as integers, because the integer is the program (Axiom 1). Every form above compiles to the existing 64 operators; the sugar adds no semantics.
Three stages
| Stage | Surface | Status |
|---|---|---|
| 1 — Text-surface LOVA | Lisp-like s-expressions compiling 1:1 to tokens | current, and now audit-oriented |
| 2 — AI-primary LOVA | one character per byte, no delimiters (core/surface2.py) | surface built and measured (Exp 14); fine-tuned model still M8 |
| 3 — Pure-AI LOVA | no text; programs are integer sequences, humans read via (explain program) | north star |
What's actually implemented
- 64-token core ISA (8 families × 8), 1 byte per operator — 52 operators
have runtime semantics, 12 are reserved (
spec/tokens.md, generated from the table byspec/generate_tokens_md.py) - Data — one cons cell (
nil/cons/head/tail/nil?) gives pairs, lists, and strings as codepoint lists, so"abc"is surface sugar and costs the token table nothing (spec/token-budget.md) - Two surfaces — Stage 1 s-expressions for authoring and audit, and
the Stage-2 projection of the byte encoding for density: one character
per byte, no delimiters, lossless in both directions
(
core/surface2.py) - IO —
stdout/stdin, the first operators that touch the world; the only non-determinism in the language, andstatic_analyzereports it - A standard library written in LOVA —
lib/prelude.lova:map,filter,fold,range,append,reverse,digits,printlnand the rest, none of them builtins. Free to include: the compiler'sdrop-unusedpass takes a program that calls none of it from 474 nodes back to 1 - A command line —
lova run | repl | emit | analyze | mcp(core/cli.py) - An MCP server —
lova mcpserveslova_execute,lova_static_analyze,lova_valid_nextandlova_emitto any Model-Context-Protocol host over stdio, with no dependency outside the standard library;lova_valid_nextis Axiom 3 as a service (core/mcp_server.py) - One error model, reachable from inside — every fault carries the
same structured anomaly, and
(when-anomaly body handler)hands a program the anomaly's code so it can recover. The substrate's termination ceiling is the one thing a program cannot mask - Populations — Axiom 6 in the language:
(defpop scorer p1 p2 …)builds a pool,(evolve pop)runs a generation with the same rule the Python engine used,(select pop 0)is the fittest, and the winner can say where it came from. Exp 15 re-runs the self-healing experiment as one LOVA program - Programs as values —
quote/eval, and the whole Meta family:(explain p)renders a program as text,(hash p)gives its integer,(why p)/(lineage-query p)/(ancestor-of a b)ask where it came from,(clone p)/(mutate p 30)derive one and record how, and(read text)isexplain's inverse, so a program can build a program from text andevalit. Axiom 5 is now true inside the language, and Stage 3'sexplainexists - The world, declared —
(boundary "fs-read clock" body)says which effectsbodymay use;fs-read/fs-write/clockare the effects. The compiler refuses a use outside a boundary that declares it, the runtime refuses a boundary the host did not grant (lova run --allow fs-read,clock), nothing is granted by default, and a generated program cannot use the world without declaring it. The network isnet-send/net-recvover UDP datagrams: the program declares the kind, the host names the places (--allow net=host:port,net=:port). Axiom 4, for effects that touch the world - A standard library a program can stand on — lists that iterate
rather than recurse (
len/map/filter/fold/sort/take/zip...), text (words/lines/split/join/parse-int/text-of), a persistent map (map-put/map-get/map-pairs, keys integers or text), andsignalso a library can raise the structured anomaly its callers can catch.apps/wordfreq.lovais the acceptance program (M22) - Libraries —
(use "evolution")includeslib/evolution.lova, where a custom evolution rule is nine lines over the six Evolution operators;(use "prelude")is the standard library, loaded by the CLI by default. Inclusion is textual, once, and free afterdrop-unused - Abstraction — unary closures with currying,
letrec, and a loop combinator, so recursion and unbounded iteration are expressible. Two always-on ceilings (MAX_CALL_DEPTH,MAX_STEPS) turn non-termination into a structured anomaly rather than a hang (core/runtime.py) - Type-directed generation — for any partial program the set of
well-typed next tokens is computable, so ill-typed programs are not
representable (
core/types.py,core/generator.py) - Conservation as a type — budget/effect bounds live in the signature;
violations are compile errors or runtime Δ-traps (
core/conservation.py) - Surprise instead of stack traces — deviations surface as structured
anomalies; the Δ-trap scanner pinpoints the deepest offending
sub-expression and the correction value (
core/runtime.py) - Lineage — every artifact carries provenance, queryable in-language
(
core/lineage.py) - Populations — a function is a pool of competing variants, not a
single definition (
core/populations.py) - Compiler — scope-check, type-check, constant-fold passes; compile
errors share the runtime anomaly schema so an agent has one error
handler (
core/compiler.py) - LOVABench — 60 tasks / 180 cases across 5 categories, with a
reference evaluator (
corpus/). Note: every task predates M9, so none of them exercises recursion or iteration (Q33).
Quick start
Requires Python ≥ 3.10. The core has no dependencies, so it also
runs under PyPy. With Rust installed, cargo build --release in
native/lova-rt builds the native runtime -- 10-12 million steps a
second, twenty times CPython -- and lova run uses it by itself for every program it
implements (--native off for the Python runtime, --native on to be
told why it could not be used): the same values, the same anomalies,
the same step counts, checked record by record against
corpus/golden/. The compiled program is cached under $LOVA_CACHE,
or %LOCALAPPDATA%\lova\cache on Windows and ~/.cache/lova
elsewhere, keyed by the source, the libraries it uses and a hash of
the implementation, so a second run of a program that pulls in one of
the 3D libraries skips a parse that costs one to two seconds;
LOVA_CACHE=off disables it.
git clone <this-repo> lova && cd lova
export PYTHONPATH="$PWD"
# run a program
python -m core.cli run apps/is_prime.lova 1999 # => 1
python -m core.cli run apps/palindrome.lova racecar # => 1
python -m core.cli run apps/palindrome.lova 's="7"' # a quoted argument is a text, even "7"
# play noughts and crosses against a negamax that never loses
python -m core.cli run apps/tictactoe.lova 0
# run untrusted programs, one per line, under a budget; report each by name
python -m core.cli run apps/sandbox.lova 5000 < programs.txt
# evolve a pool of programs toward a target and ask the winner why it exists
python -m core.cli run apps/evolve.lova 42 60
# repair a program that violates its contract, guided by surprise
python -m core.cli run apps/repair.lova 42 30 200
# a Python web shell whose only decision is a LOVA rule you can edit and break
python apps/shell/policy_app.py # http://127.0.0.1:8765
# tank battle: the window is Python, every rule of the game is LOVA
python apps/tanks/tank_game.py # arrows move, space fires
python -m core.cli run apps/tanks.lova 7 # the same game, turn by turn in the terminal
python apps/g2048/game2048.py 7 # 2048, ported from gabrielecirulli/2048
python apps/platformer/platformer.py # Kenney's 3D platformer kit, ported out of GDScript
python apps/fps/fps.py # Kenney's FPS kit: two blasters, four flying enemies
# the two kits above draw in an SDL window when pygame is there
# (`pip install pygame` for the smooth window; Tk is the fallback, and
# `--host tk` / `--host sdl` chooses. `--bench N` prints frame times)
python apps/godot/fps/build.py path/to/Starter-Kit-FPS --run # the FPS kit's rules inside Godot
# an interactive session, with the standard library loaded
python -m core.cli repl
# see a program as the Stage-2 surface, as bytes, or as one integer
python -m core.cli emit apps/coprime.lova 14 15 --form stage2
python -m core.cli emit apps/coprime.lova 14 15 --form int
# what will this program do, without running it
python -m core.cli analyze apps/collatz.lova 27
# run the examples a program declares about itself
python -m core.cli check apps/tictactoe.lova 0
# run the test suite (1 116 tests, stdlib unittest only)
python -m unittest discover -s tests
# the same under PyPy, where the whole suite is also expected to pass
pypy -m unittest discover -s tests -t .
# run an experiment
python experiments/experiment_01_hello_lova.py
# the per-app Python drivers still work, and print the whole pipeline
# (parse → analyse → compile → encode → evaluate)
python apps/is_perfect.py 28
Or install it — the wheel ships the core, the LOVA libraries and the
corpus, and puts a lova command on the path:
pip install .
lova run apps/is_prime.lova 1999
Give it to an agent
lova mcp speaks the Model Context Protocol on stdin/stdout. Any MCP
host — Claude Code, Claude Desktop, Cursor — gets four tools: run a
program (with explicit capability grants), analyse one without running
it, ask which tokens may come next in a partial program, and project a
program into Stage 2 / bytes / one integer. A failure comes back as one
line -- stage, kind, line:col, the [start,end) span lova_patch
takes, the text there and what is wrong, and for a step trap how many
steps the run needs; report: "full" returns the whole structured
anomaly.
{"mcpServers": {"lova": {"command": "lova", "args": ["mcp"]}}}
From a checkout without installing: "command": "python", "args": ["-m", "core.cli", "mcp"], "cwd": "/path/to/lova-lang".
apps/mcp_demo.py drives the server through its pipes and calls each
tool once.
All 14 experiments run. Exp 03 and Exp 07 had been dead since the corpus grew from 20 tasks to 60; they were fixed at M13 and their numbers below are the 60-task ones.
Experiment 11 additionally needs tiktoken:
pip install -e ".[experiments]"
What the programs show
Twenty-three programs in apps/, each written to use the language for
something and kept as a test. What they demonstrate:
-
It runs a game. Tank battle, in real time: eight enemies arrive along the top of the grid, wander until they see you or your base down a clear line, and shoot. Every rule -- movement, walls a bullet breaks, the enemies' aim, spawning, the win -- is
lib/tanks.lova, about 250 lines of pure functions over one world record, carrying eighteen examples of itself thatlova checkruns. The window is tkinter and owns nothing but the pixels and the keys: ten times a second it hands the LOVA program the world and the key you hold, gets the next world back, and paints it. A turn costs about 10 000 steps under a budget of 200 000, shown in the corner, and a rule that ran away would be a structured anomaly on the screen rather than a frozen window. The same rules play turn by turn in a terminal.python apps/tanks/tank_game.py # arrows move, space fires, R restarts python -m core.cli run apps/tanks.lova 7 # the terminal -
It ports someone else’s game, and proves it. 2048, after gabrielecirulli/2048 (MIT):
lib/g2048.lovawas written against the original’sjs/game_manager.js— the same traversal order, the same farthest-position walk, the same rule that a tile made this move cannot merge again, the same score, the same nine-in-ten chance of a two. The claim that a port behaves like its original is not made in prose:tests/test_2048.pyholds a transliteration of the original in Python and runs both over random positions, comparing the board cell by cell. 10 000 positions, no disagreement. One difference on purpose — the original’s chance isMath.randomand cannot be replayed; here the generator is threaded through the world, so a seed is a game. The port also found a real bug in our own compiler, in whatdrop-unuseddoes with a binding kept for its effects.python apps/g2048/game2048.py 7 # the window, in the original's colours python -m core.cli run apps/g2048.lova 7 # the terminal -
And a 3D platformer, ported from Kenney's starter kit.
lib/platformer.lovaholds the rules of KenneyNL/Starter-Kit-3D-Platformer (MIT, about 1 200 stars), written against its GDScript: the character that walks, jumps twice and squashes when it lands, the coins that bob and spin, the platforms that give way, the bricks broken from below, the camera that follows, turns and zooms, and the fall off the world that starts everything again — every constant the kit's own.lib/scene3d.lovaputs the kit's models into one picture under a camera that moves: forty-six objects placed, turned, tilted, culled and lit, about 4 000 LOVA steps a tick and 150 000 a frame. The models and the level are the kit's, read out of its.glbfiles and its scene byapps/platformer/import_kit.pyand decimated to a budget each with the paint kept where it was.tests/test_platformer.pytransliterates the kit's five scripts and runs them beside the port one tick at a time over a scripted play: every position within four thousandths of a metre, the same coins taken, and the fall off the world on the same tick.python apps/platformer/platformer.py # WASD, space, arrows, +/- python apps/platformer/platformer.py --shot out.png # one frame, no window -
And a first-person shooter, from Kenney's FPS starter kit.
lib/fps.lovaholds the rules of KenneyNL/Starter-Kit-FPS (MIT, about 1 000 stars): a player who walks at five, jumps twice, looks with the mouse and fires two blasters whose cooldown, spread, shot count and knockback are the kit's own resources; four flying enemies that hover on a cosine, turn to face him and fire a five-metre ray every quarter second; a ray test against spheres and boxes in integers; a fall off the world that starts again. The picture is seen from the eye:lib/scene3d.lovagained a first-person camera, and the weapon is held where the kit's second camera holds it, by the ratio of the two fields of view.tests/test_fps.pytransliteratesplayer.gd,enemy.gdand the two weapon resources and runs them beside the port for 642 ticks of a scripted play -- walking, looking, jumping the gap, emptying both blasters into an enemy, taking fire, sliding along a wall, falling off: the same position within four thousandths, the same yaw, pitch, health, cooldown and enemies, tick for tick. On the native runtime a tick is 2 ms and a frame 8 ms, and the SDL window holds 60 frames a second (apps/fps/README.mdhas the table); a run on both runtimes draws the same picture to the byte.python apps/fps/fps.py # WASD, space, mouse, E, left button python apps/fps/fps.py --shot out.png # one frame, no window -
The same rules, inside Godot.
native/lova-godotis the native runtime as a Godot 4 extension class, andapps/godot/fpsis the kit's own Godot project withplayer.gdandenemy.gdreplaced by scripts that calllib/fps.lovaonce a physics tick and put the answer into the kit's nodes. Godot draws its own scene -- the sky, the models, the muzzle flashes, the impact sprites, the HUD -- and LOVA decides everything that happens in it, in 0.6 ms a tick. A seven-second recording (with the sound), made bybuild.py --movie, shows the demo walk in, look round and take three of the four enemies with both weapons; the corner reads the rules' cost every tick.cargo build --release --manifest-path native/lova-godot/Cargo.toml python apps/godot/fps/build.py path/to/Starter-Kit-FPS --run # play it python apps/godot/fps/build.py --movie=demo.mp4 # record the demo -
Logic runs right the first time. The word count, the games, the log summary, the batch, the sandbox: every program's logic produced the correct result at its first execution. Errors, when they came, were caught at compile time with a repair hint, or reported at run time as a structured anomaly, never as a crash or a traceback.
-
Failure is data. The sandbox runs untrusted programs, one per line, and reports each by hash and value or by the name of its fault: an infinite loop meets its
budget, a file read meets the boundary it did not declare, text that is not a program is said to be one. Nothing reaches the sandbox, and the sandbox needs no grant. -
Contracts are the program's own. The batch gives each job its own budget and counts the jobs that exceeded it; the repairer states a
conservecontract and mutates the patient until it holds, keeping only mutations that shrink the surprise. 219 of 300 jobs finish under budget, exactly as an outside computation predicts; three repair targets converge in 39, 37 and 20 attempts, reproducibly. -
Provenance is queryable from inside. The evolved winner and the repaired program each print their text, their generation, why they exist and the length of their descent, with no help from Python.
-
The world is declared. Two processes exchange datagrams, a file is read, the clock is consulted, each under a boundary that names the kind of effect while the host names the places. A program that did not declare an effect cannot reach it, and the compiler says so before the run.
-
Programs are integers. Every one of the programs, re-run from its Stage-2 projection, gives the identical output and value, the 3 000-character game included.
-
A model writes it from one page. A fresh Claude session given
corpus/language_card.mdand the 80 tasks of LOVABench v3, one answer each and no execution, wrote 79 of 80 correct, exactly its score in Python on the same tasks; the algorithmic category was 20 of 20 in both. The language costs a model nothing to write, and gives its programs contracts, budgets and structured faults Python does not have (journal/experiment_17.md). -
A model fixes it from the fault. In a loop where a fresh session runs its code and reads what came back, ten tasks with loops, lists and text: all ten correct in both languages, LOVA in eleven submissions, Python in ten. The one LOVA miss came back as a compile fault with the excerpt, the line, and the replacement to write; the next submission passed. The LOVA answers ran as a function call under a budget with nothing granted; the Python answers needed a subprocess and a timeout (
journal/experiment_18.md). On eight bigger tasks with three sessions per language, every compile fault a session met was fixed at its next submission, and the sessions called the diagnostics "excellent"; a step budget now reports which functions it went to (journal/experiment_19.md). -
It runs anywhere Python does, and fast where Rust does. The core has no dependencies, so the same programs run under CPython and PyPy, and the test suite runs on both; the native runtime runs the same byte sequence at 10-12 million steps a second and inside Godot.
-
Text is a value. A string literal is one node;
words,split,join,parse-intand the rest are one operator each; a word count of 10 000 lines runs in 5.5 s on CPython where it took 28 (M25). -
A fault says where, and a fix is a patch. Every anomaly carries the source span of the expression at fault and its text; the MCP server's
lova_patchreplaces that span -- or a text inside a named def -- and checks the result. A failedexamplenames the single edit that makes it pass, with the replacement. The loop an agent runs is execute, patch, execute, and a fix costs the size of the fix. -
A program answers questions instead of being read.
lova_showgives one def by name with its span and parameters,lova_scopewhat is bound at a point,lova_callerswho calls whom -- so an agent reads the def it asked about, not the file. -
What the programs found was fixed the same day. Writing them surfaced four edges -- in input, in self-reference, in program ids, in arguments -- and each became a compile-time check, a prelude function or a command-line form before the day ended, with a test for every shape. The journal keeps the record.
Where LOVA fits
Every language has a place. Python is the glue and the notebook, Rust the systems layer, JavaScript the browser, Erlang the switch that never goes down. LOVA's place is code that an AI writes, a machine runs, and a person need not read: the small programs agents produce all day, the rules and policies a system lets its users or its models change, the routines a long-running service tunes by itself. What it gives that place is a set of guarantees no general-purpose language carries.
Against other languages
| What a program gets | Python | Rust | Haskell | Clojure | Unison | LOVA |
|---|---|---|---|---|---|---|
| Faults as structured data, not text | – | partly | partly | – | – | yes |
| Ill-formed programs unrepresentable to a generator | – | – | – | – | – | yes |
| Effects declared by the program, granted by the host | – | – | typed | – | partly | yes |
| Every run bounded (step and depth ceilings) | – | – | – | – | – | yes |
| Cost contracts inside the program | – | – | – | – | – | yes |
| Programs as first-class data | – | – | – | yes | yes | yes |
| Provenance queryable from inside | – | – | – | – | partly | yes |
| A function as an evolving population | – | – | – | – | – | yes |
| Repair guided by the program's own deviation | – | – | – | – | – | yes |
| Zero dependencies, one core on CPython and PyPy | core | – | – | JVM | runtime | yes |
How LOVA does each, in the order of the table:
- Every fault carries a kind, a position path and a repair hint, at
compile time and at run time alike;
when-anomalylets a program catch its own and branch on the code. valid_nextgives the legal next tokens at every step, so a generated program cannot be syntactically or scope-invalid.(boundary "fs-read" ...)declares the kind of effect,--allownames the places; an undeclared effect is a compile error.- Step and depth ceilings are built in: a loop that never ends is a structured anomaly, never a hang, and a run over budget names the functions the steps went to.
(budget n ...)per call, per job, per untrusted line; the program catches its own overrun.quote,eval,read,explain,hash: a program is one integer, and a value the language handles.why,generation,lineage-queryare operators; the record is in the value, not in a side channel.defpop,evolve,select: the winner explains its descent.conservestates the contract,surprisemeasures the miss,mutateproposes; three targets repaired in 39, 37 and 20 attempts, reproducibly.- The core is stdlib-only; the 1 116-test suite runs on both interpreters.
And the measurement behind the claim that it costs a model nothing: a fresh Claude session given one page of LOVA wrote 79 of 80 benchmark tasks correctly, single-shot, exactly its score in Python.
The nearer neighbours are the embeddable, sandboxed rule languages -- Starlark, CEL, Lua with an instruction hook, WebAssembly with fuel -- which share the bounded run and the host-granted world. What LOVA adds over them is the rest of the table, and a fault written for a model to act on: one line that says where, what, and how far over budget.
Three of these exist elsewhere, scattered: effects in types (Haskell, Koka), code as data (Lisp, Unison), a system that heals itself (Erlang). None of them has all three, and none has the other seven. LOVA is the language where they meet, in 64 operators.
Scenarios
The agent's sandbox. An agent that works needs to compute
constantly -- a sum, a transform, a check -- and today it writes Python
into a container. In LOVA the program cannot hang, cannot touch a file
or the network it did not declare, and reports every failure as data.
apps/sandbox.lova runs untrusted programs one per line, under a
budget, reporting each by digest and value or by fault name, and is
itself twelve lines of LOVA needing no grant. The MCP server (lova mcp) serves this to any host.
The rule layer of an application. Interface, storage and network
in the language you already use; the one piece that decides -- a
pricing rule, a policy, a user's or a model's script -- in LOVA, edited
live, run under a budget with no capability, and unable to hurt the
application that hosts it. apps/shell/policy_app.py is a Python web
shell whose only decision is a LOVA rule you can edit and break in the
browser; apps/tanks/tank_game.py is a tank battle whose every rule --
movement, bullets, the enemies' aim, the win -- is lib/tanks.lova,
called ten times a second from a Python window that owns nothing but
the pixels and the keys.
Generated code that must be auditable. A program is an integer
that carries its lineage: which model, when, from which parent, why.
apps/repair.lova and apps/evolve.lova print the descent of the
program they produced. Where AI-written code has to be traced before it
ships, the record is in the value, not in a side channel.
Routines that tune themselves. A service's heuristics -- retry
policy, ranking weights, thresholds -- as a defpop population:
variants compete, losers retire, winners are cloned and mutated, and
every version can say why it exists. The contracts (conserve,
budget) bound what evolution may do.
A target for constrained decoding. For a smaller or on-device
model that must emit code that compiles, valid_next is the grammar:
at every step, only the legal tokens are offered. The fine-tuning corpus
(corpus/finetune.py, 3 000 verified pairs) and the one-page language
card are ready.
What LOVA is not for: interfaces, graphics, real-time input, floating point, or code a person will maintain by hand. Those are the trades it made for the guarantees above.
Measurements
All numbers come from journal/; each links to a reproducible script in
experiments/. These are research-scale results, not benchmarks with
statistical guarantees — sample sizes are stated for each.
| Metric | Result | Source |
|---|---|---|
| pass@1, same tasks & same LLM | LOVA 60/60 vs Python 59/60 | Exp 07 (LOVABench v2, 60 tasks, single run) |
| test cases passed, same comparison | LOVA 180/180 vs Python 177/180 | Exp 07 |
| Raw byte density vs Python, number-theory tasks | 25.8× | Exp 07 (v1's 20-task slice reported 39.2×) |
| LLM-token density vs sympy-Python, number-theory tasks | 2.0× (50% fewer tokens) | Exp 11b (LOVABench v2, 60 tasks, tiktoken cl100k_base) |
| LLM-token density vs pure Python, number-theory tasks | 8.5× | Exp 11b |
| LLM-token density vs Python, algorithmic tasks — Stage 2 | 1.13× (denser) | Exp 14 |
| ...same tasks, Stage-1 s-expression surface | 0.66× — Stage 1 costs 1.5× MORE | Exp 12 |
| LLM-token density vs sympy-Python — Stage 2, LOVABench v2 | 5.38× | Exp 14 |
| Stage-2 surface losslessness | 2150 / 2150 round-trips exact | Exp 14 |
| Byte density vs Python, algorithmic tasks | 1.19× | Exp 12 |
| Tasks needing recursion/iteration that LOVA can express | 44/44 cases (0/10 before M9) | Exp 12 |
| Algorithmic density gap closed by operator spelling alone | 30%, for zero token slots | Exp 13 |
...by adding lt and sub as primitives | 9%, for 2 slots — so they shipped as macros instead | Exp 13 |
| ...residual, unreachable by any token-table change | 61% (s-expression syntax) | Exp 13 |
| Runaway programs producing a structured anomaly | 5/5, all with the full L2 schema | Exp 12 |
| Unbound references in generated programs | 248/1000 → 0/1000; runnable 29% → 38% | Exp 16 (scope-aware generation, M17 re-run) |
| Self-healing, written as a LOVA program | 9/10 seeds improve, 3/10 converge, best 35 → 1 | Exp 15 (10 seeds × 30 generations) |
| Constant-folding compression | 58.5% fewer nodes, 43.9% fewer bytes | Exp 08 |
| Telemetry-weighted vs uniform sampling | +32 pp pass-without-trap (88% vs 56%) | Exp 10 (N=50, re-run at M16 with scope-aware samplers) |
| Characters a failure costs to read (22 replayed real faults) | full anomaly 877 → one-line fault 193; a wrong value 75 (Python 71) | Exp 30 |
| ...repair with the one-line fault, 15 paired cases (pilot) | fixed 14/15 vs 11/15, 31 attempts vs 41, 7 774 chars read vs 59 585 | Exp 30 |
| Search faults, step trap that says how many steps the run needs (pilot, 18 sessions an arm) | fixed 17/18 vs 14/18, attempts 49 vs 62 | Exp 31 |
What the correctness number actually measures
The 60/60 is real and it is narrower than it looks. LOVABench's tasks were authored in LOVA, and the v2 prompts state the formula outright — "Compute p(tau(sigma(n)))". So what the Claude-as-oracle baseline measures is transcription into s-expressions, not program synthesis. Read it as evidence that the surface is writable by a model, which is worth knowing, and not as evidence that a model can program in LOVA, which it does not show. An algorithmic corpus (Q33) would measure that.
What the density numbers actually measure
Read the two density rows together, because they disagree and the disagreement is the finding.
The 8.5× comes from number-theory tasks where the LOVA program is
(sigma n) — a one-byte built-in — and the Python is an import plus a
sympy call. That comparison credits the language for its standard
library. It is a real and defensible argument for a domain-shaped
operator set, but it is not a measurement of writing programs.
Exp 12 measures ten tasks where neither side has a shortcut and both
have to write the algorithm out: factorial, fibonacci, primality,
Collatz, Euclid's gcd, and so on. There LOVA's Stage-1 surface costs
1.5× more LLM tokens than Python, and the Stage-2 projection does
not rescue it (0.65×) — (merge n -1) is seven tokens where n - 1
is three, and no tokenizer fixes an operator set that spends five AST
nodes on a decrement.
So: LOVA is dense where its built-ins match the task, and less dense than Python for general algorithmic code. Both numbers stay in the table.
Exp 13 then decomposed that gap and found the table was the wrong instrument for it: 51% of the Stage-1 token cost is operator names and 25% is parentheses, so shortening the names closed 30% of the gap for zero slots — three times what the two candidate new operators were worth — and the remaining 61% is s-expression syntax that no allocation of 64 slots can reach.
Exp 14 built the instrument that can reach it. The parentheses were never necessary: the byte encoding has no delimiters, because arity determines structure, so Stage 1 was spending a quarter of its tokens re-stating what the substrate already knew. The Stage-2 surface is the byte sequence written in characters —
Stage 1 (defn square [n] (mul n n))(square 7)
Stage 2 W0\1*LL$A7;
— and it takes algorithmic code from 0.66× to 1.13×, past the 0.76× ceiling the token table could never beat, and LOVABench from 2.00× to 5.38× against sympy-Python. It round-trips losslessly 2150/2150.
So the honest one-line claim is not "8.5× denser". It is: LOVA's Stage-2 surface is 5.4× denser than sympy-Python where its built-ins match the task, and 1.1× denser where they do not. Smaller, and it survives the obvious attack.
One thing this does not show: whether a model can write Stage 2.
valid_next should make it easier than Stage 1 — there are no
delimiters to misplace — but that is untested and is the project's
load-bearing open question (Q47).
Note on honesty: Exp 11's first run on the narrower 20-task set reported 2.5×/13.3×; re-running on the broader 60-task v2 set dropped it to 2.0×/8.5×. The v2 number is the one quoted above. NULL, weakened and — as of Exp 12 — outright negative results are kept in the journal on purpose.
Repository layout
core/ reference implementation (tokens, types, runtime,
conservation, lineage, populations, compiler, telemetry)
spec/ design documents — axioms, token table, paradigm inheritance
corpus/ LOVABench v3 (80 tasks), evaluator, fine-tuning corpus + language card
experiments/ numbered, reproducible validation scripts
journal/ research log — one entry per experiment, NULLs included
apps/ first-class LOVA programs
lib/ prelude.lova — the standard library, written in LOVA
tests/ 1 116 unit tests, stdlib only
native/ the Rust runtime (lova-rt) and its Godot extension (lova-godot)
What LOVA still cannot do
Stated plainly, because the list is short and the omissions are large:
- It is not a data language. The native VM does 10-12 million steps a second and a game's tick in under a millisecond; a word count of tens of thousands of lines is seconds. Millions of lines, or arithmetic that wants a vector unit, are not this language yet (Q76).
- IO is whole values.
fs-readreads a whole file,net-recvone datagram: there are no handles and no streams (Q72). The terminal is ambient rather than declared (Q68). - The core table is full, and the language grows past it. 63 core
operators and
END; the text family (0x40-0x4F, M25, full at M32) was the first addition beyond 64, and the next operator has to displace one of the number-theory family (Q74). - Modules are textual.
(use "name")includeslib/name.lovaonce and transitively, anddrop-unusedmakes it free — but two libraries defining the same name shadow in inclusion order; there are no namespaces (Q50 closed at that limit). - A population is its own value, not a list of programs. That
sidestepped parameterised lists (Q42) for now;
List<T>remains the better long-term shape (Q63). headis checked at run time. A cons cell holds any value — trees and lists of programs are representable since M17 — sohead's result type follows its list, which the checker cannot see. A parameterisedList<T>would recover the static answer (Q63).- Parameters are untyped. The checker infers a function's shape
— arity and return type — from its lambda (M20), so a partial
application or a call result in the wrong slot is a compile error;
but LOVA has no parameter annotations, so a parameter misused inside
a body is caught where its value is used, at run time (Q43). The
generator still works at the
Fnlevel (Q71). - Generation cannot reach mutual recursion. Since M16 the
generation state machine keeps scope, so an unbound or wrongly typed
reference is unrepresentable in a generated program (Exp 16: 704/1000
→ 0). But a left-to-right machine cannot name something bound later,
so a mutually recursive
defchain — legal since M12 — compiles and cannot be generated (Q64).
Reading order
spec/axioms.md— the 10 design invariants and the argument for eachspec/paradigm-inheritance.md— the seven PL trajectories LOVA synthesisesspec/tokens.md— the 64-operator tablejournal/README.md— the experiment logCLAUDE.md— full project orientation (written for an AI session)
Lineage
LOVA inherits its architectural vocabulary — PFS, conservation, lineage, surprise, evolution, Δ-security — from DNA OS v3, a separate (unpublished) research project by the same author. The concepts are shared; the code here is an independent reimplementation, not a fork.
Design philosophy
One goal decides every change: does an AI get more done with it, and more easily? The axioms are means to that goal and yield to it -- since 2026-09-10 the integer encoding, human readability as a non-goal, the 64-slot ceiling and stage coherence (Axioms 1, 2, 8, 10) are design preferences, not vetoes. A change enters with a measured number behind it, whatever it does to the substrate; a feature that no number supports is a proposal, however old its lineage.
There is also no PnL / reward objective anywhere in the language. Users declare their own objectives through conservation contracts and surprise budgets; the substrate only enforces compliance.
License
MIT — see LICENSE.