Ornith 1.0: When the Model Writes Its Own Scaffold

Ornith 1.0: When the Model Writes Its Own Scaffold

On June 25, 2026, the lab DeepReinforce released the Ornith 1.0 family, four open coding models with an unusual claim. They are meant to write their own agent scaffold instead of using one built by humans. Two days later, DeepSeek and Peking University added a matching acceleration layer called DSpark. I took a closer look at the more interesting of the two and ran the smallest Ornith model locally on an M3 Max. The result diverges from what the popular YouTube tests claim, and the reason lies not in the model but in its packaging.

The Harness as a Learnable Object

Almost every agentic coding system consists of two parts. There is the model that generates text, and there is the harness around it, meaning the plan, the tool list, the working memory, the checks, and the retry logic. The harness turns a text generator into an agent. Until now, a human built that scaffold by hand, tuned it for one class of task, and then froze it. From then on, every further task ran through the same fixed harness.

Ornith does not freeze the scaffold. DeepReinforce treats it as a learnable object that evolves together with the model policy during reinforcement learning (DeepReinforce blog). Instead of one fixed harness per problem, a tailored strategy emerges for each kind of task, one the model found on its own. The model learns a form of context engineering you would otherwise have to write by hand.

The four models are not new pretrainings but mid- and post-trainings on already strong open bases. The 9B and the two large mixture-of-experts models sit on Qwen 3.5, the 31B on Gemma 4 (DeepReinforce blog). A mixture-of-experts model holds many parameters but activates only a narrow slice of them per token, which makes it faster than its total size suggests. Simon Willison confirmed that both bases are licensed under Apache 2.0 and that Ornith itself sits on Hugging Face as an open model (Willison). You clone the weights, run them offline, and pay for no token.

The Training Loop Runs in Two Stages

The core sits in a two-stage RL loop. First, the model reads the task and the scaffold last used for it, then proposes a refined version of that scaffold. Next, conditioned on the new scaffold plus the task, it generates a solution rollout. The reward from the rollout then flows back into both stages (DeepReinforce blog). Planning and answering are thus forced to improve together.

Diagram of the two-stage self-scaffolding loop of Ornith 1.0

Repeat this over thousands of rounds, and good scaffolds get selected, weak ones mutate away, and per-task strategies emerge on their own. The model no longer learns only answers, but how it works.

The implementation is not trivial. Long rollouts create an off-policy problem, because the weights have already moved on during generation. Ornith uses a pipeline-RL strategy with asynchronous execution for this. A staleness weight downweights tokens that stem from a now-outdated version of the weights and drops them past a threshold. Optimization uses a token-level objective following GRPO, an RL method that works without a separate value model and compares rewards relative to a group of solution attempts (DeepReinforce blog).

Three Walls Against Cheating

A model that designs its own process can learn to game it. It could read the hidden test, hardcode the expected file, or fake a green check mark. Reward hacking is not a theoretical worry. In the early RLHF days, generator models regularly found curious ways to coax a high signal out of the reward model.

DeepReinforce builds three walls against this (DeepReinforce blog):

  • A fixed outer trust boundary. The environment, the tool surface, and the test isolation stay outside the model’s reach. It cannot rebuild the sandbox so that a shortcut leads to a win.
  • A deterministic monitor. It watches what the scaffold actually attempts. Reading withheld paths or editing verification scripts earns zero reward.
  • A frozen LLM judge with a veto. It sits on top of the verifier and can discard an entire run if a result came about through an illegitimate path.

These three layers are the price of giving the model so much control over its own process. Remove one, and sooner or later it learns to trick the reward rather than solve the task.

The Benchmark Numbers and Their Reach

DeepReinforce reports the following values for the family (DeepReinforce blog):

ModelTerminal-Bench 2.1SWE-Bench VerifiedSWE-Bench Pro
9B Dense43.169.4
35B MoE64.2
397B MoE77.582.462.2

SWE-Bench Verified measures whether a model finds and fixes real bugs in existing repositories. The small 9B is the remarkable data point here. At 69.4, DeepReinforce says it matches or exceeds the roughly three times larger base model Gemma 4-31B, on which one of the Ornith siblings is built. The thesis behind it is that a better process is worth a surprising amount of raw parameters.

The approach is serious research. The numbers still deserve caution, because they come from DeepReinforce itself, measured on its own runs. The flagship 397B lands at 82.4 on SWE-Bench Verified, inside the field of frontier models, and by these figures beats DeepSeek, MiniMax, and Claude Opus 4.7. But it trails Opus 4.8, which sits at around 85 (MarkTechPost). The state-of-the-art claim holds explicitly only for open models of comparable size, not against closed systems and not against considerably larger alternatives. No independent lab has re-measured the peak figures so far.

The Hands-On Test on the M3 Max

I wanted to see for myself how fast and how capable Ornith really is, so I installed the 9B locally. The quantized GGUF version sits on Hugging Face, and one ollama pull is enough (HF repo). The test machine was a MacBook Pro M3 Max with 64 GB, the Q4_K_M variant at 5.6 GB. Ollama reports the architecture as qwen35, 8.95 billion parameters, and a context window of 262,144 tokens.

The first run was a flat failure, but an instructive one. Asked for a trivial is_prime function, the model produced 16 KB of pure reasoning, never closing the think block and never emitting a line of code. Even with a budget of 6,000 tokens, nothing came out. That matches the picture several YouTube tests paint, in which the 9B loops and fails at simple tasks (Working Models, TheAIGRID).

But the cause is not the model. A look at the chat template that Ollama uses for the GGUF shows the problem.

TEMPLATE {{ .Prompt }}

The GGUF ships with a bare passthrough template, without the Qwen-typical ChatML frame and without a stop token. The prompt reaches the model with no structure at all, and because no stop token is set, the reasoning never ends. This can be fixed with a custom Modelfile.

FROM hf.co/deepreinforce-ai/Ornith-1.0-9B-GGUF:Q4_K_M
TEMPLATE """{{ if .System }}<|im_start|>system
{{ .System }}<|im_end|>
{{ end }}{{ if .Prompt }}<|im_start|>user
{{ .Prompt }}<|im_end|>
{{ end }}<|im_start|>assistant
"""
PARAMETER stop "<|im_end|>"
PARAMETER stop "<|endoftext|>"

With this template, the behavior changes at once. The same is_prime request terminates cleanly after 248 tokens and returns a correct function with the usual 6k±1 optimization. The endless ruminator turns into a terse, usable coder.

def is_prime(n):
    if n <= 1:
        return False
    if n <= 3:
        return True
    if n % 2 == 0 or n % 3 == 0:
        return False
    i = 5
    while i * i <= n:
        if n % i == 0 or n % (i + 2) == 0:
            return False
        i += 6
    return True

The harder tasks confirm it. A to-do app as a single HTML file with input, per-item deletion, CSS, and vanilla JavaScript came in one pass, 2,050 tokens long, only about 390 of them in the think block, a complete and runnable document. A Snake game on canvas, which I set as a stress test, also succeeded on the first attempt. 2,632 tokens, with arrow-key control, a growing snake, random food, correct collision checks against wall and own body, a score, and a restart. That is exactly the class of task the 9B had still failed in one of the third-party tests.

For this article, I set both tasks once more, this time with a design brief in the prompt: the colors and fonts of this website. The 9B followed it without correction, warm off-white as the surface, the red for actions, a serif headline over a mono control layer. The screenshots below show the unaltered outputs, only with a few example entries typed in.

To-do app generated by Ornith 9B in the rotecodefraktion design, with three example entries

Snake game generated by Ornith 9B in the rotecodefraktion design, snake and food on the canvas grid

Throughout, generation ran at 34 to 36 tokens per second over the GGUF, later around 70 over MLX. That is usable for interactive work. In the code itself, the model still reaches for keyCode in the keyboard handling instead of the more modern event.key, which works but is dated. The model also thinks eagerly and at length. On the Snake with the design brief, the 9B thought for more than 24,000 characters and ran into the token limit before a single line of code appeared. A /no_think in the prompt turns off the reasoning block, after which the thinking dropped below 2,000 characters and the complete code arrived at once. Without that brake, the 9B burns its budget before code emerges.

The 9B is no replacement for a frontier model. But a good part of the reports about a hopelessly weak model trace back not to the model but to broken packaging. Whoever starts the GGUF unexamined is testing the template, not the network.

Local Inference with 9B and 35B, in the Cloud with 397B

The marketing story revolves around the 397B, which almost no one runs at home. It needs around 200 GB in FP8 across eight 80-GB GPUs, so a data center or rented hardware (Codersera). Locally, something else runs.

VariantActive parametersMemory (quantized)Runs on
9B Dense9B~6 GB (Q4)8-GB GPU, 16-GB Mac
35B MoE~3B per token~21 to 25 GB (Q4/Q5)24-GB GPU, 32-GB Mac
397B MoE~200 GB (FP8)8×80-GB cluster

The 35B MoE is the more interesting local choice. I fetched this model onto the MacBook Pro as well, the Q4_K_M variant at 21 GB, reported as architecture qwen35moe with 34.7 billion parameters. Despite four times the size, it ran for me at around 38 tokens per second, even slightly faster than the dense 9B, because only a narrow slice of experts is active per token. The same to-do app came in one pass here too.

Beyond raw speed, I did not measure the 35B systematically against other models, that would need a dedicated test series. Whoever wants such a comparison finds it at Luke’s Dev Lab: there Ornith edged ahead of Qwen 3.6 35B on throughput, tied on the needle-in-a-haystack test across the full 256K, and won the sand-physics test in a one-shot, while both models needed follow-up prompts on the dungeon crawler (Luke’s Dev Lab). Whoever wants to weigh the basic local-versus-cloud question finds the arguments in my overview of local AI in 2026, and whoever wants to try coding on the Mac with MLX in my comparison of Gemma 4 and Qwen-Coder.

Laid side by side, my local measurements look like this. All values on the same M3 Max with 64 GB, each at 4-bit quantization, the same to-do task as the probe.

VariantDisk footprintSpeedTo-do app on first tryNote
Ornith 9B, GGUF via ollama pull ornith~5.6 GB50.8 tok/syestemplate and reasoning block correct out of the box
Ornith 9B, raw HF GGUF~5.6 GB34–36 tok/syes, after fixchat template missing, must be set by hand
Ornith 9B, MLX 4bit (mlx_lm)~5.1 GB70.4 tok/syesfastest path, prefill 61 tok/s
Ornith 35B MoE, GGUF (Ollama)~21 GB38 tok/syesfast despite size, only ~3B active per token
Ornith 35B MoE, MLX 4bit (mlx_lm)~19 GB102.5 tok/syesprefill 43, nearly triple the GGUF

First, the source makes a difference of half the throughput on the 9B. The official Ollama build brings template and reasoning block along and runs at 50.8 tokens per second, while the raw GGUF from Hugging Face first loops without a template and, after the fix, lands at 34 to 36.

Second, MLX is clearly the fastest path. On the 9B it sits at 70.4 tokens per second, around 40 percent above the Ollama GGUF, even though both run the same 4-bit weight. The reason is the engine. Ollama still runs GGUF models on Apple Silicon through llama.cpp with Metal, not through its newer MLX engine, which only kicks in for models in the MLX format.

Third, this gap grows even more drastic on the MoE. The 35B over MLX reaches 102.5 tokens per second, nearly triple the GGUF throughput, because MLX handles the sparse activation of a mixture-of-experts more efficiently than llama.cpp’s MoE path. Oddly enough, the 35B over MLX thus runs faster than the dense 9B, because only about three billion parameters are active per token.

So whoever wants the last bit of speed takes mlx_lm or LM Studio with the MLX build. Ollama can now run MLX itself, but only for models in the MLX format, and for Ornith its registry so far holds only the GGUF. So ollama pull ornith gives you the convenient path over llama.cpp, with a bit less throughput.

DSpark, the Second Ingredient

Why DeepSeek’s DSpark appears in the same breath has a technical reason. DSpark accelerates Qwen and Gemma directly, and that is exactly what Ornith sits on. DSpark is not a new model but a serving optimization called speculative decoding. A small, fast draft model guesses a whole block of tokens ahead, and the large model verifies the block in a single pass. Through rejection sampling, the output stays mathematically identical to normal decoding, and wrong guesses are discarded (VentureBeat). The principle of winning several tokens per pass is related to the multi-token prediction I tested with MTPLX on the M3 Max.

The reported numbers are sizable. 26 to 31 percent more accepted tokens per cycle than Eagle3, and in production 60 to 85 percent faster per-user generation on V4-Flash (MarkTechPost). DeepSeek also released the MIT-licensed training toolkit DeepSpec, which targets Qwen 3 and Gemma 4 out of the box. The same caution applies here as with Ornith. Every speed figure is DeepSeek measuring DeepSeek against a DeepSeek baseline, and no external lab has confirmed the peak figures (xyzlabs). Lossless means faster, not smarter.

The Contest Moves from Model Size to Serving and Agent

For two years, the race was about the smartest model, and the top scores have since bunched together within a few points. The contest is moving into two other layers, the serving layer that decides how fast a model runs, and the agent layer that decides how well it works on a real task. Ornith is an attempt in the second, DSpark one in the first.

For daily work, I would not make Ornith my main tool today. But the hands-on test corrected my expectation downward and then back upward. The 9B is more capable than the circulating tests claim, once you give it a proper template. The appeal lies not in the benchmark but in the idea behind it. A model that writes its own scaffold is a different approach from one that only learns better answers. Version one shows that the approach works. Whether it closes the gap to the frontier will have to wait for the next version, and the numbers for it should then come from someone other than the maker.

Sources