A CPU-first tensor/autograd runtime and LLM inference engine — one program, in one language. No graph compiler, no lazy evaluation: what you write is what runs, in the order you wrote it. And eager doesn't mean slow — on measured CPU shapes it matches or beats llama.cpp.
Operations name the axes they act on, and broadcasting aligns axes by name, never by position. The tag algebra is comptime-only data — it compiles down to stride math with zero runtime tagging cost, and a misuse is a compile error, not a silent transpose.
x.dot(&ctx, &w, .in) — contract the axis called .in. No axis bookkeeping, no guessing which dimension is which.The idea pays off hardest in einsum: operands already carry named axes, so there is no "gid,jd→gij" mini-language to parse at runtime — the output tag tuple is the whole equation, and a tag that exists in no operand is a compile error.
A tensor is a value handle over a reference-counted buffer. deinit isn't a naive free — it's the recycling driver: the refcount hits zero, the buffer returns to the pool, and the next same-size op gets the same address back, keeping the hot working set warm in cache.
Views are refcounted aliases — a zero-copy narrow outlives its parent safely. No arena to reset, no garbage collector to chase. An idiomatic defer x.deinit() gives an O(1) working set within a forward pass; training holds exactly what backward needs, because operand views bump refcounts. An arena allocator was evaluated and rejected — the adjudication is on record in docs/MEMORY-MODEL.md.
Nothing records a tape and nothing builds a graph object: each result simply carries a pointer to the operation that produced it, so the dependency graph already exists in the values themselves. backward() discovers its topology by walking those pointers. A variable carries that state; a constant doesn't — and the call sites are identical, so training and inference take the same kernel path and produce identical values.
deinit on it becomes a safe no-op, the whole graph lives until backward() — then one close releases the step.Backward is concurrent with no persistent engine and no trace: each node carries an atomic dependency counter and fires on a bounded worker pool when it drains. The loop closes on CPU — LoRA fine-tune a quantized GGUF, merge, re-quantize, and the exported GGUF loads and answers in llama.cpp. Optimizers (SGD / AdamW / Muon / APOLLO) are golden-parity-tested against their references.
Mainstream GPU stacks run on whole-graph machinery: fusion passes, static memory plans, captured launch sequences. Fucina builds no such graph — so there is nothing to hand a GPU, and that is the choice: on CPU, per-op dispatch costs next to nothing and kernels specialize at compile time — NEON/dotprod on Apple Silicon, AVX2/AVX-VNNI on x86 — as if -march=native were always on.
CPU-first is the destination, not a stage on the way to somewhere else. The known price: without a graph, a GPU helps only at the op seam — Fucina will never chase TensorRT-class GPU throughput, and says so.
The runtime grows through what it runs, and every family is validated against its reference implementation first: token-ID-exact tokenizers, logit-parity oracles vs llama.cpp, byte-exact quantization encoders, byte-identical GGUF re-emit. Parity first, speed second — in that order.
--moe-stream pages routed experts from disk, bit-identical to the resident path — the 142 GB Qwen3-235B and the 164.6 GB DeepSeek V4 Flash decode on a 64 GB machine.On top: lossless draft-model-free speculative decoding (up to 2.3×), batch-N multi-stream decode (3.2× aggregate at 8 streams), JSON-schema / grammar-constrained output, and an OpenAI-compatible server.
GradState needed.fucina.es trains with forward passes only — a faithful reimplementation of ES-at-scale, kept deliberately vanilla. Perturb the parameters, score each member with one reward, and step toward the members that did better.
Because the signal is a scalar, it reaches places a gradient can't: non-differentiable rewards, and quantized ternary weights that have no gradient at all. Noise is never stored — every perturbation regenerates from (seed, iteration, member), O(1) memory beyond the parameters. zig build es-spirals trains from scratch with no backward anywhere; zig build es-finetune fine-tunes a real quantized GGUF this way, LoRA-only or full-parameter.