Mark 1x-9B: a 9B model that answers in interfaces
Our first open model. It decides when a question deserves an interface, then writes one that renders on the first try — no schema, no constrained decoding, nine billion parameters. Weights, evaluation harness and every raw output are public.
Most answers are paragraphs because that is all a language model can emit. Mark 1x-9B answers in interfaces. It speaks a directive language we designed: thirteen tagged, strict-JSON blocks — scene, chart, quiz, flashcards, simulation, explore, steps and the rest — that a renderer turns into working UI. A 3D molecule you can rotate. A chart with the real numbers in it. A quiz that marks itself.
Any model can fill in a JSON schema when you clamp one onto its decoder. The hard part is deciding that a question deserves an interface at all, then writing that interface correctly on the first attempt with nothing constraining the output. That is the skill we built, and today we are releasing the result openly — weights, evaluation harness, raw generations, the lot.
- Valid on the first try 84% of the time, with no schema and no constrained decoding anywhere in the loop. Our first working checkpoint scored zero.
- Restraint at 87%: it answers in plain prose when an interface would not help, which is the half of the problem that a model taught to draw usually fails.
- Multi-turn editing at 12.3 of 14: it changes an artifact already on the screen instead of redrawing it from scratch.
- Reasoning intact: AIME 2026 83.3, AIME 2025 78.3, MMLU-Pro 80.6, GPQA Diamond 79.4 — competitive with open models a full size class larger.
- Nine billion parameters, 262,144 tokens of context, one GPU.
| Benchmark | Mark 1x-9B9B | Gemma 4 12B12B | Ornith 1.5-9B9B | Nemotron Nano9B v2 | ZAYA1-8B8B MoE |
|---|---|---|---|---|---|
| Instruction following | |||||
| IFEvalprompt-level strict | 84.7 | 97.2 | – | 90.3 | – |
| IFBenchprompt-level loose | 56.0 | – | – | – | – |
| Knowledge and reasoning | |||||
| MMLU-Pro | 80.6 | 77.2 | – | – | – |
| GPQA Diamondavg@4 | 79.4 | 78.8 | 86.4 | 64.0 | – |
| Mathematics | |||||
| AIME 2025avg@2, no tools | 78.3 | – | – | 72.1 | – |
| AIME 2026avg@2, no tools | 83.3 | 77.5 | – | – | 89.1 |
| HMMT Feb 2026avg@2, no tools | 63.6 | – | – | – | 71.6 |
| Directive output | |||||
| Directive validityschema-free, first try | 84.0 | – | – | – | – |
| Restraintno directive when none helps | 87.0 | – | – | – | – |
| Multi-turn artifact editsout of 14 | 12.3 | – | – | – | – |
An em-dash means that model publishes no number for the benchmark, which is not the same as scoring zero. Our rows are self-measured with every raw generation published; peer rows are vendor-reported. Protocol at the end of the post.
Answers as interfaces
A directive is a tag wrapping strict JSON, and the envelope has a fixed order: reasoning, then prose, then the directive last. The prose is a normal answer. The directive is what the renderer draws. A model that gets the order wrong, or emits a directive with one misplaced comma, produces a broken screen rather than a slightly worse paragraph, which is why validity on the first try is the number that matters and why we measure it with nothing forcing the output into shape.
The harder half of the skill is restraint. Most questions do not want a chart. A model that has learned to draw will draw everything, so the training data is deliberately weighted with prompts where the correct answer is plain prose, and we score that separately: 87% of the time the model correctly emits no directive at all, up from 75% for the base.
Frontier assistants emit interactive artifacts too, behind an API you cannot inspect, at a size you cannot host. Doing it at nine billion parameters, on one GPU, with nothing forcing the output into shape, is the part we think is new — and we published the harness so you can check the claim rather than trust it.
How it was trained
The obvious approach failed, and the way it failed told us what to do. Five hundred and fifty-five hand-built examples moved the training loss and changed nothing about the behaviour: schema-free validity sat at zero. The model already had a deep prior for angle-bracket tags, because that is the shape of its native tool-call format, and a few hundred examples were pushing against that gradient instead of steering it.
What worked is a method we have not seen published elsewhere, and it is the reason this model exists. Take a 27-billion-parameter teacher, hand it the complete directive schema, and let it answer 3,342 prompts spanning every directive kind, multi-turn edits and deliberate prose-only cases. Run every single candidate through the exact validator the production renderer uses, and keep only the ones that parsed and drew. Then delete the schema from the prompts before training. The student never sees the instruction sheet — it has to infer the entire format from the question, which is precisely the situation it faces at inference time. Nine hundred pages of scaffolding, thrown away on purpose, so the skill has to live in the weights.
The final set is 1,396 rows and three epochs. That is the whole recipe: a rank-32 adapter, merged to bf16, on hardware you could rent for the price of a laptop.
One finding is worth publishing on its own. The base is a hybrid architecture — eight of its 32 layers use full attention, the other 24 use linear attention with entirely different projection names. Our adapter covers the MLP path in all 32 layers but the attention path in only eight, so three-quarters of the network's attention-equivalent weights were never touched. The directive skill therefore lives almost entirely in the MLPs. If you are training small models on structured output, that is where we would tell you to spend your rank.
The trade, and what comes next
Every specialised model pays for its speciality somewhere, and we would rather tell you where than let you discover it. Ours is exact-text compliance. IFEval lands at 84.7, and the shortfall is concentrated, not diffuse: repeat-this-N-times constraints score 0%, custom-format constraints 27%, exact word counts 42%, exact ratios 45%, while ordinary format, count and sentence constraints hold between 71 and 78%. If your product hangs on counting words exactly, wait for the next checkpoint. The pattern says targeted replay data rather than a lost capability, and it is first on the roadmap.
GPQA Diamond sits at 79.4, avg@4 across all 198 questions, with 1.5 points of spread and 136 questions answered identically in every pass. Teaching one new skill costs a little general reasoning; that is the measurement, published rather than buried.
Others lead in places. ZAYA1-8B is ahead on AIME 2026 and HMMT Feb 2026 with a fraction of the active parameters, and Ornith 1.5-9B leads GPQA Diamond at the same size. Both are excellent models, and neither will draw you an interface. We optimised for the thing nobody else at this size does, and we are not going to pretend the general-purpose crown came with it.
Two things to know before you build. Free-rein tool use makes this model measurably worse — IFEval 84.7 to 77.3, MMLU-Pro 80.6 to 71.9, both maths benchmarks down more than twenty points — so put a harness in front of it rather than handing it tool_choice auto and walking away. And identity is barely trained, by design: with no system prompt the model answers from its pretraining priors, so always set one.
Running it
You run this one yourself — there is no waitlist and no hosted key to wait for. The architecture is unmodified, so it loads on vLLM, SGLang and transformers with no porting work and no upstream patch, and it carries the full 262,144-token context, which we load-tested at 48 concurrent requests on a single A100-80GB. Install vLLM, run the command below, and you have an OpenAI-compatible server on port 8000. These are the exact flags we serve with:
vllm serve saanora/mark-1x-9b \
--served-model-name mark-1x-9b \
--max-model-len 262144 --dtype bfloat16 \
--reasoning-parser qwen3 \
--enable-auto-tool-choice --tool-call-parser qwen3_coder \
--structured-outputs-config.backend auto \
--structured-outputs-config.enable_in_reasoning=False \
--enable-prefix-cachingOne flag there matters more than the rest: leave enable_in_reasoning off. Turn it on and every request carrying a response_format comes back with a null content field and the whole answer buried in the reasoning field. We ran that misconfiguration ourselves for a day before we caught it, so you do not have to. Thinking is on by default and switches off per request with a single flag, and the reasoning always arrives in its own field, separate from the answer — show it to your users or drop it.
Guaranteeing a valid directive
Unconstrained validity is 84%, which is remarkable for a model this size and still not 100%. When your product already knows which kind of interface it wants, you can have the rest. Point response_format at the per-kind strict schema that ships with the weights and validity stops being a property of the model and becomes a property of the decoder. The example below talks to the server you started above, so change nothing but the prompt to try it:
import json
from openai import OpenAI
client = OpenAI(base_url="http://localhost:8000/v1", api_key="-")
scene = json.load(open("grammars/schemas/strict/scene.schema.json"))
r = client.chat.completions.create(
model="mark-1x-9b",
messages=[{"role": "user", "content": "A 3D scene of benzene, 6-8 objects."}],
extra_body={"chat_template_kwargs": {"enable_thinking": True}},
response_format={"type": "json_schema",
"json_schema": {"name": "scene", "schema": scene}},
)
print(r.choices[0].message.reasoning) # the thinking, kept separate
print(r.choices[0].message.content) # the scene JSONThat constrains only the final, post-thinking output, so you get the bare JSON body and supply the envelope yourself. When you want the model to keep deciding whether an interface is warranted at all, there is a full-envelope grammar next to the schemas. The strict schemas are deliberately tighter than the renderer needs: a scene containing one grey unlabelled cube will parse, but it is not a good answer, and the schema refuses it.
Take it
The weights are on Hugging Face and ModelScope under an open licence. No gate, no form, no waitlist. Alongside them: the full directive specification, the per-kind schemas and the envelope grammar, the benchmark protocol behind every number on this page, and the raw generations themselves, so you can re-run all of it instead of taking our word for any of it. Mark 1x-9B is built on top of Qwen3.5-9B and the attribution its licence requires travels with the weights in the NOTICE file.
Use it now, no GPU required
You do not need to download anything to put this to work today. Open the chat at saanora.com and ask Mark a question that deserves a diagram, a simulation or a quiz. Same directive language, same renderer, same answers-as-interfaces — free to start, nothing to install, and it works on the web, on Windows and on Android.
Then take the weights and build your own. That is the point of releasing them.
If you build something with this, we genuinely want to see it. Post it and tag @SaanoraLabs on X, or send it to support@saanora.com. We read everything, and the best of it will shape what the next checkpoint learns.
Evaluation notes
- Measured 2026-09-03. Thinking on, temperature 1.0, top-p 0.95, top-k 20, presence penalty 1.5 (temperature 0.6 for coding), 32,768-token output cap. One sample per prompt, except GPQA Diamond at avg@4 and the maths benchmarks at avg@2.
- IFEval is reported prompt-level strict, the strictest of the three variants. The same runs score 87.2 prompt-level loose and 88.7 instruction-level strict.
- Directive validity, restraint and multi-turn edits come from our own harness, run with no schema and no constrained decoding. The harness, the prompts and every raw generation are published with the weights — the full protocol, including the benchmarks we chose not to report and why, is in the model card.
