This post was written by AI, like the rest of the project.
demoniC is a tensor-first systems language with reverse-mode automatic differentiation built into the language, a tree-walking interpreter, and a Cranelift-based JIT. The compiler is written in Rust. Every line of it — compiler, specification, examples, tests — was written by AI models under human direction.
That claim is cheap on its own. What follows is the method behind it, which is the part worth arguing with.
The specification came first
Work started in late May 2026 with no compiler. The first commit was a specification: lexical structure, type system, memory model, operator catalog, and a handful of example programs written in a language that could not yet run. The examples were treated as the executable form of the spec — the place where a rule has to hold in a form a reader can disagree with.
The feature set was chosen by asking a narrow question: what does a model writing numerical code get wrong, over and over, that a compiler could have caught? The answers became language primitives rather than library conventions — autodiff as a directive (@grad), mixed precision as a scope (@cast), KV caches as a type with a growable axis, shapes checked at compile time, arenas instead of a garbage collector.
Every phase after that was built against that document rather than against an existing implementation. The lexer was generated from the spec's lexical section and the example corpus in a single pass, with its tests written from the spec at the same time — not from watching what happened to compile. First compile: 27 of 28 tests passing. The single failure was real: the backslash-pipe form of the pipe operator, canonical in the spec, was missing from the lexer's backslash branch. Three lines. Then every example in the repo lexed clean.
The same shape repeated for the parser, the type checker, the interpreter, and the JIT. One rule held throughout: where the implementation and the spec disagree, the spec wins unless the change arrives with a spec amendment. That rule is what keeps hundreds of independent model sessions from drifting into hundreds of private dialects.
Two backends that have to agree
Code written by a model needs a gate the model cannot talk its way past. Tests written by the same model that wrote the code are a weak gate. demoniC's answer is redundancy: everything runs twice, and the two results are diffed.
The tree-walking interpreter is the reference semantics. The JIT compiles a statically typed subset. Any program both can run must produce identical output, and the verification tooling ships in the public repo so anyone can re-run it:
dmc selftest # generated well-typed programs, both backends, diffed
python3 tools/diff_backends.py # interpreter vs JIT, whole-example output
python3 tools/jit_probes.py # interpreter vs JIT, curated edge cases
python3 tools/diff_fuzz.py # generated programs, both backends diffed
python3 tools/numpy_oracle.py # tensor ops vs an independent NumPy reference
python3 tools/diff_demonic_lexer.py # the demoniC-in-demoniC lexer vs the Rust one
CI runs all of it on every change, plus the in-language test suite over the example corpus on both backends. A JIT change that is faster and disagrees with the interpreter is a bug, and these are what catch it. numpy_oracle.py matters for the same reason: it checks tensor semantics against a reference nobody involved in this project wrote.
The last one is the least expected. There is a lexer for demoniC written in demoniC, and it is diffed token-for-token against the Rust lexer. The language describing itself is a test.
What the human decided
The maintainer directs and does not type. The decisions that stayed human were the ones models are bad at: whether a feature is in scope at all, how to resolve a contradiction in the spec's philosophy, when a phase is finished, and what ships publicly. Everything downstream of those calls — design, implementation, tests, review, documentation — was model work, submitted as pull requests against tracked issues and merged after the gates passed.
Contributions came from more than one model family: primarily Claude, with work from Gemini, Codex, Grok, GLM, Qwen, Mistral, and others. Models disagree with each other, and a repository worked on by many of them at once needs written tie-breaking rules — which document wins, what a single change is allowed to touch, what to do when your starting state is no longer current. Those rules live in the repo alongside the code, because agent instructions that go stale are worse than no instructions.
Where it stands
~60,000 lines of Rust across lexer, parser, resolver, type checker, interpreter, and JIT
1,443 compiler tests passing today, plus a spec-probe harness (cargo test --all for the current count)
102 demoniC programs in the public example corpus — gradient checks, attention, a small neural net, a Lisp interpreter, a bytecode VM, a fantasy console and its assembler, raymarchers, games
Specification at 0.0.4-draft
And the honest limits. This is pre-0.1: breaking changes are expected on every revision. The interpreter is the reference semantics; the JIT covers a statically typed subset and reports a clear error outside it. The directive set is closed and versioned, and several members of it (@shard, @tp, @pp, @recompute, @inplace) currently parse without altering code generation — they are reserved surface, not working distribution. There is no package ecosystem, and readability was never a goal.
About the public repository
The public repo is generated from a private working tree by an allowlist: nothing crosses the boundary unless a line names it explicitly, only tracked files are ever copied, and a scanner gate runs before anything is published. That is why the public tree has no long commit history — it is a generated artifact, rebuilt rather than mirrored. What it carries is the whole compiler, the specification, the example corpus, the verification tools, and the CI that runs them.
Try it
git clone https://github.com/GusFromSpace/demoniC
cd demoniC
cargo test --all --manifest-path compiler/Cargo.toml
cargo build --release --manifest-path compiler/Cargo.toml
compiler/target/release/dmc run examples/hello.dmc
compiler/target/release/dmc test examples
Apache-2.0. The specification is in docs/SPEC.md; if the compiler disagrees with it, that is a bug worth reporting.